nut-2.8.3/0000755000200500020050000000000015001555413007316 500000000000000nut-2.8.3/LICENSE-GPL20000644000200500020050000004310314553676503010765 00000000000000 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. nut-2.8.3/scripts/0000755000200500020050000000000015001555412011004 500000000000000nut-2.8.3/scripts/Solaris/0000755000200500020050000000000015001555412012420 500000000000000nut-2.8.3/scripts/Solaris/nut.in0000755000200500020050000000271314777534446013533 00000000000000#!/sbin/sh #init.d script to start nut services NUT_DIR="@prefix@" NUT_SBIN_DIR="${NUT_DIR}/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" CONFIG="@CONFPATH@/nut.conf" # We anticipate some tighter integration with SMF later: #NUT_QUIET_INIT_UPSNOTIFY=true #export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" fi ups_stop () { pkill -n upsmon pkill -n upsd LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsdrvctl" stop > /dev/null 2>&1 } ups_start () { if [ "$MODE" = "none" ];then echo "No NUT mode set, not starting anything" >&2 exit 1 fi if [ "$MODE" != "netclient" ] ; then LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsdrvctl" start #> /dev/null 2>&1 LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsd" #> /dev/null 2>&1 fi LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsmon" #> /dev/null 2>&1 } case $1 in 'start') ups_start ;; 'stop') ups_stop ;; 'restart') ups_stop while pgrep upsd > /dev/null do sleep 1 done ups_start ;; 'poweroff') LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsmon" -K >/dev/null 2>&1 if [ $? = 0 ]; then echo "Shutting down the UPS(es) ..." echo "WARNING: UPS shutdown is currently disabled, please uncomment it in the init-script if desired" >&2 #${NUT_SBIN_DIR}/upsdrvctl shutdown fi ;; *) echo "" echo "Usage: '$0' {start | stop | restart }" echo "" exit 64 ;; esac exit $? nut-2.8.3/scripts/Solaris/preproto.pl.in0000755000200500020050000000241314553676503015177 00000000000000#!/usr/bin/env perl $temp = "prototype1"; $prototype="prototype"; $pkginfo = "pkginfo"; $checkinstall = "checkinstall"; $preinstall = "preinstall"; $postinstall = "postinstall"; $preremove = "preremove"; $postremove = "postremove"; $nutuser = "@RUN_AS_USER@"; $nutgroup = "@RUN_AS_GROUP@"; open (PREPROTO,"< $temp") || die "Unable to read prototype information ($!)\n"; open (PROTO,"> $prototype") || die "Unable to write file prototype ($!)\n"; print PROTO "i pkginfo=./$pkginfo\n"; print PROTO "i checkinstall=./$checkinstall\n"; print PROTO "i preinstall=./$preinstall\n"; print PROTO "i postinstall=./$postinstall\n"; print PROTO "i preremove=./$preremove\n"; print PROTO "i postremove=./$postremove\n"; while () { # Read the prototype information from /tmp/prototype$$ chomp; $thisline = $_; if ($thisline =~ " prototype1 ") { # We don't need that line } elsif ($thisline =~ "^[fd] ") { # Change the ownership for files and directories ($dir, $none, $file, $mode, $user, $group) = split / /,$thisline; print PROTO "$dir $none $file=$file $mode $nutuser $nutgroup\n"; } else { # Symlinks and other stuff should be printed as well ofcourse print PROTO "$thisline\n"; } } #print PROTO "f $none nut $mode root $nutgroup\n"; close PROTO; close PREPROTO; nut-2.8.3/scripts/Solaris/nut-server.xml.in0000644000200500020050000001125414777767434015640 00000000000000 nut-2.8.3/scripts/Solaris/svc-nut-monitor.in0000755000200500020050000000245614777534446016015 00000000000000#!/sbin/sh # Trivial (better is yet to come) SMF method script to start nut services # Adapted for OpenIndiana userland from init.d script template in NUT sources # Adaptation copyright (C) 2016-2017 Jim Klimov if [ -z "$SMF_FMRI" ]; then echo "$0 must be called in SMF context!" >&2 exit 1 fi # smf(5) . /lib/svc/share/smf_include.sh || exit prefix="@prefix@" NUT_DIR="@prefix@" NUT_SBIN_DIR="${NUT_DIR}/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" NUT_RUN_DIR="@ALTPIDPATH@" CONFIG="@CONFPATH@/nut.conf" NUTUSER="@RUN_AS_USER@" NUTGROUP="@RUN_AS_GROUP@" # We anticipate some tighter integration with SMF later: #NUT_QUIET_INIT_UPSNOTIFY=true #export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" fi ups_start () { if [ "$MODE" = "none" ];then echo "No NUT mode set, not starting anything" >&2 exit $SMF_EXIT_ERR_CONFIG fi # Default rights inspired by NUT scripts/Solaris/postinstall.in mkdir -p "@PIDPATH@" # (for privileged processes) mkdir -p "$NUT_RUN_DIR" && \ chown "root:$NUTGROUP" "$NUT_RUN_DIR" && \ chmod 770 "$NUT_RUN_DIR" \ || exit $SMF_EXIT_ERR_FATAL LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsmon #> /dev/null 2>&1 } case "$1" in 'start') ups_start ;; *) echo "" echo "Usage: '$0' {start}" echo "" exit $SMF_EXIT_ERR_CONFIG ;; esac exit $? nut-2.8.3/scripts/Solaris/pkginfo.in0000644000200500020050000000073214777767434014363 00000000000000PKG="NUT" NAME="Network UPS Tools" ARCH="@target_cpu@" VERSION="@PACKAGE_VERSION@" CATEGORY="application" VENDOR="@NUT_WEBSITE_BASE@" EMAIL=" " PSTAMP=" " DESCRIPTION="Network UPS Tools (NUT) is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes." BASEDIR="@prefix@" CLASSES="none" nut-2.8.3/scripts/Solaris/precheck.py.in0000755000200500020050000000607014777767434015145 00000000000000#!@PYTHON@ import sys if sys.version_info >= ( 2, 6 ): import subprocess p = subprocess.Popen(["uname", "-s"], stdout=subprocess.PIPE) platform = p.communicate()[0] if p.returncode != 0: raise Exception("FAILED to get platform from 'uname -s'!") p = subprocess.Popen(["uname", "-p"], stdout=subprocess.PIPE) architecture = p.communicate()[0] if p.returncode != 0: raise Exception("FAILED to get architecture from 'uname -p'!") else: import commands platform = commands.getoutput('uname -s') architecture = commands.getoutput('uname -p') # Newer python makes this a binary byte stream, convert into string: if platform is not str: platform = platform.decode('utf-8') if architecture is not str: architecture = architecture.decode('utf-8') # Strip end-of-line, if present: platform = platform.strip() architecture = architecture.strip() target_os='@target_os@'.lower() target_cpu='@target_cpu@'.lower() # checkinstall script creation fp=open("checkinstall","w") # Note: same arch is relevant for different bitnesses that # can be discerned via `isainfo` further (if ever needed) fp.write("#!/bin/sh\n") fp.write("\nexpected_platform=SunOS\n") if platform == "SunOS" and architecture == "i386": fp.write("expected_architecture=i386\n") elif platform == "SunOS" and architecture == "sparc": fp.write("expected_architecture=sparc\n") else: sys.stderr.write("WARNING: Failed to detect expected_architecture! platform='%s' (expected 'SunOS') architecture='%s' (expected 'i386' or 'sparc')!\n" % (platform, architecture)) if 'solaris' in target_os or 'illumos' in target_os: if target_cpu == 'x86_64' or target_cpu == 'amd64': fp.write("expected_isa=amd64\n") elif target_cpu == 'i686' or target_cpu == 'i386': fp.write("expected_isa=i386\n") elif target_cpu == 'sparcv9': fp.write("expected_isa=sparcv9\n") elif target_cpu == 'sparcv7' or target_cpu == 'sparc': fp.write("expected_isa=sparc\n") else: fp.write("expected_isa=''\n") else: fp.write("expected_isa=''\n") fp.write("platform=\"`uname -s`\"\n") fp.write("architecture=\"`uname -p`\"\n\n") fp.write("if [ \"${platform}\" = \"${expected_platform}\" ]; then\n") fp.write("\tif [ \"${architecture}\" = \"${expected_architecture}\" ]; then\n") fp.write("\t\tif [ -n \"${expected_isa}\" ]; then\n") fp.write("\t\t\tfor I in `isainfo` ; do if [ \"${I}\" = \"${expected_isa}\" ]; then\n") fp.write("\t\t\t\techo \"Checkinstall complete\"\n") fp.write("\t\t\t\texit 0\n") fp.write("\t\t\tfi; done\n") fp.write("\t\t\techo \"This is not a compatible Solaris machine: architecture='${architecture}' expected_architecture='${expected_architecture}' expected_isa='${expected_isa} (local isainfo=`isainfo`)'\"\n") fp.write("\t\t\texit 1\n") fp.write("\t\telse\n") fp.write("\t\t\techo \"Checkinstall complete\"\n") fp.write("\t\t\texit 0\n") fp.write("\t\tfi\n") fp.write("\tfi\n") fp.write("fi\n") fp.write("echo \"This is not Solaris machine: architecture='${architecture}' expected_architecture='${expected_architecture}' expected_isa='${expected_isa}'\"\n") fp.write("exit 1\n") fp.close() nut-2.8.3/scripts/Solaris/reset-ups-usb-solaris.sh.sample0000755000200500020050000000446314777534446020405 00000000000000#!/bin/sh # Copyright (C) 2020,2022 by Jim Klimov # Licensed according to GPLv2+ for the NUT project # If your USB connection on Solaris/illumos platform gets lost regularly # and might benefit from a harsh reconnection, consider customizing this # script (or its envvar args) to your deployment and adding to crontab: # 0,5,10,15,20,25,30,35,40,45,50,55 * * * * MODE=optional /etc/nut/reset-ups-usb-solaris.sh # Comment this away in your deployment after customizing defaults; # see NUT source docs/solaris-usb.txt for details: echo "WARNING: Script $0 was not yet tailored to this deployment!" >&2 ; exit # TODO: Parse CLI args? [ -n "$MODE" ] || MODE='always' # Defaults below come from documentation example: [ -n "$DEVICE" ] || DEVICE='innotech' [ -n "$CFGADM_APID" ] || CFGADM_APID="usb10/1" # Can specify '-' to not reload OS driver: [ -n "$UGEN_DRV_ID" ] || UGEN_DRV_ID='"usb665,5161.2"' if [ "$MODE" = optional ]; then if upsc "$DEVICE" 2>&1 | grep -i 'Data stale' ; then : ; else exit 0 ; fi fi # Sanity-checks command -v svcs && command -v svcadm || { echo "ERROR: This system does not have SMF tools?" >&2 ; exit 1; } command -v cfgadm || { echo "ERROR: This system does not have cfgadm?" >&2 ; exit 1; } # upsc and upsdrvctl below are rather informational command -v upsc && command -v upsdrvctl || echo "WARNING: This system does not have NUT tools?" >&2 date svcs -p "$DEVICE" ; upsc "$DEVICE" DO_SVC=false if [ "`svcs -Hostate "$DEVICE"`" = "online" ]; then DO_SVC=true svcadm disable -ts "$DEVICE" fi upsdrvctl stop "$DEVICE" || true echo "Soft-resetting connection of '${CFGADM_APID}':" cfgadm -lv "${CFGADM_APID}" cfgadm -c disconnect -y "${CFGADM_APID}" if [ "$UGEN_DRV_ID" != '-' ] ; then rem_drv ugen ; sleep 3 fi cfgadm -c configure -y "${CFGADM_APID}"; sleep 3 if [ "$UGEN_DRV_ID" != '-' ] ; then add_drv -i "$UGEN_DRV_ID" -m '* 0666 root sys' ugen fi sleep 3 cfgadm -lv "${CFGADM_APID}" if $DO_SVC ; then svcadm enable "$DEVICE" ; fi svcadm clear "$DEVICE" 2>/dev/null dmesg | tail -n 20 date svcs -p "$DEVICE" ; upsc "$DEVICE" || { \ COUNT=60 while [ "$COUNT" -gt 0 ] ; do COUNT="`expr $COUNT - 1`" if upsc "$DEVICE" 2>&1 | grep -Ei '^ups\.status:' >/dev/null ; then break ; fi sleep 1 done svcs -p "$DEVICE" ; upsc "$DEVICE" } nut-2.8.3/scripts/Solaris/Makefile.in0000644000200500020050000011577415001555011014417 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/Solaris VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_SOLARIS_SMF_TRUE@am__append_1 = check-local-solaris-smf @WITH_SOLARIS_PKG_IPS_TRUE@am__append_2 = package-solaris-ips @WITH_SOLARIS_PKG_SVR4_TRUE@am__append_3 = package-solaris-svr4 subdir = scripts/Solaris ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-driver-enumerator.xml nut-driver.xml \ nut-logger.xml nut-monitor.xml nut-server.xml nut.xml pkginfo \ svc-nut-server svc-nut-logger svc-nut-monitor precheck.py \ preinstall postinstall preremove postremove preproto.pl nut CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(solarisinitscriptdir)" \ "$(DESTDIR)$(solarissmfmethoddir)" \ "$(DESTDIR)$(solarissmfmanifestdir)" SCRIPTS = $(libexec_SCRIPTS) $(sbin_SCRIPTS) \ $(solarisinitscript_SCRIPTS) $(solarissmfmethod_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(solarissmfmanifest_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/nut-driver-enumerator.xml.in \ $(srcdir)/nut-driver.xml.in $(srcdir)/nut-logger.xml.in \ $(srcdir)/nut-monitor.xml.in $(srcdir)/nut-server.xml.in \ $(srcdir)/nut.in $(srcdir)/nut.xml.in $(srcdir)/pkginfo.in \ $(srcdir)/postinstall.in $(srcdir)/postremove.in \ $(srcdir)/precheck.py.in $(srcdir)/preinstall.in \ $(srcdir)/preproto.pl.in $(srcdir)/preremove.in \ $(srcdir)/svc-nut-logger.in $(srcdir)/svc-nut-monitor.in \ $(srcdir)/svc-nut-server.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = makelocal.sh precheck.py.in preproto.pl.in README.adoc \ reset-ups-usb-solaris.sh.sample PROTOTYPE_DIR = $(DESTDIR)@prefix@ SOLARIS_CHECK_TARGETS = $(am__append_1) SOLARIS_SMF_MANIFESTS = \ nut.xml \ nut-server.xml \ nut-logger.xml \ nut-monitor.xml \ nut-driver.xml \ nut-driver-enumerator.xml SOLARIS_SMF_METHODSCRIPTS = \ svc-nut-server \ svc-nut-logger \ svc-nut-monitor # OS equivalent of /lib/svc/method and /var/svc/manifest/application # but we can just use then from this location @WITH_SOLARIS_SMF_TRUE@solarissmfmethoddir = @datadir@/solaris-smf/method @WITH_SOLARIS_SMF_TRUE@solarissmfmanifestdir = @datadir@/solaris-smf/manifest @WITH_SOLARIS_SMF_TRUE@solarissmfmethod_SCRIPTS = $(SOLARIS_SMF_METHODSCRIPTS) @WITH_SOLARIS_SMF_TRUE@solarissmfmanifest_DATA = $(SOLARIS_SMF_MANIFESTS) @WITH_SOLARIS_SMF_TRUE@libexec_SCRIPTS = ../upsdrvsvcctl/nut-driver-enumerator.sh @WITH_SOLARIS_SMF_TRUE@sbin_SCRIPTS = ../upsdrvsvcctl/upsdrvsvcctl @WITH_SOLARIS_INIT_TRUE@solarisinitscriptdir = @datadir@/solaris-init @WITH_SOLARIS_INIT_TRUE@solarisinitscript_SCRIPTS = nut reset-ups-usb-solaris.sh.sample SOLARIS_PACKAGE_TARGETS = $(am__append_2) $(am__append_3) # TODO: Reduce build dependencies (implicit!) on python and perl # by shelling the scripts used below # NOTE: This assumes the rest of the product has already been built # and installed under PROTOTYPE_DIR, but declares no explicit # dependency on that SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS = makelocal.sh precheck.py preproto.pl SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS = preinstall postinstall preremove postremove SOLARIS_PACKAGE_SVR4_INSTALLDATA = pkginfo SPELLCHECK_SRC = README.adoc CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Solaris/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Solaris/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-driver-enumerator.xml: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver.xml: $(top_builddir)/config.status $(srcdir)/nut-driver.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-logger.xml: $(top_builddir)/config.status $(srcdir)/nut-logger.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-monitor.xml: $(top_builddir)/config.status $(srcdir)/nut-monitor.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-server.xml: $(top_builddir)/config.status $(srcdir)/nut-server.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut.xml: $(top_builddir)/config.status $(srcdir)/nut.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ pkginfo: $(top_builddir)/config.status $(srcdir)/pkginfo.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ svc-nut-server: $(top_builddir)/config.status $(srcdir)/svc-nut-server.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ svc-nut-logger: $(top_builddir)/config.status $(srcdir)/svc-nut-logger.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ svc-nut-monitor: $(top_builddir)/config.status $(srcdir)/svc-nut-monitor.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ precheck.py: $(top_builddir)/config.status $(srcdir)/precheck.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ preinstall: $(top_builddir)/config.status $(srcdir)/preinstall.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ postinstall: $(top_builddir)/config.status $(srcdir)/postinstall.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ preremove: $(top_builddir)/config.status $(srcdir)/preremove.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ postremove: $(top_builddir)/config.status $(srcdir)/postremove.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ preproto.pl: $(top_builddir)/config.status $(srcdir)/preproto.pl.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut: $(top_builddir)/config.status $(srcdir)/nut.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libexecSCRIPTS: $(libexec_SCRIPTS) @$(NORMAL_INSTALL) @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(libexecdir)'; $(am__uninstall_files_from_dir) install-sbinSCRIPTS: $(sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir) install-solarisinitscriptSCRIPTS: $(solarisinitscript_SCRIPTS) @$(NORMAL_INSTALL) @list='$(solarisinitscript_SCRIPTS)'; test -n "$(solarisinitscriptdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(solarisinitscriptdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(solarisinitscriptdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(solarisinitscriptdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(solarisinitscriptdir)$$dir" || exit $$?; \ } \ ; done uninstall-solarisinitscriptSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(solarisinitscript_SCRIPTS)'; test -n "$(solarisinitscriptdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(solarisinitscriptdir)'; $(am__uninstall_files_from_dir) install-solarissmfmethodSCRIPTS: $(solarissmfmethod_SCRIPTS) @$(NORMAL_INSTALL) @list='$(solarissmfmethod_SCRIPTS)'; test -n "$(solarissmfmethoddir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(solarissmfmethoddir)'"; \ $(MKDIR_P) "$(DESTDIR)$(solarissmfmethoddir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(solarissmfmethoddir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(solarissmfmethoddir)$$dir" || exit $$?; \ } \ ; done uninstall-solarissmfmethodSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(solarissmfmethod_SCRIPTS)'; test -n "$(solarissmfmethoddir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(solarissmfmethoddir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-solarissmfmanifestDATA: $(solarissmfmanifest_DATA) @$(NORMAL_INSTALL) @list='$(solarissmfmanifest_DATA)'; test -n "$(solarissmfmanifestdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(solarissmfmanifestdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(solarissmfmanifestdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(solarissmfmanifestdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(solarissmfmanifestdir)" || exit $$?; \ done uninstall-solarissmfmanifestDATA: @$(NORMAL_UNINSTALL) @list='$(solarissmfmanifest_DATA)'; test -n "$(solarissmfmanifestdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(solarissmfmanifestdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(solarisinitscriptdir)" "$(DESTDIR)$(solarissmfmethoddir)" "$(DESTDIR)$(solarissmfmanifestdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-solarisinitscriptSCRIPTS \ install-solarissmfmanifestDATA install-solarissmfmethodSCRIPTS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecSCRIPTS install-sbinSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecSCRIPTS uninstall-sbinSCRIPTS \ uninstall-solarisinitscriptSCRIPTS \ uninstall-solarissmfmanifestDATA \ uninstall-solarissmfmethodSCRIPTS .MAKE: check-am install-am install-strip .PHONY: all all-am check check-am check-local clean clean-generic \ clean-libtool cscopelist-am ctags-am distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libexecSCRIPTS install-man install-pdf \ install-pdf-am install-ps install-ps-am install-sbinSCRIPTS \ install-solarisinitscriptSCRIPTS \ install-solarissmfmanifestDATA install-solarissmfmethodSCRIPTS \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-libexecSCRIPTS \ uninstall-sbinSCRIPTS uninstall-solarisinitscriptSCRIPTS \ uninstall-solarissmfmanifestDATA \ uninstall-solarissmfmethodSCRIPTS .PRECIOUS: Makefile package: $(SOLARIS_PACKAGE_TARGETS) package-solaris-svr4: $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLDATA) ISANAME=''; case x"$(target_cpu)" in \ xi386|xsparc|xsparcv9|xamd64) ISANAME='$(target_cpu)' ;; \ xx86_64) ISANAME='amd64' ;; \ xi686) ISANAME='i386' ;; \ xsparcv7)ISANAME='sparc' ;; \ x) UNAME_P="`uname -p`" && ISANAME="$${UNAME_P}" ;; \ esac ; \ ISABITS=32; case x"$${ISANAME}" in \ xi386|xsparc) ISABITS=32 ;; \ xsparcv9|xamd64) ISABITS=64 ;; \ x*) echo "WARNING: Unexpected ISANAME='$${ISANAME}'" >&2 ;; \ esac; \ case x"$${ISABITS}" in \ x32) ISA_PKGNAME="NUT" ;; \ x64) ISA_PKGNAME="NUTx" ;; \ esac; \ sed -e 's/^PKG="[^"][^"]*"$$/PKG="'"$${ISA_PKGNAME}"'"/' -i $(builddir)/pkginfo || exit ; \ if test -n "@auglensdir@" && test -d "$(DESTDIR)@auglensdir@" ; then \ $(MKDIR_P) "$(DESTDIR)@datadir@/augeas-lenses" && \ ( cd "$(DESTDIR)@auglensdir@" && \ ( cp -prf ./ "$(DESTDIR)@datadir@/augeas-lenses/" || cp -rf ./ "$(DESTDIR)@datadir@/augeas-lenses/" ) ) || exit ; \ fi ; \ ( cd $(PROTOTYPE_DIR) && find . -print | pkgproto > prototype1 ) || exit ; \ cp $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLDATA) $(PROTOTYPE_DIR) || exit ; \ ( cd $(PROTOTYPE_DIR) && chmod +x $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) ) || exit ; \ ( cd $(PROTOTYPE_DIR) && perl preproto.pl ) || exit ; \ if test -n '$(PYTHON)' ; then \ ( cd $(PROTOTYPE_DIR) && $(PYTHON) precheck.py ) || exit ; \ fi ; \ ( cd $(PROTOTYPE_DIR) && rm -f prototype1 ) || exit ; \ ( cd $(PROTOTYPE_DIR) && ./makelocal.sh ) || exit ; \ cp $(PROTOTYPE_DIR)/*.gz $(builddir) || exit ; \ if [ -n "$${ISANAME}" ] ; then \ mv -f NUT*_solaris_package.local.gz "$(abs_top_builddir)/$${ISA_PKGNAME}_solaris_$${ISANAME}_package-@PACKAGE_VERSION@.local.gz" || exit ; \ fi # TODO: Define support for IPS packaging (provide p5m files and make rules) package-solaris-ips: @echo " SKIP $@ : Target is not implemented yet" check-local: $(SOLARIS_CHECK_TARGETS) check-local-solaris-smf: $(SOLARIS_SMF_MANIFESTS) @[ -x /usr/sbin/svccfg ] || { echo "WARNING : Target $@ skipped due to absent /usr/sbin/svccfg" >&2; return 0; } ; \ RES=0 ; for F in $? ; do \ echo " SVCCFG-VALIDATE $$F"; \ /usr/sbin/svccfg validate "$$F" || RES=$$? ; \ done; exit $$RES # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/Solaris/README.adoc0000644000200500020050000000544214777534446014161 00000000000000Solaris/illumos helper scripts and resources ============================================ Overview -------- This directory contains init-scripts and SMF manifests and methods for better integration of NUT services with Solaris and descendant operating systems, covering SVR4 packaging with init scripts and/or SMF services (as called from `make package` in the source root). NOTE: IPS (`pkg(5)`) packaging is not currently provided here, but is a concern of particular distributions. See for example the OpenIndiana userland recipe at https://github.com/OpenIndiana/oi-userland/tree/oi/hipster/components/sysutils/nut This also includes the `nut-driver-enumerator.sh` (service and implementation method) and `upsdrvsvcctl` (tool) to manage NUT drivers as service instances, which are stored in `../upsdrvsvcctl/` subdirectory (portable codebase shared with Linux systemd). SMF integration --------------- The default implementation (which runs once per invocation) can be enabled with: ---- :; svcadm enable nut-driver-enumerator:default ---- Note that at the moment there is no out-of-the-box integration for triggering a restart/refresh of the `nut-driver-enumerator` SMF service at the very instant when the `ups.conf` file is modified, like there is with systemd path unit type. Due to this, the systems administrator is expected to either invoke `svcadm refresh nut-driver-enumerator` after changing the NUT configuration, or wait until the daemonized mode, if enabled, picks up the change (should do so within a minute by default). However, a DTrace script or a tool like https://github.com/emcrisostomo/fswatch wrapped into a service might be used for equivalent effect. Alternatively, but in a potentially more computationally expensive fashion, the same `nut-driver-enumerator.sh` script can be executed in a loop as the payload of the SMF service to keep inspecting the configuration regularly and so apply changes to the running system. It is not a common use-case to keep changing device setups, so this solution is not enforced by default ;) although an SMF service variant for this is provided... Note that only one of these implementations can be enabled at the same time: ---- :; svcadm disable nut-driver-enumerator:default :; svcadm enable nut-driver-enumerator:daemon ---- Other ----- For special notes about USB-connected device monitoring with NUT under Solaris and related operating systems, see also `docs/solaris-usb.txt`. The example `reset-ups-usb-solaris.sh.sample` script can be used to reset USB connections if a driver (or UPS controller) gets stuck -- but it needs to be adapted to *your* system first. Credits ------- * Init-script solution and SVR4 packaging contributed by numerous authors over the years * SMF solution and OpenIndiana packaging contributed by Jim Klimov nut-2.8.3/scripts/Solaris/Makefile.am0000644000200500020050000001375515001552635014413 00000000000000# Network UPS Tools: scripts/Solaris EXTRA_DIST = makelocal.sh precheck.py.in preproto.pl.in README.adoc PROTOTYPE_DIR = $(DESTDIR)@prefix@ SOLARIS_CHECK_TARGETS = PYTHON = @PYTHON@ SOLARIS_SMF_MANIFESTS = \ nut.xml \ nut-server.xml \ nut-logger.xml \ nut-monitor.xml \ nut-driver.xml \ nut-driver-enumerator.xml SOLARIS_SMF_METHODSCRIPTS = \ svc-nut-server \ svc-nut-logger \ svc-nut-monitor if WITH_SOLARIS_SMF # OS equivalent of /lib/svc/method and /var/svc/manifest/application # but we can just use then from this location solarissmfmethoddir = @datadir@/solaris-smf/method solarissmfmanifestdir = @datadir@/solaris-smf/manifest solarissmfmethod_SCRIPTS = $(SOLARIS_SMF_METHODSCRIPTS) solarissmfmanifest_DATA = $(SOLARIS_SMF_MANIFESTS) libexec_SCRIPTS = ../upsdrvsvcctl/nut-driver-enumerator.sh sbin_SCRIPTS = ../upsdrvsvcctl/upsdrvsvcctl SOLARIS_CHECK_TARGETS += check-local-solaris-smf endif if WITH_SOLARIS_INIT solarisinitscriptdir = @datadir@/solaris-init solarisinitscript_SCRIPTS = nut reset-ups-usb-solaris.sh.sample endif EXTRA_DIST += reset-ups-usb-solaris.sh.sample SOLARIS_PACKAGE_TARGETS = if WITH_SOLARIS_PKG_IPS SOLARIS_PACKAGE_TARGETS += package-solaris-ips endif if WITH_SOLARIS_PKG_SVR4 SOLARIS_PACKAGE_TARGETS += package-solaris-svr4 endif package: $(SOLARIS_PACKAGE_TARGETS) # TODO: Reduce build dependencies (implicit!) on python and perl # by shelling the scripts used below # NOTE: This assumes the rest of the product has already been built # and installed under PROTOTYPE_DIR, but declares no explicit # dependency on that SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS = makelocal.sh precheck.py preproto.pl SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS = preinstall postinstall preremove postremove SOLARIS_PACKAGE_SVR4_INSTALLDATA = pkginfo package-solaris-svr4: $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLDATA) ISANAME=''; case x"$(target_cpu)" in \ xi386|xsparc|xsparcv9|xamd64) ISANAME='$(target_cpu)' ;; \ xx86_64) ISANAME='amd64' ;; \ xi686) ISANAME='i386' ;; \ xsparcv7)ISANAME='sparc' ;; \ x) UNAME_P="`uname -p`" && ISANAME="$${UNAME_P}" ;; \ esac ; \ ISABITS=32; case x"$${ISANAME}" in \ xi386|xsparc) ISABITS=32 ;; \ xsparcv9|xamd64) ISABITS=64 ;; \ x*) echo "WARNING: Unexpected ISANAME='$${ISANAME}'" >&2 ;; \ esac; \ case x"$${ISABITS}" in \ x32) ISA_PKGNAME="NUT" ;; \ x64) ISA_PKGNAME="NUTx" ;; \ esac; \ sed -e 's/^PKG="[^"][^"]*"$$/PKG="'"$${ISA_PKGNAME}"'"/' -i $(builddir)/pkginfo || exit ; \ if test -n "@auglensdir@" && test -d "$(DESTDIR)@auglensdir@" ; then \ $(MKDIR_P) "$(DESTDIR)@datadir@/augeas-lenses" && \ ( cd "$(DESTDIR)@auglensdir@" && \ ( cp -prf ./ "$(DESTDIR)@datadir@/augeas-lenses/" || cp -rf ./ "$(DESTDIR)@datadir@/augeas-lenses/" ) ) || exit ; \ fi ; \ ( cd $(PROTOTYPE_DIR) && find . -print | pkgproto > prototype1 ) || exit ; \ cp $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLDATA) $(PROTOTYPE_DIR) || exit ; \ ( cd $(PROTOTYPE_DIR) && chmod +x $(SOLARIS_PACKAGE_SVR4_HELPERSCRIPTS) $(SOLARIS_PACKAGE_SVR4_INSTALLSCRIPTS) ) || exit ; \ ( cd $(PROTOTYPE_DIR) && perl preproto.pl ) || exit ; \ if test -n '$(PYTHON)' ; then \ ( cd $(PROTOTYPE_DIR) && $(PYTHON) precheck.py ) || exit ; \ fi ; \ ( cd $(PROTOTYPE_DIR) && rm -f prototype1 ) || exit ; \ ( cd $(PROTOTYPE_DIR) && ./makelocal.sh ) || exit ; \ cp $(PROTOTYPE_DIR)/*.gz $(builddir) || exit ; \ if [ -n "$${ISANAME}" ] ; then \ mv -f NUT*_solaris_package.local.gz "$(abs_top_builddir)/$${ISA_PKGNAME}_solaris_$${ISANAME}_package-@PACKAGE_VERSION@.local.gz" || exit ; \ fi # TODO: Define support for IPS packaging (provide p5m files and make rules) package-solaris-ips: @echo " SKIP $@ : Target is not implemented yet" check-local: $(SOLARIS_CHECK_TARGETS) check-local-solaris-smf: $(SOLARIS_SMF_MANIFESTS) @[ -x /usr/sbin/svccfg ] || { echo "WARNING : Target $@ skipped due to absent /usr/sbin/svccfg" >&2; return 0; } ; \ RES=0 ; for F in $? ; do \ echo " SVCCFG-VALIDATE $$F"; \ /usr/sbin/svccfg validate "$$F" || RES=$$? ; \ done; exit $$RES SPELLCHECK_SRC = README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.3/scripts/Solaris/nut-driver.xml.in0000644000200500020050000001104714777767434015625 00000000000000 nut-2.8.3/scripts/Solaris/preinstall.in0000755000200500020050000000111414553676503015065 00000000000000#!/bin/sh # Preinstall script for Network UPS Tools package NUT_DIR="@prefix@" # Create group nut grep -w "@RUN_AS_GROUP@" /etc/group if [ "$?" != 0 ]; then /usr/sbin/groupadd "@RUN_AS_GROUP@" fi # Create user for installing "Network UPS Tools" grep -w "@RUN_AS_USER@" /etc/passwd if [ "$?" != 0 ]; then /usr/sbin/useradd -c "Network UPS Tools" -g "@RUN_AS_GROUP@" -G root -d "@STATEPATH@" -s /bin/false "@RUN_AS_USER@" fi res="`groups "@RUN_AS_GROUP@" | grep -w "@RUN_AS_USER@"`" || res="" if [ -z "$res" ]; then /usr/sbin/usermod -g "@RUN_AS_GROUP@" -G root "@RUN_AS_USER@" fi nut-2.8.3/scripts/Solaris/nut-driver-enumerator.xml.in0000644000200500020050000001425214777767434020005 00000000000000 nut-2.8.3/scripts/Solaris/nut-logger.xml.in0000644000200500020050000000607214777767434015613 00000000000000 nut-2.8.3/scripts/Solaris/postinstall.in0000755000200500020050000001164514777534446015305 00000000000000#!/bin/sh # Postinstall script for Network UPS Tools package NUT_DIR="@prefix@" prefix="@prefix@" # expanded as part of some autoconf macros below # TODO/FIXME : Should "/var/run" be a configure variable? # Note that "/var/run" is transient tmpfs, so upgrade has to be done during same uptime. ACTIVE_ENUMERATOR_FMRI_FILE="/var/run/nut-driver-enumerator-fmri.prev" # make sure the nut user exists and has correct memberships res="`getent group @RUN_AS_GROUP@`" || res="" if [ -z "$res" ]; then /usr/sbin/groupadd "@RUN_AS_GROUP@" fi res="`getent passwd @RUN_AS_USER@`" || res="" if [ -z "$res" ]; then /usr/sbin/useradd -c "Network UPS Tools" -g "@RUN_AS_GROUP@" -G root -d "@STATEPATH@" -s /bin/false @RUN_AS_USER@ fi res="`groups "@RUN_AS_GROUP@" | grep -w "@RUN_AS_USER@"`" || res="" if [ -z "$res" ]; then /usr/sbin/usermod -g "@RUN_AS_GROUP@" -G root "@RUN_AS_USER@" fi # make sure that conffiles are secured and have the correct ownerships if [ -d "@CONFPATH@" ] ; then chown "root:@RUN_AS_GROUP@" "@CONFPATH@" fi for file in nut.conf ups.conf upsd.conf upsmon.conf upsd.users upssched.conf nut-driver-enumerator.conf; do if [ -f "@CONFPATH@/$file" ] ; then chown "root:@RUN_AS_GROUP@" "@CONFPATH@/$file" chmod 640 "@CONFPATH@/$file" fi done # make sure that /var/run exists (for privileged processes) if [ ! -d "@PIDPATH@" ] ; then mkdir -p "@PIDPATH@" fi # make sure that /var/run/nut exists and has the correct ownerships if [ ! -d "@ALTPIDPATH@" ] ; then mkdir -p "@ALTPIDPATH@" fi if [ -d "@ALTPIDPATH@" ] ; then chown "root:@RUN_AS_GROUP@" "@ALTPIDPATH@" chmod 770 "@ALTPIDPATH@" fi # make sure that /var/state/ups exists and has the correct ownerships if [ ! -d "@STATEPATH@" ] ; then mkdir -p "@STATEPATH@" fi if [ -d "@STATEPATH@" ] ; then chown "root:@RUN_AS_GROUP@" "@STATEPATH@" chmod 770 "@STATEPATH@" fi if [ -n "@auglensdir@" ] && [ -d "@auglensdir@" ] && [ -d "@datarootdir@/augeas-lenses" ] ; then ( cd "@datarootdir@/augeas-lenses" && cp -prf ./ "@auglensdir@"/ ) fi if test -x /usr/sbin/svcadm && test -x /usr/sbin/svccfg && test -x /usr/bin/svcs ; then echo "Register SMF services..." for S in nut-driver-enumerator nut-driver nut-server nut-monitor nut ; do echo "Importing NUT service manifest: $S..." /usr/sbin/svccfg import "@datarootdir@/solaris-smf/manifest/$S.xml" done # Enable services if the system already has a configuration (e.g. upgrade) if test -s "@CONFPATH@/ups.conf" ; then echo "Stopping NUT drivers, if any (in case of upgrade)..." @SBINDIR@/upsdrvsvcctl stop @SBINDIR@/upsdrvctl -DDDDD stop sleep 5 echo "(Re-)register NUT drivers (if any)..." REPORT_RESTART_42=no AUTO_START=no "@NUT_LIBEXECDIR@/nut-driver-enumerator.sh" --reconfigure sleep 2 echo "Enable NUT drivers (if any)..." # Note: we now provide two services, a daemon that keeps checking # the config for changes and a default one that should be refreshed # manually to reconfigure nut-driver instances - and is "cheaper". # This may still fail if the daemon instance is somehow enabled (admin) PREV_ACTIVE_ENUMERATOR="" if test -s "${ACTIVE_ENUMERATOR_FMRI_FILE}" ; then PREV_ACTIVE_ENUMERATOR="`head -1 "${ACTIVE_ENUMERATOR_FMRI_FILE}"`" fi [ x"nut-driver-enumerator:default" = x"${PREV_ACTIVE_ENUMERATOR}" ] && PREV_ACTIVE_ENUMERATOR="" for ACTIVE_ENUMERATOR in ${PREV_ACTIVE_ENUMERATOR} nut-driver-enumerator:default ; do /usr/sbin/svcadm enable -s ${ACTIVE_ENUMERATOR} || \ { /usr/sbin/svcadm clear ${ACTIVE_ENUMERATOR} 2>/dev/null ; \ /usr/sbin/svcadm enable -s ${ACTIVE_ENUMERATOR} ; } && break || true done @SBINDIR@/upsdrvsvcctl start else echo "NOT ENABLING nut-driver-enumerator at this time : missing or empty @CONFPATH@/ups.conf" >&2 fi if test -s "@CONFPATH@/ups.conf" && test -e "@CONFPATH@/upsd.conf" && test -e "@CONFPATH@/upsd.users" ; then # Note on the mix of "-s" and "-e" in tests above: # it is a valid use-case for an admin to have just touched an # empty upsd.conf and so use default settings for the daemon echo "Enable NUT upsd data server..." /usr/sbin/svcadm enable -s nut-server else echo "NOT ENABLING nut-server at this time : missing at least one of : @CONFPATH@/ups.conf @CONFPATH@/upsd.conf @CONFPATH@/upsd.users" >&2 fi if test -s "@CONFPATH@/upsmon.conf" ; then echo "Enable NUT upsmon client..." /usr/sbin/svcadm enable -s nut-monitor else echo "NOT ENABLING nut-monitor at this time : missing or empty @CONFPATH@/upsmon.conf" >&2 fi echo "Enable NUT umbrella service..." /usr/sbin/svcadm enable -s nut else echo "Put init script in /etc/init.d..." cp -pf "@NUT_DATADIR@/solaris-init/nut" /etc/init.d chown root:bin /etc/init.d/nut chmod 744 /etc/init.d/nut ln -s ../init.d/nut /etc/rc3.d/S90nut > /dev/null 2>&1 ln -s ../init.d/nut /etc/rc3.d/K10nut > /dev/null 2>&1 # Start nut services #echo "Starting nut services" #$NUT_DIR/sbin/upsdrvctl start #> /dev/null 2>&1 #$NUT_DIR/sbin/upsd #> /dev/null 2>&1 #$NUT_DIR/sbin/upsmon #> /dev/null 2>&1 fi nut-2.8.3/scripts/Solaris/nut.xml.in0000644000200500020050000000721014777767434014331 00000000000000 nut-2.8.3/scripts/Solaris/preremove.in0000755000200500020050000000564014553676503014724 00000000000000#!/bin/sh # Preremove script for Network UPS Tools package # Stop all nut services NUT_DIR="@prefix@" prefix="@prefix@" # expanded as part of some autoconf macros below # TODO/FIXME : Should "/var/run" be a configure variable? # Note that "/var/run" is transient tmpfs, so upgrade has to be done during same uptime. ACTIVE_ENUMERATOR_FMRI_FILE="/var/run/nut-driver-enumerator-fmri.prev" if test -x /usr/sbin/svcadm && test -x /usr/sbin/svccfg && test -x /usr/bin/svcs ; then # Unconfigure SMF services # First detect the first active (online, maintenance, etc.) # instance of nut-driver-enumerator so we can pass it to the # next lifetime in case of re-install of NUT and keep the # user's previously declared preference. ACTIVE_ENUMERATOR="`/usr/bin/svcs -H -o state,fmri '*/nut-driver-enumerator:*' | while read S F ; do [ "$S" != "disabled" ] && [ "$S" != "offline" ] && echo "$F" && break ; done`" if [ -n "$ACTIVE_ENUMERATOR" ]; then rm -f "${ACTIVE_ENUMERATOR_FMRI_FILE}" touch "${ACTIVE_ENUMERATOR_FMRI_FILE}" chmod 600 "${ACTIVE_ENUMERATOR_FMRI_FILE}" chown 0:0 "${ACTIVE_ENUMERATOR_FMRI_FILE}" echo "${ACTIVE_ENUMERATOR}" > "${ACTIVE_ENUMERATOR_FMRI_FILE}" fi # First tell the automagic to stop, so it does not interfere; diligently clean it out below /usr/sbin/svcadm disable nut-driver-enumerator:default || true /usr/sbin/svcadm disable nut-driver-enumerator:daemon || true for S in nut nut-monitor nut-server ; do echo "Stopping NUT service: $S..." /usr/sbin/svcadm clear "$S" 2>/dev/null /usr/sbin/svcadm disable -s "$S" echo "Removing NUT service: $S..." /usr/sbin/svccfg delete "$S" || \ /usr/sbin/svccfg -s "$S" delete || \ /usr/sbin/svccfg -s "$S" delete default done echo "Stopping NUT drivers, if any..." @SBINDIR@/upsdrvsvcctl stop @SBINDIR@/upsdrvctl -DDDDD stop sleep 5 for S in `/usr/bin/svcs -H -o fmri '*/nut-driver:*'` `/usr/bin/svcs -H -o fmri '*/nut-driver-enumerator:*'` ; do echo "Stopping NUT service: $S..." /usr/sbin/svcadm clear "$S" 2>/dev/null /usr/sbin/svcadm disable -s "$S" done sleep 5 for S in `/usr/bin/svcs -H -o fmri '*/nut-driver:*' | grep -wv default` `/usr/bin/svcs -H -o fmri '*/nut-driver-enumerator:*' | grep -wv default` ; do echo "Removing NUT service: $S..." # Note: S here is a full FMRI URL SB="`echo "$S" | sed 's,:[^:]*$,,'`" SI="`echo "$S" | sed 's,^.*:\([^:]*\)$,\1,'`" /usr/sbin/svcadm disable -s "$S" /usr/sbin/svccfg -s "$SB" delete -f "$SI" || \ /usr/sbin/svccfg delete "$S" done for S in nut-driver-enumerator nut-driver ; do echo "Removing NUT service: $S..." && \ /usr/sbin/svccfg delete "$S" || \ /usr/sbin/svccfg -s "$S" delete || \ /usr/sbin/svccfg -s "$S" delete default done else [ -x /etc/init.d/nut ] && /etc/init.d/nut stop fi if [ -n "@auglensdir@" ] && [ -d "@auglensdir@" ] && [ -d "@datarootdir@/augeas-lenses" ] ; then ( cd "@datarootdir@/augeas-lenses" && find . -type f -exec rm -f "@auglensdir@"/'{}' \; ) fi nut-2.8.3/scripts/Solaris/makelocal.sh0000755000200500020050000000066614553676503014657 00000000000000#!/bin/sh # Creates the package file from current-directory contents # Called by Makefile starting from installed prototype directory echo "Making Solaris SVR4 package metadata..." && \ pkgmk -o -d "`pwd`" && \ echo "Making Solaris SVR4 package archive file..." && \ ( yes "" | pkgtrans "`pwd`" "`pwd`/NUT_solaris_package.local" ) && \ echo "Compressing Solaris SVR4 package archive file..." && \ gzip "`pwd`/NUT_solaris_package.local" nut-2.8.3/scripts/Solaris/postremove.in0000755000200500020050000000062014777534446015123 00000000000000#!/bin/sh # Postremove script for Network UPS Tools package # Remove init script from /etc/init.d - created by scripts not packaging rm -f /etc/init.d/nut rm -f /etc/rc3.d/S90nut rm -f /etc/rc3.d/K10nut # Remove nut group and user /usr/sbin/userdel "@RUN_AS_USER@" /usr/sbin/groupdel "@RUN_AS_GROUP@" # Remove /var/run/nut rm -rf "@ALTPIDPATH@" # Remove /var/state/ups rm -rf "@STATEPATH@" nut-2.8.3/scripts/Solaris/svc-nut-server.in0000755000200500020050000000373014777534446015630 00000000000000#!/sbin/sh # Trivial (better is yet to come) SMF method script to start nut services # Adapted for OpenIndiana userland from init.d script template in NUT sources # Adaptation copyright (C) 2016 Jim Klimov if [ -z "$SMF_FMRI" ]; then echo "$0 must be called in SMF context!" >&2 exit 1 fi # smf(5) . /lib/svc/share/smf_include.sh || exit prefix="@prefix@" NUT_DIR="@prefix@" NUT_SBIN_DIR="$NUT_DIR/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" NUT_RUN_DIR="`svcprop -p nut/NUT_RUN_DIR $SMF_FMRI`" \ && [ -n "$NUT_RUN_DIR" ] \ || NUT_RUN_DIR="@ALTPIDPATH@" CONFIG="@CONFPATH@/nut.conf" NUTUSER="`svcprop -p nut/NUTUSER $SMF_FMRI`" \ && [ -n "$NUTUSER" ] \ || NUTUSER="@RUN_AS_USER@" NUTGROUP="`svcprop -p nut/NUTGROUP $SMF_FMRI`" \ && [ -n "$NUTGROUP" ] \ || NUTGROUP="@RUN_AS_GROUP@" # We anticipate some tighter integration with SMF later: #NUT_QUIET_INIT_UPSNOTIFY=true #export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" fi create_run_dir () { # Default rights inspired by NUT scripts/Solaris/postinstall.in #mkdir -p "@PIDPATH@" # (for privileged processes - not upsd) mkdir -p "$NUT_RUN_DIR" && \ chown "root:$NUTGROUP" "$NUT_RUN_DIR" && \ chmod 770 "$NUT_RUN_DIR" \ || exit $SMF_EXIT_ERR_FATAL } ups_start () { create_run_dir if [ "$MODE" = "none" ];then echo "No NUT mode set, not starting anything" >&2 exit 1 fi if [ "$MODE" != "netclient" ] ; then # In this distribution, UPS drivers are wrapped by service instances #LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsdrvctl" start #> /dev/null 2>&1 LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsd" #> /dev/null 2>&1 fi } case "$1" in 'start') ups_start ;; 'refresh'|'reload') LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}/upsd" -c reload ;; "create_run_dir") # Mostly provided for the sake of nut-driver service create_run_dir ;; *) echo "" echo "Usage: '$0' {start}" echo "" exit $SMF_EXIT_ERR_CONFIG ;; esac exit $? nut-2.8.3/scripts/Solaris/nut-monitor.xml.in0000644000200500020050000000643714777767434016030 00000000000000 nut-2.8.3/scripts/Solaris/svc-nut-logger.in0000755000200500020050000000337714777767434015615 00000000000000#!/sbin/sh # Trivial (better is yet to come) SMF method script to start nut services # Adapted for OpenIndiana userland from init.d script template in NUT sources # Adaptation copyright (C) 2016-2025 Jim Klimov if [ -z "$SMF_FMRI" ]; then echo "$0 must be called in SMF context!" >&2 exit 1 fi # smf(5) . /lib/svc/share/smf_include.sh || exit prefix="@prefix@" NUT_DIR="@prefix@" NUT_SBIN_DIR="${NUT_DIR}/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" NUT_RUN_DIR="@ALTPIDPATH@" CONFIG="@CONFPATH@/nut.conf" DAEMON_CONFIG="@CONFPATH@/upslog.conf" NUTUSER="@RUN_AS_USER@" NUTGROUP="@RUN_AS_GROUP@" # We anticipate some tighter integration with SMF later: #NUT_QUIET_INIT_UPSNOTIFY=true #export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" fi if [ -s "$DAEMON_CONFIG" ] ; then . "$DAEMON_CONFIG" else echo "Daemon config file '$DAEMON_CONFIG' not found or populated, not starting anything" >&2 exit $SMF_EXIT_ERR_CONFIG fi ups_start () { if [ "$MODE" = "none" ];then echo "No NUT mode set, not starting anything" >&2 exit $SMF_EXIT_ERR_CONFIG fi if [ x"${UPSLOG_ARGS-}" = x ; then echo "UPSLOG_ARGS not found or populated in configuration, not starting anything" >&2 exit $SMF_EXIT_ERR_CONFIG fi # Default rights inspired by NUT scripts/Solaris/postinstall.in mkdir -p "@PIDPATH@" # (for privileged processes) mkdir -p "$NUT_RUN_DIR" && \ chown "root:$NUTGROUP" "$NUT_RUN_DIR" && \ chmod 770 "$NUT_RUN_DIR" \ || exit $SMF_EXIT_ERR_FATAL # Fork and background regardless of logging to a file or stdout (-) LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upslog -B $UPSLOG_ARGS #> /dev/null 2>&1 } case "$1" in 'start') ups_start ;; *) echo "" echo "Usage: '$0' {start}" echo "" exit $SMF_EXIT_ERR_CONFIG ;; esac exit $? nut-2.8.3/scripts/Makefile.in0000644000200500020050000007367315001555011013004 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts (root) VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = scripts ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = \ README.adoc \ avahi/nut.service.in \ HP-UX/nut-drvctl \ HP-UX/nut-drvctl.sh \ HP-UX/nut-upsd \ HP-UX/nut-upsd.sh \ HP-UX/nut-upsmon \ HP-UX/nut-upsmon.sh \ logrotate/nutlogd \ misc/nut.bash_completion \ misc/osd-notify \ perl/Nut.pm \ RedHat/halt.patch \ RedHat/README.adoc \ RedHat/ups.in \ RedHat/upsd.in \ RedHat/upsmon.in \ Solaris8/S99upsmon \ subdriver/gen-usbhid-subdriver.sh \ subdriver/gen-snmp-subdriver.sh \ upower/95-upower-hid.hwdb \ upower/95-upower-hid.rules \ usb_resetter/README.adoc \ usb_resetter/nut-driver.service \ valgrind/README.adoc \ valgrind/.valgrind.supp.in \ valgrind/valgrind.sh.in \ Windows/halt.c \ Windows/Makefile SUBDIRS = augeas devd hotplug installer python systemd udev ufw Solaris Windows upsdrvsvcctl external_apis SPELLCHECK_SRC = README.adoc RedHat/README.adoc usb_resetter/README.adoc valgrind/README.adoc CLEANFILES = *-spellchecked RedHat/*-spellchecked usb_resetter/*-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-recursive .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) $(AM_MAKEFLAGS) -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/systemd/0000755000200500020050000000000015001555412012474 500000000000000nut-2.8.3/scripts/systemd/nut-driver@.service.in0000644000200500020050000001176014777767434016643 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - device driver for %I After=local-fs.target # Note: If the "Before" line below is uncommented, the target unit # would only become initialized after the driver units are all in # a final state (active, failed, ...) and would allow nut-server # (upsd) to start up and represent those devices on the network. # With this constraint commented away, the nut-server should start # earlier, but may initially report some devices as Not connected # (they should appear when drivers complete their initialization - # e.g. snmp walks of large MIBs can take a while): #Before=nut-driver.target # Propagate stopping of the target: PartOf=nut-driver.target Documentation=man:upsdrvsvcctl(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsdrvsvcctl.html Documentation=man:ups.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html # Note: The choice of "network.target" allows to schedule this unit # roughly when the network stack of this OS is ready (e.g. that the # subsequent `upsd` will have a `0.0.0.0` or a `localhost` to bind # to); however this target does not ensure availability of a real # connection or final IP addresses. Drivers that require network as # a media for interaction with UPSes (snmp-ups, netxml-ups, ipmi etc.) # may want to extend this unit with `Requires=network-online.target` # instead. Also note that *generally* this should not be a problem, # since the drivers have a few retries with timeouts during startup, # and typically by the time the box gets an IP address, the driver # is still retrying to start and will succeed. # Extending the unit does not require *this* file to be edited, you # can instead drop in an additional piece of configuration, e.g. to # require that a NUT driver only starts after external networking # is configured (usable IP addresses appear in the system) you can # add a `/etc/systemd/system/nut-driver@.service.d/network.conf` with: # [Unit] # Requires=network-online.target # After=network-online.target # If your `upsd` requires specific IP addresses to be available before # starting, a `/etc/systemd/system/nut-driver.target.d/network.conf` # can be used in a similar manner. # Finally note that "nut-driver-enumerator.service" should take care of this. [Service] Environment=NUT_IGNORE_NOWAIT=true Environment=NUT_QUIET_INIT_NDE_WARNING=true EnvironmentFile=-@CONFPATH@/nut.conf SyslogIdentifier=%N ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStart=/bin/sh -c 'NUTDEV="`@NUT_LIBEXECDIR@/nut-driver-enumerator.sh --get-device-for-service %i`" && [ -n "$NUTDEV" ] || { echo "FATAL: Could not find a NUT device section for service unit %i" >&2 ; exit 1 ; } ; exec @SBINDIR@/upsdrvctl @SYSTEMD_DAEMON_ARGS_DRIVER@ start "$NUTDEV"' # SIGHUP: simple reload (ignore values we can not change on the fly) # SIGUSR1: reload-or-exit (let systemd resuscitate the service then) ExecReload=/bin/kill -USR1 $MAINPID ExecStop=/bin/sh -c 'NUTDEV="`@NUT_LIBEXECDIR@/nut-driver-enumerator.sh --get-device-for-service %i`" && [ -n "$NUTDEV" ] || { echo "FATAL: Could not find a NUT device section for service unit %i" >&2 ; exit 1 ; } ; @SBINDIR@/upsdrvctl stop "$NUTDEV"' # Restart really always, do not stop trying: StartLimitInterval=0 Restart=always # Protract the "hold-off" interval, so if the device connection is # lost, the driver does not rapidly restart and fail too many times, # and then systemd would keep the unit failed without further retries. # Notably, this helps start "dummy-ups" drivers retranslating local # devices (so getting a chicken-and-egg problem for driver-upsd-driver # orderly series of initializations). More details in NUT issue #779. RestartSec=15s Type=@SYSTEMD_DAEMON_TYPE_DRIVER@ @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ # Note: if you set up with systemd notification support, you can take # advantage of watchdog mechanism. Timeouts involved are deployment # dependent (how many devices you monitor, how stressed are they and # the monitoring system, protocol used -- e.g. SNMP walks can take long), # so distributions should not pre-define this (at least not to a small # value): @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ # Note: If you customize the "maxstartdelay" in ups.conf or in your # NUT compilation defaults, so it exceeds the default systemd unit # startup timeout (typically 90 sec), then make sure to set a slightly # longer systemd timeout for the nut-driver unit instances. You can # do this by populating a drop-in configuration, so it is not later # overwritten by updates to your NUT package -- create a dir+file: # /etc/systemd/system/nut-driver@.service.d/timeout.conf with lines: # [Service] # TimeoutStartSec=190s [Install] WantedBy=nut-driver.target nut-2.8.3/scripts/systemd/Makefile.in0000644000200500020050000011233215001555011014456 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/systemd VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @HAVE_SYSTEMD_TRUE@@WITH_LIBSYSTEMD_INHIBITOR_FALSE@am__append_1 = \ @HAVE_SYSTEMD_TRUE@@WITH_LIBSYSTEMD_INHIBITOR_FALSE@ nut-sleep.service # Add files not generated from .in templates @HAVE_SYSTEMD_TRUE@am__append_2 = nut-sleep.service nut-systemd.preset nut-udev-settle.service @HAVE_SYSTEMD_FALSE@am__append_3 = \ @HAVE_SYSTEMD_FALSE@ nut.target.in nut-systemd.preset \ @HAVE_SYSTEMD_FALSE@ nut-driver@.service.in nut-driver.target.in \ @HAVE_SYSTEMD_FALSE@ nut-server.service.in nut-udev-settle.service \ @HAVE_SYSTEMD_FALSE@ nut-logger.service.in nut-monitor.service.in \ @HAVE_SYSTEMD_FALSE@ nut-sleep.service nutshutdown.in \ @HAVE_SYSTEMD_FALSE@ nut-driver-enumerator.path.in nut-driver-enumerator.service.in \ @HAVE_SYSTEMD_FALSE@ nut-driver-enumerator-daemon-activator.path.in \ @HAVE_SYSTEMD_FALSE@ nut-driver-enumerator-daemon-activator.service.in \ @HAVE_SYSTEMD_FALSE@ nut-driver-enumerator-daemon.service.in subdir = scripts/systemd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut.target nut-common-tmpfiles.conf \ nut-driver.target nut-driver@.service nut-logger.service \ nut-monitor.service nut-server.service \ nut-driver-enumerator.service nut-driver-enumerator.path \ nut-driver-enumerator-daemon.service \ nut-driver-enumerator-daemon-activator.service \ nut-driver-enumerator-daemon-activator.path nutshutdown CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(systemdshutdowndir)" \ "$(DESTDIR)$(systemdsystempresetdir)" \ "$(DESTDIR)$(systemdsystemunitdir)" \ "$(DESTDIR)$(systemdtmpfilesdir)" SCRIPTS = $(libexec_SCRIPTS) $(sbin_SCRIPTS) \ $(systemdshutdown_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(systemdsystempreset_DATA) $(systemdsystemunit_DATA) \ $(systemdtmpfiles_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/nut-common-tmpfiles.conf.in \ $(srcdir)/nut-driver-enumerator-daemon-activator.path.in \ $(srcdir)/nut-driver-enumerator-daemon-activator.service.in \ $(srcdir)/nut-driver-enumerator-daemon.service.in \ $(srcdir)/nut-driver-enumerator.path.in \ $(srcdir)/nut-driver-enumerator.service.in \ $(srcdir)/nut-driver.target.in \ $(srcdir)/nut-driver@.service.in \ $(srcdir)/nut-logger.service.in \ $(srcdir)/nut-monitor.service.in \ $(srcdir)/nut-server.service.in $(srcdir)/nut.target.in \ $(srcdir)/nutshutdown.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README.adoc $(am__append_2) $(am__append_3) @HAVE_SYSTEMD_TRUE@systemdsystemunit_DATA = \ @HAVE_SYSTEMD_TRUE@ nut-driver-enumerator.service \ @HAVE_SYSTEMD_TRUE@ nut-driver-enumerator.path \ @HAVE_SYSTEMD_TRUE@ nut-driver-enumerator-daemon-activator.path \ @HAVE_SYSTEMD_TRUE@ nut-driver-enumerator-daemon-activator.service \ @HAVE_SYSTEMD_TRUE@ nut-driver-enumerator-daemon.service \ @HAVE_SYSTEMD_TRUE@ nut-driver@.service nut-logger.service \ @HAVE_SYSTEMD_TRUE@ nut-monitor.service nut-server.service \ @HAVE_SYSTEMD_TRUE@ nut-driver.target nut-udev-settle.service \ @HAVE_SYSTEMD_TRUE@ nut.target $(am__append_1) @HAVE_SYSTEMD_TRUE@systemdtmpfiles_DATA = \ @HAVE_SYSTEMD_TRUE@ nut-common-tmpfiles.conf @HAVE_SYSTEMD_TRUE@systemdsystempreset_DATA = \ @HAVE_SYSTEMD_TRUE@ nut-systemd.preset @HAVE_SYSTEMD_TRUE@systemdshutdown_SCRIPTS = nutshutdown @HAVE_SYSTEMD_TRUE@libexec_SCRIPTS = ../upsdrvsvcctl/nut-driver-enumerator.sh @HAVE_SYSTEMD_TRUE@sbin_SCRIPTS = ../upsdrvsvcctl/upsdrvsvcctl # NOTE: Do not EXTRA_DIST nut-common-tmpfiles.conf.in - it is generated per build SPELLCHECK_SRC = README.adoc CLEANFILES = *-spellchecked # Generated by autogen.sh and needed to run the configure script: MAINTAINERCLEANFILES = Makefile.in .dirstamp \ nut-common-tmpfiles.conf.in all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/systemd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/systemd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut.target: $(top_builddir)/config.status $(srcdir)/nut.target.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-common-tmpfiles.conf: $(top_builddir)/config.status $(srcdir)/nut-common-tmpfiles.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver.target: $(top_builddir)/config.status $(srcdir)/nut-driver.target.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver@.service: $(top_builddir)/config.status $(srcdir)/nut-driver@.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-logger.service: $(top_builddir)/config.status $(srcdir)/nut-logger.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-monitor.service: $(top_builddir)/config.status $(srcdir)/nut-monitor.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-server.service: $(top_builddir)/config.status $(srcdir)/nut-server.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver-enumerator.service: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver-enumerator.path: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator.path.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver-enumerator-daemon.service: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator-daemon.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver-enumerator-daemon-activator.service: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator-daemon-activator.service.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-driver-enumerator-daemon-activator.path: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator-daemon-activator.path.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutshutdown: $(top_builddir)/config.status $(srcdir)/nutshutdown.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-libexecSCRIPTS: $(libexec_SCRIPTS) @$(NORMAL_INSTALL) @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-libexecSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(libexec_SCRIPTS)'; test -n "$(libexecdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(libexecdir)'; $(am__uninstall_files_from_dir) install-sbinSCRIPTS: $(sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir) install-systemdshutdownSCRIPTS: $(systemdshutdown_SCRIPTS) @$(NORMAL_INSTALL) @list='$(systemdshutdown_SCRIPTS)'; test -n "$(systemdshutdowndir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(systemdshutdowndir)'"; \ $(MKDIR_P) "$(DESTDIR)$(systemdshutdowndir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(systemdshutdowndir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(systemdshutdowndir)$$dir" || exit $$?; \ } \ ; done uninstall-systemdshutdownSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(systemdshutdown_SCRIPTS)'; test -n "$(systemdshutdowndir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(systemdshutdowndir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-systemdsystempresetDATA: $(systemdsystempreset_DATA) @$(NORMAL_INSTALL) @list='$(systemdsystempreset_DATA)'; test -n "$(systemdsystempresetdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystempresetdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(systemdsystempresetdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystempresetdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystempresetdir)" || exit $$?; \ done uninstall-systemdsystempresetDATA: @$(NORMAL_UNINSTALL) @list='$(systemdsystempreset_DATA)'; test -n "$(systemdsystempresetdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(systemdsystempresetdir)'; $(am__uninstall_files_from_dir) install-systemdsystemunitDATA: $(systemdsystemunit_DATA) @$(NORMAL_INSTALL) @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemunitdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(systemdsystemunitdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystemunitdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystemunitdir)" || exit $$?; \ done uninstall-systemdsystemunitDATA: @$(NORMAL_UNINSTALL) @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(systemdsystemunitdir)'; $(am__uninstall_files_from_dir) install-systemdtmpfilesDATA: $(systemdtmpfiles_DATA) @$(NORMAL_INSTALL) @list='$(systemdtmpfiles_DATA)'; test -n "$(systemdtmpfilesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(systemdtmpfilesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(systemdtmpfilesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdtmpfilesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdtmpfilesdir)" || exit $$?; \ done uninstall-systemdtmpfilesDATA: @$(NORMAL_UNINSTALL) @list='$(systemdtmpfiles_DATA)'; test -n "$(systemdtmpfilesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(systemdtmpfilesdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(systemdshutdowndir)" "$(DESTDIR)$(systemdsystempresetdir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(systemdtmpfilesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-systemdshutdownSCRIPTS \ install-systemdsystempresetDATA install-systemdsystemunitDATA \ install-systemdtmpfilesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libexecSCRIPTS install-sbinSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libexecSCRIPTS uninstall-sbinSCRIPTS \ uninstall-systemdshutdownSCRIPTS \ uninstall-systemdsystempresetDATA \ uninstall-systemdsystemunitDATA uninstall-systemdtmpfilesDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libexecSCRIPTS install-man install-pdf install-pdf-am \ install-ps install-ps-am install-sbinSCRIPTS install-strip \ install-systemdshutdownSCRIPTS install-systemdsystempresetDATA \ install-systemdsystemunitDATA install-systemdtmpfilesDATA \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-libexecSCRIPTS uninstall-sbinSCRIPTS \ uninstall-systemdshutdownSCRIPTS \ uninstall-systemdsystempresetDATA \ uninstall-systemdsystemunitDATA uninstall-systemdtmpfilesDATA .PRECIOUS: Makefile # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/systemd/nutshutdown.in0000755000200500020050000000745214777767434015415 00000000000000#!/bin/sh # Network UPS Tools (NUT) systemd-shutdown integration handler. # # NOTE: This script requires both nut-server package (or more specifically, # the drivers for your device, which may be in further packages grouped # by media/protocol and third-party dependencies), nut-client (upsmon), # and their configuration files to be present locally and on still-mounted # filesystems (may be read-only). # # Copyright (C) 2011-2025 by NUT contributors # Michal Hlavinka, Laurent Bigonville, Arnaud Quette, Jim Klimov et al. # # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # # 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. if [ -s "@CONFPATH@/nut.conf" ]; then . "@CONFPATH@/nut.conf" || true fi [ x"${POWEROFF_QUIET-}" = xtrue ] \ || POWEROFF_QUIET="false" [ -x "@SBINDIR@/upsmon" ] || { $POWEROFF_QUIET || echo "$0: SKIP: could not locate '@SBINDIR@/upsmon''" >&2 exit 1 } # Will at most run the optional power-race avoidance sleep part [ -x "@SBINDIR@/upsdrvctl" ] || { $POWEROFF_QUIET || echo "$0: WARNING: could not locate '@SBINDIR@/upsdrvctl' - will not command any UPS devices to shut down" >&2 } if @SBINDIR@/upsmon -K >/dev/null 2>&1; then if [ -x "@SBINDIR@/upsdrvctl" ] ; then $POWEROFF_QUIET || { echo "$0: Commanding UPSes (if any) to shutdown" >&2 [ -w /dev/console ] && echo "`TZ=UTC LANG=C date`: $0: Commanding UPSes (if any) to shutdown" >/dev/console || true } NUT_QUIET_INIT_NDE_WARNING=true export NUT_QUIET_INIT_NDE_WARNING @SBINDIR@/upsdrvctl shutdown || echo "$0: Something failed about UPS shutdown commands" >&2 fi if [ -n "$POWEROFF_WAIT" ] ; then # Avoid the power-race condition (if wall power returned # while we were shutting down, so some UPSes would not # shutdown and/or powercycle the load as commanded above). # Sleep "long enough" to drain the battery if the UPS is # in fact on battery, or reboot if it became alive, so # this computer is not in limbo forever. $POWEROFF_QUIET || { echo "$0: Power-race avoidance: sleeping $POWEROFF_WAIT" >&2 [ -w /dev/console ] && echo "`TZ=UTC LANG=C date`: $0: Power-race avoidance: sleeping $POWEROFF_WAIT" >/dev/console || true } # The argument may be anything compatible with /bin/sleep # (on OSes with systemd - assuming GNU coreutils or compatible, # so not necessarily a non-negative integer) /bin/sleep $POWEROFF_WAIT $POWEROFF_QUIET || { echo "$0: Power-race avoidance: sleep finished, rebooting..." >&2 [ -w /dev/console ] && echo "`TZ=UTC LANG=C date`: $0: Power-race avoidance: sleep finished, rebooting..." >/dev/console || true } # We need to pass --force twice here to bypass systemd # and execute the reboot directly ourself. /bin/systemctl reboot --force --force else $POWEROFF_QUIET || echo "$0: Power-race avoidance: POWEROFF_WAIT is not configured at this time, proceeding to shutdown" >&2 fi else $POWEROFF_QUIET || echo "$0: SKIP: Not in FSD (killpower) mode at this time" >&2 fi exit 0 nut-2.8.3/scripts/systemd/nut-driver-enumerator-daemon-activator.path.in0000644000200500020050000000226414777767434023450 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] # Trigger restart of nut-driver-enumerator-daemon-activator.service # whenever ups.conf is edited, which would cause reload-or-restart # of the nut-driver-enumerator-daemon.service for actual reconfig. Description=Network UPS Tools - Trigger reload-or-restart of nut-driver-enumerator-daemon.service whenever ups.conf is edited Conflicts=nut-driver-enumerator.service nut-driver-enumerator.path After=local-fs.target Before=nut-driver.target PartOf=nut.target Documentation=man:nut-driver-enumerator(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut-driver-enumerator.html Documentation=man:ups.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:upsdrvsvcctl(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsdrvsvcctl.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Path] PathModified=@CONFPATH@/ups.conf [Install] WantedBy=nut.target nut-2.8.3/scripts/systemd/nut-sleep.service0000644000200500020050000000154314777767434015751 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # A rather blunt solution for system sleeping support, for cases where # we can not use a native libsystemd "inhibitor interface". This helps # avoid NUT shutting down a woken-up system just because its power state # was critical before the sleep, and a next-read timestamp was not seen # (deemed to be a stale UPS, meaning lost comms during critical state, # so must go down ASAP). [Unit] Description=Network UPS Tools - sleep hook Before=sleep.target StopWhenUnneeded=yes [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/systemctl stop nut.target ExecStop=/usr/bin/systemctl start --no-block nut.target [Install] WantedBy=sleep.target nut-2.8.3/scripts/systemd/nut-udev-settle.service0000644000200500020050000000351414777767434017102 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2025- by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # # This file was adapted from systemd-udev-settle.service provided as part of # systemd. The original service is no longer recommended for general use in # recent distributions (does not guarantee reliable detection, and delays # system readiness for log-in), but waiting for udev to settle its currently # running operations has proven useful in some cases for NUT practice. # # Original file's terms: # # SPDX-License-Identifier: LGPL-2.1-or-later # # This file is part of systemd. # # systemd 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.1 of the License, or # (at your option) any later version. # This service can dynamically be pulled-in by legacy services which # cannot reliably cope with dynamic device configurations, and wrongfully # expect a populated /dev during bootup. [Unit] Description=Wait for udev To Complete Device Initialization before USB-capable NUT drivers start Documentation=man:systemd-udev-settle.service(8) DefaultDependencies=no Wants=systemd-udevd.service After=systemd-udev-trigger.service ConditionPathIsReadWrite=/sys # Used when/if requested by specific nut-driver@.service instances. # No auto-start or dependency otherwise. [Service] Type=oneshot TimeoutSec=180 # We want to re-trigger this service during NUT driver restarts # (maybe several at once) as we reconnect after e.g. USB bus reset, # for changes in USB/Serial/... devices that may need permissions # for NUT to be applied. So we do not want it to remain "active". #RemainAfterExit=yes ExecStart=udevadm settle nut-2.8.3/scripts/systemd/nut-systemd.preset0000644000200500020050000000626214777767434016176 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # This file enables a default selection of NUT systemd units, # reasonable for a typical server with one or a few UPS devices # (their drivers, NDE, and data server), and the upsmon client. # Adapt to your system as needed. # There are several separate variants of NDE usage to process the # "ups.conf" file and create/update/remove `nut-driver@.service` # unit instances: # * Manual run of `nut-driver-enumerator.sh (--reconfigure)` # * Single run at system start-up (nut-driver-enumerator.service unit) # ** perhaps additionally upon edits of the file (path unit), # if it works (may get ignored on busy systems) # * Daemon mode that runs once to update the nut-driver population, # and then loops to to pick up any subsequent changes (maybe more # reliably than the filesystem notification processing would allow). # ** nut-driver-enumerator-daemon.service provides the daemon # ** nut-driver-enumerator-daemon-activator.* units optionally # reload it if "ups.conf" is edited (if the path unit does work) # and apply changes without waiting for the inter-loop sleep. # Typical systems do not monitor hordes of devices with a dynamically # changing population of those (e.g. data center monitoring appliances), # so the daemon mode is an overkill for these smaller use-cases. disable nut-driver-enumerator-daemon-activator.path disable nut-driver-enumerator-daemon-activator.service disable nut-driver-enumerator-daemon.service enable nut-driver-enumerator.path enable nut-driver-enumerator.service # Activate systemd unit instances prepared by NDE (service above # or a manual run of the script), each wrapping one NUT driver. # Requires "ups.conf" with corresponding section for the device: enable nut-driver.target # I don't think a template can be activated/deactivated; anyhow # this is NDE's bread and butter at run-time: #enable nut-driver@.service # The nut-udev-settle.service would be used by USB/Serial/... drivers # wrapped by NDE, and so referenced there if needed. It should not # auto-start if not used by any driver: enable nut-udev-settle.service # Activate the "upsd" data server, to represent drivers on the network. # Requires "ups.conf", "upsd.conf", "upsd.users": enable nut-server.service # Activate the "upsmon" client to shut down the local system. # Can run on same or different system as the data server. # Requires "upsmon.conf": enable nut-monitor.service # Pull in activated units, to orchestrate their starting or stopping # in one command: enable nut.target # OPTIONAL: Normally NUT programs are built to use the native libsystemd # "inhibitor interface" to gracefully handle clock jumps when the server # sleeps and later wakes up. If this is not possible for whatever reason, # this "sleep hook" unit provides a workaround (stop/start nut.target): disable nut-sleep.service # OPTIONAL: Log snapshots of UPS state into a file (or stdout to # systemd journal); needs an "upslog.conf" file defining tuples like # UPSLOG_ARGS="-m ups,file -m ups,file..." disable nut-logger.service nut-2.8.3/scripts/systemd/nut-driver-enumerator.service.in0000644000200500020050000000410114777767434020711 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] # This unit starts early in system lifecycle to set up nut-driver instances. # End-user may also restart this unit after editing ups.conf to automatically # un-register or add new instances as appropriate. Description=Network UPS Tools - enumeration of configure-file devices into systemd unit instances Conflicts=nut-driver-enumerator-daemon.service nut-driver-enumerator-daemon-activator.path nut-driver-enumerator-daemon-activator.service After=local-fs.target Before=nut-driver.target PartOf=nut.target Documentation=man:nut-driver-enumerator(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut-driver-enumerator.html Documentation=man:ups.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:upsdrvsvcctl(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsdrvsvcctl.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Service] ### Script needs privileges to restart units #User=@RUN_AS_USER@ #Group=@RUN_AS_GROUP@ User=root SyslogIdentifier=%N # it is expected that the process has to exit before systemd starts follow-up # units; it should not be a problem for those Type=oneshot # Currently systemd does not support restarting of oneshot services, and does # not seem to guarantee that other services would only start after the script # completes, for a non-oneshot case. The script itself handles restarting of # nut-server which is the primary concerned dependency at the moment, so we # don't want it to fail the unit (when it can't restart). Environment=REPORT_RESTART_42=no EnvironmentFile=-@CONFPATH@/nut.conf ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStart=@NUT_LIBEXECDIR@/nut-driver-enumerator.sh ExecReload=@NUT_LIBEXECDIR@/nut-driver-enumerator.sh [Install] WantedBy=nut.target nut-2.8.3/scripts/systemd/README.adoc0000644000200500020050000000343314777767434014240 00000000000000NUT resources for systemd integration ===================================== Overview -------- This directory contains the NUT support files for `systemd`, the System and Service Manager used in many Linux distributions. These files are automatically installed, upon detection (at `configure` time) of a systemd enabled target system, or if corresponding configuration options were requested. If you need to tweak some of the services, prefer to use systemd "drop-in" configuration files rather than editing the installed unit files directly (lest your changes be lost upon upgrade), e.g.: ---- # cat /etc/systemd/system/nut-monitor.service.d/debug.conf [Service] Environment="NUT_DEBUG_PID=yes" ---- ...followed up by `systemctl daemon-reload` and a restart of the unit itself. This also uses the `nut-driver-enumerator.sh` (service and implementation method) and `upsdrvsvcctl` (tool) to manage NUT drivers as service instances located in `../upsdrvsvcctl/` source subdirectory. Two service bundles are provided for this: * a set of `nut-driver-enumerator-daemon*` units starts the script as a daemon to regularly inspect and apply the NUT configuration to OS service unit wrappings (mainly intended for monitoring systems with a dynamic set of monitored power devices, or for systems where filesystem events monitoring is not a clockwork-reliable mechanism to 100% rely on); * the other `nut-driver-enumerator.*` units run the script once per triggering of the service (usually during boot-up; configuration file changes can be detected and propagated by systemd most of the time). Credits ------- * Contributed by Michal Hlavinka * Updated 2016-2018 by Michal Hrusecky and Jim Klimov * Maintained since 2020 by Jim Klimov nut-2.8.3/scripts/systemd/nut-driver.target.in0000644000200500020050000000111714777767434016364 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - target for power device drivers on this system After=local-fs.target # network.target PartOf=nut.target # TODO: Dedicated man pages? Documentation=man:ups.conf(5) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:nut.conf(5) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Install] WantedBy=nut.target nut-2.8.3/scripts/systemd/nut-driver-enumerator-daemon-activator.service.in0000644000200500020050000000462614777767434024160 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] # This unit starts via nut-driver-enumerator-daemon-activator.path # activation due to changes in ups.conf file, and triggers a reload # of the nut-driver-enumerator-daemon.service so that one quickly # re-processes the new configuration state. # NOTE: This unit is intentionally not installed as PartOf/WantedBy # anything, as it is only meant to be triggered by the path unit. Description=Network UPS Tools - enumeration of configure-file devices into systemd unit instances (FS event-based activator for daemonized mode) Conflicts=nut-driver-enumerator.service nut-driver-enumerator.path After=local-fs.target #Before=nut-driver.target #PartOf=nut.target Documentation=man:nut-driver-enumerator(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut-driver-enumerator.html Documentation=man:ups.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:upsdrvsvcctl(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsdrvsvcctl.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Service] ### Script needs privileges to restart units #User=@RUN_AS_USER@ #Group=@RUN_AS_GROUP@ User=root Type=oneshot # Non-blocking systemd message posting should not take long, # or should be aborted and retried if it does (system bugs) TimeoutStartSec=10s # If some process is writing the ups.conf file, it can be interpreted in # some conditions by .path unit as many events requiring it to start - # and eventually this gets throttled as a quickly started-restarted unit. # While it should be permitted for manual start (likely .path trigger too) # after interval expiration, this might race-condition to not detect some # latest update into the configuration file if it happens after the main # script loop has slurped intermediate state of device config. # Note: Using the older but still supported Service/StartLimitInterval # see https://lists.freedesktop.org/archives/systemd-devel/2017-July/039255.html # for broader compatibility. StartLimitInterval=0 ExecStart=/bin/systemctl reload-or-restart --no-block nut-driver-enumerator-daemon.service [Install] ### No install, see comment above #WantedBy=nut.target nut-2.8.3/scripts/systemd/nut-driver-enumerator-daemon.service.in0000644000200500020050000000342514777767434022162 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] # This unit starts early in system lifecycle to set up nut-driver instances # and stays running as a loop to pick up any subsequent changes maybe more # reliably than the filesystem notification processing would allow. # End-user may also restart this unit after editing ups.conf to automatically # un-register or add new instances as appropriate. Description=Network UPS Tools - enumeration of configure-file devices into systemd unit instances (daemonized mode) Conflicts=nut-driver-enumerator.service nut-driver-enumerator.path After=local-fs.target Before=nut-driver.target PartOf=nut.target Documentation=man:nut-driver-enumerator(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut-driver-enumerator.html Documentation=man:ups.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:upsdrvsvcctl(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsdrvsvcctl.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Service] ### Script needs privileges to restart units #User=@RUN_AS_USER@ #Group=@RUN_AS_GROUP@ User=root # it is expected that this process has to fork the daemon before systemd # starts follow-up units; it should not be a problem for those Type=forking Restart=always Environment=REPORT_RESTART_42=no ExecStart=@NUT_LIBEXECDIR@/nut-driver-enumerator.sh --daemon-after # Note: this is an async event, actual reconfiguration may take some time to # complete after this signal. ExecReload=/bin/kill -HUP $MAINPID [Install] WantedBy=nut.target nut-2.8.3/scripts/systemd/Makefile.am0000644000200500020050000000711314777767434014506 00000000000000# Network UPS Tools: scripts/systemd EXTRA_DIST = README.adoc if HAVE_SYSTEMD systemdsystemunit_DATA = \ nut-driver-enumerator.service \ nut-driver-enumerator.path \ nut-driver-enumerator-daemon-activator.path \ nut-driver-enumerator-daemon-activator.service \ nut-driver-enumerator-daemon.service \ nut-driver@.service \ nut-logger.service \ nut-monitor.service \ nut-server.service \ nut-driver.target \ nut-udev-settle.service \ nut.target if !WITH_LIBSYSTEMD_INHIBITOR systemdsystemunit_DATA += \ nut-sleep.service endif !WITH_LIBSYSTEMD_INHIBITOR systemdtmpfiles_DATA = \ nut-common-tmpfiles.conf systemdsystempreset_DATA = \ nut-systemd.preset # Add files not generated from .in templates EXTRA_DIST += nut-sleep.service nut-systemd.preset nut-udev-settle.service systemdshutdown_SCRIPTS = nutshutdown libexec_SCRIPTS = ../upsdrvsvcctl/nut-driver-enumerator.sh sbin_SCRIPTS = ../upsdrvsvcctl/upsdrvsvcctl else !HAVE_SYSTEMD EXTRA_DIST += \ nut.target.in nut-systemd.preset \ nut-driver@.service.in nut-driver.target.in \ nut-server.service.in nut-udev-settle.service \ nut-logger.service.in nut-monitor.service.in \ nut-sleep.service nutshutdown.in \ nut-driver-enumerator.path.in nut-driver-enumerator.service.in \ nut-driver-enumerator-daemon-activator.path.in \ nut-driver-enumerator-daemon-activator.service.in \ nut-driver-enumerator-daemon.service.in # NOTE: Do not EXTRA_DIST nut-common-tmpfiles.conf.in - it is generated per build endif !HAVE_SYSTEMD SPELLCHECK_SRC = README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by autogen.sh and needed to run the configure script: MAINTAINERCLEANFILES += nut-common-tmpfiles.conf.in nut-2.8.3/scripts/systemd/nut-server.service.in0000644000200500020050000000711714777767434016557 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - power devices information server After=local-fs.target network.target nut-driver.target # We don't Require drivers to be successfully started! This would be # a change of behavior compared to init SysV, and could prevent from # accessing successfully started, at least to audit a system. Wants=nut-driver.target # The `upsd` is a networked service (even if bound to a `localhost`) # so it requires that the OS has some notion of networking already. # Extending the unit does not require *this* file to be edited, you # can instead drop in an additional piece of configuration, e.g. to # require that NUT data server only starts after external networking # is configured (usable IP addresses appear in the system) you can # add a `/etc/systemd/system/nut-server.service.d/network.conf` with: # [Unit] # Requires=network-online.target # After=network-online.target Requires=network.target Before=nut-monitor.service PartOf=nut.target Documentation=man:upsd(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsd.html Documentation=man:ups.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:upsd.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsd.conf.html Documentation=man:upsd.users(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsd.users.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Service] # A busy server can be monitoring a lot of devices as well as replying # to many clients. The "infinity" definition is actually capped by OS # settings and hard-coded defaults; typically can be 65535+ nowadays. # On 64-bit distros this can well be set into hundreds of thousands # as well (though note each connection has a CPU and RAM overhead # so one can strike physical limits upon deployment and/or bring the # poorly sized system to a crawl, or worse). On a running system you # can check /proc/$MAINPID/limits for active ulimits of the process. # From my experiments, up to 1048576 can be set, but any larger value # falls back to 65536. The systemd definition of "infinity" is 65536 # too (or maybe it falls back to that); though this may be OS/distro # limitation and not systemd fault specifically. #LimitNOFILE=infinity #LimitNOFILE=65535 LimitNOFILE=1048576 EnvironmentFile=-@CONFPATH@/nut.conf SyslogIdentifier=%N # Note: foreground mode "-F" by default skips writing a PID file (and # needs default Type=simple); we can use "-FF" here to create the file # anyway, so that old "upsd -c reload" works rather than systemd action: ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStart=@SBINDIR@/upsd @SYSTEMD_DAEMON_ARGS_UPSD@ ExecReload=@SBINDIR@/upsd -c reload -P $MAINPID ExecStartPost=-/bin/grep -E 'Units|Max open files' /proc/${MAINPID}/limits # No tracking for PIDFile path and service attribute here (it might not # even exist). # If "-FF" or background-daemon mode is used, so that PID file exists # and "upsd -c stop" in particular can be used from command-line or # legacy scripts, it causes a clean and intentional exit of the daemon. # Then systemd should not revive it - hence restart it only on failure: Restart=on-failure Type=@SYSTEMD_DAEMON_TYPE_UPSD@ @SYSTEMD_DAEMON_WATCHDOG_UPSD@ @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ [Install] WantedBy=nut.target Alias=upsd.service nut-2.8.3/scripts/systemd/nut.target.in0000644000200500020050000000153714777767434015101 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - target for power device drivers, data server and monitoring client (if enabled) on this system After=local-fs.target nut-driver.target nut-server.service nut-monitor.service nut-logger.service Wants=local-fs.target nut-driver.target nut-server.service nut-monitor.service # network.target # nut-logger.service ### not enabled by default # TODO: Dedicated man pages? Documentation=man:ups.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Install] WantedBy=multi-user.target nut-2.8.3/scripts/systemd/nut-driver-enumerator.path.in0000644000200500020050000000215714777767434020216 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] # Trigger restart of nut-driver-enumerator.service whenever ups.conf is edited Description=Network UPS Tools - Trigger restart of nut-driver-enumerator.service whenever ups.conf is edited Conflicts=nut-driver-enumerator-daemon.service nut-driver-enumerator-daemon-activator.path nut-driver-enumerator-daemon-activator.service After=local-fs.target Before=nut-driver.target PartOf=nut.target Documentation=man:nut-driver-enumerator(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut-driver-enumerator.html Documentation=man:ups.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/ups.conf.html Documentation=man:upsdrvsvcctl(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsdrvsvcctl.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Path] PathModified=@CONFPATH@/ups.conf [Install] WantedBy=nut.target nut-2.8.3/scripts/systemd/nut-common-tmpfiles.conf.in0000644000200500020050000000106015001555032017600 00000000000000# Network UPS Tools (NUT) systemd integration # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # See also: https://github.com/networkupstools/nut/wiki/Technicalities:-Work-with-PID-and-state-file-paths#pidpath-altpidpath-statepath # State file (e.g. upsd to driver pipes) and PID file location for NUT: d @STATEPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - # Default PIPEFN and LOCKFN locations per upssched.conf: d @STATEPATH@/upssched 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @STATEPATH@ nut-2.8.3/scripts/systemd/nut-logger.service.in0000644000200500020050000000523414777767434016526 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - optional logging daemon (for status collection and analysis) # Log UPS values to a file for later collection and analysis After=local-fs.target network.target nut-server.service # Note: We do not specify Requires nut-server.service because # the `upsd` daemon(s) may be running on a different machine # (connected to the UPSes) than this client program. # The "Wants" directive would try to start the nut-server but # would not abort if that attempt fails for whatever reason. Wants=nut-server.service # Extending the unit does not require *this* file to be edited, you # can instead drop in an additional piece of configuration, e.g. to # require the logging client to only start after external networking # is configured (usable IP addresses appear in the system) you can # add a `/etc/systemd/system/nut-logger.service.d/network.conf` with: # [Unit] # Requires=network-online.target # After=network-online.target PartOf=nut.target ### not enabled by default, but ordered if enabled by user: Before=nut.target Documentation=man:upslog(8) Documentation=@NUT_WEBSITE_BASE@/docs/man/upslog.html Documentation=man:nut.conf(5) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html # Should contain UPSLOG_ARGS=... (or a systemd drop-in could provide it) # with a series of `-m upsname@server,logfile` definitions, where `logfile` # may be `-` for stdout. See about more variants in man page. ConditionPathExists=@CONFPATH@/upslog.conf [Service] EnvironmentFile=-@CONFPATH@/nut.conf EnvironmentFile=@CONFPATH@/upslog.conf SyslogIdentifier=%N ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStartPre=/bin/test -n "${UPSLOG_ARGS}" ExecStart=@BINDIR@/upslog @SYSTEMD_DAEMON_ARGS_UPSLOG@ $UPSLOG_ARGS # NOTE: SIGHUP is supported to re-open the log file, # which is the default systemd ReloadSignal (only # sent by systemd 253 and newer) ExecReload=/bin/kill -HUP $MAINPID PIDFile=@PIDPATH@/upslog.pid # With this program, the PID file always exists and "kill -TERM" in particular # can be used from command-line or some legacy scripts, it causes a clean and # intentional exit of the daemon (some other signals are also supported). # Then systemd should not revive it - hence restart it only on failure: Restart=on-failure Type=@SYSTEMD_DAEMON_TYPE_UPSLOG@ @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ [Install] # WantedBy=nut.target ### not enabled by default Alias=upslog.service nut-2.8.3/scripts/systemd/nut-monitor.service.in0000644000200500020050000000434114777767434016734 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2011-2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Network UPS Tools - power device monitor and shutdown controller # Note: do not mistake this historic misnomer for "NUT-Monitor" Python GUI client After=local-fs.target network.target nut-server.service # Note: We do not specify Requires nut-server.service because # the `upsd` daemon(s) may be running on a different machine # (connected to the UPSes) than the `upsmon` shutdown protector. # The "Wants" directive would try to start the nut-server but # would not abort if that attempt fails for whatever reason. Wants=nut-server.service # Extending the unit does not require *this* file to be edited, you # can instead drop in an additional piece of configuration, e.g. to # require the monitoring client to only start after external networking # is configured (usable IP addresses appear in the system) you can # add a `/etc/systemd/system/nut-monitor.service.d/network.conf` with: # [Unit] # Requires=network-online.target # After=network-online.target PartOf=nut.target Documentation=man:upsmon(@MAN_SECTION_CMD_SYS@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsmon.html Documentation=man:upsmon.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/upsmon.conf.html Documentation=man:nut.conf(@MAN_SECTION_CFG@) Documentation=@NUT_WEBSITE_BASE@/docs/man/nut.conf.html [Service] EnvironmentFile=-@CONFPATH@/nut.conf SyslogIdentifier=%N ExecStartPre=-@SYSTEMD_TMPFILES_PROGRAM@ --create @systemdtmpfilesdir@/nut-common-tmpfiles.conf ExecStart=@SBINDIR@/upsmon @SYSTEMD_DAEMON_ARGS_UPSMON@ ExecReload=@SBINDIR@/upsmon -c reload PIDFile=@PIDPATH@/upsmon.pid # If "-FF" or background-daemon mode is used, so that PID file exists # and "upsmon -c stop" in particular can be used from command-line or # legacy scripts, it causes a clean and intentional exit of the daemon. # Then systemd should not revive it - hence restart it only on failure: Restart=on-failure Type=@SYSTEMD_DAEMON_TYPE_UPSMON@ @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ [Install] WantedBy=nut.target Alias=upsmon.service nut-2.8.3/scripts/augeas/0000755000200500020050000000000015001555411012250 500000000000000nut-2.8.3/scripts/augeas/Makefile.in0000644000200500020050000007203415001555011014237 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/augeas VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_AUGLENS_FALSE@am__append_1 = \ @WITH_AUGLENS_FALSE@ nuthostsconf.aug.in nutupsconf.aug.in nutupsdusers.aug.in nutupsschedconf.aug.in \ @WITH_AUGLENS_FALSE@ nutnutconf.aug.in nutupsdconf.aug.in nutupsmonconf.aug.in nutupssetconf.aug.in subdir = scripts/augeas ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nutnutconf.aug nutupsdconf.aug nutupsdusers.aug \ nutupsmonconf.aug nutupsschedconf.aug nuthostsconf.aug \ nutupssetconf.aug gen-nutupsconf-aug.py nutupsconf.aug CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(auglensdir)" \ "$(DESTDIR)$(auglenstestsdir)" DATA = $(auglens_DATA) $(auglenstests_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/gen-nutupsconf-aug.py.in \ $(srcdir)/nuthostsconf.aug.in $(srcdir)/nutnutconf.aug.in \ $(srcdir)/nutupsconf.aug.in $(srcdir)/nutupsdconf.aug.in \ $(srcdir)/nutupsdusers.aug.in $(srcdir)/nutupsmonconf.aug.in \ $(srcdir)/nutupsschedconf.aug.in \ $(srcdir)/nutupssetconf.aug.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ # Note: spellchecking is currently ensured by docs/Makefile.am # due to inclusion into docs/developer-guide.txt, and the heading # level may be also dictated by that. PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ # Part of dist tarball, regardless of use for current build: EXTRA_DIST = gen-nutupsconf-aug.py.in nutupsconf.aug.tpl README.adoc \ tests/test_nut.aug $(am__append_1) nutupsconf.aug.in # Now "make install" should cover delivery of Augeas lenses... # The "auglensdir" and "auglenstestsdir" values should be set up by configure # The *.aug files are generated by rule above or by autogen.sh and/or configure @WITH_AUGLENS_TRUE@auglens_DATA = \ @WITH_AUGLENS_TRUE@ nuthostsconf.aug nutupsconf.aug nutupsdusers.aug nutupsschedconf.aug \ @WITH_AUGLENS_TRUE@ nutnutconf.aug nutupsdconf.aug nutupsmonconf.aug nutupssetconf.aug @WITH_AUGLENS_TRUE@auglenstests_DATA = \ @WITH_AUGLENS_TRUE@ tests/test_nut.aug # Generated by autogen.sh and needed to run the configure script: MAINTAINERCLEANFILES = Makefile.in .dirstamp nutupsconf.aug.in \ nutupsconf.aug.in.AUTOGEN_WITHOUT CLEANFILES = *-spellchecked README # Can be re-generated by configure script and/or make: DISTCLEANFILES = gen-nutupsconf-aug.py *.aug all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/augeas/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/augeas/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nutnutconf.aug: $(top_builddir)/config.status $(srcdir)/nutnutconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsdconf.aug: $(top_builddir)/config.status $(srcdir)/nutupsdconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsdusers.aug: $(top_builddir)/config.status $(srcdir)/nutupsdusers.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsmonconf.aug: $(top_builddir)/config.status $(srcdir)/nutupsmonconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsschedconf.aug: $(top_builddir)/config.status $(srcdir)/nutupsschedconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nuthostsconf.aug: $(top_builddir)/config.status $(srcdir)/nuthostsconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupssetconf.aug: $(top_builddir)/config.status $(srcdir)/nutupssetconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gen-nutupsconf-aug.py: $(top_builddir)/config.status $(srcdir)/gen-nutupsconf-aug.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nutupsconf.aug: $(top_builddir)/config.status $(srcdir)/nutupsconf.aug.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-auglensDATA: $(auglens_DATA) @$(NORMAL_INSTALL) @list='$(auglens_DATA)'; test -n "$(auglensdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(auglensdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(auglensdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(auglensdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(auglensdir)" || exit $$?; \ done uninstall-auglensDATA: @$(NORMAL_UNINSTALL) @list='$(auglens_DATA)'; test -n "$(auglensdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(auglensdir)'; $(am__uninstall_files_from_dir) install-auglenstestsDATA: $(auglenstests_DATA) @$(NORMAL_INSTALL) @list='$(auglenstests_DATA)'; test -n "$(auglenstestsdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(auglenstestsdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(auglenstestsdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(auglenstestsdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(auglenstestsdir)" || exit $$?; \ done uninstall-auglenstestsDATA: @$(NORMAL_UNINSTALL) @list='$(auglenstests_DATA)'; test -n "$(auglenstestsdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(auglenstestsdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook @HAVE_AUGPARSE_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(auglensdir)" "$(DESTDIR)$(auglenstestsdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-auglensDATA install-auglenstestsDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-auglensDATA uninstall-auglenstestsDATA .MAKE: check-am install-am install-strip .PHONY: all all-am check check-am check-local clean clean-generic \ clean-libtool cscopelist-am ctags-am dist-hook distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am install-auglensDATA \ install-auglenstestsDATA install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-auglensDATA \ uninstall-auglenstestsDATA .PRECIOUS: Makefile # only call the script to generate Augeas ups.conf lens upon "make dist", # and if Python is present; the distributed gen-nutupsconf-aug.py.in template # is assumed to only differ from a generated gen-nutupsconf-aug.py by the # @PYTHON@ shebang. dist-hook: @if [ -n "$(PYTHON)" ] && [ x"no" != x"$(PYTHON)" ] && $(PYTHON) -c "import re,glob,codecs"; then \ echo "Regenerating Augeas ups.conf lens with '$(PYTHON)'."; \ $(PYTHON) $(distdir)/gen-nutupsconf-aug.py.in $(distdir)/; \ else \ echo "----------------------------------------------------------------------"; \ echo "Warning: Python is not available."; \ echo "Skipping regeneration of Augeas lens for ups.conf parsing." ; \ echo "----------------------------------------------------------------------"; \ fi # This needs augparse from augeas-tools @HAVE_AUGPARSE_TRUE@check-local: @HAVE_AUGPARSE_TRUE@ @echo "augparse proceeding to lenses verification job..."; \ @HAVE_AUGPARSE_TRUE@ echo "DISABLED for now due to https://github.com/networkupstools/nut/issues/657 -" ; \ @HAVE_AUGPARSE_TRUE@ echo "as a developer, you can run the tests below manually but not automatically:" ; \ @HAVE_AUGPARSE_TRUE@ echo " $(AUGPARSE) -I $(builddir)/ -I $(srcdir)/ $(srcdir)/tests/test_nut.aug" ; \ @HAVE_AUGPARSE_TRUE@ echo "or 'make check-augeas' or 'make check-augeas-all' in `pwd`" @HAVE_AUGPARSE_TRUE@check-augeas: @HAVE_AUGPARSE_TRUE@ $(AUGPARSE) -I $(builddir)/ -I $(srcdir)/ $(srcdir)/tests/test_nut.aug @HAVE_AUGPARSE_TRUE@check-augeas-all: check-augeas @HAVE_AUGPARSE_TRUE@ $(AUGPARSE) -I $(builddir)/ -I $(srcdir)/ $(srcdir)/tests/test_nut_flaky.aug @HAVE_AUGPARSE_TRUE@ $(AUGPARSE) -I $(builddir)/ -I $(srcdir)/ $(srcdir)/tests/test_nut_fixme.aug # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/augeas/README.adoc0000644000200500020050000001727514777534446014021 00000000000000NUT configuration management with Augeas ======================================== Introduction ------------ Configuration has long been one of the two main NUT weaknesses. This is mostly due to the framework nature of NUT, and its many components and features, which make NUT configuration a very complex task. In order to address this point, NUT now provides configuration tools and manipulation abstraction, to anybody who want to manipulate NUT configuration, through Augeas lenses and modules. .From link:http://augeas.net[Augeas homepage]: [quote] ____ _Augeas is a configuration editing tool. It parses configuration files in their native formats and transforms them into a tree. Configuration changes are made by manipulating this tree and saving it back into native config files._ ____ In other words, Augeas is the dreamed Registry, with all the advantages (such as a uniform interface and tools), and the added bonus of being free/libre open source software and letting liberty on configuration file format. Requirements ------------ To be able to use Augeas with NUT, you will need to install Augeas, and also the NUT provided lenses, which describe NUT configuration files format. Augeas ~~~~~~ Having link:http://augeas.net[Augeas] installed. You will need at least version 0.5.1 (prior versions may work too, reports are welcome). As an example, on Debian and derivatives, do the following: :; apt-get install augeas-lenses augeas-tools And optionally: :; apt-get install libaugeas0 libaugeas-dev python-augeas On RedHat and derivatives, you have to install the packages 'augeas' and 'augeas-libs'. [[augeas_user]] NUT lenses and modules for Augeas ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are the `*.aug` files in the present directory. You can either install the files to the right location on your system, generally in `/usr/share/augeas/lenses/`, or use these from NUT source directory (`nut/scripts/augeas`). The latter is to be preferred for the time being. Create a test sandbox --------------------- NOTE: For now, it is easier to include an existing `/etc/nut/` directory. :; export AUGEAS_ROOT=./augeas-sandbox :; mkdir $AUGEAS_ROOT :; sudo cp -pr /etc/nut $AUGEAS_ROOT :; sudo chown -R $(id -nu):$(id -ng) $AUGEAS_ROOT Start testing and using ----------------------- Augeas provides many tools and link:http://augeas.net/download.html[languages bindings] (Python, Perl, Java, PHP, Ruby, ...), still with the same simple logic. This chapter will only illustrate some of these. Refer to the language binding's help and link:http://augeas.net/docs/index.html[Augeas documentation] for more information. Shell ~~~~~ Start an augeas shell using: :; augtool -b NOTE: If you have not installed NUT lenses, add `-I/path/to/nut/scripts/augeas`. From there, you can perform different actions like: - list existing NUT-related files: augtool> ls /files/etc/nut/ nut.conf/ = (none) upsd.users/ = (none) upsmon.conf = (none) ups.conf/ = (none) upsd.conf/ = (none + or using the matcher: + augtool> match /files/etc/nut/* /files/etc/nut/nut.conf = (none) /files/etc/nut/upsd.users = (none) /files/etc/nut/upsmon.conf = (none) /files/etc/nut/ups.conf = (none) /files/etc/nut/upsd.conf = (none) + [NOTE] ====== If you don't see anything, you may search for error messages by using: augtool> ls /augeas/files/etc/nut/*/errors and augtool> get /augeas/files/etc/nut/ups.conf/error/message /augeas/files/etc/nut/ups.conf/error/message = Permission denied ====== - create a new device entry (in `ups.conf`), called `augtest`: augtool> set /files/etc/nut/ups.conf/augtest/driver dummy-ups augtool> set /files/etc/nut/ups.conf/augtest/port auto augtool> save - list the devices currently using the `usbhid-ups` driver: augtool> match /files/etc/nut/ups.conf/*/driver dummy-ups C ~ A library is available for C programs, along with `pkg-config` support. You can get the compilation and link flags using the following code in your program's `configure` script or `Makefile`: CFLAGS="`pkg-config --silence-errors --cflags augeas`" LDFLAGS="`pkg-config --silence-errors --libs augeas`" Here is a code sample using this library for NUT configuration: -------------------------------------------------------------------------------- augeas *a = aug_init(NULL, NULL, AUG_NONE); ret = aug_match(a, "/files/etc/nut/*", &matches_p); ret = aug_set(a, "/files/etc/nut/ups.conf/augtest/driver", "dummy-ups"); ret = aug_set(a, "/files/etc/nut/ups.conf/augtest/port", "auto"); ret = aug_save(a); -------------------------------------------------------------------------------- Python ~~~~~~ The `augeas` class abstracts access to the configuration files. $ python Python 2.5.1 (r251:54863, Apr 8 2008, 01:19:33) [GCC 4.3.0 20080404 (Red Hat 4.3.0-6)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import augeas >>> a = augeas.augeas() >>> a.match("/files/etc/nut/*") ['/files/etc/nut/upsd.users', '/files/etc/nut/upsmon.conf', '/files/etc/nut/ups.conf', '/files/etc/nut/upsd.conf'] >>> a.set("/files/etc/nut/ups.conf/augtest/driver", "dummy-ups") True >>> a.set("/files/etc/nut/ups.conf/augtest/port", "auto") True >>> a.save() True >>> $ grep -A 2 augtest /etc/nut/ups.conf [augtest] driver=dummy-ups port=auto Perl ~~~~ The Perl binding is available through CPAN and packages. use Config::Augeas; my $aug = Config::Augeas->new( root => $aug_root ) ; my @a = $aug->match("/files/etc/nut/*") ; my $nb = $aug->count_match("/files/etc/nut/*") ; $aug->set("/files/etc/nut/ups.conf/augtest/driver", "dummy-ups") ; $aug->set("/files/etc/nut/ups.conf/augtest/port", "auto") ; $aug->save ; Test the conformity testing module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Existing configuration files can be tested for conformity. To do so, use: $ augparse -I ./ ./test_nut.aug Complete configuration wizard example ------------------------------------- Here is a Python example that generate a complete and usable standalone configuration: -------------------------------------------------------------------------------- import augeas device_name="dev1" driver_name="usbhid-ups" port_name="auto" a = augeas.augeas() # Generate nut.conf a.set("/files/etc/nut/nut.conf/MODE", "standalone") # Generate ups.conf # FIXME: chroot, driverpath? a.set(("/files/etc/nut/ups.conf/%s/driver" % device_name), driver_name) a.set(("/files/etc/nut/ups.conf/%s/port" % device_name), port_name) # Generate upsd.conf a.set("/files/etc/nut/upsd.conf/#comment[1]", "just to touch the file!") # Generate upsd.users user = "admin" a.set(("/files/etc/nut/upsd.users/%s/password" % user), "dummypass") a.set(("/files/etc/nut/upsd.users/%s/actions/SET" % user), "") # FIXME: instcmds lens should be fixed, as per the above rule a.set(("/files/etc/nut/upsd.users/%s/instcmds" % user), "ALL") monuser = "monuser" monpasswd = "******" a.set(("/files/etc/nut/upsd.users/%s/password" % monuser), monpasswd) a.set(("/files/etc/nut/upsd.users/%s/upsmon" % monuser), "primary") # Generate upsmon.conf a.set("/files/etc/nut/upsmon.conf/MONITOR/system/upsname", device_name) # Note: we prefer to omit localhost, not to be bound to a specific # entry in /etc/hosts, and thus be more generic #a.set("/files/etc/nut/upsmon.conf/MONITOR/system/hostname", "localhost") a.set("/files/etc/nut/upsmon.conf/MONITOR/powervalue", "1") a.set("/files/etc/nut/upsmon.conf/MONITOR/username", monuser) a.set("/files/etc/nut/upsmon.conf/MONITOR/password", monpasswd) a.set("/files/etc/nut/upsmon.conf/MONITOR/type", "primary") # FIXME: glitch on the generated content a.set("/files/etc/nut/upsmon.conf/SHUTDOWNCMD", "/sbin/shutdown -h +0") # save config a.save() a.close() -------------------------------------------------------------------------------- nut-2.8.3/scripts/augeas/Makefile.am0000644000200500020050000000560614777767434014270 00000000000000# Network UPS Tools: scripts/augeas EXTRA_DIST = gen-nutupsconf-aug.py.in nutupsconf.aug.tpl \ README.adoc tests/test_nut.aug # Note: spellchecking is currently ensured by docs/Makefile.am # due to inclusion into docs/developer-guide.txt, and the heading # level may be also dictated by that. PYTHON = @PYTHON@ # only call the script to generate Augeas ups.conf lens upon "make dist", # and if Python is present; the distributed gen-nutupsconf-aug.py.in template # is assumed to only differ from a generated gen-nutupsconf-aug.py by the # @PYTHON@ shebang. dist-hook: @if [ -n "$(PYTHON)" ] && [ x"no" != x"$(PYTHON)" ] && $(PYTHON) -c "import re,glob,codecs"; then \ echo "Regenerating Augeas ups.conf lens with '$(PYTHON)'."; \ $(PYTHON) $(distdir)/gen-nutupsconf-aug.py.in $(distdir)/; \ else \ echo "----------------------------------------------------------------------"; \ echo "Warning: Python is not available."; \ echo "Skipping regeneration of Augeas lens for ups.conf parsing." ; \ echo "----------------------------------------------------------------------"; \ fi # This needs augparse from augeas-tools if HAVE_AUGPARSE check-local: @echo "augparse proceeding to lenses verification job..."; \ echo "DISABLED for now due to https://github.com/networkupstools/nut/issues/657 -" ; \ echo "as a developer, you can run the tests below manually but not automatically:" ; \ echo " $(AUGPARSE) -I $(builddir)/ -I $(srcdir)/ $(srcdir)/tests/test_nut.aug" ; \ echo "or 'make check-augeas' or 'make check-augeas-all' in `pwd`" check-augeas: $(AUGPARSE) -I $(builddir)/ -I $(srcdir)/ $(srcdir)/tests/test_nut.aug check-augeas-all: check-augeas $(AUGPARSE) -I $(builddir)/ -I $(srcdir)/ $(srcdir)/tests/test_nut_flaky.aug $(AUGPARSE) -I $(builddir)/ -I $(srcdir)/ $(srcdir)/tests/test_nut_fixme.aug endif if WITH_AUGLENS # Now "make install" should cover delivery of Augeas lenses... # The "auglensdir" and "auglenstestsdir" values should be set up by configure # The *.aug files are generated by rule above or by autogen.sh and/or configure auglens_DATA = \ nuthostsconf.aug nutupsconf.aug nutupsdusers.aug nutupsschedconf.aug \ nutnutconf.aug nutupsdconf.aug nutupsmonconf.aug nutupssetconf.aug auglenstests_DATA = \ tests/test_nut.aug else EXTRA_DIST += \ nuthostsconf.aug.in nutupsconf.aug.in nutupsdusers.aug.in nutupsschedconf.aug.in \ nutnutconf.aug.in nutupsdconf.aug.in nutupsmonconf.aug.in nutupssetconf.aug.in endif MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *-spellchecked README # Can be re-generated by configure script and/or make: DISTCLEANFILES = gen-nutupsconf-aug.py # Generated by autogen.sh and needed to run the configure script: MAINTAINERCLEANFILES += nutupsconf.aug.in nutupsconf.aug.in.AUTOGEN_WITHOUT # Part of dist tarball, regardless of use for current build: EXTRA_DIST += nutupsconf.aug.in DISTCLEANFILES += *.aug nut-2.8.3/scripts/augeas/nutupsdusers.aug.in0000644000200500020050000000551714777767434016124 00000000000000(* Module: NutUpsdUsers Parses @CONFPATH@/upsd.users Author: Raphael Pinson Frederic Bohe Jim Klimov About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all users granted to send commands to UPS > /files@CONFPATH@/upsd.users/fred/actions/SET About: Configuration files This lens applies to @CONFPATH@/upsd.users. See . *) module NutUpsdUsers = autoload upsd_users_xfm (************************************************************************ * Group: UPSD.USERS *************************************************************************) (* general *) let del_spc = Util.del_opt_ws "" let sep_spc = Util.del_ws_spc let eol = Util.eol let ip = /[0-9A-Za-z\.:]+/ let num = /[0-9]+/ let word = /[^"#; \t\n]+/ let empty = Util.empty (* let netblock = /[0-9A-Za-z\.:\/]+/ *) let netblock = word let path = word let upsd_users_comment = IniFile.comment IniFile.comment_re IniFile.comment_default let upsd_users_sep = IniFile.sep IniFile.sep_re IniFile.sep_default let upsd_users_fields = "password" | "instcmds" let upsd_users_entry = IniFile.indented_entry upsd_users_fields upsd_users_sep upsd_users_comment let upsd_users_actions_entry = [ key /SET|FSD/ ] let upsd_users_actions = [ del_spc . key "actions" . upsd_users_sep . del_spc . upsd_users_actions_entry . ( sep_spc . upsd_users_actions_entry )* . ( upsd_users_comment|eol ) ] (* FIXME: NEEDED? can be all, or a list of instant commands *) let upsd_users_instcmds_entry = [ key /ALL|FSD/ ] let upsd_users_instcmds = [ del_spc . key "instcmds" . upsd_users_sep . del_spc . upsd_users_instcmds_entry . ( sep_spc . upsd_users_instcmds_entry )* . ( upsd_users_comment|eol ) ] let upsd_users_upsmon_type_re = /(master|primary|slave|secondary)/ let upsd_users_upsmon = [ del_spc . key "upsmon" . sep_spc . store upsd_users_upsmon_type_re . eol ] let upsd_users_title = IniFile.indented_title IniFile.record_re let upsd_users_record = IniFile.record upsd_users_title (upsd_users_entry|upsd_users_actions|upsd_users_upsmon) let upsd_users_lns = IniFile.lns upsd_users_record upsd_users_comment let upsd_users_filter = ( incl "@CONFPATH@/upsd.users" ) . Util.stdexcl let upsd_users_xfm = transform upsd_users_lns upsd_users_filter nut-2.8.3/scripts/augeas/nuthostsconf.aug.in0000644000200500020050000000236314553676503016055 00000000000000(* Module: NutHostsConf Parses @CONFPATH@/hosts.conf Author: Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all monitored upsd > print /files@CONFPATH@/hosts.conf/MONITOR About: Configuration files This lens applies to @CONFPATH@/hosts.conf. See . *) module NutHostsConf = autoload hosts_xfm (************************************************************************ * Group: HOSTS.CONF *************************************************************************) (* general *) let del_spc = Util.del_opt_ws "" let sep_spc = Util.del_ws_spc let eol = Util.eol let word = /[^"#; \t\n]+/ let empty = Util.empty let comment = Util.comment let quoted_string = del "\"" "\"" . store /[^"\n]+/ . del "\"" "\"" let hosts_notify = [ del_spc . key "MONITOR" . sep_spc . [ label "system" . store word . sep_spc ] . [ label "description" . quoted_string ] . eol ] let hosts_lns = (hosts_notify|comment|empty)* let hosts_filter = ( incl "@CONFPATH@/hosts.conf" ) . Util.stdexcl let hosts_xfm = transform hosts_lns hosts_filter nut-2.8.3/scripts/augeas/gen-nutupsconf-aug.py.in0000755000200500020050000001000714777767434016732 00000000000000#!@PYTHON@ # Copyright (C) # 2010 - Arnaud Quette # 2020 - 2024 Jim Klimov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # This program extracts all drivers specific variables, declared # using 'addvar()' and output a complete ups.conf lens for Augeas from __future__ import print_function import sys import re import glob import codecs # Return a sorted list of unique entries, based on the input 'list' def sortUnique(list): newVarList = [] prevVar = '' # sort the list list.sort() for curVariable in list: if curVariable != prevVar: newVarList.append(curVariable) prevVar = curVariable return newVarList # Grep for 'string' pattern in the text 'list', # excluding C/C++ styles comments # Return the list of matching lines def grep(string,list): matchList = [] expr = re.compile(string) for text in list: match = expr.search(text) if match != None: # Exclude comments exprComment = re.compile(r'(/\*([^*]|(\*+[^*/]))*\*+/)|(//.*)') if (exprComment.search(match.string) == None): matchList.append(match.string) return matchList if __name__ == '__main__': rawCount = 0 #global finalCount variableNames = [] specificVars = "" #global inLensContent #global finalLensContent Exceptionlist = ['../../drivers/main.c', '../../drivers/skel.c'] outputFilename = 'nutupsconf.aug.in' templateFilename = 'nutupsconf.aug.tpl' dirPrefix = '' if (len(sys.argv) == 2): dirPrefix = sys.argv[1] print(dirPrefix) # 1/ Extract all specific drivers parameters, in a sorted list with unique entries # 1.1/ List all drivers implementation files for filename in glob.glob('../../drivers/*.c'): # 1.2/ Exclude main.c, which defines addvar() and skel.c (example driver) if filename not in Exceptionlist: fd = codecs.open(filename, encoding='utf-8') # 1.3/ Grep for the "addvar(..." pattern matchResults = grep (r'.*addvar[\ ]*\(.*(VAR_FLAG|VAR_VALUE)*,.*', fd) # 1.4/ Extract variable names for line in matchResults: if ("Could not addvar" in line): # Debug trace e.g. in snmp-ups.c continue row = line.split(',') if len(row) >= 2: # Absence of quotes indicate that we have a #define # Let's grep in .ch related files if (row[1].find('"') == -1): for defFilename in glob.glob(filename.replace('.c', '.[ch]')): defFd = codecs.open(defFilename, encoding='utf-8') matchString = '^#define.*' + row[1].replace('"', '').lstrip() + '.*' matchResult = grep (matchString, defFd) for varDefine in matchResult: # Now search for a string defRow = re.findall(r'"([^"]*)",?', varDefine) if (len(defRow) == 1): variableNames.append(defRow[0]) else: # Remove quotes variableNames.append(row[1].replace('"', '').lstrip()) # Filter multiply defined variables variableNames = sortUnique(variableNames) # Create the formated list of specific variables for name in variableNames: specificVars += " | \"%s\"\n" %(name) # 2/ Load the template lens tplFd = codecs.open(dirPrefix + templateFilename, encoding='utf-8') # 2.1/ Search for the pattern to replace outputText = tplFd.read() outputText = outputText.replace('@SPECIFIC_DRV_VARS@', specificVars) # 3/ Output final lens outFd = codecs.open(outputFilename, mode='w', encoding='utf-8') outFd.write(outputText) nut-2.8.3/scripts/augeas/nutupsschedconf.aug.in0000644000200500020050000000416314553676503016533 00000000000000(* Module: NutUpsSchedConf Parses @CONFPATH@/upssched.conf Author: Raphael Pinson Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print the command script: > print /files@CONFPATH@/upssched.conf/CMDSCRIPT About: Configuration files This lens applies to @CONFPATH@/upssched.conf. See . *) module NutUpsschedConf = autoload upssched_xfm (************************************************************************ * Group: UPSSCHED.CONF *************************************************************************) (* general *) let sep_spc = Util.del_ws_spc let eol = Util.eol let num = /[0-9]+/ let word = /[^"#; \t\n]+/ let empty = Util.empty let comment = Util.comment (* Variable: quoted_word *) let word_space = /"[^"\n]+"/ let quoted_word = /"[^" \t\n]+"/ (* Variable: word_all *) let word_all = word_space | word | quoted_word let upssched_re = "CMDSCRIPT" | "PIPEFN" | "LOCKFN" let upssched_opt = [ key upssched_re . sep_spc . store word_all . eol ] let upssched_start_timer = [ key "START-TIMER" . sep_spc . [ label "timername" . store word ] . sep_spc . [ label "interval" . store num ] ] let upssched_cancel_timer = [ key "CANCEL-TIMER" . sep_spc . [ label "timername" . store word ] . ( sep_spc . [ label "cmd" . store word_all ])* ] let upssched_execute_timer = [ key "EXECUTE" . sep_spc . [ label "command" . store word_all ] ] let upssched_command = (upssched_start_timer|upssched_cancel_timer|upssched_execute_timer) let upssched_at = [ key "AT" . sep_spc . [ label "notifytype" . store word ] . sep_spc . [ label "upsname" . store word ] . sep_spc . upssched_command . eol ] let upssched_lns = (upssched_at|upssched_opt|comment|empty)* let upssched_filter = ( incl "@CONFPATH@/upssched.conf" ) . Util.stdexcl let upssched_xfm = transform upssched_lns upssched_filter nut-2.8.3/scripts/augeas/nutupsdconf.aug.in0000644000200500020050000001035314777767434015702 00000000000000(* Module: NutUpsdConf Parses @CONFPATH@/upsd.conf Author: Raphael Pinson Frederic Bohe Arnaud Quette Jim Klimov About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all network interface upsd will listen to > print /files@CONFPATH@/upsd.conf/LISTEN About: Configuration files This lens applies to @CONFPATH@/upsd.conf. See . *) module NutUpsdConf = autoload upsd_xfm (************************************************************************ * Group: UPSD.CONF *************************************************************************) (* general *) let sep_spc = Util.del_ws_spc let opt_spc = Util.del_opt_ws "" let eol = Util.eol let ip = /[0-9A-Za-z\.:]+/ let num = /[0-9]+/ let word = /[^"#; \t\n]+/ let empty = Util.empty let comment = Util.comment let path = word (* TOTHINK: What if we have spaces? Is "word" good? *) let certname = word let dbpass = word let upsd_debug_min = [ opt_spc . key "DEBUG_MIN" . sep_spc . store num . eol ] let upsd_maxage = [ opt_spc . key "MAXAGE" . sep_spc . store num . eol ] let upsd_trackingdelay = [ opt_spc . key "TRACKINGDELAY" . sep_spc . store num . eol ] let upsd_allow_no_device = [ opt_spc . key "ALLOW_NO_DEVICE" . sep_spc . store num . eol ] let upsd_allow_not_all_listeners = [ opt_spc . key "ALLOW_NOT_ALL_LISTENERS" . sep_spc . store num . eol ] let upsd_disable_weak_ssl = [ opt_spc . key "DISABLE_WEAK_SSL" . sep_spc . store num . eol ] let upsd_statepath = [ opt_spc . key "STATEPATH" . sep_spc . store path . eol ] let upsd_listen = [ opt_spc . key "LISTEN" . sep_spc . [ label "interface" . store ip ] . [ sep_spc . label "port" . store num]? ] let upsd_listen_list = upsd_listen . eol let upsd_maxconn = [ opt_spc . key "MAXCONN" . sep_spc . store num . eol ] let upsd_certfile = [ opt_spc . key "CERTFILE" . sep_spc . store path . eol ] let upsd_certpath = [ opt_spc . key "CERTPATH" . sep_spc . store path . eol ] let upsd_certident = [ opt_spc . key "CERTIDENT" . sep_spc . [ label "certname" . store certname ] . [ sep_spc . label "dbpass" . store dbpass ] . eol ] let upsd_certrequest = [ opt_spc . key "CERTREQUEST" . sep_spc . store num . eol ] (************************************************************************ * DEBUG_MIN level * MAXAGE seconds * TRACKINGDELAY seconds * ALLOW_NO_DEVICE Boolean * ALLOW_NOT_ALL_LISTENERS Boolean * DISABLE_WEAK_SSL Boolean * STATEPATH path * LISTEN interface port * Multiple lines each with one LISTEN address (or host name) and an optional * port may be specified. The default is to bind to IPv4 and IPv6 "localhost" * addresses (subject to CLI options `-4` or `-6` constraining IP version, * or system configuration or support), if no LISTEN addresses are specified. * LISTEN 127.0.0.1 * LISTEN 192.168.50.1 * LISTEN ::1 * LISTEN 2001:0db8:1234:08d3:1319:8a2e:0370:7344 * MAXCONN count * CERTFILE path * Single certificate file (SSL with OpenSSL) * CERTPATH path * Path to certificate database split into 3 files (SSL with NSS) * CERTIDENT certname dbpass * Certificate identity to use by the server, and database password * as needed to read it (SSL with NSS) * CERTREQUEST level * Request or require client cert? (SSL with NSS) * Possible values are : * - 0 to not request to clients to provide any certificate * - 1 to require to all clients a certificate * - 2 to require to all clients a valid certificate * *************************************************************************) let upsd_other = upsd_debug_min | upsd_maxage | upsd_trackingdelay | upsd_allow_no_device | upsd_allow_not_all_listeners | upsd_disable_weak_ssl | upsd_statepath | upsd_listen_list | upsd_maxconn | upsd_certfile | upsd_certpath | upsd_certident | upsd_certrequest let upsd_lns = (upsd_other|comment|empty)* let upsd_filter = (incl "@CONFPATH@/upsd.conf") . Util.stdexcl let upsd_xfm = transform upsd_lns upsd_filter nut-2.8.3/scripts/augeas/nutupsconf.aug.tpl0000644000200500020050000000422714777767434015732 00000000000000(* Module: NutUpsConf Parses @CONFPATH@/ups.conf Author: Raphael Pinson Frederic Bohe Arnaud Quette Jim Klimov About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all drivers used > print /files/@CONFPATH@/ups.conf/*/driver About: Configuration files This lens applies to @CONFPATH@/ups.conf. See . *) module NutUpsConf = autoload ups_xfm (************************************************************************ * Group: UPS.CONF *************************************************************************) let ups_comment = IniFile.comment IniFile.comment_re IniFile.comment_default let ups_sep = IniFile.sep IniFile.sep_re IniFile.sep_default let ups_global = "chroot" | "driverpath" | "maxstartdelay" | "maxretry" | "nowait" | "retrydelay" | "pollinterval" | "synchronous" | "user" | "group" | "debug_min" | "STATEPATH" | "statepath" (* This expression did involve a lot of courtship around the parser *) let ups_fields_re = /(default|override)\.[^:=#\r\t\n \/]+/ let ups_fields = "driver" | "port" | "sdorder" | "desc" | "nolock" | "ignorelb" | "maxstartdelay" | "synchronous" | "user" | "group" | "debug_min" | "LIBUSB_DEBUG" @SPECIFIC_DRV_VARS@ let ups_entry = IniFile.indented_entry (ups_global|ups_fields|ups_fields_re) ups_sep ups_comment let ups_title = IniFile.indented_title IniFile.record_re let ups_record = IniFile.record ups_title ups_entry let ups_lns = IniFile.lns ups_record ups_comment let ups_filter = (incl "@CONFPATH@/ups.conf") . Util.stdexcl let ups_xfm = transform ups_lns ups_filter nut-2.8.3/scripts/augeas/tests/0000755000200500020050000000000015001555411013412 500000000000000nut-2.8.3/scripts/augeas/tests/test_nut.aug0000644000200500020050000001274614777767434015744 00000000000000(* Tests for the Nut module *) module Test_nut = let nut_conf = " MODE=standalone " test NutNutConf.nut_lns get nut_conf = { } { "MODE" = "standalone" } (* desc is a single token made of two words below *) let ups_conf1 = " [testups] driver = dummy-ups port = auto desc = \"Dummy UPS Driver\" " test NutUpsConf.ups_lns get ups_conf1 = { } { "testups" { "driver" = "dummy-ups" } { "port" = "auto" } { "desc" = "Dummy UPS Driver" } } (* desc is a single token made of two words prefixed by one quote * as part of its content below (escaped by backslashes) *) let ups_conf2 = " [testups] driver = dummy-ups port = auto desc = \"\\\"Dummy UPS\" # comment line " test NutUpsConf.ups_lns get ups_conf2 = { } { "testups" { "driver" = "dummy-ups" } { "port" = "auto" } { "desc" = "\\\"Dummy UPS" { "#comment" = "comment line" } } } (* desc is a single token made of two words surrounded by quotes * as part of its content below (escaped by backslashes) *) (* FIXME: Lens fails to parse the second escaped slash, probably * because of "to_comment_re" or "entry_generic_nocomment" * test below is truncated so far: * ./tests/test_nut.aug:53.0-58.41:exception thrown in test * ./tests/test_nut.aug:53.5-.37:exception: Get did not match entire input * Lens: /usr/share/augeas/lenses/dist/inifile.aug:497.25-.43: * Error encountered at 5:0 (44 characters into string) * * * Tree generated so far: * /testups * /testups/driver = "dummy-ups" * /testups/port = "auto" * * NOTE That for NUT parsing, such trailing slash is likely a problem * that is not caught by lens parser either: it should mean escaping * the next character (quote) and so an unfinished line. This test case * should have failed but currently does not. *) let ups_conf3 = " [testups] driver = dummy-ups port = auto desc = \"\\\"Dummy UPS\\\" " test NutUpsConf.ups_lns get ups_conf3 = { } { "testups" { "driver" = "dummy-ups" } { "port" = "auto" } { "desc" = "\\\"Dummy UPS\\" } } let upsd_conf = " MAXAGE 30 TRACKINGDELAY 600 ALLOW_NO_DEVICE 1 LISTEN 0.0.0.0 3493 MAXCONN 1024 " test NutUpsdConf.upsd_lns get upsd_conf = { } { "MAXAGE" = "30" } { "TRACKINGDELAY" = "600" } { "ALLOW_NO_DEVICE" = "1" } { "LISTEN" { "interface" = "0.0.0.0" } { "port" = "3493" } } { "MAXCONN" = "1024" } let upsd_users = " [admin] password = upsman actions = SET FSD instcmds = ALL [pfy] password = duh instcmds = test.panel.start instcmds = test.panel.stop [upswired] password = blah upsmon primary [observer] password = abcd upsmon secondary " test NutUpsdUsers.upsd_users_lns get upsd_users = { } { "admin" { "password" = "upsman" } { "actions" { "SET" } { "FSD" } } { "instcmds" = "ALL" } { } } { "pfy" { "password" = "duh" } { "instcmds" = "test.panel.start" } { "instcmds" = "test.panel.stop" } { } } { "upswired" { "password" = "blah" } { "upsmon" = "primary" } { } } { "observer" { "password" = "abcd" } { "upsmon" = "secondary" } } let upsmon_conf = " MONITOR testups@localhost 1 upswired blah primary MINSUPPLIES 1 SHUTDOWNCMD /sbin/shutdown -h +0 POLLFREQ 5 POLLFREQALERT 5 HOSTSYNC 30 DEADTIME 15 POWERDOWNFLAG /etc/killpower RBWARNTIME 43200 NOCOMMWARNTIME 300 FINALDELAY 5 " test NutUpsmonConf.upsmon_lns get upsmon_conf = { } { "MONITOR" { "system" { "upsname" = "testups" } { "hostname" = "localhost" } } { "powervalue" = "1" } { "username" = "upswired" } { "password" = "blah" } { "type" = "primary" } } { } { "MINSUPPLIES" = "1" } { "SHUTDOWNCMD" = "/sbin/shutdown -h +0" } { "POLLFREQ" = "5" } { "POLLFREQALERT" = "5" } { "HOSTSYNC" = "30" } { "DEADTIME" = "15" } { "POWERDOWNFLAG" = "/etc/killpower" } { "RBWARNTIME" = "43200" } { "NOCOMMWARNTIME" = "300" } { "FINALDELAY" = "5" } let upsset_conf = " I_HAVE_SECURED_MY_CGI_DIRECTORY " test NutUpssetConf.upsset_lns get upsset_conf = { } { "auth" = "I_HAVE_SECURED_MY_CGI_DIRECTORY" } let upssched_conf = " CMDSCRIPT /upssched-cmd PIPEFN /var/state/ups/upssched/upssched.pipe LOCKFN /var/state/ups/upssched/upssched.lock AT COMMBAD * START-TIMER upsgone 10 AT COMMOK myups@localhost CANCEL-TIMER upsgone AT ONLINE * EXECUTE ups-back-on-line " test NutUpsschedConf.upssched_lns get upssched_conf = { } { "CMDSCRIPT" = "/upssched-cmd" } { "PIPEFN" = "/var/state/ups/upssched/upssched.pipe" } { "LOCKFN" = "/var/state/ups/upssched/upssched.lock" } { "AT" { "notifytype" = "COMMBAD" } { "upsname" = "*" } { "START-TIMER" { "timername" = "upsgone" } { "interval" = "10" } } } { "AT" { "notifytype" = "COMMOK" } { "upsname" = "myups@localhost" } { "CANCEL-TIMER" { "timername" = "upsgone" } } } { "AT" { "notifytype" = "ONLINE" } { "upsname" = "*" } { "EXECUTE" { "command" = "ups-back-on-line" } } } let hosts_conf = " MONITOR myups@localhost \"Local UPS\" MONITOR su2200@10.64.1.1 \"Finance department\" MONITOR matrix@shs-server.example.edu \"Sierra High School data room #1\" " test NutHostsConf.hosts_lns get hosts_conf = { } { "MONITOR" { "system" = "myups@localhost" } { "description" = "Local UPS" } } { "MONITOR" { "system" = "su2200@10.64.1.1" } { "description" = "Finance department" } } { "MONITOR" { "system" = "matrix@shs-server.example.edu" } { "description" = "Sierra High School data room #1" } } nut-2.8.3/scripts/augeas/nutupsconf.aug.in0000644000200500020050000002456515001555210015510 00000000000000(* Module: NutUpsConf Parses @CONFPATH@/ups.conf Author: Raphael Pinson Frederic Bohe Arnaud Quette Jim Klimov About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all drivers used > print /files/@CONFPATH@/ups.conf/*/driver About: Configuration files This lens applies to @CONFPATH@/ups.conf. See . *) module NutUpsConf = autoload ups_xfm (************************************************************************ * Group: UPS.CONF *************************************************************************) let ups_comment = IniFile.comment IniFile.comment_re IniFile.comment_default let ups_sep = IniFile.sep IniFile.sep_re IniFile.sep_default let ups_global = "chroot" | "driverpath" | "maxstartdelay" | "maxretry" | "nowait" | "retrydelay" | "pollinterval" | "synchronous" | "user" | "group" | "debug_min" | "STATEPATH" | "statepath" (* This expression did involve a lot of courtship around the parser *) let ups_fields_re = /(default|override)\.[^:=#\r\t\n \/]+/ let ups_fields = "driver" | "port" | "sdorder" | "desc" | "nolock" | "ignorelb" | "maxstartdelay" | "synchronous" | "user" | "group" | "debug_min" | "LIBUSB_DEBUG" | "BYPASS" | "CHRG_addr" | "CHRG_noro" | "CHRG_regtype" | "CP" | "CS" | "DISCHRG_addr" | "DISCHRG_noro" | "DISCHRG_regtype" | "FSD_addr" | "FSD_noro" | "FSD_pulse_duration" | "FSD_regtype" | "HB_addr" | "HB_noro" | "HB_regtype" | "ID" | "LB" | "LB_addr" | "LB_noro" | "LB_regtype" | "LowBatt" | "OB_addr" | "OB_noro" | "OB_regtype" | "OL" | "OL_addr" | "OL_noro" | "OL_regtype" | "OffDelay" | "OnDelay" | "RB" | "RB_addr" | "RB_noro" | "RB_regtype" | "SD" | "addr" | "advanced_eco_mode" | "advorder" | "ah" | "alarm_control" | "allow_duplicates" | "authPassword" | "authProtocol" | "authtype" | "awd" | "batteryPercentage" | "battery_alarm" | "battery_max" | "battery_min" | "battery_number" | "battery_open_status_check" | "battery_voltage_reports_one_pack" | "battext" | "battvoltmult" | "baud" | "baud_rate" | "baudrate" | "bus" | "busport" | "bypass_alarm" | "bypass_forbidding" | "bypass_when_off" | "cable" | "cablepower" | "chargetime" | "community" | "constant_phase_angle" | "converter_mode" | "cshdelay" | "databits" | "daysoff" | "daysweek" | "debug_pkt_data" | "debug_pkt_hwinfo" | "debug_pkt_raw" | "dev_slave_id" | "device" | "device_mfr" | "device_model" | "disable_fix_report_desc" | "do_convert_deci" | "dumbterm" | "eco_mode" | "explore" | "fake_lowbatt" | "fault_1" | "fault_2" | "fault_3" | "fault_4" | "fault_5" | "flash" | "frequency" | "fruid" | "full_update" | "hb" | "houroff" | "houron" | "i2c_address" | "idleload" | "ignoresab" | "input_fault_voltage" | "input_timeout" | "interrupt_pipe_no_events_tolerance" | "interruptonly" | "interruptsize" | "langid_fix" | "lb" | "lbrb_log_delay_sec" | "lbrb_log_delay_without_calibrating" | "limited_runtime_on_battery" | "linevoltage" | "load.off" | "load.on" | "load.status" | "loadPercentage" | "localcalculation" | "login" | "lowbatt" | "manufacturer" | "max_bypass_freq" | "max_bypass_volt" | "max_load" | "max_polls_without_data" | "maxreport" | "methodOfFlowControl" | "mfr" | "mibs" | "min_bypass_freq" | "min_bypass_volt" | "mincharge" | "minruntime" | "mod_byte_to_s" | "mod_byte_to_us" | "mod_resp_to_s" | "mod_resp_to_us" | "model" | "modelname" | "nobt" | "nohang" | "nombattvolt" | "nominal_cell_voltage" | "nooutstats" | "norating" | "noscanlangid" | "notification" | "notransferoids" | "novendor" | "nowarn_noimp" | "numOfBytesFromUPS" | "numbatteries" | "number_of_battery_cells" | "offdelay" | "oldmac" | "ondelay" | "onlinedischarge" | "onlinedischarge_calibration" | "onlinedischarge_log_throttle_hovercharge" | "onlinedischarge_log_throttle_sec" | "onlinedischarge_onbattery" | "output_pace" | "output_phase_angle" | "output_voltages" | "parity" | "password" | "pf" | "pins_shutdown_mode" | "pollfreq" | "pollonly" | "porttype" | "powercom_sdcmd_byte_order_fallback" | "powerup" | "prefix" | "prgshut" | "privPassword" | "privProtocol" | "product" | "productid" | "protocol" | "rebootdelay" | "recharge_time" | "repeater_disable_strict_start" | "reset_to_default" | "response_timeout_ms" | "retry" | "rio_slave_id" | "rules" | "runtime_full" | "runtime_half" | "runtimecal" | "sdtime" | "sdtype" | "secLevel" | "secName" | "semistaticfreq" | "sensorid" | "ser_baud_rate" | "ser_data_bit" | "ser_parity" | "ser_stop_bit" | "serial" | "serialnumber" | "series" | "shutdownArguments" | "shutdown_delay" | "shutdown_duration" | "shutdown_timer" | "silent" | "site_fault_detection" | "slave_address" | "slaveid" | "snmp_retries" | "snmp_timeout" | "snmp_version" | "startdelay" | "status_only" | "stayoff" | "stopbits" | "subdriver" | "subscribe" | "symmetrathreephase" | "sysfs_dir" | "testing" | "testtime" | "timeout" | "ttymode" | "type" | "ups.delay.shutdown" | "ups.delay.start" | "upsid" | "upstype" | "usb_config_index" | "usb_hid_desc_index" | "usb_hid_ep_in" | "usb_hid_ep_out" | "usb_hid_rep_index" | "usb_set_altinterface" | "usd" | "use_crlf" | "use_pre_lf" | "username" | "va" | "validationSequence" | "vbat" | "vendor" | "vendorid" | "vin_high_crit_perc" | "vin_high_warn_perc" | "vin_low_crit_perc" | "vin_low_warn_perc" | "voltage" | "wait" | "waitbeforereconnect" | "work_range_type" | "wugrace" let ups_entry = IniFile.indented_entry (ups_global|ups_fields|ups_fields_re) ups_sep ups_comment let ups_title = IniFile.indented_title IniFile.record_re let ups_record = IniFile.record ups_title ups_entry let ups_lns = IniFile.lns ups_record ups_comment let ups_filter = (incl "@CONFPATH@/ups.conf") . Util.stdexcl let ups_xfm = transform ups_lns ups_filter nut-2.8.3/scripts/augeas/nutnutconf.aug.in0000644000200500020050000000453514777767434015542 00000000000000(* Module: NutNutConf Parses @CONFPATH@/nut.conf Author: Frederic Bohe Jim Klimov About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print NUT MODE start-up configuration: > print /files@CONFPATH@/nut.conf/MODE About: Configuration files This lens applies to @CONFPATH@/nut.conf. See . *) module NutNutConf = autoload nut_xfm (************************************************************************ * Group: NUT.CONF *************************************************************************) (* general *) let def_sep = IniFile.sep IniFile.sep_re IniFile.sep_default let sep_spc = Util.del_opt_ws "" let eol = Util.eol let comment = Util.comment let empty = Util.empty (* note different definitions than in other configs - this one is shell-syntax *) let bool = /true|false|"true"|"false"|'true'|'false'/ let num = /[0-9]+|"[0-9]+"|'[0-9]+'/ let num_signed = /[+-]?[0-9]+|"[+-]?[0-9]+"|'[+-]?[0-9]+'/ let word = /[^"#; \t\n]+/ (* Variable: quoted_word *) let word_space = /"[^"\n]+"/ let quoted_word = /"[^" \t\n]+"|'[^' \t\n]+'/ (* Variable: word_all *) let word_all = word_space | word | quoted_word let nut_possible_mode = "none" | "standalone" | "netserver" | "netclient" | "controlled" | "manual" let nut_mode = [ sep_spc . key "MODE" . def_sep . sep_spc . store nut_possible_mode . eol ] let nut_bool_re = "ALLOW_NO_DEVICE" | "ALLOW_NOT_ALL_LISTENERS" | "POWEROFF_QUIET" let nut_bool = [ sep_spc . key nut_bool_re . def_sep . sep_spc . store bool . eol ] let nut_num_re = "POWEROFF_WAIT" let nut_num = [ sep_spc . key nut_num_re . def_sep . sep_spc . store num . eol ] let nut_num_signed_re = "NUT_DEBUG_LEVEL" let nut_num_signed = [ sep_spc . key nut_num_signed_re . def_sep . sep_spc . store num_signed . eol ] let nut_word_all_re = "UPSD_OPTIONS" | "UPSMON_OPTIONS" let nut_word_all = [ sep_spc . key nut_word_all_re . def_sep . sep_spc . store word_all . eol ] let nut_lns = (nut_mode|nut_bool|nut_num|nut_num_signed|nut_word_all|comment|empty)* let nut_filter = ( incl "@CONFPATH@/nut.conf" ) . Util.stdexcl let nut_xfm = transform nut_lns nut_filter nut-2.8.3/scripts/augeas/nutupssetconf.aug.in0000644000200500020050000000220014553676503016226 00000000000000(* Module: NutUpssetConf Parses @CONFPATH@/upsset.conf Author: Raphael Pinson Frederic Bohe About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print the string declaring secured cgi directory: > print /files@CONFPATH@/upsset.conf/auth About: Configuration files This lens applies to @CONFPATH@/upsset.conf. See . *) module NutUpssetConf = autoload upsset_xfm (************************************************************************ * Group: UPSSET.CONF *************************************************************************) (* general *) let sep_spc = Util.del_opt_ws "" let eol = Util.eol let comment = Util.comment let empty = Util.empty let upsset_key_word = "I_HAVE_SECURED_MY_CGI_DIRECTORY" let upsset_key = [ label "auth" . sep_spc . store upsset_key_word . eol ] let upsset_lns = (upsset_key|comment|empty)* let upsset_filter = ( incl "@CONFPATH@/upsset.conf" ) . Util.stdexcl let upsset_xfm = transform upsset_lns upsset_filter nut-2.8.3/scripts/augeas/nutupsmonconf.aug.in0000644000200500020050000001350015001552635016215 00000000000000(* Module: NutUpsmonConf Parses @CONFPATH@/upsmon.conf Author: Raphael Pinson Frederic Bohe Jim Klimov About: License This file is licensed under the GPL. About: Lens Usage Sample usage of this lens in augtool * Print all notification messages > print /files@CONFPATH@/upsmon.conf/NOTIFYMSG About: Configuration files This lens applies to @CONFPATH@/upsmon.conf. See . *) module NutUpsmonConf = autoload upsmon_xfm (************************************************************************ * Group: UPSMON.CONF *************************************************************************) (* general *) let del_spc = Util.del_opt_ws "" let sep_spc = Util.del_ws_spc let eol = Util.eol let num = /[0-9]+/ let num_signed = /[+-]?[0-9]+/ let bool = /([01]|yes|no|true|false|on|off|ok)/ let num_bool = /([0-9]+|yes|no|true|false|on|off|ok)/ let word = /[^"#; \t\n]+/ let empty = Util.empty let comment = Util.comment let quoted_string = del "\"" "\"" . store /[^"\n]+/ . del "\"" "\"" (* UPS identifier * [@[:]] * * There might be a cleaner way to write this * but I'm stuck with (hostname | hostname . port)? *) (* Disregard named ports, we use numbers *) let hostspec = /([^ \t\n:]+|[^ \t\n:]+:[0-9]+)/ let hostname = [ label "hostname" . store /[^ \t\n:]+/ ] let port = [ label "port" . store num ] let identifier = [ label "upsname" . store /[^ \t\n@]+/ ] . ( ( Util.del_str "@" . hostname ) | ( Util.del_str "@" . hostname . Util.del_str ":" . port ) )? let upsmon_num_re = "DEADTIME" | "FINALDELAY" | "HOSTSYNC" | "MINSUPPLIES" | "NOCOMMWARNTIME" | "POLLFREQ" | "POLLFREQALERT" | "RBWARNTIME" let upsmon_num_signed_re = "DEBUG_MIN" | "POLLFAIL_LOG_THROTTLE_MAX" | "OFFDURATION" | "OBLBDURATION" | "OVERDURATION" let upsmon_num_bool_re = "SHUTDOWNEXIT" let upsmon_bool_re = "CERTVERIFY" | "FORCESSL" | "ALARMCRITICAL" let upsmon_num = [ del_spc . key upsmon_num_re . sep_spc . store num . eol ] let upsmon_num_signed = [ del_spc . key upsmon_num_signed_re . sep_spc . store num_signed . eol ] let upsmon_num_bool = [ del_spc . key upsmon_num_bool_re . sep_spc . store num_bool . eol ] let upsmon_bool = [ del_spc . key upsmon_bool_re . sep_spc . store bool . eol ] let upsmon_word = [ del_spc . key "RUN_AS_USER" . sep_spc . store word . eol ] let upsmon_file_re = "NOTIFYCMD" | "POWERDOWNFLAG" | "SHUTDOWNCMD" | "CERTFILE" | "CERTPATH" let sto_to_eol = IniFile.sto_to_eol (* here we should support both quoted and not quoted * string but I can't manage to find the right way of doing this *) let upsmon_file = [ del_spc . key upsmon_file_re . sto_to_eol . eol ] (* MONITOR system powervalue username password type *) let upsmon_monitor_type_re = /(master|primary|slave|secondary)/ (* TOTHINK: What if we have spaces? Is "word" good? *) let upsmon_monitor = [ del_spc . key "MONITOR" . sep_spc . [ label "system" . identifier ] . sep_spc . [ label "powervalue" . store num ] . sep_spc . [ label "username" . store word ] . sep_spc . [ label "password" . store word ] . sep_spc . [ label "type" . store upsmon_monitor_type_re ] . eol ] let upsmon_notify_type = "ONLINE" | "ONBATT" | "LOWBATT" | "FSD" | "COMMOK" | "COMMBAD" | "SHUTDOWN" | "REPLBATT" | "NOCOMM" | "NOPARENT" | "CAL" | "NOTCAL" | "OFF" | "NOTOFF" | "BYPASS" | "NOTBYPASS" | "ECO" | "NOTECO" | "ALARM" | "NOTALARM" | "OVER" | "NOTOVER" | "TRIM" | "NOTTRIM" | "BOOST" | "NOTBOOST" | "OTHER" | "NOTOTHER" | "SUSPEND_STARTING" | "SUSPEND_FINISHED" let upsmon_notify = [ del_spc . key "NOTIFYMSG" . sep_spc . [ label "type" . store upsmon_notify_type . sep_spc ] . [ label "message" . quoted_string ] . eol ] let flags = "IGNORE" | "SYSLOG" | "WALL" | "EXEC" let plus = [ del /\+*/ "" ] (*let entries = /IGNORE|SYSLOG|WALL|EXEC+/*) let record = [ seq "record" . plus . store flags ] let upsmon_notify_flag = [ counter "record" . del_spc . key "NOTIFYFLAG" . sep_spc . [ label "type" . store upsmon_notify_type . sep_spc ] . record+ . eol ] (* TOTHINK: What if we have spaces? Is "word" good? *) let certname = word let dbpass = word let upsmon_certident = [ del_spc . key "CERTIDENT" . sep_spc . [ label "certname" . store certname ] . [ sep_spc . label "dbpass" . store dbpass ] . eol ] (* we can have an array of these *) let upsmon_certhost = [ del_spc . key "CERTHOST" . sep_spc . [ label "hostspec" . store hostspec ] . [ sep_spc . label "certname" . store certname ] . [ sep_spc . label "certverify" . store num_bool ] . [ sep_spc . label "forcessl" . store num_bool ] . eol ] let upsmon_certhost_list = upsmon_certhost . eol let upsmon_record = upsmon_num|upsmon_num_signed|upsmon_num_bool|upsmon_bool|upsmon_word|upsmon_file|upsmon_monitor|upsmon_notify|upsmon_notify_flag|upsmon_certident|upsmon_certhost_list let upsmon_lns = (upsmon_record|comment|empty)* let upsmon_filter = ( incl "@CONFPATH@/upsmon.conf" ) . Util.stdexcl let upsmon_xfm = transform upsmon_lns upsmon_filter nut-2.8.3/scripts/usb_resetter/0000755000200500020050000000000015001555411013511 500000000000000nut-2.8.3/scripts/usb_resetter/nut-driver.service0000644000200500020050000000063414777534446017145 00000000000000[Unit] Description=Network UPS Tools - power device driver controller After=local-fs.target network.target StopWhenUnneeded=no [Service] ExecStartPre=-/usr/bin/systemd-tmpfiles --create /usr/lib/tmpfiles.d/nut-client.conf ExecStartPre=/usr/local/bin/usb_resetter --reset-hub --device 0665:5161 ExecStart=/usr/sbin/upsdrvctl start ExecStop=/usr/sbin/upsdrvctl stop Type=forking Restart=on-failure RestartSec=5s nut-2.8.3/scripts/usb_resetter/README.adoc0000644000200500020050000000776414777534446015264 00000000000000Method for resetting unreliable USB UPS interfaces (on Linux) ============================================================= Orsiris de Jong - NetInvent SASU v1.0, 30 Mar 2023 (start date) Some cheaper USB UPS have the same kind of unreliable USB to serial interface, often being a "Cypress Semiconductor USB to Serial" or "INNO TECH USB to Serial" (often with the `0665:5161` VendorID/ProductID seen in examples below). Most of them use `blazer_usb` or `nutdrv_qx` NUT driver, and sometimes the driver can't start because it can't communicate with the UPS. NOTE: It is believed that in some cases the chip on UPS side can go into a sort of power-saving mode after some quiet time, so increasing the NUT driver polling frequency may help avoid that particular situation. Unplugging and plugging the USB port usually fixes this, but that's not convenient. That's where `usb_resetter` comes in handy (see the https://github.com/netinvent/usb_resetter project page for more info). You would need a Python environment to run the script, and it is limited to Linux platforms as of this writing. Grab a copy via `pip` with `pip install usb_resetter`, or make a plain install directly from GitHub with e.g.: ---- :; curl -o /usr/local/bin/usb_resetter -L \ https://raw.githubusercontent.com/netinvent/usb_resetter/main/usb_resetter/usb_resetter.py \ && chmod +x /usr/local/bin/usb_resetter ---- Once you have got the script, identify the USB UPS with: ---- :; usb_resetter --list ---- In our case, we could see something like: ---- Found device 0665:5161 at /dev/bus/usb/001/002 Manufacturer=INNO TECH, Product=USB to Serial ---- The `usb_resetter` can work in three different ways: - Reset device itself - Reset the hub the device is attached to - Reset all USB controllers A simple USB device reset typically isn't sufficient for those UPS devices, so we would need to reset the hub it's attached to. The command for doing that is: ---- :; usb_resetter --reset-hub --device 0665:5161 ---- Bear in mind that this will reset other devices connected to the same hub. While this isn't a problem for a keyboard/mouse, it might be for a USB storage device. On some hardware, each USB plug gets its own hub. On others, two or more USB plugs share one hub. A good practice would be to isolate the USB UPS on a hub without any other device in order to not interfere with other hardware, or to associate it on a hub where a non-critical device is already plugged. Getting the hub your device is attached to can be done with: ---- :; usb_resetter --list-hubs --device 0665:5161 ---- The easiest way to integrate this activity with the `nut-driver` service is to modify the systemd service file (or ideally use a separate "drop-in" snippet file) with the following line: ---- ExecStartPre=/usr/local/bin/usb_reset.py --reset-hub --device 0665:5161 ---- An example modified `nut-driver.service` file which may be applicable to a NUT v2.7.4 or older release (modulo the paths and the particular VID:PID) is provided in this directory. Those releases packaged a single service unit for all the drivers you have, managed as one bundle. With current NUT releases (2.8.0+), a `nut-driver@.service` template is used to run each driver in a dedicated instance, declared manually or often by the `nut-driver-enumerator` script or service (tracking `ups.conf` sections). The added call to `usb_resetter` can then be a systemd drop-in file tailored for that particular device and named like `/etc/systemd/system/nut-driver@myups.service.d/usbreset.conf`, so it does not impact others (unless they use the same USB hub). This way, every time the nut-driver service is restarted, the USB UPS link is reset. NOTE: In author's testing, there were no additional delays required after the `usb_resetter` before starting the driver. Generally however, keep in mind that after a (re-)connection, the OS re-discovers the device, then it gets owned by kernel, then the udev/upower/... subsystem hands it off to a NUT run-time account, and only then can it be opened by a driver. nut-2.8.3/scripts/ufw/0000755000200500020050000000000015001555412011605 500000000000000nut-2.8.3/scripts/ufw/nut.ufw.profile.in0000644000200500020050000000021314553676503015136 00000000000000[NUT] title=NUT - Network UPS Tools server description=NUT is a client - server system with support for UPS, PDU and PSU. ports=@PORT@/tcp nut-2.8.3/scripts/ufw/README.adoc0000644000200500020050000000152114777534446013340 00000000000000Uncomplicated Firewall (UFW) support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NUT can tightly integrate with link:http://en.wikipedia.org/wiki/Uncomplicated_Firewall[Uncomplicated Firewall] using the provided profile (nut.ufw.profile). You must first install the profile on your system: $ cp nut.ufw.profile /etc/ufw/applications.d/ To enable outside access to your local upsd, use: $ ufw allow NUT To restrict access to the network '192.168.X.Y', use: $ ufw allow from 192.168.0.0/16 to any app NUT You can also use graphical frontends, such as gui-ufw (gufw), ufw-kde or ufw-frontends. For more information, refer to: - link:http://gufw.tuxfamily.org/[UFW homepage], - link:https://launchpad.net/ufw[UFW project page], - link:https://wiki.ubuntu.com/UncomplicatedFirewall[UFW wiki], - UFW manual page, section APPLICATION INTEGRATION nut-2.8.3/scripts/ufw/Makefile.am0000644000200500020050000000047414777534446013615 00000000000000# Network UPS Tools: scripts/ufw EXTRA_DIST = README.adoc nut.ufw.profile.in # Note: spellchecking is currently ensured by docs/Makefile.am # due to inclusion into docs/security.txt, and the heading level # is also dictated by that. MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *-spellchecked README nut-2.8.3/scripts/ufw/Makefile.in0000644000200500020050000005235315001555011013575 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/ufw VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = scripts/ufw ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut.ufw.profile CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/nut.ufw.profile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README.adoc nut.ufw.profile.in # Note: spellchecking is currently ensured by docs/Makefile.am # due to inclusion into docs/security.txt, and the heading level # is also dictated by that. MAINTAINERCLEANFILES = Makefile.in .dirstamp CLEANFILES = *-spellchecked README all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/ufw/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/ufw/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut.ufw.profile: $(top_builddir)/config.status $(srcdir)/nut.ufw.profile.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/Solaris8/0000755000200500020050000000000015001555411012507 500000000000000nut-2.8.3/scripts/Solaris8/S99upsmon0000755000200500020050000000140014777534446014226 00000000000000#! /bin/sh # Copyright (c) 1995-2000 ??? # # Author: Sandro Wefel # # Put it in /etc/rc2.d/ or /etc/rc3.d depending on runlevel # PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH UPSDPATH=/usr/local/ups/sbin NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY # See how we are called. case "$1" in 'start') if [ -x $UPSDPATH/upsmon ]; then echo "NUT Starting UPS monitor " $UPSDPATH/upsmon >/dev/console 2>&1 touch /var/lock/subsys/upsmon fi ;; 'stop') echo "NUT Stopping UPS monitor " /usr/bin/pkill -x upsmon rm -f /var/lock/subsys/upsmon ;; 'restart') $0 stop $0 start ;; *) echo "Usage: upsmon {start|stop|restart}" exit 1 ;; esac exit 0 nut-2.8.3/scripts/upsdrvsvcctl/0000755000200500020050000000000015001555412013546 500000000000000nut-2.8.3/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in0000644000200500020050000023657114777767434020757 00000000000000#!/bin/sh # BIG NOTE: Not bash, not any other predetermined shell implementation # # NOTE: This script is intentionally written with portable shell constructs # with the aim and hope to work in different interpreters, so it is a # bit dumber and less efficient than could be achieved with the more # featured shells in the spectrum. Also, to minimize the in-memory and # debug-console traffics, tests for (non-)emptiness of anticipated large # strings are not done by `test -n/-z`, but by counting the size of the # string (zero or not). # NOTE ALSO: The configuration parser in this script is not meant to be a # reference or 100% compliant with what the binary code uses; its aim # is to just pick out some strings relevant for tracking config changes. # # Copyright (C) 2016-2020 Eaton # Copyright (C) 2020-2025 Jim Klimov # # 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. # #! \file nut-driver-enumerator.sh(.in) # \author Jim Klimov # \brief Enumerate NUT devices for service-unit instance configuration # \details This script allows to enumerate UPSes in order to produce the # individual service unit instances for each defined configuration. # It assumes the user has adequate permissions to inspect and create # services (e.g. is a root or has proper RBAC profiles to do so). # It helps service frameworks such as Linux systemd and Solaris SMF. # When executed, this script looks for all configured ups.conf # sections and registered service instances, and makes these two # lists match up. It has also a mode to do this in a loop, to keep # checking for differences and applying them, on systems where it's # problematic to trigger it in response to FS event notifications. # Returns exit codes: # 0 Sections and services already match up # 42 Sections and services differed, but now match up - # now the caller should likely restart some services. # Note that the drivers' service instances were started or # stopped as required (by AUTO_START=yes) - but maybe the # upsd or upsmon services should restart. If you pass envvar # REPORT_RESTART_42=no then this codepath would return 0. # In default mode, such non-null reconfiguration should cause # the nut-driver-enumerator service to restart and this would # propagate to other NUT services that depend on it. # 13 Sections and services differed, and still do not match up # 1 Bad inputs, e.g. unrecognized service management framework # 2 Absent or unreadable ups.conf file # # NOTE: Currently found caveats that might be solved later but require # considerable effort: # * Solaris SMF constrains the syntax of valid strings for instance names # (e.g. not starting with a digit, no period chars) which blocks creation # of some UPS driver instances. This might be worked around by hashing # the device name e.g. to base64 (and un-hashing instance name when calling # upsdrvctl), but is not quite user-friendly. Also can store device name # in a service attribute while mangling the instance name to a valid subset. # Comparisons (if devices are already wrapped) becomes more complicated in # the script in either case, as well as in the service startup method. # ** The `+` `/` `=` characters from base64 are also invalid for SMF instance # name, but the first two can be sed'ed to `-` `_` and back, for example. # Some prefix word is also needed (avoid starting with a digit). # The trailing padding `=` can be dropped, and added until we get a # non-empty decode. Conversions can be done by # `echo "$string" | openssl base64 -e|-d` # * Dummy-UPS services that "proxy" another locally defined section are # essentially a circular dependency for upsd. While the system might # start-up lacking a driver, there should be some timer to re-enable # failed not-disabled drivers (would be useful in any case though). # Directory where NUT configs are located, e.g. /etc/nut or /etc/ups # Set at package configuration, compiled into daemons and drivers prefix="@prefix@" [ -n "${NUT_CONFPATH-}" ] || NUT_CONFPATH="@sysconfdir@" # Technically this should be a distribution-dependent value configured # during package build. But everyone has it the same from systemd defaults: [ -n "${SYSTEMD_CONFPATH-}" ] || SYSTEMD_CONFPATH="/etc/systemd/system" if [ -n "$ZSH_VERSION" ]; then ### Problem: loops like `for UPS in $UPSLIST` do not separate ### the UPSLIST into many tokens but use it as one string. echo "FATAL: zsh is not supported in this script" >&2 exit 1 # setopt noglob # setopt +F # IFS="`printf ' \t\r\n'`" ; export IFS fi if set | grep -E '^(shell|version|t?csh)' | grep -E 't?csh' >/dev/null ; then echo "FATAL: csh or tcsh is not supported in this script" >&2 exit 1 fi # Third-party services to depend on (can be overridden by config file) ### Note that for systemd+udev integration, it may be better to set up ### triggers in udev, see e.g. ### http://stackoverflow.com/questions/18463755/linux-start-daemon-on-connected-usb-serial-dongle ### Also can tune whether a driver "Wants" another service (would consider ### ordering if that one is enabled, but live if it is disabled), or if it ### "Requires" that (would cause that to start). DEPSVC_USB_SYSTEMD="systemd-udevd.service nut-udev-settle.service" DEPREQ_USB_SYSTEMD="Wants" # Serial drivers may rely on USB dongles or even custom-owned real ports: DEPSVC_SERIAL_SYSTEMD="systemd-udevd.service nut-udev-settle.service" DEPREQ_SERIAL_SYSTEMD="Wants" DEPSVC_NET_FULL_SYSTEMD="network-online.target systemd-resolved.service ifplugd.service" DEPREQ_NET_FULL_SYSTEMD="Wants" DEPSVC_NET_LOCAL_SYSTEMD="network.target" DEPREQ_NET_LOCAL_SYSTEMD="Wants" SVCNAME_SYSTEMD="nut-driver" # Some or all of these FMRIs may be related to dynamically changing hardware # require_all) ;; # All cited services are running (online or degraded) # require_any) ;; # At least one of the cited services is running # optional_all) ;; # (All) cited services are running or would not run # # without administrative action (disabled, maintenance, # # not present, or are waiting for dependencies which do # # not start without administrative action). DEPSVC_USB_SMF="svc:/system/hotplug:default svc:/system/dbus:default svc:/system/hal:default svc:/milestone/devices:default" DEPREQ_USB_SMF="optional_all" # By default there are several physical network FMRIs shipped and at most # only one is enabled on a particular system (e.g. :default or :nwam) DEPSVC_NET_FULL_SMF="svc:/network/physical svc:/milestone/name-services" DEPREQ_NET_FULL_SMF="optional_all" DEPSVC_NET_LOCAL_SMF="svc:/network/loopback:default" DEPREQ_NET_LOCAL_SMF="optional_all" SVCNAME_SMF="svc:/system/power/nut-driver" [ -z "${NUT_DRIVER_ENUMERATOR_CONF-}" ] && \ NUT_DRIVER_ENUMERATOR_CONF="${NUT_CONFPATH}/nut-driver-enumerator.conf" [ -s "${NUT_DRIVER_ENUMERATOR_CONF}" ] && \ echo "Sourcing config file: ${NUT_DRIVER_ENUMERATOR_CONF}" && \ . "${NUT_DRIVER_ENUMERATOR_CONF}" [ -z "${UPSCONF-}" ] && \ UPSCONF="${NUT_CONFPATH}/ups.conf" # Start a freshly-registered unit? [ -z "${AUTO_START-}" ] && AUTO_START=yes # We avoid regex '\t' which gets misinterpreted by some tools TABCHAR="`printf '\t'`" || TABCHAR=' ' if [ -z "${SERVICE_FRAMEWORK-}" ] ; then [ -x /usr/sbin/svcadm ] && [ -x /usr/sbin/svccfg ] && [ -x /usr/bin/svcs ] && [ -x /usr/bin/svcprop ] && \ SERVICE_FRAMEWORK="smf" [ -z "${SERVICE_FRAMEWORK-}" ] && \ [ -x /bin/systemctl ] && \ SERVICE_FRAMEWORK="systemd" fi # Optionally use Coreutils timeout to limit the # (potentially hanging) calls to systemd tools... # Should not hurt with SMF too, if it ever misbehaves. if [ -z "${TIMEOUT_CMD+x}" ]; then # Envvar not set at all (set but empty is okay, caller wants that then) TIMEOUT_CMD="" TIMEOUT_ARGS="" if which timeout 2>/dev/null >/dev/null ; then # Systemd default timeout for unit start/stop TIMEOUT_CMD="timeout" TIMEOUT_ARGS="90s" fi fi # Should be populated by configure script during NUT build: NUT_WEBSITE_BASE='@NUT_WEBSITE_BASE@' # Fallback, no trailing slash! [ -n "${NUT_WEBSITE_BASE-}" ] || NUT_WEBSITE_BASE='https://www.networkupstools.org' # Cache needed bits of ups.conf to speed up later parsing. Note that these # data are needed for most operations, and populated by upslist_readFile() UPSCONF_DATA="" # Subset of normalized data above that only has sections, drivers and ports (SDP) UPSCONF_DATA_SDP="" # List of configured UPSes in the config-file UPSLIST_FILE="" # List of configured service instances for UPS drivers UPSLIST_SVCS="" # Framework-specific implementations are generally hooked here: hook_registerInstance="" hook_unregisterInstance="" hook_refreshSupervizor="" hook_listInstances="" hook_listInstances_raw="" hook_validInstanceName="" hook_validFullUnitName="" hook_validInstanceSuffixName="" hook_getSavedDeviceName="" hook_findSavedDeviceName="" hook_setSavedDeviceName="" hook_setDocLink="" hook_getSavedMD5="" hook_setSavedMD5="" hook_restart_upsd="" hook_restart_drv="" case "${SERVICE_FRAMEWORK-}" in smf) hook_registerInstance="smf_registerInstance" hook_unregisterInstance="smf_unregisterInstance" hook_refreshSupervizor="smf_refreshSupervizor" hook_listInstances="smf_listInstances" hook_listInstances_raw="smf_listInstances_raw" hook_validInstanceName="smf_validInstanceName" hook_validFullUnitName="smf_validFullUnitName" hook_validInstanceSuffixName="smf_validInstanceSuffixName" hook_getSavedDeviceName="smf_getSavedDeviceName" hook_findSavedDeviceName="smf_findSavedDeviceName" hook_setSavedDeviceName="smf_setSavedDeviceName" hook_setDocLink="smf_setDocLink" hook_getSavedMD5="smf_getSavedMD5" hook_setSavedMD5="smf_setSavedMD5" hook_restart_upsd="smf_restart_upsd" hook_restart_drv="smf_restart_drv" ;; systemd) hook_registerInstance="systemd_registerInstance" hook_unregisterInstance="systemd_unregisterInstance" hook_refreshSupervizor="systemd_refreshSupervizor" hook_listInstances="systemd_listInstances" hook_listInstances_raw="systemd_listInstances_raw" hook_validInstanceName="systemd_validInstanceName" hook_validFullUnitName="systemd_validFullUnitName" hook_validInstanceSuffixName="systemd_validInstanceSuffixName" hook_getSavedDeviceName="systemd_getSavedDeviceName" hook_findSavedDeviceName="systemd_findSavedDeviceName" hook_setSavedDeviceName="systemd_setSavedDeviceName" hook_setDocLink="systemd_setDocLink" hook_getSavedMD5="systemd_getSavedMD5" hook_setSavedMD5="systemd_setSavedMD5" hook_restart_upsd="systemd_restart_upsd" hook_restart_drv="systemd_restart_drv" ;; selftest) hook_registerInstance="selftest_NOOP" hook_unregisterInstance="selftest_NOOP" hook_refreshSupervizor="selftest_NOOP" hook_listInstances="selftest_NOOP" hook_listInstances_raw="selftest_NOOP" hook_validInstanceName="selftest_NOOP" hook_validFullUnitName="selftest_NOOP" hook_validInstanceSuffixName="selftest_NOOP" hook_getSavedDeviceName="selftest_NOOP" hook_findSavedDeviceName="selftest_NOOP" hook_setSavedDeviceName="selftest_NOOP" hook_setDocLink="selftest_NOOP" hook_getSavedMD5="selftest_NOOP" hook_setSavedMD5="selftest_NOOP" hook_restart_upsd="selftest_NOOP" hook_restart_drv="selftest_NOOP" ;; "") echo "Error detecting the service-management framework on this OS" >&2 exit 1 ;; *) echo "Error: User provided an unknown service-management framework '$SERVICE_FRAMEWORK'" >&2 exit 1 ;; esac selftest_NOOP() { echo "NO-OP: Self-testing context does not do systems configuration" >&2 return 0 } common_isFiled() { [ "${#UPSLIST_FILE}" != 0 ] && \ for UPSF in $UPSLIST_FILE ; do [ "$1" = "$UPSF" ] && return 0 [ "`$hook_validInstanceName "$UPSF"`" = "$1" ] && return 0 done return 1 } common_isRegistered() { [ "${#UPSLIST_SVCS}" != 0 ] && \ for UPSS in $UPSLIST_SVCS ; do [ "$1" = "$UPSS" ] && return 0 [ "`$hook_validInstanceName "$1"`" = "$UPSS" ] && return 0 done return 1 } upslist_equals() { # Compare pre-sorted list of DEVICES ($1) and SVCINSTs ($2) including # the possible mangling for service names. Return 0 if lists describe # exactly same set of devices and their services. # Note: This logic only checks the names, not the contents of device # sections, so re-definitions of an existing device configuration # would not trigger a service restart by itself. Such deeper check # belongs in a different routine, see upssvcconf_checksum_unchanged(). # Trivial case 0: one string is empty, another is not # Note: `echo '' | wc -l` == "1" not "0"! [ "${#1}" != 0 -a "${#2}" = 0 ] && return 1 [ "${#1}" = 0 -a "${#2}" != 0 ] && return 1 # Trivial case 1: equal strings [ "$1" = "$2" ] && return 0 # Trivial case 2: different amount of entries [ "`echo "$1" | wc -l`" = "`echo "$2" | wc -l`" ] || return $? _TMP_DEV_SVC="" for _DEV in $1 ; do DEVINST="`$hook_validInstanceName "${_DEV}"`" for _SVC in $2 ; do [ "${_DEV}" = "${_SVC}" ] \ || [ "$DEVINST" = "${_SVC}" ] \ && { [ "${#_TMP_DEV_SVC}" = 0 ] \ && _TMP_DEV_SVC="${_DEV} = ${_SVC}" \ || _TMP_DEV_SVC="${_TMP_DEV_SVC} ${_DEV} = ${_SVC}" ; } done done # Input was not empty; did anything in output fit? [ "${#_TMP_DEV_SVC}" = 0 ] && return 1 # Exit code : is the built mapping as long as the source list(s)? [ "`echo "$1" | wc -l`" = "`echo "${_TMP_DEV_SVC}" | wc -l`" ] } upssvcconf_checksum_unchanged() { # $1 = dev, $2 = svc # compare checksums of the configuration section from the file and the # stashed configuration in a service instance (if any). # FIXME : optimize by caching, we likely have quite a few requests [ "`upsconf_getSection_MD5 "$1"`" = "`$hook_getSavedMD5 "$2"`" ] } upslist_checksums_unchanged() { # For each device and its corresponding unit, compare checksums of the # configuration section from the file and the stashed configuration in # a service instance. Prints a list of mismatching service names that # should get reconfigured. [ "${#1}" = 0 -o "${#2}" = 0 ] && return 1 _TMP_SVC="" for _DEV in $1 ; do DEVINST="`$hook_validInstanceName "${_DEV}"`" for _SVC in $2 ; do if [ "${_DEV}" = "${_SVC}" ] \ || [ "$DEVINST" = "${_SVC}" ] \ ; then upssvcconf_checksum_unchanged "${_DEV}" "${_SVC}" || \ { [ "${#_TMP_SVC}" = 0 ] \ && _TMP_SVC="${_SVC}" \ || _TMP_SVC="${_TMP_SVC} ${_SVC}" ; } fi done done [ "${#_TMP_SVC}" = 0 ] && return 0 echo "${_TMP_SVC}" return 1 } upslist_savednames_find_missing() { # Verify that all existing service units have a saved DEVICE name # Report those that do not have a value there (any value) so we can # amend those quickly after an upgrade. Otherwise we trust these. # Return codes: # 0) Some services were defined and at least one had DEVICE values # (those that did not are reported in stdout) # 1) No services defined yet (empty stdout) # 2) All service units do not have DEVICE values (all reported in stdout) # Get full instance names from system and from props SVCINSTS="`$hook_listInstances_raw`" && [ "${#SVCINSTS}" != 0 ] || return 1 # If no props were found, (over)write them all SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ "${#SVCINST_PROPS}" != 0 ] \ || { echo $SVCINSTS ; return 2; } # Find and report services which do *not* have saved device names in # props (do not report those that have a non-trivial prop value): # whether an empty value or completely absent from the list for SVCINST in $SVCINSTS ; do echo "$SVCINST_PROPS" | grep -E "^${SVCINST}${TABCHAR}"'$' >/dev/null && echo "$SVCINST" echo "$SVCINST_PROPS" | grep -E "^${SVCINST}${TABCHAR}" >/dev/null || echo "$SVCINST" done return 0 } upslist_savednames_find_mismatch() { # NOTE: Not used currently (as of NUT v2.8.2) # TODO: Make use of this to fsck the enumerator configs # TODO: Complete checking MD5 normalized names if original not hit # TODO: Report all unit names if none has the DEVICE values? (code 2) # # Verify that all existing service units have a saved DEVICE name # and that such name does match the unit instance's name (original # or MD5 normalized version). If something does not match, returns # the unit name so it can be redefined by caller. This does not # inspect whether such DEVICE is defined in NUT configuration. # This situation might occur in some errors, but the likely case # is updating from versions that did not track this info yet (but # upslist_savednames_find_missing() should have handled those). # Return codes: # 0) Some services were defined and at least one had DEVICE values # (those that did not are reported in stdout) # 1) No services defined yet (empty stdout) # 2) All service units do not have DEVICE values (empty stdout) # Get full instance names from system and from props SVCINSTS="`$hook_listInstances_raw`" && [ "${#SVCINSTS}" != 0 ] || return 1 SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ "${#SVCINST_PROPS}" != 0 ] || return 2 # Find services whose props exist but services themselves do not # (e.g. upgrading from some version with different naming patterns) echo "$SVCINST_PROPS" | while read SVCINST_PROP DEVNAME_PROP ; do echo "$SVCINSTS" | grep -E "^${SVCINST_PROP}"'$' >/dev/null || echo "$SVCINST_PROP" done # Find and report services which do *not* have saved device names in # props (do not report those that have a non-trivial prop value): # whether an empty value or completely absent from the list for SVCINST in $SVCINSTS ; do echo "$SVCINST_PROPS" | grep -E "^${SVCINST}${TABCHAR}"'$' >/dev/null && echo "$SVCINST" echo "$SVCINST_PROPS" | grep -E "^${SVCINST}${TABCHAR}" >/dev/null || echo "$SVCINST" done return 0 } upsconf_getSection_content() { # "$1" = name of ups.conf section to display in whole, from whatever # comes on stdin (file or a pre-made normalized variable) # empty "$1" means the global config (before any sections) # # NOTE (TODO?): This routine finds the one NUT device section, prints it # and returns when the section is over. It currently does not cover (in # a way allowing to do it efficiently) selection of several sections, # or storing each section content in some array or dynamic variables # (as would be better fit for portable shells) to later address them # quickly without re-parsing the file or big envvar many times. # CURR_SECTION="" SECTION_CONTENT="" RES=1 [ -n "$1" ] || RES=0 while read LINE ; do case "$LINE" in \["$1"\]) if [ "$RES" = 0 ]; then # We have already displayed a section, here is a new one, # and this routine only displays one (TODO: toggle?) break fi SECTION_CONTENT="$LINE" CURR_SECTION="$1" RES=0 continue ;; \[*\ *\]|\[*"$TABCHAR"*\]) # Note that section-name brackets should contain a single token # Fall through to add the line to contents of existing section ;; \[*\]) [ "$CURR_SECTION" = "$1" ] && break # Use a value that can not be a section name here: CURR_SECTION="[]" continue ;; "") continue ;; *) ;; # Fall through to add the line to contents of existing section esac if [ "$CURR_SECTION" = "$1" ]; then if [ "${#SECTION_CONTENT}" = 0 ]; then SECTION_CONTENT="$LINE" else SECTION_CONTENT="$SECTION_CONTENT $LINE" fi fi done if [ "${#SECTION_CONTENT}" != 0 ]; then echo "$SECTION_CONTENT" fi [ "$RES" = 0 ] || echo "ERROR: Section [$1] was not found in the '$UPSCONF' file" >&2 return $RES } upsconf_getSection() { # Use the whole output of normalization parser if [ x"${AVOID_REPARSE}" != xyes ] ; then upslist_normalizeFile_once || return # Propagate errors upwards fi upsconf_getSection_content "$@" << EOF ${UPSCONF_DATA} EOF } upsconf_getSection_MD5() { calc_md5 "`upsconf_getSection "$@"`" } upsconf_getSection_SDP() { # Use the section-driver-port subset if [ x"${AVOID_REPARSE}" != xyes ] ; then upslist_normalizeFile_once || return # Propagate errors upwards fi upsconf_getSection_content "$@" << EOF ${UPSCONF_DATA_SDP} EOF } upsconf_getValue() { # "$1" = name of ups.conf section, may be empty for global config # "$2..$N" = name of config key; we will echo its value ### [ -n "$1" ] || return $? [ -n "$2" ] || return $? [ -n "$GETSECTION" ] || GETSECTION="upsconf_getSection" CURR_SECTION="" # Gets set by a GETSECTION implementation RES=0 # Note: Primary aim of this egrep is to pick either assignments or flags # As a by-product it can be used to test if a particular value is set ;) SECTION_CONTENT="`$GETSECTION "$1"`" || return shift KEYS="$*" while [ "$#" -gt 0 ] ; do RES_L=0 VALUE="" LINE="`echo "$SECTION_CONTENT" | grep -E '(^'"$1"'=|^'"$1"'$)'`" \ && VALUE="$(echo "$LINE" | sed -e "s,^$1=,," -e 's,^\"\(.*\)\"$,\1,' -e "s,^'\(.*\)'\$,\1,")" \ || RES_L=$? [ "$RES_L" = 0 ] || { RES="$RES_L" ; echo "ERROR: Section [$CURR_SECTION] or key '$1' in it was not found in the '$UPSCONF' file" >&2 ; } echo "$VALUE" shift done [ "$RES" = 0 ] || echo "ERROR: Section [$CURR_SECTION] or key(s) '$KEYS' in it was not found in the '$UPSCONF' file" >&2 return $RES } upsconf_getDriver() { # "$1" = name of ups.conf section; return (echo) the driver name used there # In the context this function is used, UPSCONF exists and section is there GETSECTION="upsconf_getSection_SDP" upsconf_getValue "$1" "driver" return $? } upsconf_getPort() { # "$1" = name of ups.conf section; return (echo) the "port" name used there # In the context this function is used, UPSCONF exists and section is there GETSECTION="upsconf_getSection_SDP" upsconf_getValue "$1" "port" return $? } upsconf_getDriverMedia() { # "$1" = name of ups.conf section; return (echo) name and type of driver as # needed for dependency evaluation (what services we must depend on for this # unit), newline-separated (drvnametype). Empty type for unclassified # results, assuming no known special dependencies (note that depending on # particular system's physics, both serial and network media may need USB). CURR_DRV="`upsconf_getDriver "$1"`" || return $? case "$CURR_DRV" in *netxml*|*snmp*|*ipmi*|*powerman*|*-mib*|*avahi*) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; *apcupsd-ups*) # Relay from a nearby apcupsd network server into NUT ecosystem: CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in *localhost*|*127.0.0.1*|*::1*) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; esac ;; *apc_modbus*) CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" CURR_PORTTYPE="`upsconf_getValue "$1" 'porttype'`" || CURR_PORTTYPE="" case "$CURR_PORTTYPE" in *usb*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; *serial*) printf '%s\n%s\n' "$CURR_DRV" "serial" ; return ;; *) # default depends on driver build (against libmodbus # version with or without support for usb) # TOTHINK: Check for presence of config values like # vendorid (USB) or baud (Serial)? They are optional # with reasonable defaults anyway... case "$CURR_PORT" in *auto*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; /*) printf '%s\n%s\n' "$CURR_DRV" "serial" ; return ;; *localhost*|*127.0.0.1*|*::1*) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; esac # returns are above, but just in case - have a fallback: printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *usb*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; nutdrv_qx) # May be direct serial or USB CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in auto|/dev/*usb*|/dev/*hid*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; /dev/*) # See drivers/nutdrv_qx.c :: upsdrv_initups() for a list if [ -n "`upsconf_getValue "$1" 'subdriver' 'vendorid' 'productid' 'vendor' 'product' 'serial' 'bus' 'busport' 'langid_fix'`" ] \ ; then printf '%s\n%s\n' "$CURR_DRV" "usb" ; return else printf '%s\n%s\n' "$CURR_DRV" "serial" ; return fi ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *dummy*|*clone*) # May be networked (proxy to remote NUT) CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in *@localhost|*@|*@127.0.0.1|*@::1) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *@*) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; # FIXME: other modbus? sysfs like INA219? GPIO? Other local devices? *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac } upsconf_getMedia() { _DRVMED="`upsconf_getDriverMedia "$1"`" || return echo "${_DRVMED}" | tail -n +2 return 0 } upsconf_debug() { _DRV="`upsconf_getDriver "$1"`" _PRT="`upsconf_getPort "$1"`" _MED="`upsconf_getMedia "$1"`" _MD5="`upsconf_getSection_MD5 "$1"`" NAME_MD5="`calc_md5 "$1"`" echo "INST: ${NAME_MD5}~[$1]: DRV='${_DRV}' PORT='${_PRT}' MEDIA='${_MED}' SECTIONMD5='${_MD5}'" } calc_md5() { # Tries several ways to produce an MD5 of the "$1" argument _MD5="`echo "$1" | md5sum 2>/dev/null | awk '{print $1}'`" && [ -n "${_MD5}" ] || \ { _MD5="`echo "$1" | openssl dgst -md5 2>/dev/null | awk '{print $NF}'`" && [ -n "${_MD5}" ]; } || \ return 1 echo "${_MD5}" } calc_md5_file() { # Tries several ways to produce an MD5 of the file named by "$1" argument [ -s "$1" ] || return 2 _MD5="`md5sum 2>/dev/null < "$1" | awk '{print $1}'`" && [ -n "${_MD5}" ] || \ { _MD5="`openssl dgst -md5 2>/dev/null < "$1" | awk '{print $NF}'`" && [ -n "${_MD5}" ]; } || \ return 1 echo "${_MD5}" } smf_validFullUnitName() { case "$1" in *:*) echo "$1" ;; *) echo "$SVCNAME_SMF:$1" ;; esac } smf_validInstanceName() { echo "MD5_`calc_md5 "$1"`" } smf_validInstanceSuffixName() { case "$1" in *:*) echo "$1" | sed 's,^.*:\([^:]*\)$,\1,' ;; *) echo "$1" ;; esac } smf_registerInstance() { DEVICE="$1" SVCINST="$1" if /usr/bin/svcs "nut-driver:$SVCINST" >/dev/null 2>&1 ; then smf_unregisterInstance "$SVCINST" fi /usr/sbin/svccfg -s nut-driver add "$DEVICE" || \ { SVCINST="`smf_validInstanceName "$1"`" || return if /usr/bin/svcs "nut-driver:$SVCINST" >/dev/null 2>&1 ; then smf_unregisterInstance "$SVCINST" fi /usr/sbin/svccfg -s nut-driver add "$SVCINST" || return ; } echo "Added instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" case "${_MED}" in usb) DEPSVC="$DEPSVC_USB_SMF" DEPREQ="$DEPREQ_USB_SMF" ;; network-localhost) DEPSVC="$DEPSVC_NET_LOCAL_SMF" DEPREQ="$DEPREQ_NET_LOCAL_SMF" ;; network) DEPSVC="$DEPSVC_NET_FULL_SMF" DEPREQ="$DEPREQ_NET_FULL_SMF" ;; serial) ;; '') ;; *) echo "WARNING: Unexpected NUT media type ignored: '${_MED}'" >&2 ;; esac TARGET_FMRI="nut-driver:$SVCINST" if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="optional_all" echo "Adding '$DEPREQ' dependency for '$SVCINST' on '$DEPSVC'..." DEPPG="nut-driver-enumerator-generated" RESTARTON="refresh" /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$DEPPG" dependency && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/grouping = astring: "$DEPREQ" && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/restart_on = astring: "$RESTARTON" && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/type = astring: service && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/entities = fmri: "($DEPSVC)" && \ echo "OK" || echo "FAILED to define the dependency" >&2 fi smf_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" # Save original device (config section) name to speed up some searches smf_setSavedDeviceName "$SVCINST" "$DEVICE" smf_setDocLink "$SVCINST" "$DEVICE" /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return if [ "$AUTO_START" = yes ] ; then /usr/sbin/svcadm clear "${TARGET_FMRI}" 2>/dev/null || true /usr/sbin/svcadm enable "${TARGET_FMRI}" || return echo "Started instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 fi } smf_unregisterInstance() { echo "Removing instance: 'nut-driver:$1' ..." >&2 /usr/sbin/svcadm disable -ts 'nut-driver:'"$1" || false /usr/sbin/svccfg -s nut-driver delete "$1" } smf_refreshSupervizor() { : } smf_listInstances_raw() { # Newer versions have pattern matching; older SMF might not have this luxury /usr/bin/svcs -a -H -o fmri | grep -E '/nut-driver:' } smf_listInstances() { # Chop twice, in case there is a leading "svc:/...." smf_listInstances_raw | sed -e 's/^.*://' -e 's/^.*://' | sort -k1n -k1 } smf_getSavedMD5() { # Query service instance $1 PG="nut-driver-enumerator-generated-checksum" PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then TARGET_FMRI="nut-driver:$1" else # Global section TARGET_FMRI="nut-driver" PROP="SECTION_CHECKSUM_GLOBAL" fi # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } smf_findSavedDeviceName() { # Returns long service FMRI which has DEVICE=="$1" # For empty "$1" returns a list of all recorded "FMRIDEVICE" if [ -z "$1" ]; then /usr/bin/svcprop -p "nut-driver-enumerator-generated-devicename/DEVICE" \ 'svc:/system/power/nut-driver:*' 2>/dev/null \ | sed 's|^\(svc:/[^:]*:[^/:]*\)/:properties/nut-driver-enumerator-generated-devicename/DEVICE astring \(.*\)$|\1\t\2|' else /usr/bin/svcprop -p "nut-driver-enumerator-generated-devicename/DEVICE" \ "svc:/system/power/nut-driver:$1" 2>/dev/null \ | sed 's|^\(svc:/[^:]*:[^/:]*\)/:prop.*$|\1|' fi } smf_getSavedDeviceName() { # Query service instance $1 PG="nut-driver-enumerator-generated-devicename" PROP="DEVICE" if [ -n "$1" ]; then TARGET_FMRI="nut-driver:$1" else # Global section echo "" return 0 fi # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } smf_setSavedUniq() { # Save data value $5 of type $4 into service FMRI $1 # under (scrapped and) newly created property group $2 # and property name $3 __TARGET_FMRI="$1" __PG="$2" __PROP="$3" __TYPE="$4" case "${__TYPE}" in *:) ;; *) __TYPE="${__TYPE}:" ;; esac __VAL="$5" /usr/sbin/svccfg -s "${__TARGET_FMRI}" delprop "${__PG}" 2>/dev/null || true /usr/sbin/svccfg -s "${__TARGET_FMRI}" addpg "${__PG}" application && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/${__PROP}" = "${__TYPE}" "${__VAL}" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property ${__PG}/${__PROP}">&2 ; return 1 ; } case "${__TARGET_FMRI}" in svc:/*:*) ;; # A service instance by full FMRI, refresh svc:/*/nut-driver|nut-driver) return 0 ;; # A base non-instance service item for nut-driver (known multi-instance only) svc:/*) ;; # A base non-instance service item (not nut-driver) *:*) ;; # A service instance by short FMRI, refresh *) ;; # A base non-instance service item (not nut-driver) esac /usr/sbin/svcadm refresh "${__TARGET_FMRI}" || return } smf_setSavedMD5() { # Save checksum value $2 into service instance $1 _PG="nut-driver-enumerator-generated-checksum" _PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then _TARGET_FMRI="nut-driver:$1" else # Global section _TARGET_FMRI="nut-driver" _PROP="SECTION_CHECKSUM_GLOBAL" fi smf_setSavedUniq "${_TARGET_FMRI}" "${_PG}" "${_PROP}" astring "$2" } smf_setSavedDeviceName() { [ -n "$1" ] || return # No-op for global section smf_setSavedUniq "nut-driver:$1" "nut-driver-enumerator-generated-devicename" "DEVICE" astring "$2" } smf_setDocLink() { # Save documentation links for driver of device (config section) named $2 # into service instance $1 [ -n "$1" ] || return # No-op for global section __TARGET_FMRI="nut-driver:$1" __DRV="`upsconf_getDriver "$2"`" ### Sample: #tm_common_name template #tm_common_name/C ustring "physical network interface autoconfiguration" #tm_doc_Network_Auto-Magic_OpenSolaris_Project_Page template #tm_doc_Network_Auto-Magic_OpenSolaris_Project_Page/name astring "Network Auto-Magic OpenSolaris Project Page" #tm_doc_Network_Auto-Magic_OpenSolaris_Project_Page/uri astring http://hub.opensolaris.org/bin/view/Project+nwam/ #tm_man_nwamd8 template #tm_man_nwamd8/manpath astring /usr/share/man #tm_man_nwamd8/section astring 8 #tm_man_nwamd8/title astring nwamd __PG="tm_doc_${__DRV}_Page" /usr/sbin/svccfg -s "${__TARGET_FMRI}" delprop "${__PG}" 2>/dev/null || true /usr/sbin/svccfg -s "${__TARGET_FMRI}" addpg "${__PG}" template && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/name" = "astring:" "\"${__DRV} online\"" && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/uri" = "astring:" "${NUT_WEBSITE_BASE}/docs/man/${__DRV}.html" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property group '${__PG}' for online docs">&2 ; return 1 ; } __PG="tm_man_${__DRV}@MAN_SECTION_CMD_SYS@" /usr/sbin/svccfg -s "${__TARGET_FMRI}" delprop "${__PG}" 2>/dev/null || true /usr/sbin/svccfg -s "${__TARGET_FMRI}" addpg "${__PG}" template && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/manpath" = "astring:" "@NUT_MANDIR@" && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/section" = "astring:" "@MAN_SECTION_CMD_SYS@" && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/title" = "astring:" "${__DRV}" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property group '${__PG}' for local docs">&2 ; return 1 ; } unset __DRV __PG __TARGET_FMRI [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the device doc links">&2 ; return 1 ; } } smf_restart_upsd() { echo "Reloading or restarting NUT data server to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-server" 2>/dev/null /usr/sbin/svcadm clear "nut-server" 2>/dev/null /usr/sbin/svcadm refresh "nut-server" || \ /usr/sbin/svcadm restart "nut-server" } smf_restart_drv() { echo "Reloading or restarting NUT driver instance '$1' to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-driver:$1" 2>/dev/null /usr/sbin/svcadm clear "nut-driver:$1" 2>/dev/null /usr/sbin/svcadm refresh "nut-driver:$1" || \ /usr/sbin/svcadm restart "nut-driver:$1" } systemd_validFullUnitName() { case "$1" in *@*.*) echo "$1" ;; *@*) echo "$1.service" ;; *) echo "$SVCNAME_SYSTEMD@$1.service" ;; esac } systemd_validInstanceName() { echo "MD5_`calc_md5 "$1"`" } systemd_validInstanceSuffixName() { echo "$1" | sed -e 's,^.*@,,' -e 's,\.service$,,' } systemd_registerInstance() { # Instance is registered by device section name; ultimate name in systemd may differ DEVICE="$1" SVCINST="$1" /bin/systemctl enable 'nut-driver@'"$DEVICE".service || \ { SVCINST="`systemd_validInstanceName "$1"`" && \ /bin/systemctl enable 'nut-driver@'"$SVCINST".service || return ; } echo "Enabled instance: 'nut-driver@$SVCINST' for NUT configuration section '$DEVICE'" >&2 DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" case "${_MED}" in usb) DEPSVC="$DEPSVC_USB_SYSTEMD" DEPREQ="$DEPREQ_USB_SYSTEMD" ;; network-localhost) DEPSVC="$DEPSVC_NET_LOCAL_SYSTEMD" DEPREQ="$DEPREQ_NET_LOCAL_SYSTEMD" ;; network) DEPSVC="$DEPSVC_NET_FULL_SYSTEMD" DEPREQ="$DEPREQ_NET_FULL_SYSTEMD" ;; serial) DEPSVC="$DEPSVC_SERIAL_SYSTEMD" DEPREQ="$DEPREQ_SERIAL_SYSTEMD" ;; '') ;; # FIXME: modbus? sysfs like INA219? GPIO? Other local devices? *) echo "WARNING: Unexpected NUT media type ignored: '${_MED}'" >&2 ;; esac if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="#Wants" echo "Adding '$DEPREQ'+After dependency for '$SVCINST' on '$DEPSVC'..." mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$SVCINST.service.d" && \ cat > "${SYSTEMD_CONFPATH}/nut-driver@$SVCINST.service.d/nut-driver-enumerator-generated.conf" <&2 fi systemd_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" systemd_setSavedDeviceName "$SVCINST" "$DEVICE" systemd_setDocLink "$SVCINST" "$DEVICE" if [ "$AUTO_START" = yes ] ; then systemd_refreshSupervizor || echo "WARNING: Somehow managed to fail systemd_refreshSupervizor()" >&2 $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl start --no-block 'nut-driver@'"$SVCINST".service || return echo "Started instance: 'nut-driver@$SVCINST' for NUT configuration section '$DEVICE'" >&2 fi } systemd_unregisterInstance() { echo "Removing instance: 'nut-driver@$1' ..." >&2 $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || false /bin/systemctl disable 'nut-driver@'"$1".service rm -rf "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" /bin/systemctl reset-failed 'nut-driver@'"$1".service } systemd_refreshSupervizor() { /bin/systemctl daemon-reload } systemd_listInstances_raw() { /bin/systemctl show 'nut-driver@*' -p Id | grep -E '=nut-driver' | sed 's,^Id=,,' } systemd_listInstances() { systemd_listInstances_raw | sed -e 's/^.*@//' -e 's/\.service$//' | sort -k1n -k1 } systemd_getSavedMD5() { # Query service instance $1 or global section PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" [ -s "${PROPFILE}" ] \ && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } } systemd_findSavedDeviceName() { # Returns long service instance name which has DEVICE=="$1" # For empty "$1" returns a list of all recorded "SVCDEVICE" if [ -z "$1" ]; then grep -H "Environment='DEVICE=" \ "${SYSTEMD_CONFPATH}"/nut-driver@*.service.d/nut-driver-enumerator-generated-devicename.conf \ | sed 's|^'"${SYSTEMD_CONFPATH}"'/\(nut-driver@[^/]*\.service\)\.d/.*DEVICE='"[\"']*\([^\"']*\)[\"']*"'$|\1\t\2|' else grep -E -H "Environment='DEVICE=($1|\"$1\")'" \ "${SYSTEMD_CONFPATH}"/nut-driver@*.service.d/nut-driver-enumerator-generated-devicename.conf \ | sed 's|^'"${SYSTEMD_CONFPATH}"'/\(nut-driver@[^/]*\.service\)\.d/.*$|\1|' fi } systemd_getSavedDeviceName() { # Query service instance "$1" (quiet NO-OP if empty, for mis-use # in global sections context) to get the unquoted saved DEVICE # section name corresponding to this service instance [ -n "$1" ] || { echo ""; return 0; } PROP="DEVICE" PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" [ -s "${PROPFILE}" ] \ && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," -e 's,^"\(.*\)"$,\1,' \ || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } } systemd_setSavedDeviceName() { # Save device (config section) name $2 into service instance $1 [ -n "$1" ] || return # No-op for global section PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ cat > "${PROPFILE}" << EOF [Service] Environment='DEVICE="$2"' EOF [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the device name">&2 ; return 1 ; } } systemd_setDocLink() { # Save documentation links for driver of device (config section) named $2 # into service instance $1 [ -n "$1" ] || return # No-op for global section PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-doclink.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ __DRV="`upsconf_getDriver "$2"`" cat > "${PROPFILE}" << EOF [Unit] Documentation=man:${__DRV}(@MAN_SECTION_CMD_SYS@) Documentation=${NUT_WEBSITE_BASE}/docs/man/${__DRV}.html EOF unset __DRV [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the device name">&2 ; return 1 ; } } systemd_setSavedMD5() { # Save checksum value $2 into service instance $1 PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ cat > "${PROPFILE}" << EOF [Service] Environment='$PROP=$2' EOF [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } } systemd_restart_upsd() { # Do not restart/reload if not already running case "`/bin/systemctl is-active "nut-server"`" in active|unknown) ;; # unknown meant "starting" in our testing... failed) echo "Note: nut-server unit was 'failed' - not disabled by user, so (re)starting it (probably had no config initially)" >&2 ;; *) return 0 ;; esac echo "Reloading or restarting NUT data server to make sure it knows new configuration..." # Note: reload is a better way to go about this, so the # data service is not interrupted by re-initialization # of the daemon. But systemd/systemctl sometimes stalls... $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl reload-or-restart "nut-server" || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl restart "nut-server" } systemd_restart_drv() { # Do not restart/reload if not already running case "`/bin/systemctl is-active "nut-driver@$1"`" in active|unknown) ;; *) return 0 ;; esac echo "Reloading or restarting NUT driver instance '$1' to make sure it knows new configuration..." # Full restart, e.g. in case we changed the user= in configs # however let "reload" try, in case we changed something that # can be updated "on the fly", like the "debug_min" setting. $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl reload-or-restart "nut-driver@$1" || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl restart "nut-driver@$1" } upslist_normalizeFile_filter() { # See upslist_normalizeFile() detailed comments below; this routine # is a pipe worker to prepare the text into a simpler expected form. # Pick the lines which contain a bracket or assignment character, # or a single token (certain keywords come as just NUT "flags"), # trim leading and trailing whitespace, comment-only lines, and in # assignment lines trim the spaces around equality character and # quoting characters around assignment of values without whitespaces. # Any whitespace characters around a section name (single token that # starts the line and is enclosed in brackets) and a trailing comment # are dropped. Note that brackets with spaces inside, and brackets # that do not start the non-whitespace payload of the line, are not # sections. grep -E -v '(^$|^#)' | \ sed -e 's,^['"$TABCHAR"'\ ]*,,' \ -e 's,^\#.*$,,' \ -e 's,['"$TABCHAR"'\ ]*$,,' \ -e 's,^\([^=\ '"$TABCHAR"']*\)['"$TABCHAR"'\ ]*=['"$TABCHAR"'\ ]*,\1=,g' \ -e 's,=\"\([^\ '"$TABCHAR"']*\)\"$,=\1,' \ -e 's,^\(\[[^]'"$TABCHAR"'\ ]*\]\)['"$TABCHAR"'\ ]*\(#.*\)*$,\1,' \ | grep -E -v '^$' \ | grep -E '([\[\=]|^[^ '"$TABCHAR"']*$|^[^ '"$TABCHAR"']*[ '"$TABCHAR"']*#.*$)' } upslist_normalizeFile() { # Read the ups.conf file and find all defined sections (names of # configuration blocks for drivers that connect to a certain device # using specified protocol and media); normalize section contents # as detailed below, to simplify subsequent parsing and comparison. # File contents UPSCONF_DATA="" UPSCONF_DATA_SDP="" if [ -n "$UPSCONF" ] && [ -f "$UPSCONF" ] && [ -r "$UPSCONF" ]; then [ ! -s "$UPSCONF" ] \ && echo "WARNING: The '$UPSCONF' file exists but is empty" >&2 \ && return 0 # Ok to continue - we may end up removing all instances else echo "FATAL: The '$UPSCONF' file does not exist or is not readable" >&2 return 2 fi # Store a normalized version of NUT configuration file contents. # Also use a SDP subset with just section, driver and port info # for faster parsing when determining driver-required media etc. UPSCONF_DATA="$(upslist_normalizeFile_filter < "$UPSCONF")" \ && [ "${#UPSCONF_DATA}" != 0 ] \ && UPSCONF_DATA_SDP="`grep -E '^(\[.*\]|driver=|port=)' << EOF $UPSCONF_DATA EOF`" \ || { echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: nothing left after normalization" >&2 UPSCONF_DATA="" UPSCONF_DATA_SDP="" } } upslist_normalizeFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) [ "${#UPSCONF_DATA}" = 0 ] && [ "${#UPSCONF_DATA_SDP}" = 0 ] || return 0 upslist_normalizeFile } upslist_readFile() { # Use the routine above (unconditionally) to get or update the # listing of device sections known at this moment. # List of devices from the config file UPSLIST_FILE="" if [ "$DO_NORMALIZE_ONCE" = yes ]; then upslist_normalizeFile_once || return # Propagate errors upwards else upslist_normalizeFile || return # Propagate errors upwards fi if [ "${#UPSCONF_DATA}" != 0 ] ; then # Note that section-name brackets should contain a single token UPSLIST_FILE="$(echo "$UPSCONF_DATA_SDP" | grep -E '^\[[^'"$TABCHAR"'\ ]*\]$' | sed 's,^\[\(.*\)\]$,\1,' | sort -k1n -k1)" \ || UPSLIST_FILE="" if [ "${#UPSLIST_FILE}" = 0 ] ; then echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: no section declarations in parsed normalized contents" >&2 fi fi # Ok to continue with empty results - we may end up removing all instances } upslist_readFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) [ "${#UPSLIST_FILE}" = 0 ] || return 0 DO_NORMALIZE_ONCE=yes upslist_readFile } upslist_readSvcs() { UPSLIST_SVCS="`$hook_listInstances`" || UPSLIST_SVCS="" if [ "${#UPSLIST_SVCS}" = 0 ] && [ "$1" != "-" ] ; then EXPLAIN="" [ -z "$1" ] || EXPLAIN=" - $1" echo "Error reading the list of ${SERVICE_FRAMEWORK-} service instances for UPS drivers, or none are defined${EXPLAIN}" >&2 # Ok to continue - we may end up defining new instances fi } upslist_debug() { for UPSF in "" $UPSLIST_FILE ; do upsconf_debug "$UPSF" done } upslist_addSvcs() { # Note: This routine registers service instances for device config sections # that are not wrapped currently. Support for redefined previously existing # sections - is attained by removing the old service instance elsewhere and # recreating it here, since any data could change including the dependency # list, etc. for UPSF in $UPSLIST_FILE ; do if ! common_isRegistered "$UPSF" ; then echo "Adding new ${SERVICE_FRAMEWORK} service instance for power device [${UPSF}]..." >&2 $hook_registerInstance "$UPSF" fi done } upslist_delSvcs() { for UPSS in $UPSLIST_SVCS ; do if ! common_isFiled "$UPSS" ; then echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] which is no longer in config file..." >&2 $hook_unregisterInstance "$UPSS" fi done } upslist_restartSvcs() { for UPSS in $UPSLIST_SVCS ; do if common_isFiled "$UPSS" ; then $hook_restart_drv "$UPSS" fi done } # FIXME : process via kill -l? # Different shells use a SIG prefix or not to signal names # so standard numbers are in fact more portable :\ TERMINATION_SIGNALS="2 3 15" RECONFIGURATION_SIGNALS="1" TERMINATE_ASAP=false trap_handle_interruption_exit() { # Handle SIGINT, SIGQUIT, SIGTERM with a message echo "`date -u` : Received an interruption signal, terminating the script now" >&2 exit 0 } trap_handle_interruption() { # Handle SIGINT, SIGQUIT, SIGTERM gracefully - tell the main # iteration to complete and just then abort echo "`date -u` : Received an interruption signal, will terminate the script after ending the main routine. Repeat the signal if urgent!" >&2 TERMINATE_ASAP=true trap 'trap_handle_interruption_exit' $TERMINATION_SIGNALS } nut_driver_enumerator_main() { ################# MAIN PROGRAM by default TERMINATE_ASAP=false trap 'trap_handle_interruption' $TERMINATION_SIGNALS # Note: do not use the read..._once() here, to ensure that the # looped daemon sees the whole picture, which can be new every time upslist_readFile || return $? #upslist_debug upslist_readSvcs "before manipulations" # Test if global config has changed since last run # Note that we have upslist_normalizeFile called from upslist_readFile # just above, so even if it came empty (e.g. new NUT installation, no # device sections yet) we do not want to spend time and log storage to # parse again and complain again. RESTART_ALL=no AVOID_REPARSE=yes upssvcconf_checksum_unchanged "" || { echo "`date -u` : Detected changes in global section of '$UPSCONF', will restart all drivers"; RESTART_ALL=yes; } # Quickly exit if there's nothing to do (both lists empty or equal); note # the lists are pre-sorted. Otherwise a non-zero exit will be done below. # Note: We implement testing in detail whether section definitions were # changed since last run, as a first step before checking that name # lists are still equivalent, because we need to always have the result # of the "has it changed?" check as a hit-list of something to remove, # while the check for no new device section definitions is just boolean. # We can only exit quickly if both there are no changed sections and no # new or removed sections since last run. { [ -z "$UPSLIST_FILE" -a -z "$UPSLIST_SVCS" ] || { \ NEW_CHECKSUM="`upslist_checksums_unchanged "$UPSLIST_FILE" "$UPSLIST_SVCS"`" \ && [ "${#NEW_CHECKSUM}" = 0 ] \ && upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" ; \ } ; } \ && if [ -z "$DAEMON_SLEEP" -o "${VERBOSE_LOOP}" = yes ] ; then \ echo "`date -u` : OK: No changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" ; \ fi \ && [ "$RESTART_ALL" = no ] && return 0 # Check list of devices with new section contents (per checksum) as # compared to older runs (stashed in service instance configurations). if [ "${#NEW_CHECKSUM}" = 0 ]; then if [ "${VERBOSE_LOOP}" = yes ] ; then echo "`date -u` : No changes to reconcile between *contents* of ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF', but the *list* of instances vs. devices seems to have changed" fi else if [ "${VERBOSE_LOOP}" = yes ] ; then echo "`date -u` : Got some changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF', content checksums changed for: `echo ${NEW_CHECKSUM} | tr '\n' ' '`" fi for UPSS in $NEW_CHECKSUM ; do # NOTE: Pedantically, UPSS is a service instance name, # and may be the MD5-normalized version in certain cases. # For some operations below we need the original ups.conf # section name for the device - the CURR_DEV value. CURR_DEV="`USE_SAVEDINST=true get_device_for_service "${UPSS}"`" && [ "${#CURR_DEV}" -gt 0 ] || CURR_DEV="${UPSS}" CURR_DRV="`upsconf_getDriver "${CURR_DEV}"`" || CURR_DRV="" DO_UNREGISTER=yes if [ -n "$CURR_DRV" ] ; then # If reload is handled and does not complain, # we are OK to proceed without re-defining # and restarting the driver service instance. if [ "${VERBOSE_LOOP}" = yes ] ; then echo "`date -u` : Reloading ${SERVICE_FRAMEWORK} service instance '${UPSS}' whose section '${CURR_DEV}' in config file has changed: calling driver program '${CURR_DRV}' for the low-level work..." >&2 fi "@DRVPATH@/$CURR_DRV" -a "${CURR_DEV}" -c reload-or-error >/dev/null 2>/dev/null \ || { if [ "${VERBOSE_LOOP}" = yes ] ; then sleep 1; "@DRVPATH@/$CURR_DRV" -a "${CURR_DEV}" -c reload-or-error >&2 ; fi; } \ && DO_UNREGISTER=no fi if [ "$DO_UNREGISTER" = yes ] ; then echo "Dropping old ${SERVICE_FRAMEWORK} service instance '${UPSS}' whose section '${CURR_DEV}' in config file has changed..." >&2 $hook_unregisterInstance "$UPSS" # Re-registration to reconcile below should set the "saved" values else echo "Keeping ${SERVICE_FRAMEWORK} service instance '${UPSS}' whose section '${CURR_DEV}' in config file has changed: live reload sufficed. Saving updated info into service properties." >&2 $hook_setSavedMD5 "$UPSS" "`upsconf_getSection_MD5 "${CURR_DEV}"`" # TOTHINK: This is already there, else we redefine units for bigger discrepancies? # $hook_setSavedDeviceName "$UPSS" "${CURR_DEV}" fi done upslist_readSvcs "after updating for new config section checksums" fi if [ "${#UPSLIST_SVCS}" != 0 ]; then # Drop services that are not in config file (any more?) upslist_delSvcs if [ "$RESTART_ALL" = yes ] && [ "$AUTO_START" = yes ] ; then # Here restart only existing services; new ones will (try to) # start soon after creation and upsd is handled below upslist_restartSvcs fi fi if [ "$RESTART_ALL" = yes ] ; then # Save new checksum of global config $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" fi if [ "${#UPSLIST_FILE}" != 0 ]; then # Add services for sections that are in config file but not yet wrapped upslist_addSvcs $hook_refreshSupervizor upslist_readSvcs "after checking for new config sections to define service instances" fi upslist_readSvcs if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi # We had some changes to the config file; upsd must be made aware if [ "$AUTO_START" = yes ] ; then $hook_restart_upsd fi # Return 42 if there was a change applied succesfully # (but e.g. some services should restart - upsd, maybe upsmon) UPSLIST_EQ_RES=0 upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? # File processing and service startups take a while; # make sure upsconf did not change while we worked... # NOTE: Check this at the last moment to minimize # the chance of still not noticing the change made # at just the wrong moment. UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then # NOTE: even if daemonized, the sleep between iterations # can be configured into an uncomfortably long lag, so # we should re-sync the system config in any case. echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up the late-coming changes" # Make sure the cycle does not repeat itself due to diffs # from an ages-old state of the file from when we started. UPSCONF_CHECKSUM_START="$UPSCONF_CHECKSUM_END" ( nut_driver_enumerator_main ) ; return $? # The "main" routine at the end of recursions will # do REPORT_RESTART_42 logic or the error exit-code fi if [ "$UPSLIST_EQ_RES" = 0 ] ; then echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" [ "${REPORT_RESTART_42-}" = no ] && return 0 || return 42 fi return 13 } nut_driver_enumerator_full_reconfigure() { # Similar to the main routine for reconciling data, # but this one removes all service instances and # defines current mappings from scratch after that upslist_readFile_once || return $? upslist_readSvcs "before manipulations" if [ "${#UPSLIST_SVCS}" != 0 ]; then for UPSS in $UPSLIST_SVCS ; do echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] to reconfigure the service unit..." >&2 $hook_unregisterInstance "$UPSS" done upslist_readSvcs "after dropping" fi if [ "${#UPSLIST_FILE}" != 0 ]; then upslist_addSvcs upslist_readSvcs "after checking for new config sections to define service instances" fi # Save new checksum of global config $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" # Service units were manipulated, including saving of checksums; # refresh the service management daemon if needed $hook_refreshSupervizor if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi # We had some changes to the config file; upsd must be made aware if [ "$AUTO_START" = yes ] ; then $hook_restart_upsd fi # Return 42 if there was a change applied succesfully # (but e.g. some services should restart - upsd, maybe upsmon) UPSLIST_EQ_RES=0 upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? # File processing and service startups take a while; # make sure upsconf did not change while we worked... # NOTE: Check this at the last moment to minimize # the chance of still not noticing the change made # at just the wrong moment. UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up and reconcile the late-coming changes" nut_driver_enumerator_main ; return $? # The "main" routine will do REPORT_RESTART_42 logic too fi if [ "$UPSLIST_EQ_RES" = 0 ] ; then echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" [ "${REPORT_RESTART_42-}" = no ] && return 0 || return 42 fi return 13 } list_services_for_devices() { FINAL_RES=0 upslist_readFile_once && [ "${#UPSLIST_FILE}" != 0 ] \ || { echo "No devices detected in '$UPSCONF'" >&2 ; return 1 ; } upslist_readSvcs "by user request" && [ "${#UPSLIST_SVCS}" != 0 ] \ || { echo "No service instances detected" >&2 ; return 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ "${#UPSLIST_SVCS_RAW}" != 0 ] \ || { echo "No service units detected" >&2 ; return 1; } for DEV in $UPSLIST_FILE ; do vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" vUNITI="`$hook_validFullUnitName "$vINST"`" # First pass over simple verbatim names for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$DEV" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITD" ] ; then printf '%s\t%s\n' "$UNIT" "$DEV" continue 3 fi done fi done for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$vINST" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITI" ] ; then printf '%s\t%s\n' "$UNIT" "$DEV" continue 3 fi done fi done echo "WARNING: no service instances detected that match device '$DEV'" >&2 FINAL_RES=1 done return $FINAL_RES } SVCS_DEVS_LIST="" list_services_for_devices_once() { # On first call, caches the system reponse # On next calls returns what it got earlier # Does not return any text, just the exit code # (0 = data avail, even if empty, in SVCS_DEVS_LIST) [ "${#SVCS_DEVS_LIST}" != 0 ] && return # Pre-cache config file data, if nobody read it yet, # and keep in main script context for reuse (no subshell) upslist_readFile_once && \ SVCS_DEVS_LIST="`list_services_for_devices "$@"`" || return $? } get_device_for_service() { [ -z "$1" ] && echo "Service (instance) name argument required" >&2 && return 1 # Instance name can be a hash or "native" NUT section name SVC="`$hook_validInstanceSuffixName "$1"`" && [ -n "$SVC" ] \ || { echo "Error getting SVC name from the inputs" >&2 ; return 1; } # Reading the config is too expensive to do for every # driver management attempt when there are many devices if [ "${USE_SAVEDINST-}" != false ]; then # Try to use last-stashed values from service properties first # (NOTE: saved value is assumed to be valid if present) SAVEDINST="`$hook_getSavedDeviceName "$SVC"`" || SAVEDINST="" [ "${#SAVEDINST}" = 0 ] || { echo "$SAVEDINST" ; return 0 ; } fi case "$SVC" in MD5_*) ;; # fall through to the bulk of code *) upslist_readFile_once || return $? echo "$UPSLIST_FILE" | grep -E "^$SVC\$" return $? ;; esac # Inspect SVC=MD5_* usecase FINAL_RES=0 list_services_for_devices_once && [ "${#SVCS_DEVS_LIST}" != 0 ] || FINAL_RES=$? if [ "$FINAL_RES" = 0 ]; then echo "$SVCS_DEVS_LIST" | grep "$SVC" | ( \ while read _SVC _DEV ; do _SVC="`$hook_validInstanceSuffixName "${_SVC}"`" || exit [ "${_SVC}" = "${SVC}" ] && echo "${_DEV}" && exit 0 done ; exit 1 ) && return 0 fi echo "No service instance '$1' was detected that matches a NUT device" >&2 return 1 } get_service_for_device() { DEV="$1" [ -z "$DEV" ] && echo "Device name argument required" >&2 && return 1 # Cheap check in service instance metadata, if saved # (NOTE: saved value is assumed to be valid if present) if [ "${USE_SAVEDSVC-}" != false ]; then SAVEDSVC="`$hook_findSavedDeviceName "$DEV"`" || SAVEDSVC="" [ "${#SAVEDSVC}" = 0 ] || { echo "$SAVEDSVC" ; return 0 ; } fi # Trawl all the data we have... # TODO: Reorder to avoid extra parsing if we have an early hit? upslist_readSvcs "by user request" && [ "${#UPSLIST_SVCS}" != 0 ] \ || { echo "No service instances detected" >&2 ; return 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ "${#UPSLIST_SVCS_RAW}" != 0 ] \ || { echo "No service units detected" >&2 ; return 1; } vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" vUNITI="`$hook_validFullUnitName "$vINST"`" # First pass over simple verbatim names for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$DEV" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITD" ] ; then echo "$UNIT" return 0 fi done fi done # Second pass over other options for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$vINST" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITI" ] ; then echo "$UNIT" return 0 fi done fi done echo "No service instances detected that match device '$DEV'" >&2 return 1 } update_upslist_savednames_find_missing() { # Runs once in production modes that inspect and reconcile # configs, to handle upgraded NUT deployments SVCINSTS_NO_DEVICE="`upslist_savednames_find_missing`" || \ case "$?" in 1) return 0 ;; # No services defined yet 2) ;; # All service units do not have DEVICE values esac # Something found... or not? Or all is populated? [ "${#SVCINSTS_NO_DEVICE}" != 0 ] || return 0 # Make a list of what devices are known in config matched # to service instances defined in the system, if any # Note to not check the service instance properties which # we are validating and currently to not quite trust. USE_SAVEDINST=false list_services_for_devices_once \ && [ "${#SVCS_DEVS_LIST}" != 0 ] || return 0 # Go over services with no device value saved into properties, # and write the values learned from mapping above _MISSING_RES=0 for SVCINST in $SVCINSTS_NO_DEVICE ; do _DEV="`printf '%s\n' "$SVCS_DEVS_LIST" | awk '( \$1 == "'"${SVCINST}"'" ) {print \$NF}'`" echo "Service instance '$SVCINST' did not have a device recorded into properties, setting to '${_DEV}'" [ -n "${_DEV}" ] || { echo "The device name value for '$SVCINST' is empty, skipping" >&2 ; _MISSING_RES=1 ; continue ; } $hook_setSavedDeviceName "`$hook_validInstanceSuffixName "$SVCINST"`" "${_DEV}" || _MISSING_RES=$? done return ${_MISSING_RES} } RECONFIGURE_ASAP=false trap_handle_hup_main() { echo "`date -u` : Received a HUP during processing, scheduling reconfiguration to repeat ASAP (after the current iteration is done)" >&2 # Note: in the worst case the reconfig would run twice; # we do not update UPSCONF_CHECKSUM_START in this case # to avoid corrupting decisions of the currently running # processing. RECONFIGURE_ASAP=true } trap_handle_hup_sleep() { echo "`date -u` : Received a HUP in my sleep, reprocessing configs right now!" >&2 # Avoid re-parsing main twice, though don't recalculate # checksums needlessly on every loop cycle, either... UPSCONF_CHECKSUM_START="`calc_md5_file "$UPSCONF"`" || true RECONFIGURE_ASAP=true if [ -n "$1" ] ; then # Kill the sleeper PID kill "$1" fi } daemonize() { # Note: do not further sub-shell this routine, so systemd # is not confused whom to signal. echo "`date -u` : Daemonizing $0 with config re-evaluation frequency $DAEMON_SLEEP" >&2 # Support (SIG)HUP == signal code 1 to quickly reconfigure, # e.g. to request it while the sleep is happening or while # "main" is processing an earlier change of the file. RECONFIGURE_ASAP=false trap 'trap_handle_hup_main' $RECONFIGURATION_SIGNALS update_upslist_savednames_find_missing # Note: this loop would die on errors with config file or # inability to ensure that it matches the list of services. # If caller did not `export REPORT_RESTART_42=no` then the # loop would exit with code 42, and probably trigger restart # of the service which wraps this daemon do topple others that # depend on it. # Note: do not quickly skip the "main" based on full-file # checksum refresh, to ensure that whatever is configured # gets applied (e.g. if user disabled some services or they # died, or some config was not applied due to coding error). while nut_driver_enumerator_main ; do trap 'trap_handle_interruption_exit' $TERMINATION_SIGNALS if $TERMINATE_ASAP ; then echo "`date -u` : Trapped a SIGTERM/SIGINT/SIGQUIT during last run of nut_driver_enumerator_main, terminating gracefully now" >&2 exit 0 fi if $RECONFIGURE_ASAP ; then echo "`date -u` : Trapped a SIGHUP during last run of nut_driver_enumerator_main, repeating reconfiguration quickly" >&2 else sleep $DAEMON_SLEEP & trap "trap_handle_hup_sleep $!" $RECONFIGURATION_SIGNALS wait $! fi RECONFIGURE_ASAP=false trap 'trap_handle_hup_main' $RECONFIGURATION_SIGNALS done exit $? } # Save the checksum of ups.conf as early as possible, # to test in the end that it is still the same file. UPSCONF_CHECKSUM_START="`calc_md5_file "$UPSCONF"`" || true # By default, update wrapping of devices into services if [ $# = 0 ]; then update_upslist_savednames_find_missing nut_driver_enumerator_main ; exit $? fi if [ $# = 1 ] ; then [ -n "$DAEMON_SLEEP" ] || DAEMON_SLEEP=60 # Note: Not all shells have 'case ... ;&' support case "$1" in --daemon=*) DAEMON_SLEEP="`echo "$1" | sed 's,^--daemon=,,'`" ;; --daemon-after=*) DAEMON_SLEEP="`echo "$1" | sed 's,^--daemon-after=,,'`" ;; esac case "$1" in --daemon-after|--daemon-after=*) REPORT_RESTART_42=no nut_driver_enumerator_main || exit $? daemonize & exit $? ;; --daemon|--daemon=*) daemonize & exit $? ;; esac fi unset DAEMON_SLEEP usage() { cat << EOF $0 (no args) Update wrapping of devices into services $0 --daemon(=freq) Update wrapping of devices into services in an infinite loop Default freq is 60 sec $0 --daemon-after(=freq) Update wrapping of devices into services in an infinite loop; first do one run of the loop though, then daemonize (this way service unit is deemed started only when NUT config and driver instances are in sync). Default freq is 60 sec. $0 --reconfigure Stop and un-register all service instances and recreate them (e.g. if new dependency template was defined in a new version of this script and/or NUT package) $0 --get-service-framework Print the detected service management framework in this OS $0 --list-devices Print list of devices in NUT config $0 --list-services Print list of service instances which wrap registered NUT devices (full name of service unit) $0 --list-instances Print list of service instances which wrap registered NUT devices (just instance suffix) $0 --get-service-for-device DEV Print the full name of service unit which wraps a NUT device named "DEV" $0 --get-device-for-service SVC Print the NUT device name for full or instance-suffix name of a service unit which wraps it $0 --list-services-for-devices Print a TAB-separated list of service units and corresponding NUT device names which each such unit wraps $0 --show-configs|--show-all-configs Show the complete normalized list of device configuration blocks $0 --show-config DEV $0 --show-device-config DEV Show configuration block of the specified NUT device $0 --show-device-config-value DEV KEY [KEY...] Show single configuration key value of the specified NUT device For flags, shows the flag name if present in the section If several keys or flags are requested, their values are reported one per line in the same order (including empty lines for missing values); any missing value yields a non-zero exit code. For more information please Read The Fine Manual ('man nut-driver-enumerator') and/or see ${NUT_WEBSITE_BASE}/docs/man/nut-driver-enumerator.html Also check documentation of ups.conf and upsdrvsvcctl EOF } while [ $# -gt 0 ]; do case "$1" in --help|-h|-help) usage; exit 0 ;; --get-service-framework) echo "${SERVICE_FRAMEWORK}" ; exit 0 ;; --reconfigure) nut_driver_enumerator_full_reconfigure "$@" exit $? ;; --list-devices) upslist_readFile_once && \ if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" >&2 echo "$UPSLIST_FILE" exit 0 fi echo "No devices detected in '$UPSCONF'" >&2 exit 1 ;; --list-services) UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && \ if [ "${#UPSLIST_SVCS_RAW}" != 0 ] ; then echo "=== The currently defined service units are:" >&2 echo "$UPSLIST_SVCS_RAW" exit 0 fi echo "No service units detected" >&2 exit 1 ;; --list-instances) upslist_readSvcs "by user request" && \ if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" >&2 echo "$UPSLIST_SVCS" exit 0 fi echo "No service instances detected" >&2 exit 1 ;; --get-service-for-device) shift get_service_for_device "$@" exit $? ;; --get-device-for-service) shift get_device_for_service "$@" exit $? ;; --list-services-for-devices) shift list_services_for_devices "$@" exit $? ;; --show-configs|--show-device-configs|--show-all-configs|--show-all-device-configs) RES=0 upslist_readFile_once || RES=$? [ "$RES" != 0 ] && { echo "ERROR: upslist_readFile_once () failed with code $RES" >&2; exit $RES; } [ "${#UPSLIST_FILE}" != 0 ] \ || { echo "WARNING: No devices detected in '$UPSCONF'" >&2 ; RES=1 ; } echo "$UPSCONF_DATA" exit $RES ;; --show-config|--show-device-config) [ -z "$2" ] && echo "WARNING: Device name argument empty, will show global config" >&2 DEV="$2" upsconf_getSection "$DEV" exit $? ;; --show-config-value|--show-device-config-value) [ -z "$3" ] && echo "At least one configuration key name argument is required" >&2 && exit 1 [ -z "$2" ] && echo "WARNING: Device name argument empty, will show global config" >&2 DEV="$2" shift 2 upsconf_getValue "$DEV" "$@" exit $? ;; upsconf_debug) # Not public, not in usage() [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 upsconf_debug "$2" exit $? ;; upslist_debug) # Not public, not in usage() upslist_readFile_once || exit upslist_debug exit $? ;; upslist_savednames_find_missing) # Not public, not in usage() upslist_savednames_find_missing exit $? ;; upslist_savednames_find_mismatch) # Not public, not in usage() upslist_savednames_find_mismatch exit $? ;; update_upslist_savednames_find_missing) # Not public, not in usage() update_upslist_savednames_find_missing exit $? ;; hook_findSavedDeviceName) shift ; $hook_findSavedDeviceName "$@" ; exit $? ;; hook_getSavedDeviceName) shift ; $hook_getSavedDeviceName "$@" ; exit $? ;; *) echo "Unrecognized argument: $1" >&2 ; exit 1 ;; esac shift done nut-2.8.3/scripts/upsdrvsvcctl/upsdrvsvcctl.in0000755000200500020050000003322614777767434016625 00000000000000#!/bin/sh # # Copyright (C) 2016-2018 Eaton # Copyright (C) 2020-2024 Jim Klimov # # 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. # #! \file upsdrvsvcctl(.in) # \author Jim Klimov # \brief Manage NUT devices registered as service-unit instances # if [ -z "${SERVICE_FRAMEWORK-}" ] ; then [ -x /usr/sbin/svcadm ] && [ -x /usr/sbin/svccfg ] && [ -x /usr/bin/svcs ] && \ SERVICE_FRAMEWORK="smf" [ -z "${SERVICE_FRAMEWORK-}" ] && \ [ -x /bin/systemctl ] && \ SERVICE_FRAMEWORK="systemd" fi VERB="" CMD="" CMDARG="" # Note: some frameworks separate the commands for acting and for reporting CMDREPORT="" CMDREPORTARG="" case "$SERVICE_FRAMEWORK" in smf) CMD="/usr/sbin/svcadm" CMDREPORT="/usr/bin/svcs" [ -n "${ENUMERATOR-}" ] && export ENUMERATOR || ENUMERATOR="@NUT_LIBEXECDIR@/nut-driver-enumerator.sh" ;; systemd) CMD="/bin/systemctl" CMDREPORT="${CMD}" [ -n "${ENUMERATOR-}" ] && export ENUMERATOR || ENUMERATOR="@NUT_LIBEXECDIR@/nut-driver-enumerator.sh" ;; *) echo "Unrecognized SERVICE_FRAMEWORK: $SERVICE_FRAMEWORK" >&2 ; exit ;; esac [ -n "${UPSDRVCTL-}" ] && export UPSDRVCTL || UPSDRVCTL='@SBINDIR@/upsdrvctl' PACKAGE_VERSION='@PACKAGE_VERSION@' # Should be populated by configure script during NUT build: NUT_WEBSITE_BASE='@NUT_WEBSITE_BASE@' # Fallback, no trailing slash! [ -n "${NUT_WEBSITE_BASE-}" ] || NUT_WEBSITE_BASE='https://www.networkupstools.org' usage() { # Note: version header differs from UPS_VERSION in binaries that # might also have the git-version suffixed during build time cat << EOF Network UPS Tools - UPS driver controller ${PACKAGE_VERSION} Starts and stops UPS drivers via system service instances, see the $ENUMERATOR script for more details. usage: $0 [OPTIONS] (start | stop | shutdown) [] Options: -h display this help -V display upsdrvctl binary program version (should not differ from script version above, but...) -t testing mode - prints actions without doing them -D raise debugging level --timeout-cmd service management calls will be time-limited --timeout-args by calling the specified program with its args. By default, if coreutils timeout is found, it would be used to limit service calls by 90 sec. start start all UPS drivers in ups.conf start only start driver for UPS stop stop all UPS drivers in ups.conf stop only stop driver for UPS Note: the "shutdown" options from original upsdrvctl are not currently directly supported by this service management framework wrapper; instead they are passed to the native upsdrvctl binary (your current user account should have sufficient permissions to do that all): shutdown shutdown all UPS drivers in ups.conf shutdown only shutdown UPS usage: $0 [OPTIONS] resync resync call $ENUMERATOR to update the mapping of service instances for NUT drivers to device sections in 'ups.conf' usage: $0 [OPTIONS] reconfigure reconfigure call $ENUMERATOR to remove and re-create the mapping of all service instances for NUT drivers to device sections in 'ups.conf' e.g. after a NUT package upgrade usage: $0 [OPTIONS] list [] list call $ENUMERATOR to list the mapping of service instances to device sections list (optionally return the service instance name for one device) usage: $0 [OPTIONS] status [] status report run-time status for each driver in ups.conf and call $ENUMERATOR to list the mapping of service instances to device sections and report run-time status for each one that was matched status (optionally return the status info only for one device) Fields: SVC_NAME SVC_STATE UPSNAME UPSDRV RUNNING PF_PID S_RESPONSIVE S_PID S_STATUS (SVC_* according to service management framework; and PF_* = according to PID file, if any; S_* = via socket protocol -- as defined by upsdrvctl) usage: $0 [OPTIONS] show-config [] show-config output config section from ups.conf for device show-config ...or all devices if no argument was passed For more information please Read The Fine Manual ('man upsdrvsvcctl') and/or see ${NUT_WEBSITE_BASE}/docs/man/upsdrvsvcctl.html Also check documentation of nut-driver-enumerator and plain old upsdrvctl tools EOF } ACTION="" SVCINST="" DRYRUN="" DEBUG=0 # Note: DEBUG is UNUSED_PARAM so far # Optionally use Coreutils timeout to limit the # (potentially hanging) calls to systemd tools... # Should not hurt with SMF too, if it ever misbehaves. TIMEOUT_CMD="" TIMEOUT_ARGS="" if which timeout 2>/dev/null >/dev/null ; then # Systemd default timeout for unit start/stop TIMEOUT_CMD="timeout" TIMEOUT_ARGS="90s" fi while [ $# -gt 0 ]; do case "$1" in resync) eval $DRYRUN $ENUMERATOR ; exit $? ;; reconf|reconfigure) eval $DRYRUN $ENUMERATOR --reconfigure ; exit $? ;; list) if [ -n "$2" ] ; then eval $ENUMERATOR --get-service-for-device "$2" ; exit $? else eval $ENUMERATOR --list-services-for-devices ; exit $? fi ;; show-config) if [ -n "$2" ] ; then eval $ENUMERATOR --show-device-config "$2" ; exit $? else eval $ENUMERATOR --show-all-configs ; exit $? fi ;; status) RES=0 STATUSES="`NUT_QUIET_INIT_BANNER=true "${UPSDRVCTL}" status $2`" || RES=$? if [ x"${STATUSES}" = x ]; then exit $RES fi SVCINSTS="`$0 list $2`" || RES=$? # Use a common approach below, even if we only got one instance name from list() if [ -n "$2" ] && [ -n "${SVCINSTS}" ] ; then SVCINSTS="${SVCINSTS} $2" ; fi # Accomodate svc:/system/power/nut-driver:dummy (SMF) # or nut-driver@dummy.service (systemd) case "$SERVICE_FRAMEWORK" in smf) SVC_NAME_WIDTH="39" ; SVC_STATE_WIDTH="11" ;; systemd) SVC_NAME_WIDTH="30" ; SVC_STATE_WIDTH="23" ;; esac echo "$STATUSES" | ( COUNT=0; while IFS='' read LINE ; do COUNT="`expr $COUNT + 1`" if [ "$COUNT" = 1 ] ; then # Header line printf '%-'"${SVC_NAME_WIDTH}"'s\t%'"${SVC_STATE_WIDTH}"'s\t%s\n' "SVC_NAME" "SVC_STATE" "$LINE" continue fi DEV_NAME="`echo "$LINE" | awk '{print $1}'`" SVC_NAME="`echo "$SVCINSTS" | awk '($NF == "'"${DEV_NAME}"'") {print $1}'`" && [ -n "$SVC_NAME" ] || SVC_NAME="N/A" if [ x"$SVC_NAME" = "N/A" ]; then SVC_STATE="N/A" else case "$SERVICE_FRAMEWORK" in smf) SVC_STATE="`$CMDREPORT -Hostate ${SVC_NAME} 2>/dev/null`" \ && [ -n "$SVC_STATE" ] && [ 1 = `echo "$SVC_STATE" | wc -l` ] \ || SVC_STATE="N/A" ;; systemd) SVC_STATE="" CMDRES=0 OUT="`$CMDREPORT is-enabled "${SVC_NAME}" 2>/dev/null`" || CMDRES=$? if [ x"$OUT" != x ] ; then SVC_STATE="${OUT}" ; else [ 0 = "$CMDRES" ] && SVC_STATE="enabled" || SVC_STATE="disabled" fi # At this point we should have some value, so others below # may be or not be suffixed with a comma. # The masked unit state has no separate query in some (all?) # systemd versions and can be reported as part of the above CMDRES=0 OUT="`$CMDREPORT is-masked "${SVC_NAME}" 2>/dev/null`" || CMDRES=$? if [ x"$OUT" != x ] ; then if [ x"${SVC_STATE}" != xmasked ] && [ x"${SVC_STATE}" != x"${OUT}" ] ; then SVC_STATE="${SVC_STATE},${OUT}" fi else [ 0 = "$CMDRES" ] && SVC_STATE="${SVC_STATE},masked" || true fi CMDRES=0 OUT="`$CMDREPORT is-active "${SVC_NAME}" 2>/dev/null`" || CMDRES=$? if [ x"$OUT" != x ] ; then SVC_STATE="${SVC_STATE},${OUT}" else [ 0 = "$CMDRES" ] && SVC_STATE="${SVC_STATE},active" || true fi CMDRES=0 OUT="`$CMDREPORT is-failed "${SVC_NAME}" 2>/dev/null`" || CMDRES=$? if [ x"$OUT" != x ] ; then if [ x"${OUT}" != xactive ] && [ x"${OUT}" != xinactive ] ; then SVC_STATE="${SVC_STATE},${OUT}" fi else [ 0 = "$CMDRES" ] && SVC_STATE="${SVC_STATE},failed" || true fi ;; esac fi printf '%-'"${SVC_NAME_WIDTH}"'s\t%'"${SVC_STATE_WIDTH}"'s\t%s\n' "$SVC_NAME" "$SVC_STATE" "$LINE" done ) exit $RES ;; start|stop) ACTION="$1" if [ -n "$2" ] ; then SVCINST="`$ENUMERATOR --get-service-for-device "$2"`" || exit shift fi ;; shutdown) echo "NOTE: Action '$1' is not implemented via services currently, will call upsdrvctl" >&2 echo "Stopping the driver service instance(s) to release exclusive resources, if any..." >&2 RES=0 $0 stop $2 "${UPSDRVCTL}" shutdown $2 || RES=$? echo "Starting the driver service instance(s) so they can reconnect when the UPS returns..." >&2 $0 start $2 exit $RES ;; --timeout-length|--timeout-len|--timeout-args) TIMEOUT_ARGS="$2" shift ;; --timeout-cmd) if [ -n "$2" ] ; then if [ -x "$2" ] || which "$2" 2>/dev/null >/dev/null ; then TIMEOUT_CMD="$2" else echo "ERROR: Received a '$2' argument for $1, and can not find such program; clearing the option so the basic functionality can proceed" >&2 TIMEOUT_CMD="" TIMEOUT_ARGS="" fi else echo "INFO: Received an empty argument for $1, clearing the option" >&2 TIMEOUT_CMD="" TIMEOUT_ARGS="" fi shift ;; -t) DRYRUN="echo" ;; -h) usage; exit 0 ;; -V) "${UPSDRVCTL}" -V ; exit ;; -D) DEBUG="`expr $DEBUG + 1`" ;; -r|-u) echo "Option '$1 $2' is not implemented via services currently" >&2 ; shift;; *) echo "Unrecognized argument: $1" >&2 ; exit ;; esac shift done if [ -z "$ENUMERATOR" ] || [ ! -s "$ENUMERATOR" ] || [ ! -x "$ENUMERATOR" ] ; then echo "ENUMERATOR script (nut-driver-enumerator.sh) not found!" >&2 exit 1 fi if [ -z "$ACTION" ]; then echo "No action was requested!" >&2 exit 1 fi if [ -n "$TIMEOUT_CMD" ]; then echo "INFO: Detected presence of $TIMEOUT_CMD so will limit service management calls by passing the args: $TIMEOUT_ARGS" >&2 fi if [ -z "$SVCINST" ]; then SVCINST="`$ENUMERATOR --list-services`" || exit fi # TODO: Support shutdown of one or all UPSes by stopping its service # and then calling the original upsdrvctl on it? case "$ACTION" in start) VERB="Starting" case "$SERVICE_FRAMEWORK" in smf) CMDARG="enable -ts" ;; systemd) CMDARG="start" ;; esac ;; stop) VERB="Stopping" case "$SERVICE_FRAMEWORK" in smf) CMDARG="disable -ts" ;; systemd) CMDARG="stop" ;; esac ;; *) echo "Unrecognized ACTION: $ACTION" >&2 ; exit ;; esac for INST in $SVCINST ; do echo "$VERB $INST ..." >&2 $DRYRUN $TIMEOUT_CMD $TIMEOUT_ARGS $CMD $CMDARG "$INST" & done wait case "$SERVICE_FRAMEWORK" in smf) sleep 1 echo "Post-process clearing services that failed early..." >&2 for INST in $SVCINST ; do echo "Clearing $INST (if it got broken) ..." >&2 $DRYRUN $TIMEOUT_CMD $TIMEOUT_ARGS $CMD clear "$INST" & done ;; esac wait nut-2.8.3/scripts/upsdrvsvcctl/README.adoc0000644000200500020050000000144114777534446015302 00000000000000Shared resources for NUT service unit integrations ================================================== This directory contains the shared NUT support files for Linux systemd (the System and Service Manager) and Solaris SMF (Service Management Framework). It includes the `nut-driver-enumerator.sh` (service and implementation method) and `upsdrvsvcctl` (tool) to manage NUT drivers as service instances. These files are automatically installed into `SBINDIR/upsdrvsvcctl` and `LIBEXECDIR/nut-driver-enumerator.sh`, upon detection (at `configure` time) of a systemd or SMF enabled system, with Makefiles of the `../systemd/` and `../Solaris/` source directories respectively. Contributed 2016-2018 by Jim Klimov Maintained since 2020 by Jim Klimov nut-2.8.3/scripts/upsdrvsvcctl/Makefile.am0000644000200500020050000000425014777767434015557 00000000000000# Network UPS Tools: scripts/upsdrvsvcctl EXTRA_DIST = README.adoc if HAVE_SYSTEMD EXTRA_DIST += nut-driver-enumerator.sh upsdrvsvcctl else if WITH_SOLARIS_SMF EXTRA_DIST += nut-driver-enumerator.sh upsdrvsvcctl endif endif EXTRA_DIST += nut-driver-enumerator.sh.in upsdrvsvcctl.in SPELLCHECK_SRC = README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.3/scripts/upsdrvsvcctl/upsdrvsvcctl0000755000200500020050000003327515001555034016170 00000000000000#!/bin/sh # # Copyright (C) 2016-2018 Eaton # Copyright (C) 2020-2024 Jim Klimov # # 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. # #! \file upsdrvsvcctl(.in) # \author Jim Klimov # \brief Manage NUT devices registered as service-unit instances # if [ -z "${SERVICE_FRAMEWORK-}" ] ; then [ -x /usr/sbin/svcadm ] && [ -x /usr/sbin/svccfg ] && [ -x /usr/bin/svcs ] && \ SERVICE_FRAMEWORK="smf" [ -z "${SERVICE_FRAMEWORK-}" ] && \ [ -x /bin/systemctl ] && \ SERVICE_FRAMEWORK="systemd" fi VERB="" CMD="" CMDARG="" # Note: some frameworks separate the commands for acting and for reporting CMDREPORT="" CMDREPORTARG="" case "$SERVICE_FRAMEWORK" in smf) CMD="/usr/sbin/svcadm" CMDREPORT="/usr/bin/svcs" [ -n "${ENUMERATOR-}" ] && export ENUMERATOR || ENUMERATOR="/usr/local/ups/libexec/nut-driver-enumerator.sh" ;; systemd) CMD="/bin/systemctl" CMDREPORT="${CMD}" [ -n "${ENUMERATOR-}" ] && export ENUMERATOR || ENUMERATOR="/usr/local/ups/libexec/nut-driver-enumerator.sh" ;; *) echo "Unrecognized SERVICE_FRAMEWORK: $SERVICE_FRAMEWORK" >&2 ; exit ;; esac [ -n "${UPSDRVCTL-}" ] && export UPSDRVCTL || UPSDRVCTL='/usr/local/ups/sbin/upsdrvctl' PACKAGE_VERSION='2.8.3' # Should be populated by configure script during NUT build: NUT_WEBSITE_BASE='https://www.networkupstools.org/historic/v2.8.3' # Fallback, no trailing slash! [ -n "${NUT_WEBSITE_BASE-}" ] || NUT_WEBSITE_BASE='https://www.networkupstools.org' usage() { # Note: version header differs from UPS_VERSION in binaries that # might also have the git-version suffixed during build time cat << EOF Network UPS Tools - UPS driver controller ${PACKAGE_VERSION} Starts and stops UPS drivers via system service instances, see the $ENUMERATOR script for more details. usage: $0 [OPTIONS] (start | stop | shutdown) [] Options: -h display this help -V display upsdrvctl binary program version (should not differ from script version above, but...) -t testing mode - prints actions without doing them -D raise debugging level --timeout-cmd service management calls will be time-limited --timeout-args by calling the specified program with its args. By default, if coreutils timeout is found, it would be used to limit service calls by 90 sec. start start all UPS drivers in ups.conf start only start driver for UPS stop stop all UPS drivers in ups.conf stop only stop driver for UPS Note: the "shutdown" options from original upsdrvctl are not currently directly supported by this service management framework wrapper; instead they are passed to the native upsdrvctl binary (your current user account should have sufficient permissions to do that all): shutdown shutdown all UPS drivers in ups.conf shutdown only shutdown UPS usage: $0 [OPTIONS] resync resync call $ENUMERATOR to update the mapping of service instances for NUT drivers to device sections in 'ups.conf' usage: $0 [OPTIONS] reconfigure reconfigure call $ENUMERATOR to remove and re-create the mapping of all service instances for NUT drivers to device sections in 'ups.conf' e.g. after a NUT package upgrade usage: $0 [OPTIONS] list [] list call $ENUMERATOR to list the mapping of service instances to device sections list (optionally return the service instance name for one device) usage: $0 [OPTIONS] status [] status report run-time status for each driver in ups.conf and call $ENUMERATOR to list the mapping of service instances to device sections and report run-time status for each one that was matched status (optionally return the status info only for one device) Fields: SVC_NAME SVC_STATE UPSNAME UPSDRV RUNNING PF_PID S_RESPONSIVE S_PID S_STATUS (SVC_* according to service management framework; and PF_* = according to PID file, if any; S_* = via socket protocol -- as defined by upsdrvctl) usage: $0 [OPTIONS] show-config [] show-config output config section from ups.conf for device show-config ...or all devices if no argument was passed For more information please Read The Fine Manual ('man upsdrvsvcctl') and/or see ${NUT_WEBSITE_BASE}/docs/man/upsdrvsvcctl.html Also check documentation of nut-driver-enumerator and plain old upsdrvctl tools EOF } ACTION="" SVCINST="" DRYRUN="" DEBUG=0 # Note: DEBUG is UNUSED_PARAM so far # Optionally use Coreutils timeout to limit the # (potentially hanging) calls to systemd tools... # Should not hurt with SMF too, if it ever misbehaves. TIMEOUT_CMD="" TIMEOUT_ARGS="" if which timeout 2>/dev/null >/dev/null ; then # Systemd default timeout for unit start/stop TIMEOUT_CMD="timeout" TIMEOUT_ARGS="90s" fi while [ $# -gt 0 ]; do case "$1" in resync) eval $DRYRUN $ENUMERATOR ; exit $? ;; reconf|reconfigure) eval $DRYRUN $ENUMERATOR --reconfigure ; exit $? ;; list) if [ -n "$2" ] ; then eval $ENUMERATOR --get-service-for-device "$2" ; exit $? else eval $ENUMERATOR --list-services-for-devices ; exit $? fi ;; show-config) if [ -n "$2" ] ; then eval $ENUMERATOR --show-device-config "$2" ; exit $? else eval $ENUMERATOR --show-all-configs ; exit $? fi ;; status) RES=0 STATUSES="`NUT_QUIET_INIT_BANNER=true "${UPSDRVCTL}" status $2`" || RES=$? if [ x"${STATUSES}" = x ]; then exit $RES fi SVCINSTS="`$0 list $2`" || RES=$? # Use a common approach below, even if we only got one instance name from list() if [ -n "$2" ] && [ -n "${SVCINSTS}" ] ; then SVCINSTS="${SVCINSTS} $2" ; fi # Accomodate svc:/system/power/nut-driver:dummy (SMF) # or nut-driver@dummy.service (systemd) case "$SERVICE_FRAMEWORK" in smf) SVC_NAME_WIDTH="39" ; SVC_STATE_WIDTH="11" ;; systemd) SVC_NAME_WIDTH="30" ; SVC_STATE_WIDTH="23" ;; esac echo "$STATUSES" | ( COUNT=0; while IFS='' read LINE ; do COUNT="`expr $COUNT + 1`" if [ "$COUNT" = 1 ] ; then # Header line printf '%-'"${SVC_NAME_WIDTH}"'s\t%'"${SVC_STATE_WIDTH}"'s\t%s\n' "SVC_NAME" "SVC_STATE" "$LINE" continue fi DEV_NAME="`echo "$LINE" | awk '{print $1}'`" SVC_NAME="`echo "$SVCINSTS" | awk '($NF == "'"${DEV_NAME}"'") {print $1}'`" && [ -n "$SVC_NAME" ] || SVC_NAME="N/A" if [ x"$SVC_NAME" = "N/A" ]; then SVC_STATE="N/A" else case "$SERVICE_FRAMEWORK" in smf) SVC_STATE="`$CMDREPORT -Hostate ${SVC_NAME} 2>/dev/null`" \ && [ -n "$SVC_STATE" ] && [ 1 = `echo "$SVC_STATE" | wc -l` ] \ || SVC_STATE="N/A" ;; systemd) SVC_STATE="" CMDRES=0 OUT="`$CMDREPORT is-enabled "${SVC_NAME}" 2>/dev/null`" || CMDRES=$? if [ x"$OUT" != x ] ; then SVC_STATE="${OUT}" ; else [ 0 = "$CMDRES" ] && SVC_STATE="enabled" || SVC_STATE="disabled" fi # At this point we should have some value, so others below # may be or not be suffixed with a comma. # The masked unit state has no separate query in some (all?) # systemd versions and can be reported as part of the above CMDRES=0 OUT="`$CMDREPORT is-masked "${SVC_NAME}" 2>/dev/null`" || CMDRES=$? if [ x"$OUT" != x ] ; then if [ x"${SVC_STATE}" != xmasked ] && [ x"${SVC_STATE}" != x"${OUT}" ] ; then SVC_STATE="${SVC_STATE},${OUT}" fi else [ 0 = "$CMDRES" ] && SVC_STATE="${SVC_STATE},masked" || true fi CMDRES=0 OUT="`$CMDREPORT is-active "${SVC_NAME}" 2>/dev/null`" || CMDRES=$? if [ x"$OUT" != x ] ; then SVC_STATE="${SVC_STATE},${OUT}" else [ 0 = "$CMDRES" ] && SVC_STATE="${SVC_STATE},active" || true fi CMDRES=0 OUT="`$CMDREPORT is-failed "${SVC_NAME}" 2>/dev/null`" || CMDRES=$? if [ x"$OUT" != x ] ; then if [ x"${OUT}" != xactive ] && [ x"${OUT}" != xinactive ] ; then SVC_STATE="${SVC_STATE},${OUT}" fi else [ 0 = "$CMDRES" ] && SVC_STATE="${SVC_STATE},failed" || true fi ;; esac fi printf '%-'"${SVC_NAME_WIDTH}"'s\t%'"${SVC_STATE_WIDTH}"'s\t%s\n' "$SVC_NAME" "$SVC_STATE" "$LINE" done ) exit $RES ;; start|stop) ACTION="$1" if [ -n "$2" ] ; then SVCINST="`$ENUMERATOR --get-service-for-device "$2"`" || exit shift fi ;; shutdown) echo "NOTE: Action '$1' is not implemented via services currently, will call upsdrvctl" >&2 echo "Stopping the driver service instance(s) to release exclusive resources, if any..." >&2 RES=0 $0 stop $2 "${UPSDRVCTL}" shutdown $2 || RES=$? echo "Starting the driver service instance(s) so they can reconnect when the UPS returns..." >&2 $0 start $2 exit $RES ;; --timeout-length|--timeout-len|--timeout-args) TIMEOUT_ARGS="$2" shift ;; --timeout-cmd) if [ -n "$2" ] ; then if [ -x "$2" ] || which "$2" 2>/dev/null >/dev/null ; then TIMEOUT_CMD="$2" else echo "ERROR: Received a '$2' argument for $1, and can not find such program; clearing the option so the basic functionality can proceed" >&2 TIMEOUT_CMD="" TIMEOUT_ARGS="" fi else echo "INFO: Received an empty argument for $1, clearing the option" >&2 TIMEOUT_CMD="" TIMEOUT_ARGS="" fi shift ;; -t) DRYRUN="echo" ;; -h) usage; exit 0 ;; -V) "${UPSDRVCTL}" -V ; exit ;; -D) DEBUG="`expr $DEBUG + 1`" ;; -r|-u) echo "Option '$1 $2' is not implemented via services currently" >&2 ; shift;; *) echo "Unrecognized argument: $1" >&2 ; exit ;; esac shift done if [ -z "$ENUMERATOR" ] || [ ! -s "$ENUMERATOR" ] || [ ! -x "$ENUMERATOR" ] ; then echo "ENUMERATOR script (nut-driver-enumerator.sh) not found!" >&2 exit 1 fi if [ -z "$ACTION" ]; then echo "No action was requested!" >&2 exit 1 fi if [ -n "$TIMEOUT_CMD" ]; then echo "INFO: Detected presence of $TIMEOUT_CMD so will limit service management calls by passing the args: $TIMEOUT_ARGS" >&2 fi if [ -z "$SVCINST" ]; then SVCINST="`$ENUMERATOR --list-services`" || exit fi # TODO: Support shutdown of one or all UPSes by stopping its service # and then calling the original upsdrvctl on it? case "$ACTION" in start) VERB="Starting" case "$SERVICE_FRAMEWORK" in smf) CMDARG="enable -ts" ;; systemd) CMDARG="start" ;; esac ;; stop) VERB="Stopping" case "$SERVICE_FRAMEWORK" in smf) CMDARG="disable -ts" ;; systemd) CMDARG="stop" ;; esac ;; *) echo "Unrecognized ACTION: $ACTION" >&2 ; exit ;; esac for INST in $SVCINST ; do echo "$VERB $INST ..." >&2 $DRYRUN $TIMEOUT_CMD $TIMEOUT_ARGS $CMD $CMDARG "$INST" & done wait case "$SERVICE_FRAMEWORK" in smf) sleep 1 echo "Post-process clearing services that failed early..." >&2 for INST in $SVCINST ; do echo "Clearing $INST (if it got broken) ..." >&2 $DRYRUN $TIMEOUT_CMD $TIMEOUT_ARGS $CMD clear "$INST" & done ;; esac wait nut-2.8.3/scripts/upsdrvsvcctl/nut-driver-enumerator.sh0000755000200500020050000023657715001555034020327 00000000000000#!/bin/sh # BIG NOTE: Not bash, not any other predetermined shell implementation # # NOTE: This script is intentionally written with portable shell constructs # with the aim and hope to work in different interpreters, so it is a # bit dumber and less efficient than could be achieved with the more # featured shells in the spectrum. Also, to minimize the in-memory and # debug-console traffics, tests for (non-)emptiness of anticipated large # strings are not done by `test -n/-z`, but by counting the size of the # string (zero or not). # NOTE ALSO: The configuration parser in this script is not meant to be a # reference or 100% compliant with what the binary code uses; its aim # is to just pick out some strings relevant for tracking config changes. # # Copyright (C) 2016-2020 Eaton # Copyright (C) 2020-2025 Jim Klimov # # 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. # #! \file nut-driver-enumerator.sh(.in) # \author Jim Klimov # \brief Enumerate NUT devices for service-unit instance configuration # \details This script allows to enumerate UPSes in order to produce the # individual service unit instances for each defined configuration. # It assumes the user has adequate permissions to inspect and create # services (e.g. is a root or has proper RBAC profiles to do so). # It helps service frameworks such as Linux systemd and Solaris SMF. # When executed, this script looks for all configured ups.conf # sections and registered service instances, and makes these two # lists match up. It has also a mode to do this in a loop, to keep # checking for differences and applying them, on systems where it's # problematic to trigger it in response to FS event notifications. # Returns exit codes: # 0 Sections and services already match up # 42 Sections and services differed, but now match up - # now the caller should likely restart some services. # Note that the drivers' service instances were started or # stopped as required (by AUTO_START=yes) - but maybe the # upsd or upsmon services should restart. If you pass envvar # REPORT_RESTART_42=no then this codepath would return 0. # In default mode, such non-null reconfiguration should cause # the nut-driver-enumerator service to restart and this would # propagate to other NUT services that depend on it. # 13 Sections and services differed, and still do not match up # 1 Bad inputs, e.g. unrecognized service management framework # 2 Absent or unreadable ups.conf file # # NOTE: Currently found caveats that might be solved later but require # considerable effort: # * Solaris SMF constrains the syntax of valid strings for instance names # (e.g. not starting with a digit, no period chars) which blocks creation # of some UPS driver instances. This might be worked around by hashing # the device name e.g. to base64 (and un-hashing instance name when calling # upsdrvctl), but is not quite user-friendly. Also can store device name # in a service attribute while mangling the instance name to a valid subset. # Comparisons (if devices are already wrapped) becomes more complicated in # the script in either case, as well as in the service startup method. # ** The `+` `/` `=` characters from base64 are also invalid for SMF instance # name, but the first two can be sed'ed to `-` `_` and back, for example. # Some prefix word is also needed (avoid starting with a digit). # The trailing padding `=` can be dropped, and added until we get a # non-empty decode. Conversions can be done by # `echo "$string" | openssl base64 -e|-d` # * Dummy-UPS services that "proxy" another locally defined section are # essentially a circular dependency for upsd. While the system might # start-up lacking a driver, there should be some timer to re-enable # failed not-disabled drivers (would be useful in any case though). # Directory where NUT configs are located, e.g. /etc/nut or /etc/ups # Set at package configuration, compiled into daemons and drivers prefix="/usr/local/ups" [ -n "${NUT_CONFPATH-}" ] || NUT_CONFPATH="${prefix}/etc" # Technically this should be a distribution-dependent value configured # during package build. But everyone has it the same from systemd defaults: [ -n "${SYSTEMD_CONFPATH-}" ] || SYSTEMD_CONFPATH="/etc/systemd/system" if [ -n "$ZSH_VERSION" ]; then ### Problem: loops like `for UPS in $UPSLIST` do not separate ### the UPSLIST into many tokens but use it as one string. echo "FATAL: zsh is not supported in this script" >&2 exit 1 # setopt noglob # setopt +F # IFS="`printf ' \t\r\n'`" ; export IFS fi if set | grep -E '^(shell|version|t?csh)' | grep -E 't?csh' >/dev/null ; then echo "FATAL: csh or tcsh is not supported in this script" >&2 exit 1 fi # Third-party services to depend on (can be overridden by config file) ### Note that for systemd+udev integration, it may be better to set up ### triggers in udev, see e.g. ### http://stackoverflow.com/questions/18463755/linux-start-daemon-on-connected-usb-serial-dongle ### Also can tune whether a driver "Wants" another service (would consider ### ordering if that one is enabled, but live if it is disabled), or if it ### "Requires" that (would cause that to start). DEPSVC_USB_SYSTEMD="systemd-udevd.service nut-udev-settle.service" DEPREQ_USB_SYSTEMD="Wants" # Serial drivers may rely on USB dongles or even custom-owned real ports: DEPSVC_SERIAL_SYSTEMD="systemd-udevd.service nut-udev-settle.service" DEPREQ_SERIAL_SYSTEMD="Wants" DEPSVC_NET_FULL_SYSTEMD="network-online.target systemd-resolved.service ifplugd.service" DEPREQ_NET_FULL_SYSTEMD="Wants" DEPSVC_NET_LOCAL_SYSTEMD="network.target" DEPREQ_NET_LOCAL_SYSTEMD="Wants" SVCNAME_SYSTEMD="nut-driver" # Some or all of these FMRIs may be related to dynamically changing hardware # require_all) ;; # All cited services are running (online or degraded) # require_any) ;; # At least one of the cited services is running # optional_all) ;; # (All) cited services are running or would not run # # without administrative action (disabled, maintenance, # # not present, or are waiting for dependencies which do # # not start without administrative action). DEPSVC_USB_SMF="svc:/system/hotplug:default svc:/system/dbus:default svc:/system/hal:default svc:/milestone/devices:default" DEPREQ_USB_SMF="optional_all" # By default there are several physical network FMRIs shipped and at most # only one is enabled on a particular system (e.g. :default or :nwam) DEPSVC_NET_FULL_SMF="svc:/network/physical svc:/milestone/name-services" DEPREQ_NET_FULL_SMF="optional_all" DEPSVC_NET_LOCAL_SMF="svc:/network/loopback:default" DEPREQ_NET_LOCAL_SMF="optional_all" SVCNAME_SMF="svc:/system/power/nut-driver" [ -z "${NUT_DRIVER_ENUMERATOR_CONF-}" ] && \ NUT_DRIVER_ENUMERATOR_CONF="${NUT_CONFPATH}/nut-driver-enumerator.conf" [ -s "${NUT_DRIVER_ENUMERATOR_CONF}" ] && \ echo "Sourcing config file: ${NUT_DRIVER_ENUMERATOR_CONF}" && \ . "${NUT_DRIVER_ENUMERATOR_CONF}" [ -z "${UPSCONF-}" ] && \ UPSCONF="${NUT_CONFPATH}/ups.conf" # Start a freshly-registered unit? [ -z "${AUTO_START-}" ] && AUTO_START=yes # We avoid regex '\t' which gets misinterpreted by some tools TABCHAR="`printf '\t'`" || TABCHAR=' ' if [ -z "${SERVICE_FRAMEWORK-}" ] ; then [ -x /usr/sbin/svcadm ] && [ -x /usr/sbin/svccfg ] && [ -x /usr/bin/svcs ] && [ -x /usr/bin/svcprop ] && \ SERVICE_FRAMEWORK="smf" [ -z "${SERVICE_FRAMEWORK-}" ] && \ [ -x /bin/systemctl ] && \ SERVICE_FRAMEWORK="systemd" fi # Optionally use Coreutils timeout to limit the # (potentially hanging) calls to systemd tools... # Should not hurt with SMF too, if it ever misbehaves. if [ -z "${TIMEOUT_CMD+x}" ]; then # Envvar not set at all (set but empty is okay, caller wants that then) TIMEOUT_CMD="" TIMEOUT_ARGS="" if which timeout 2>/dev/null >/dev/null ; then # Systemd default timeout for unit start/stop TIMEOUT_CMD="timeout" TIMEOUT_ARGS="90s" fi fi # Should be populated by configure script during NUT build: NUT_WEBSITE_BASE='https://www.networkupstools.org/historic/v2.8.3' # Fallback, no trailing slash! [ -n "${NUT_WEBSITE_BASE-}" ] || NUT_WEBSITE_BASE='https://www.networkupstools.org' # Cache needed bits of ups.conf to speed up later parsing. Note that these # data are needed for most operations, and populated by upslist_readFile() UPSCONF_DATA="" # Subset of normalized data above that only has sections, drivers and ports (SDP) UPSCONF_DATA_SDP="" # List of configured UPSes in the config-file UPSLIST_FILE="" # List of configured service instances for UPS drivers UPSLIST_SVCS="" # Framework-specific implementations are generally hooked here: hook_registerInstance="" hook_unregisterInstance="" hook_refreshSupervizor="" hook_listInstances="" hook_listInstances_raw="" hook_validInstanceName="" hook_validFullUnitName="" hook_validInstanceSuffixName="" hook_getSavedDeviceName="" hook_findSavedDeviceName="" hook_setSavedDeviceName="" hook_setDocLink="" hook_getSavedMD5="" hook_setSavedMD5="" hook_restart_upsd="" hook_restart_drv="" case "${SERVICE_FRAMEWORK-}" in smf) hook_registerInstance="smf_registerInstance" hook_unregisterInstance="smf_unregisterInstance" hook_refreshSupervizor="smf_refreshSupervizor" hook_listInstances="smf_listInstances" hook_listInstances_raw="smf_listInstances_raw" hook_validInstanceName="smf_validInstanceName" hook_validFullUnitName="smf_validFullUnitName" hook_validInstanceSuffixName="smf_validInstanceSuffixName" hook_getSavedDeviceName="smf_getSavedDeviceName" hook_findSavedDeviceName="smf_findSavedDeviceName" hook_setSavedDeviceName="smf_setSavedDeviceName" hook_setDocLink="smf_setDocLink" hook_getSavedMD5="smf_getSavedMD5" hook_setSavedMD5="smf_setSavedMD5" hook_restart_upsd="smf_restart_upsd" hook_restart_drv="smf_restart_drv" ;; systemd) hook_registerInstance="systemd_registerInstance" hook_unregisterInstance="systemd_unregisterInstance" hook_refreshSupervizor="systemd_refreshSupervizor" hook_listInstances="systemd_listInstances" hook_listInstances_raw="systemd_listInstances_raw" hook_validInstanceName="systemd_validInstanceName" hook_validFullUnitName="systemd_validFullUnitName" hook_validInstanceSuffixName="systemd_validInstanceSuffixName" hook_getSavedDeviceName="systemd_getSavedDeviceName" hook_findSavedDeviceName="systemd_findSavedDeviceName" hook_setSavedDeviceName="systemd_setSavedDeviceName" hook_setDocLink="systemd_setDocLink" hook_getSavedMD5="systemd_getSavedMD5" hook_setSavedMD5="systemd_setSavedMD5" hook_restart_upsd="systemd_restart_upsd" hook_restart_drv="systemd_restart_drv" ;; selftest) hook_registerInstance="selftest_NOOP" hook_unregisterInstance="selftest_NOOP" hook_refreshSupervizor="selftest_NOOP" hook_listInstances="selftest_NOOP" hook_listInstances_raw="selftest_NOOP" hook_validInstanceName="selftest_NOOP" hook_validFullUnitName="selftest_NOOP" hook_validInstanceSuffixName="selftest_NOOP" hook_getSavedDeviceName="selftest_NOOP" hook_findSavedDeviceName="selftest_NOOP" hook_setSavedDeviceName="selftest_NOOP" hook_setDocLink="selftest_NOOP" hook_getSavedMD5="selftest_NOOP" hook_setSavedMD5="selftest_NOOP" hook_restart_upsd="selftest_NOOP" hook_restart_drv="selftest_NOOP" ;; "") echo "Error detecting the service-management framework on this OS" >&2 exit 1 ;; *) echo "Error: User provided an unknown service-management framework '$SERVICE_FRAMEWORK'" >&2 exit 1 ;; esac selftest_NOOP() { echo "NO-OP: Self-testing context does not do systems configuration" >&2 return 0 } common_isFiled() { [ "${#UPSLIST_FILE}" != 0 ] && \ for UPSF in $UPSLIST_FILE ; do [ "$1" = "$UPSF" ] && return 0 [ "`$hook_validInstanceName "$UPSF"`" = "$1" ] && return 0 done return 1 } common_isRegistered() { [ "${#UPSLIST_SVCS}" != 0 ] && \ for UPSS in $UPSLIST_SVCS ; do [ "$1" = "$UPSS" ] && return 0 [ "`$hook_validInstanceName "$1"`" = "$UPSS" ] && return 0 done return 1 } upslist_equals() { # Compare pre-sorted list of DEVICES ($1) and SVCINSTs ($2) including # the possible mangling for service names. Return 0 if lists describe # exactly same set of devices and their services. # Note: This logic only checks the names, not the contents of device # sections, so re-definitions of an existing device configuration # would not trigger a service restart by itself. Such deeper check # belongs in a different routine, see upssvcconf_checksum_unchanged(). # Trivial case 0: one string is empty, another is not # Note: `echo '' | wc -l` == "1" not "0"! [ "${#1}" != 0 -a "${#2}" = 0 ] && return 1 [ "${#1}" = 0 -a "${#2}" != 0 ] && return 1 # Trivial case 1: equal strings [ "$1" = "$2" ] && return 0 # Trivial case 2: different amount of entries [ "`echo "$1" | wc -l`" = "`echo "$2" | wc -l`" ] || return $? _TMP_DEV_SVC="" for _DEV in $1 ; do DEVINST="`$hook_validInstanceName "${_DEV}"`" for _SVC in $2 ; do [ "${_DEV}" = "${_SVC}" ] \ || [ "$DEVINST" = "${_SVC}" ] \ && { [ "${#_TMP_DEV_SVC}" = 0 ] \ && _TMP_DEV_SVC="${_DEV} = ${_SVC}" \ || _TMP_DEV_SVC="${_TMP_DEV_SVC} ${_DEV} = ${_SVC}" ; } done done # Input was not empty; did anything in output fit? [ "${#_TMP_DEV_SVC}" = 0 ] && return 1 # Exit code : is the built mapping as long as the source list(s)? [ "`echo "$1" | wc -l`" = "`echo "${_TMP_DEV_SVC}" | wc -l`" ] } upssvcconf_checksum_unchanged() { # $1 = dev, $2 = svc # compare checksums of the configuration section from the file and the # stashed configuration in a service instance (if any). # FIXME : optimize by caching, we likely have quite a few requests [ "`upsconf_getSection_MD5 "$1"`" = "`$hook_getSavedMD5 "$2"`" ] } upslist_checksums_unchanged() { # For each device and its corresponding unit, compare checksums of the # configuration section from the file and the stashed configuration in # a service instance. Prints a list of mismatching service names that # should get reconfigured. [ "${#1}" = 0 -o "${#2}" = 0 ] && return 1 _TMP_SVC="" for _DEV in $1 ; do DEVINST="`$hook_validInstanceName "${_DEV}"`" for _SVC in $2 ; do if [ "${_DEV}" = "${_SVC}" ] \ || [ "$DEVINST" = "${_SVC}" ] \ ; then upssvcconf_checksum_unchanged "${_DEV}" "${_SVC}" || \ { [ "${#_TMP_SVC}" = 0 ] \ && _TMP_SVC="${_SVC}" \ || _TMP_SVC="${_TMP_SVC} ${_SVC}" ; } fi done done [ "${#_TMP_SVC}" = 0 ] && return 0 echo "${_TMP_SVC}" return 1 } upslist_savednames_find_missing() { # Verify that all existing service units have a saved DEVICE name # Report those that do not have a value there (any value) so we can # amend those quickly after an upgrade. Otherwise we trust these. # Return codes: # 0) Some services were defined and at least one had DEVICE values # (those that did not are reported in stdout) # 1) No services defined yet (empty stdout) # 2) All service units do not have DEVICE values (all reported in stdout) # Get full instance names from system and from props SVCINSTS="`$hook_listInstances_raw`" && [ "${#SVCINSTS}" != 0 ] || return 1 # If no props were found, (over)write them all SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ "${#SVCINST_PROPS}" != 0 ] \ || { echo $SVCINSTS ; return 2; } # Find and report services which do *not* have saved device names in # props (do not report those that have a non-trivial prop value): # whether an empty value or completely absent from the list for SVCINST in $SVCINSTS ; do echo "$SVCINST_PROPS" | grep -E "^${SVCINST}${TABCHAR}"'$' >/dev/null && echo "$SVCINST" echo "$SVCINST_PROPS" | grep -E "^${SVCINST}${TABCHAR}" >/dev/null || echo "$SVCINST" done return 0 } upslist_savednames_find_mismatch() { # NOTE: Not used currently (as of NUT v2.8.2) # TODO: Make use of this to fsck the enumerator configs # TODO: Complete checking MD5 normalized names if original not hit # TODO: Report all unit names if none has the DEVICE values? (code 2) # # Verify that all existing service units have a saved DEVICE name # and that such name does match the unit instance's name (original # or MD5 normalized version). If something does not match, returns # the unit name so it can be redefined by caller. This does not # inspect whether such DEVICE is defined in NUT configuration. # This situation might occur in some errors, but the likely case # is updating from versions that did not track this info yet (but # upslist_savednames_find_missing() should have handled those). # Return codes: # 0) Some services were defined and at least one had DEVICE values # (those that did not are reported in stdout) # 1) No services defined yet (empty stdout) # 2) All service units do not have DEVICE values (empty stdout) # Get full instance names from system and from props SVCINSTS="`$hook_listInstances_raw`" && [ "${#SVCINSTS}" != 0 ] || return 1 SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ "${#SVCINST_PROPS}" != 0 ] || return 2 # Find services whose props exist but services themselves do not # (e.g. upgrading from some version with different naming patterns) echo "$SVCINST_PROPS" | while read SVCINST_PROP DEVNAME_PROP ; do echo "$SVCINSTS" | grep -E "^${SVCINST_PROP}"'$' >/dev/null || echo "$SVCINST_PROP" done # Find and report services which do *not* have saved device names in # props (do not report those that have a non-trivial prop value): # whether an empty value or completely absent from the list for SVCINST in $SVCINSTS ; do echo "$SVCINST_PROPS" | grep -E "^${SVCINST}${TABCHAR}"'$' >/dev/null && echo "$SVCINST" echo "$SVCINST_PROPS" | grep -E "^${SVCINST}${TABCHAR}" >/dev/null || echo "$SVCINST" done return 0 } upsconf_getSection_content() { # "$1" = name of ups.conf section to display in whole, from whatever # comes on stdin (file or a pre-made normalized variable) # empty "$1" means the global config (before any sections) # # NOTE (TODO?): This routine finds the one NUT device section, prints it # and returns when the section is over. It currently does not cover (in # a way allowing to do it efficiently) selection of several sections, # or storing each section content in some array or dynamic variables # (as would be better fit for portable shells) to later address them # quickly without re-parsing the file or big envvar many times. # CURR_SECTION="" SECTION_CONTENT="" RES=1 [ -n "$1" ] || RES=0 while read LINE ; do case "$LINE" in \["$1"\]) if [ "$RES" = 0 ]; then # We have already displayed a section, here is a new one, # and this routine only displays one (TODO: toggle?) break fi SECTION_CONTENT="$LINE" CURR_SECTION="$1" RES=0 continue ;; \[*\ *\]|\[*"$TABCHAR"*\]) # Note that section-name brackets should contain a single token # Fall through to add the line to contents of existing section ;; \[*\]) [ "$CURR_SECTION" = "$1" ] && break # Use a value that can not be a section name here: CURR_SECTION="[]" continue ;; "") continue ;; *) ;; # Fall through to add the line to contents of existing section esac if [ "$CURR_SECTION" = "$1" ]; then if [ "${#SECTION_CONTENT}" = 0 ]; then SECTION_CONTENT="$LINE" else SECTION_CONTENT="$SECTION_CONTENT $LINE" fi fi done if [ "${#SECTION_CONTENT}" != 0 ]; then echo "$SECTION_CONTENT" fi [ "$RES" = 0 ] || echo "ERROR: Section [$1] was not found in the '$UPSCONF' file" >&2 return $RES } upsconf_getSection() { # Use the whole output of normalization parser if [ x"${AVOID_REPARSE}" != xyes ] ; then upslist_normalizeFile_once || return # Propagate errors upwards fi upsconf_getSection_content "$@" << EOF ${UPSCONF_DATA} EOF } upsconf_getSection_MD5() { calc_md5 "`upsconf_getSection "$@"`" } upsconf_getSection_SDP() { # Use the section-driver-port subset if [ x"${AVOID_REPARSE}" != xyes ] ; then upslist_normalizeFile_once || return # Propagate errors upwards fi upsconf_getSection_content "$@" << EOF ${UPSCONF_DATA_SDP} EOF } upsconf_getValue() { # "$1" = name of ups.conf section, may be empty for global config # "$2..$N" = name of config key; we will echo its value ### [ -n "$1" ] || return $? [ -n "$2" ] || return $? [ -n "$GETSECTION" ] || GETSECTION="upsconf_getSection" CURR_SECTION="" # Gets set by a GETSECTION implementation RES=0 # Note: Primary aim of this egrep is to pick either assignments or flags # As a by-product it can be used to test if a particular value is set ;) SECTION_CONTENT="`$GETSECTION "$1"`" || return shift KEYS="$*" while [ "$#" -gt 0 ] ; do RES_L=0 VALUE="" LINE="`echo "$SECTION_CONTENT" | grep -E '(^'"$1"'=|^'"$1"'$)'`" \ && VALUE="$(echo "$LINE" | sed -e "s,^$1=,," -e 's,^\"\(.*\)\"$,\1,' -e "s,^'\(.*\)'\$,\1,")" \ || RES_L=$? [ "$RES_L" = 0 ] || { RES="$RES_L" ; echo "ERROR: Section [$CURR_SECTION] or key '$1' in it was not found in the '$UPSCONF' file" >&2 ; } echo "$VALUE" shift done [ "$RES" = 0 ] || echo "ERROR: Section [$CURR_SECTION] or key(s) '$KEYS' in it was not found in the '$UPSCONF' file" >&2 return $RES } upsconf_getDriver() { # "$1" = name of ups.conf section; return (echo) the driver name used there # In the context this function is used, UPSCONF exists and section is there GETSECTION="upsconf_getSection_SDP" upsconf_getValue "$1" "driver" return $? } upsconf_getPort() { # "$1" = name of ups.conf section; return (echo) the "port" name used there # In the context this function is used, UPSCONF exists and section is there GETSECTION="upsconf_getSection_SDP" upsconf_getValue "$1" "port" return $? } upsconf_getDriverMedia() { # "$1" = name of ups.conf section; return (echo) name and type of driver as # needed for dependency evaluation (what services we must depend on for this # unit), newline-separated (drvnametype). Empty type for unclassified # results, assuming no known special dependencies (note that depending on # particular system's physics, both serial and network media may need USB). CURR_DRV="`upsconf_getDriver "$1"`" || return $? case "$CURR_DRV" in *netxml*|*snmp*|*ipmi*|*powerman*|*-mib*|*avahi*) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; *apcupsd-ups*) # Relay from a nearby apcupsd network server into NUT ecosystem: CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in *localhost*|*127.0.0.1*|*::1*) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; esac ;; *apc_modbus*) CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" CURR_PORTTYPE="`upsconf_getValue "$1" 'porttype'`" || CURR_PORTTYPE="" case "$CURR_PORTTYPE" in *usb*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; *serial*) printf '%s\n%s\n' "$CURR_DRV" "serial" ; return ;; *) # default depends on driver build (against libmodbus # version with or without support for usb) # TOTHINK: Check for presence of config values like # vendorid (USB) or baud (Serial)? They are optional # with reasonable defaults anyway... case "$CURR_PORT" in *auto*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; /*) printf '%s\n%s\n' "$CURR_DRV" "serial" ; return ;; *localhost*|*127.0.0.1*|*::1*) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; esac # returns are above, but just in case - have a fallback: printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *usb*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; nutdrv_qx) # May be direct serial or USB CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in auto|/dev/*usb*|/dev/*hid*) printf '%s\n%s\n' "$CURR_DRV" "usb" ; return ;; /dev/*) # See drivers/nutdrv_qx.c :: upsdrv_initups() for a list if [ -n "`upsconf_getValue "$1" 'subdriver' 'vendorid' 'productid' 'vendor' 'product' 'serial' 'bus' 'busport' 'langid_fix'`" ] \ ; then printf '%s\n%s\n' "$CURR_DRV" "usb" ; return else printf '%s\n%s\n' "$CURR_DRV" "serial" ; return fi ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; *dummy*|*clone*) # May be networked (proxy to remote NUT) CURR_PORT="`upsconf_getPort "$1"`" || CURR_PORT="" case "$CURR_PORT" in *@localhost|*@|*@127.0.0.1|*@::1) printf '%s\n%s\n' "$CURR_DRV" "network-localhost" ; return ;; *@*) printf '%s\n%s\n' "$CURR_DRV" "network" ; return ;; *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac ;; # FIXME: other modbus? sysfs like INA219? GPIO? Other local devices? *) printf '%s\n%s\n' "$CURR_DRV" "" ; return ;; esac } upsconf_getMedia() { _DRVMED="`upsconf_getDriverMedia "$1"`" || return echo "${_DRVMED}" | tail -n +2 return 0 } upsconf_debug() { _DRV="`upsconf_getDriver "$1"`" _PRT="`upsconf_getPort "$1"`" _MED="`upsconf_getMedia "$1"`" _MD5="`upsconf_getSection_MD5 "$1"`" NAME_MD5="`calc_md5 "$1"`" echo "INST: ${NAME_MD5}~[$1]: DRV='${_DRV}' PORT='${_PRT}' MEDIA='${_MED}' SECTIONMD5='${_MD5}'" } calc_md5() { # Tries several ways to produce an MD5 of the "$1" argument _MD5="`echo "$1" | md5sum 2>/dev/null | awk '{print $1}'`" && [ -n "${_MD5}" ] || \ { _MD5="`echo "$1" | openssl dgst -md5 2>/dev/null | awk '{print $NF}'`" && [ -n "${_MD5}" ]; } || \ return 1 echo "${_MD5}" } calc_md5_file() { # Tries several ways to produce an MD5 of the file named by "$1" argument [ -s "$1" ] || return 2 _MD5="`md5sum 2>/dev/null < "$1" | awk '{print $1}'`" && [ -n "${_MD5}" ] || \ { _MD5="`openssl dgst -md5 2>/dev/null < "$1" | awk '{print $NF}'`" && [ -n "${_MD5}" ]; } || \ return 1 echo "${_MD5}" } smf_validFullUnitName() { case "$1" in *:*) echo "$1" ;; *) echo "$SVCNAME_SMF:$1" ;; esac } smf_validInstanceName() { echo "MD5_`calc_md5 "$1"`" } smf_validInstanceSuffixName() { case "$1" in *:*) echo "$1" | sed 's,^.*:\([^:]*\)$,\1,' ;; *) echo "$1" ;; esac } smf_registerInstance() { DEVICE="$1" SVCINST="$1" if /usr/bin/svcs "nut-driver:$SVCINST" >/dev/null 2>&1 ; then smf_unregisterInstance "$SVCINST" fi /usr/sbin/svccfg -s nut-driver add "$DEVICE" || \ { SVCINST="`smf_validInstanceName "$1"`" || return if /usr/bin/svcs "nut-driver:$SVCINST" >/dev/null 2>&1 ; then smf_unregisterInstance "$SVCINST" fi /usr/sbin/svccfg -s nut-driver add "$SVCINST" || return ; } echo "Added instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" case "${_MED}" in usb) DEPSVC="$DEPSVC_USB_SMF" DEPREQ="$DEPREQ_USB_SMF" ;; network-localhost) DEPSVC="$DEPSVC_NET_LOCAL_SMF" DEPREQ="$DEPREQ_NET_LOCAL_SMF" ;; network) DEPSVC="$DEPSVC_NET_FULL_SMF" DEPREQ="$DEPREQ_NET_FULL_SMF" ;; serial) ;; '') ;; *) echo "WARNING: Unexpected NUT media type ignored: '${_MED}'" >&2 ;; esac TARGET_FMRI="nut-driver:$SVCINST" if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="optional_all" echo "Adding '$DEPREQ' dependency for '$SVCINST' on '$DEPSVC'..." DEPPG="nut-driver-enumerator-generated" RESTARTON="refresh" /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$DEPPG" dependency && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/grouping = astring: "$DEPREQ" && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/restart_on = astring: "$RESTARTON" && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/type = astring: service && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$DEPPG"/entities = fmri: "($DEPSVC)" && \ echo "OK" || echo "FAILED to define the dependency" >&2 fi smf_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" # Save original device (config section) name to speed up some searches smf_setSavedDeviceName "$SVCINST" "$DEVICE" smf_setDocLink "$SVCINST" "$DEVICE" /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return if [ "$AUTO_START" = yes ] ; then /usr/sbin/svcadm clear "${TARGET_FMRI}" 2>/dev/null || true /usr/sbin/svcadm enable "${TARGET_FMRI}" || return echo "Started instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 fi } smf_unregisterInstance() { echo "Removing instance: 'nut-driver:$1' ..." >&2 /usr/sbin/svcadm disable -ts 'nut-driver:'"$1" || false /usr/sbin/svccfg -s nut-driver delete "$1" } smf_refreshSupervizor() { : } smf_listInstances_raw() { # Newer versions have pattern matching; older SMF might not have this luxury /usr/bin/svcs -a -H -o fmri | grep -E '/nut-driver:' } smf_listInstances() { # Chop twice, in case there is a leading "svc:/...." smf_listInstances_raw | sed -e 's/^.*://' -e 's/^.*://' | sort -k1n -k1 } smf_getSavedMD5() { # Query service instance $1 PG="nut-driver-enumerator-generated-checksum" PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then TARGET_FMRI="nut-driver:$1" else # Global section TARGET_FMRI="nut-driver" PROP="SECTION_CHECKSUM_GLOBAL" fi # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } smf_findSavedDeviceName() { # Returns long service FMRI which has DEVICE=="$1" # For empty "$1" returns a list of all recorded "FMRIDEVICE" if [ -z "$1" ]; then /usr/bin/svcprop -p "nut-driver-enumerator-generated-devicename/DEVICE" \ 'svc:/system/power/nut-driver:*' 2>/dev/null \ | sed 's|^\(svc:/[^:]*:[^/:]*\)/:properties/nut-driver-enumerator-generated-devicename/DEVICE astring \(.*\)$|\1\t\2|' else /usr/bin/svcprop -p "nut-driver-enumerator-generated-devicename/DEVICE" \ "svc:/system/power/nut-driver:$1" 2>/dev/null \ | sed 's|^\(svc:/[^:]*:[^/:]*\)/:prop.*$|\1|' fi } smf_getSavedDeviceName() { # Query service instance $1 PG="nut-driver-enumerator-generated-devicename" PROP="DEVICE" if [ -n "$1" ]; then TARGET_FMRI="nut-driver:$1" else # Global section echo "" return 0 fi # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } smf_setSavedUniq() { # Save data value $5 of type $4 into service FMRI $1 # under (scrapped and) newly created property group $2 # and property name $3 __TARGET_FMRI="$1" __PG="$2" __PROP="$3" __TYPE="$4" case "${__TYPE}" in *:) ;; *) __TYPE="${__TYPE}:" ;; esac __VAL="$5" /usr/sbin/svccfg -s "${__TARGET_FMRI}" delprop "${__PG}" 2>/dev/null || true /usr/sbin/svccfg -s "${__TARGET_FMRI}" addpg "${__PG}" application && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/${__PROP}" = "${__TYPE}" "${__VAL}" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property ${__PG}/${__PROP}">&2 ; return 1 ; } case "${__TARGET_FMRI}" in svc:/*:*) ;; # A service instance by full FMRI, refresh svc:/*/nut-driver|nut-driver) return 0 ;; # A base non-instance service item for nut-driver (known multi-instance only) svc:/*) ;; # A base non-instance service item (not nut-driver) *:*) ;; # A service instance by short FMRI, refresh *) ;; # A base non-instance service item (not nut-driver) esac /usr/sbin/svcadm refresh "${__TARGET_FMRI}" || return } smf_setSavedMD5() { # Save checksum value $2 into service instance $1 _PG="nut-driver-enumerator-generated-checksum" _PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then _TARGET_FMRI="nut-driver:$1" else # Global section _TARGET_FMRI="nut-driver" _PROP="SECTION_CHECKSUM_GLOBAL" fi smf_setSavedUniq "${_TARGET_FMRI}" "${_PG}" "${_PROP}" astring "$2" } smf_setSavedDeviceName() { [ -n "$1" ] || return # No-op for global section smf_setSavedUniq "nut-driver:$1" "nut-driver-enumerator-generated-devicename" "DEVICE" astring "$2" } smf_setDocLink() { # Save documentation links for driver of device (config section) named $2 # into service instance $1 [ -n "$1" ] || return # No-op for global section __TARGET_FMRI="nut-driver:$1" __DRV="`upsconf_getDriver "$2"`" ### Sample: #tm_common_name template #tm_common_name/C ustring "physical network interface autoconfiguration" #tm_doc_Network_Auto-Magic_OpenSolaris_Project_Page template #tm_doc_Network_Auto-Magic_OpenSolaris_Project_Page/name astring "Network Auto-Magic OpenSolaris Project Page" #tm_doc_Network_Auto-Magic_OpenSolaris_Project_Page/uri astring http://hub.opensolaris.org/bin/view/Project+nwam/ #tm_man_nwamd8 template #tm_man_nwamd8/manpath astring /usr/share/man #tm_man_nwamd8/section astring 8 #tm_man_nwamd8/title astring nwamd __PG="tm_doc_${__DRV}_Page" /usr/sbin/svccfg -s "${__TARGET_FMRI}" delprop "${__PG}" 2>/dev/null || true /usr/sbin/svccfg -s "${__TARGET_FMRI}" addpg "${__PG}" template && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/name" = "astring:" "\"${__DRV} online\"" && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/uri" = "astring:" "${NUT_WEBSITE_BASE}/docs/man/${__DRV}.html" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property group '${__PG}' for online docs">&2 ; return 1 ; } __PG="tm_man_${__DRV}8" /usr/sbin/svccfg -s "${__TARGET_FMRI}" delprop "${__PG}" 2>/dev/null || true /usr/sbin/svccfg -s "${__TARGET_FMRI}" addpg "${__PG}" template && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/manpath" = "astring:" "/usr/local/ups/share/man" && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/section" = "astring:" "8" && \ /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/title" = "astring:" "${__DRV}" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property group '${__PG}' for local docs">&2 ; return 1 ; } unset __DRV __PG __TARGET_FMRI [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the device doc links">&2 ; return 1 ; } } smf_restart_upsd() { echo "Reloading or restarting NUT data server to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-server" 2>/dev/null /usr/sbin/svcadm clear "nut-server" 2>/dev/null /usr/sbin/svcadm refresh "nut-server" || \ /usr/sbin/svcadm restart "nut-server" } smf_restart_drv() { echo "Reloading or restarting NUT driver instance '$1' to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-driver:$1" 2>/dev/null /usr/sbin/svcadm clear "nut-driver:$1" 2>/dev/null /usr/sbin/svcadm refresh "nut-driver:$1" || \ /usr/sbin/svcadm restart "nut-driver:$1" } systemd_validFullUnitName() { case "$1" in *@*.*) echo "$1" ;; *@*) echo "$1.service" ;; *) echo "$SVCNAME_SYSTEMD@$1.service" ;; esac } systemd_validInstanceName() { echo "MD5_`calc_md5 "$1"`" } systemd_validInstanceSuffixName() { echo "$1" | sed -e 's,^.*@,,' -e 's,\.service$,,' } systemd_registerInstance() { # Instance is registered by device section name; ultimate name in systemd may differ DEVICE="$1" SVCINST="$1" /bin/systemctl enable 'nut-driver@'"$DEVICE".service || \ { SVCINST="`systemd_validInstanceName "$1"`" && \ /bin/systemctl enable 'nut-driver@'"$SVCINST".service || return ; } echo "Enabled instance: 'nut-driver@$SVCINST' for NUT configuration section '$DEVICE'" >&2 DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" case "${_MED}" in usb) DEPSVC="$DEPSVC_USB_SYSTEMD" DEPREQ="$DEPREQ_USB_SYSTEMD" ;; network-localhost) DEPSVC="$DEPSVC_NET_LOCAL_SYSTEMD" DEPREQ="$DEPREQ_NET_LOCAL_SYSTEMD" ;; network) DEPSVC="$DEPSVC_NET_FULL_SYSTEMD" DEPREQ="$DEPREQ_NET_FULL_SYSTEMD" ;; serial) DEPSVC="$DEPSVC_SERIAL_SYSTEMD" DEPREQ="$DEPREQ_SERIAL_SYSTEMD" ;; '') ;; # FIXME: modbus? sysfs like INA219? GPIO? Other local devices? *) echo "WARNING: Unexpected NUT media type ignored: '${_MED}'" >&2 ;; esac if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="#Wants" echo "Adding '$DEPREQ'+After dependency for '$SVCINST' on '$DEPSVC'..." mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$SVCINST.service.d" && \ cat > "${SYSTEMD_CONFPATH}/nut-driver@$SVCINST.service.d/nut-driver-enumerator-generated.conf" <&2 fi systemd_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" systemd_setSavedDeviceName "$SVCINST" "$DEVICE" systemd_setDocLink "$SVCINST" "$DEVICE" if [ "$AUTO_START" = yes ] ; then systemd_refreshSupervizor || echo "WARNING: Somehow managed to fail systemd_refreshSupervizor()" >&2 $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl start --no-block 'nut-driver@'"$SVCINST".service || return echo "Started instance: 'nut-driver@$SVCINST' for NUT configuration section '$DEVICE'" >&2 fi } systemd_unregisterInstance() { echo "Removing instance: 'nut-driver@$1' ..." >&2 $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl stop 'nut-driver@'"$1".service || false /bin/systemctl disable 'nut-driver@'"$1".service rm -rf "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" /bin/systemctl reset-failed 'nut-driver@'"$1".service } systemd_refreshSupervizor() { /bin/systemctl daemon-reload } systemd_listInstances_raw() { /bin/systemctl show 'nut-driver@*' -p Id | grep -E '=nut-driver' | sed 's,^Id=,,' } systemd_listInstances() { systemd_listInstances_raw | sed -e 's/^.*@//' -e 's/\.service$//' | sort -k1n -k1 } systemd_getSavedMD5() { # Query service instance $1 or global section PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" [ -s "${PROPFILE}" ] \ && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } } systemd_findSavedDeviceName() { # Returns long service instance name which has DEVICE=="$1" # For empty "$1" returns a list of all recorded "SVCDEVICE" if [ -z "$1" ]; then grep -H "Environment='DEVICE=" \ "${SYSTEMD_CONFPATH}"/nut-driver@*.service.d/nut-driver-enumerator-generated-devicename.conf \ | sed 's|^'"${SYSTEMD_CONFPATH}"'/\(nut-driver@[^/]*\.service\)\.d/.*DEVICE='"[\"']*\([^\"']*\)[\"']*"'$|\1\t\2|' else grep -E -H "Environment='DEVICE=($1|\"$1\")'" \ "${SYSTEMD_CONFPATH}"/nut-driver@*.service.d/nut-driver-enumerator-generated-devicename.conf \ | sed 's|^'"${SYSTEMD_CONFPATH}"'/\(nut-driver@[^/]*\.service\)\.d/.*$|\1|' fi } systemd_getSavedDeviceName() { # Query service instance "$1" (quiet NO-OP if empty, for mis-use # in global sections context) to get the unquoted saved DEVICE # section name corresponding to this service instance [ -n "$1" ] || { echo ""; return 0; } PROP="DEVICE" PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" [ -s "${PROPFILE}" ] \ && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," -e 's,^"\(.*\)"$,\1,' \ || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } } systemd_setSavedDeviceName() { # Save device (config section) name $2 into service instance $1 [ -n "$1" ] || return # No-op for global section PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ cat > "${PROPFILE}" << EOF [Service] Environment='DEVICE="$2"' EOF [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the device name">&2 ; return 1 ; } } systemd_setDocLink() { # Save documentation links for driver of device (config section) named $2 # into service instance $1 [ -n "$1" ] || return # No-op for global section PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-doclink.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ __DRV="`upsconf_getDriver "$2"`" cat > "${PROPFILE}" << EOF [Unit] Documentation=man:${__DRV}(8) Documentation=${NUT_WEBSITE_BASE}/docs/man/${__DRV}.html EOF unset __DRV [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the device name">&2 ; return 1 ; } } systemd_setSavedMD5() { # Save checksum value $2 into service instance $1 PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ cat > "${PROPFILE}" << EOF [Service] Environment='$PROP=$2' EOF [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } } systemd_restart_upsd() { # Do not restart/reload if not already running case "`/bin/systemctl is-active "nut-server"`" in active|unknown) ;; # unknown meant "starting" in our testing... failed) echo "Note: nut-server unit was 'failed' - not disabled by user, so (re)starting it (probably had no config initially)" >&2 ;; *) return 0 ;; esac echo "Reloading or restarting NUT data server to make sure it knows new configuration..." # Note: reload is a better way to go about this, so the # data service is not interrupted by re-initialization # of the daemon. But systemd/systemctl sometimes stalls... $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl reload-or-restart "nut-server" || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl restart "nut-server" } systemd_restart_drv() { # Do not restart/reload if not already running case "`/bin/systemctl is-active "nut-driver@$1"`" in active|unknown) ;; *) return 0 ;; esac echo "Reloading or restarting NUT driver instance '$1' to make sure it knows new configuration..." # Full restart, e.g. in case we changed the user= in configs # however let "reload" try, in case we changed something that # can be updated "on the fly", like the "debug_min" setting. $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl reload-or-restart "nut-driver@$1" || \ $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl restart "nut-driver@$1" } upslist_normalizeFile_filter() { # See upslist_normalizeFile() detailed comments below; this routine # is a pipe worker to prepare the text into a simpler expected form. # Pick the lines which contain a bracket or assignment character, # or a single token (certain keywords come as just NUT "flags"), # trim leading and trailing whitespace, comment-only lines, and in # assignment lines trim the spaces around equality character and # quoting characters around assignment of values without whitespaces. # Any whitespace characters around a section name (single token that # starts the line and is enclosed in brackets) and a trailing comment # are dropped. Note that brackets with spaces inside, and brackets # that do not start the non-whitespace payload of the line, are not # sections. grep -E -v '(^$|^#)' | \ sed -e 's,^['"$TABCHAR"'\ ]*,,' \ -e 's,^\#.*$,,' \ -e 's,['"$TABCHAR"'\ ]*$,,' \ -e 's,^\([^=\ '"$TABCHAR"']*\)['"$TABCHAR"'\ ]*=['"$TABCHAR"'\ ]*,\1=,g' \ -e 's,=\"\([^\ '"$TABCHAR"']*\)\"$,=\1,' \ -e 's,^\(\[[^]'"$TABCHAR"'\ ]*\]\)['"$TABCHAR"'\ ]*\(#.*\)*$,\1,' \ | grep -E -v '^$' \ | grep -E '([\[\=]|^[^ '"$TABCHAR"']*$|^[^ '"$TABCHAR"']*[ '"$TABCHAR"']*#.*$)' } upslist_normalizeFile() { # Read the ups.conf file and find all defined sections (names of # configuration blocks for drivers that connect to a certain device # using specified protocol and media); normalize section contents # as detailed below, to simplify subsequent parsing and comparison. # File contents UPSCONF_DATA="" UPSCONF_DATA_SDP="" if [ -n "$UPSCONF" ] && [ -f "$UPSCONF" ] && [ -r "$UPSCONF" ]; then [ ! -s "$UPSCONF" ] \ && echo "WARNING: The '$UPSCONF' file exists but is empty" >&2 \ && return 0 # Ok to continue - we may end up removing all instances else echo "FATAL: The '$UPSCONF' file does not exist or is not readable" >&2 return 2 fi # Store a normalized version of NUT configuration file contents. # Also use a SDP subset with just section, driver and port info # for faster parsing when determining driver-required media etc. UPSCONF_DATA="$(upslist_normalizeFile_filter < "$UPSCONF")" \ && [ "${#UPSCONF_DATA}" != 0 ] \ && UPSCONF_DATA_SDP="`grep -E '^(\[.*\]|driver=|port=)' << EOF $UPSCONF_DATA EOF`" \ || { echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: nothing left after normalization" >&2 UPSCONF_DATA="" UPSCONF_DATA_SDP="" } } upslist_normalizeFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) [ "${#UPSCONF_DATA}" = 0 ] && [ "${#UPSCONF_DATA_SDP}" = 0 ] || return 0 upslist_normalizeFile } upslist_readFile() { # Use the routine above (unconditionally) to get or update the # listing of device sections known at this moment. # List of devices from the config file UPSLIST_FILE="" if [ "$DO_NORMALIZE_ONCE" = yes ]; then upslist_normalizeFile_once || return # Propagate errors upwards else upslist_normalizeFile || return # Propagate errors upwards fi if [ "${#UPSCONF_DATA}" != 0 ] ; then # Note that section-name brackets should contain a single token UPSLIST_FILE="$(echo "$UPSCONF_DATA_SDP" | grep -E '^\[[^'"$TABCHAR"'\ ]*\]$' | sed 's,^\[\(.*\)\]$,\1,' | sort -k1n -k1)" \ || UPSLIST_FILE="" if [ "${#UPSLIST_FILE}" = 0 ] ; then echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: no section declarations in parsed normalized contents" >&2 fi fi # Ok to continue with empty results - we may end up removing all instances } upslist_readFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) [ "${#UPSLIST_FILE}" = 0 ] || return 0 DO_NORMALIZE_ONCE=yes upslist_readFile } upslist_readSvcs() { UPSLIST_SVCS="`$hook_listInstances`" || UPSLIST_SVCS="" if [ "${#UPSLIST_SVCS}" = 0 ] && [ "$1" != "-" ] ; then EXPLAIN="" [ -z "$1" ] || EXPLAIN=" - $1" echo "Error reading the list of ${SERVICE_FRAMEWORK-} service instances for UPS drivers, or none are defined${EXPLAIN}" >&2 # Ok to continue - we may end up defining new instances fi } upslist_debug() { for UPSF in "" $UPSLIST_FILE ; do upsconf_debug "$UPSF" done } upslist_addSvcs() { # Note: This routine registers service instances for device config sections # that are not wrapped currently. Support for redefined previously existing # sections - is attained by removing the old service instance elsewhere and # recreating it here, since any data could change including the dependency # list, etc. for UPSF in $UPSLIST_FILE ; do if ! common_isRegistered "$UPSF" ; then echo "Adding new ${SERVICE_FRAMEWORK} service instance for power device [${UPSF}]..." >&2 $hook_registerInstance "$UPSF" fi done } upslist_delSvcs() { for UPSS in $UPSLIST_SVCS ; do if ! common_isFiled "$UPSS" ; then echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] which is no longer in config file..." >&2 $hook_unregisterInstance "$UPSS" fi done } upslist_restartSvcs() { for UPSS in $UPSLIST_SVCS ; do if common_isFiled "$UPSS" ; then $hook_restart_drv "$UPSS" fi done } # FIXME : process via kill -l? # Different shells use a SIG prefix or not to signal names # so standard numbers are in fact more portable :\ TERMINATION_SIGNALS="2 3 15" RECONFIGURATION_SIGNALS="1" TERMINATE_ASAP=false trap_handle_interruption_exit() { # Handle SIGINT, SIGQUIT, SIGTERM with a message echo "`date -u` : Received an interruption signal, terminating the script now" >&2 exit 0 } trap_handle_interruption() { # Handle SIGINT, SIGQUIT, SIGTERM gracefully - tell the main # iteration to complete and just then abort echo "`date -u` : Received an interruption signal, will terminate the script after ending the main routine. Repeat the signal if urgent!" >&2 TERMINATE_ASAP=true trap 'trap_handle_interruption_exit' $TERMINATION_SIGNALS } nut_driver_enumerator_main() { ################# MAIN PROGRAM by default TERMINATE_ASAP=false trap 'trap_handle_interruption' $TERMINATION_SIGNALS # Note: do not use the read..._once() here, to ensure that the # looped daemon sees the whole picture, which can be new every time upslist_readFile || return $? #upslist_debug upslist_readSvcs "before manipulations" # Test if global config has changed since last run # Note that we have upslist_normalizeFile called from upslist_readFile # just above, so even if it came empty (e.g. new NUT installation, no # device sections yet) we do not want to spend time and log storage to # parse again and complain again. RESTART_ALL=no AVOID_REPARSE=yes upssvcconf_checksum_unchanged "" || { echo "`date -u` : Detected changes in global section of '$UPSCONF', will restart all drivers"; RESTART_ALL=yes; } # Quickly exit if there's nothing to do (both lists empty or equal); note # the lists are pre-sorted. Otherwise a non-zero exit will be done below. # Note: We implement testing in detail whether section definitions were # changed since last run, as a first step before checking that name # lists are still equivalent, because we need to always have the result # of the "has it changed?" check as a hit-list of something to remove, # while the check for no new device section definitions is just boolean. # We can only exit quickly if both there are no changed sections and no # new or removed sections since last run. { [ -z "$UPSLIST_FILE" -a -z "$UPSLIST_SVCS" ] || { \ NEW_CHECKSUM="`upslist_checksums_unchanged "$UPSLIST_FILE" "$UPSLIST_SVCS"`" \ && [ "${#NEW_CHECKSUM}" = 0 ] \ && upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" ; \ } ; } \ && if [ -z "$DAEMON_SLEEP" -o "${VERBOSE_LOOP}" = yes ] ; then \ echo "`date -u` : OK: No changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" ; \ fi \ && [ "$RESTART_ALL" = no ] && return 0 # Check list of devices with new section contents (per checksum) as # compared to older runs (stashed in service instance configurations). if [ "${#NEW_CHECKSUM}" = 0 ]; then if [ "${VERBOSE_LOOP}" = yes ] ; then echo "`date -u` : No changes to reconcile between *contents* of ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF', but the *list* of instances vs. devices seems to have changed" fi else if [ "${VERBOSE_LOOP}" = yes ] ; then echo "`date -u` : Got some changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF', content checksums changed for: `echo ${NEW_CHECKSUM} | tr '\n' ' '`" fi for UPSS in $NEW_CHECKSUM ; do # NOTE: Pedantically, UPSS is a service instance name, # and may be the MD5-normalized version in certain cases. # For some operations below we need the original ups.conf # section name for the device - the CURR_DEV value. CURR_DEV="`USE_SAVEDINST=true get_device_for_service "${UPSS}"`" && [ "${#CURR_DEV}" -gt 0 ] || CURR_DEV="${UPSS}" CURR_DRV="`upsconf_getDriver "${CURR_DEV}"`" || CURR_DRV="" DO_UNREGISTER=yes if [ -n "$CURR_DRV" ] ; then # If reload is handled and does not complain, # we are OK to proceed without re-defining # and restarting the driver service instance. if [ "${VERBOSE_LOOP}" = yes ] ; then echo "`date -u` : Reloading ${SERVICE_FRAMEWORK} service instance '${UPSS}' whose section '${CURR_DEV}' in config file has changed: calling driver program '${CURR_DRV}' for the low-level work..." >&2 fi "/usr/local/ups/bin/$CURR_DRV" -a "${CURR_DEV}" -c reload-or-error >/dev/null 2>/dev/null \ || { if [ "${VERBOSE_LOOP}" = yes ] ; then sleep 1; "/usr/local/ups/bin/$CURR_DRV" -a "${CURR_DEV}" -c reload-or-error >&2 ; fi; } \ && DO_UNREGISTER=no fi if [ "$DO_UNREGISTER" = yes ] ; then echo "Dropping old ${SERVICE_FRAMEWORK} service instance '${UPSS}' whose section '${CURR_DEV}' in config file has changed..." >&2 $hook_unregisterInstance "$UPSS" # Re-registration to reconcile below should set the "saved" values else echo "Keeping ${SERVICE_FRAMEWORK} service instance '${UPSS}' whose section '${CURR_DEV}' in config file has changed: live reload sufficed. Saving updated info into service properties." >&2 $hook_setSavedMD5 "$UPSS" "`upsconf_getSection_MD5 "${CURR_DEV}"`" # TOTHINK: This is already there, else we redefine units for bigger discrepancies? # $hook_setSavedDeviceName "$UPSS" "${CURR_DEV}" fi done upslist_readSvcs "after updating for new config section checksums" fi if [ "${#UPSLIST_SVCS}" != 0 ]; then # Drop services that are not in config file (any more?) upslist_delSvcs if [ "$RESTART_ALL" = yes ] && [ "$AUTO_START" = yes ] ; then # Here restart only existing services; new ones will (try to) # start soon after creation and upsd is handled below upslist_restartSvcs fi fi if [ "$RESTART_ALL" = yes ] ; then # Save new checksum of global config $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" fi if [ "${#UPSLIST_FILE}" != 0 ]; then # Add services for sections that are in config file but not yet wrapped upslist_addSvcs $hook_refreshSupervizor upslist_readSvcs "after checking for new config sections to define service instances" fi upslist_readSvcs if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi # We had some changes to the config file; upsd must be made aware if [ "$AUTO_START" = yes ] ; then $hook_restart_upsd fi # Return 42 if there was a change applied succesfully # (but e.g. some services should restart - upsd, maybe upsmon) UPSLIST_EQ_RES=0 upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? # File processing and service startups take a while; # make sure upsconf did not change while we worked... # NOTE: Check this at the last moment to minimize # the chance of still not noticing the change made # at just the wrong moment. UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then # NOTE: even if daemonized, the sleep between iterations # can be configured into an uncomfortably long lag, so # we should re-sync the system config in any case. echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up the late-coming changes" # Make sure the cycle does not repeat itself due to diffs # from an ages-old state of the file from when we started. UPSCONF_CHECKSUM_START="$UPSCONF_CHECKSUM_END" ( nut_driver_enumerator_main ) ; return $? # The "main" routine at the end of recursions will # do REPORT_RESTART_42 logic or the error exit-code fi if [ "$UPSLIST_EQ_RES" = 0 ] ; then echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" [ "${REPORT_RESTART_42-}" = no ] && return 0 || return 42 fi return 13 } nut_driver_enumerator_full_reconfigure() { # Similar to the main routine for reconciling data, # but this one removes all service instances and # defines current mappings from scratch after that upslist_readFile_once || return $? upslist_readSvcs "before manipulations" if [ "${#UPSLIST_SVCS}" != 0 ]; then for UPSS in $UPSLIST_SVCS ; do echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] to reconfigure the service unit..." >&2 $hook_unregisterInstance "$UPSS" done upslist_readSvcs "after dropping" fi if [ "${#UPSLIST_FILE}" != 0 ]; then upslist_addSvcs upslist_readSvcs "after checking for new config sections to define service instances" fi # Save new checksum of global config $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" # Service units were manipulated, including saving of checksums; # refresh the service management daemon if needed $hook_refreshSupervizor if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi # We had some changes to the config file; upsd must be made aware if [ "$AUTO_START" = yes ] ; then $hook_restart_upsd fi # Return 42 if there was a change applied succesfully # (but e.g. some services should restart - upsd, maybe upsmon) UPSLIST_EQ_RES=0 upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? # File processing and service startups take a while; # make sure upsconf did not change while we worked... # NOTE: Check this at the last moment to minimize # the chance of still not noticing the change made # at just the wrong moment. UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up and reconcile the late-coming changes" nut_driver_enumerator_main ; return $? # The "main" routine will do REPORT_RESTART_42 logic too fi if [ "$UPSLIST_EQ_RES" = 0 ] ; then echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" [ "${REPORT_RESTART_42-}" = no ] && return 0 || return 42 fi return 13 } list_services_for_devices() { FINAL_RES=0 upslist_readFile_once && [ "${#UPSLIST_FILE}" != 0 ] \ || { echo "No devices detected in '$UPSCONF'" >&2 ; return 1 ; } upslist_readSvcs "by user request" && [ "${#UPSLIST_SVCS}" != 0 ] \ || { echo "No service instances detected" >&2 ; return 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ "${#UPSLIST_SVCS_RAW}" != 0 ] \ || { echo "No service units detected" >&2 ; return 1; } for DEV in $UPSLIST_FILE ; do vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" vUNITI="`$hook_validFullUnitName "$vINST"`" # First pass over simple verbatim names for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$DEV" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITD" ] ; then printf '%s\t%s\n' "$UNIT" "$DEV" continue 3 fi done fi done for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$vINST" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITI" ] ; then printf '%s\t%s\n' "$UNIT" "$DEV" continue 3 fi done fi done echo "WARNING: no service instances detected that match device '$DEV'" >&2 FINAL_RES=1 done return $FINAL_RES } SVCS_DEVS_LIST="" list_services_for_devices_once() { # On first call, caches the system reponse # On next calls returns what it got earlier # Does not return any text, just the exit code # (0 = data avail, even if empty, in SVCS_DEVS_LIST) [ "${#SVCS_DEVS_LIST}" != 0 ] && return # Pre-cache config file data, if nobody read it yet, # and keep in main script context for reuse (no subshell) upslist_readFile_once && \ SVCS_DEVS_LIST="`list_services_for_devices "$@"`" || return $? } get_device_for_service() { [ -z "$1" ] && echo "Service (instance) name argument required" >&2 && return 1 # Instance name can be a hash or "native" NUT section name SVC="`$hook_validInstanceSuffixName "$1"`" && [ -n "$SVC" ] \ || { echo "Error getting SVC name from the inputs" >&2 ; return 1; } # Reading the config is too expensive to do for every # driver management attempt when there are many devices if [ "${USE_SAVEDINST-}" != false ]; then # Try to use last-stashed values from service properties first # (NOTE: saved value is assumed to be valid if present) SAVEDINST="`$hook_getSavedDeviceName "$SVC"`" || SAVEDINST="" [ "${#SAVEDINST}" = 0 ] || { echo "$SAVEDINST" ; return 0 ; } fi case "$SVC" in MD5_*) ;; # fall through to the bulk of code *) upslist_readFile_once || return $? echo "$UPSLIST_FILE" | grep -E "^$SVC\$" return $? ;; esac # Inspect SVC=MD5_* usecase FINAL_RES=0 list_services_for_devices_once && [ "${#SVCS_DEVS_LIST}" != 0 ] || FINAL_RES=$? if [ "$FINAL_RES" = 0 ]; then echo "$SVCS_DEVS_LIST" | grep "$SVC" | ( \ while read _SVC _DEV ; do _SVC="`$hook_validInstanceSuffixName "${_SVC}"`" || exit [ "${_SVC}" = "${SVC}" ] && echo "${_DEV}" && exit 0 done ; exit 1 ) && return 0 fi echo "No service instance '$1' was detected that matches a NUT device" >&2 return 1 } get_service_for_device() { DEV="$1" [ -z "$DEV" ] && echo "Device name argument required" >&2 && return 1 # Cheap check in service instance metadata, if saved # (NOTE: saved value is assumed to be valid if present) if [ "${USE_SAVEDSVC-}" != false ]; then SAVEDSVC="`$hook_findSavedDeviceName "$DEV"`" || SAVEDSVC="" [ "${#SAVEDSVC}" = 0 ] || { echo "$SAVEDSVC" ; return 0 ; } fi # Trawl all the data we have... # TODO: Reorder to avoid extra parsing if we have an early hit? upslist_readSvcs "by user request" && [ "${#UPSLIST_SVCS}" != 0 ] \ || { echo "No service instances detected" >&2 ; return 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ "${#UPSLIST_SVCS_RAW}" != 0 ] \ || { echo "No service units detected" >&2 ; return 1; } vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" vUNITI="`$hook_validFullUnitName "$vINST"`" # First pass over simple verbatim names for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$DEV" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITD" ] ; then echo "$UNIT" return 0 fi done fi done # Second pass over other options for INST in $UPSLIST_SVCS ; do if [ "$INST" = "$vINST" ] ; then for UNIT in $UPSLIST_SVCS_RAW ; do if [ "$UNIT" = "$vUNITI" ] ; then echo "$UNIT" return 0 fi done fi done echo "No service instances detected that match device '$DEV'" >&2 return 1 } update_upslist_savednames_find_missing() { # Runs once in production modes that inspect and reconcile # configs, to handle upgraded NUT deployments SVCINSTS_NO_DEVICE="`upslist_savednames_find_missing`" || \ case "$?" in 1) return 0 ;; # No services defined yet 2) ;; # All service units do not have DEVICE values esac # Something found... or not? Or all is populated? [ "${#SVCINSTS_NO_DEVICE}" != 0 ] || return 0 # Make a list of what devices are known in config matched # to service instances defined in the system, if any # Note to not check the service instance properties which # we are validating and currently to not quite trust. USE_SAVEDINST=false list_services_for_devices_once \ && [ "${#SVCS_DEVS_LIST}" != 0 ] || return 0 # Go over services with no device value saved into properties, # and write the values learned from mapping above _MISSING_RES=0 for SVCINST in $SVCINSTS_NO_DEVICE ; do _DEV="`printf '%s\n' "$SVCS_DEVS_LIST" | awk '( \$1 == "'"${SVCINST}"'" ) {print \$NF}'`" echo "Service instance '$SVCINST' did not have a device recorded into properties, setting to '${_DEV}'" [ -n "${_DEV}" ] || { echo "The device name value for '$SVCINST' is empty, skipping" >&2 ; _MISSING_RES=1 ; continue ; } $hook_setSavedDeviceName "`$hook_validInstanceSuffixName "$SVCINST"`" "${_DEV}" || _MISSING_RES=$? done return ${_MISSING_RES} } RECONFIGURE_ASAP=false trap_handle_hup_main() { echo "`date -u` : Received a HUP during processing, scheduling reconfiguration to repeat ASAP (after the current iteration is done)" >&2 # Note: in the worst case the reconfig would run twice; # we do not update UPSCONF_CHECKSUM_START in this case # to avoid corrupting decisions of the currently running # processing. RECONFIGURE_ASAP=true } trap_handle_hup_sleep() { echo "`date -u` : Received a HUP in my sleep, reprocessing configs right now!" >&2 # Avoid re-parsing main twice, though don't recalculate # checksums needlessly on every loop cycle, either... UPSCONF_CHECKSUM_START="`calc_md5_file "$UPSCONF"`" || true RECONFIGURE_ASAP=true if [ -n "$1" ] ; then # Kill the sleeper PID kill "$1" fi } daemonize() { # Note: do not further sub-shell this routine, so systemd # is not confused whom to signal. echo "`date -u` : Daemonizing $0 with config re-evaluation frequency $DAEMON_SLEEP" >&2 # Support (SIG)HUP == signal code 1 to quickly reconfigure, # e.g. to request it while the sleep is happening or while # "main" is processing an earlier change of the file. RECONFIGURE_ASAP=false trap 'trap_handle_hup_main' $RECONFIGURATION_SIGNALS update_upslist_savednames_find_missing # Note: this loop would die on errors with config file or # inability to ensure that it matches the list of services. # If caller did not `export REPORT_RESTART_42=no` then the # loop would exit with code 42, and probably trigger restart # of the service which wraps this daemon do topple others that # depend on it. # Note: do not quickly skip the "main" based on full-file # checksum refresh, to ensure that whatever is configured # gets applied (e.g. if user disabled some services or they # died, or some config was not applied due to coding error). while nut_driver_enumerator_main ; do trap 'trap_handle_interruption_exit' $TERMINATION_SIGNALS if $TERMINATE_ASAP ; then echo "`date -u` : Trapped a SIGTERM/SIGINT/SIGQUIT during last run of nut_driver_enumerator_main, terminating gracefully now" >&2 exit 0 fi if $RECONFIGURE_ASAP ; then echo "`date -u` : Trapped a SIGHUP during last run of nut_driver_enumerator_main, repeating reconfiguration quickly" >&2 else sleep $DAEMON_SLEEP & trap "trap_handle_hup_sleep $!" $RECONFIGURATION_SIGNALS wait $! fi RECONFIGURE_ASAP=false trap 'trap_handle_hup_main' $RECONFIGURATION_SIGNALS done exit $? } # Save the checksum of ups.conf as early as possible, # to test in the end that it is still the same file. UPSCONF_CHECKSUM_START="`calc_md5_file "$UPSCONF"`" || true # By default, update wrapping of devices into services if [ $# = 0 ]; then update_upslist_savednames_find_missing nut_driver_enumerator_main ; exit $? fi if [ $# = 1 ] ; then [ -n "$DAEMON_SLEEP" ] || DAEMON_SLEEP=60 # Note: Not all shells have 'case ... ;&' support case "$1" in --daemon=*) DAEMON_SLEEP="`echo "$1" | sed 's,^--daemon=,,'`" ;; --daemon-after=*) DAEMON_SLEEP="`echo "$1" | sed 's,^--daemon-after=,,'`" ;; esac case "$1" in --daemon-after|--daemon-after=*) REPORT_RESTART_42=no nut_driver_enumerator_main || exit $? daemonize & exit $? ;; --daemon|--daemon=*) daemonize & exit $? ;; esac fi unset DAEMON_SLEEP usage() { cat << EOF $0 (no args) Update wrapping of devices into services $0 --daemon(=freq) Update wrapping of devices into services in an infinite loop Default freq is 60 sec $0 --daemon-after(=freq) Update wrapping of devices into services in an infinite loop; first do one run of the loop though, then daemonize (this way service unit is deemed started only when NUT config and driver instances are in sync). Default freq is 60 sec. $0 --reconfigure Stop and un-register all service instances and recreate them (e.g. if new dependency template was defined in a new version of this script and/or NUT package) $0 --get-service-framework Print the detected service management framework in this OS $0 --list-devices Print list of devices in NUT config $0 --list-services Print list of service instances which wrap registered NUT devices (full name of service unit) $0 --list-instances Print list of service instances which wrap registered NUT devices (just instance suffix) $0 --get-service-for-device DEV Print the full name of service unit which wraps a NUT device named "DEV" $0 --get-device-for-service SVC Print the NUT device name for full or instance-suffix name of a service unit which wraps it $0 --list-services-for-devices Print a TAB-separated list of service units and corresponding NUT device names which each such unit wraps $0 --show-configs|--show-all-configs Show the complete normalized list of device configuration blocks $0 --show-config DEV $0 --show-device-config DEV Show configuration block of the specified NUT device $0 --show-device-config-value DEV KEY [KEY...] Show single configuration key value of the specified NUT device For flags, shows the flag name if present in the section If several keys or flags are requested, their values are reported one per line in the same order (including empty lines for missing values); any missing value yields a non-zero exit code. For more information please Read The Fine Manual ('man nut-driver-enumerator') and/or see ${NUT_WEBSITE_BASE}/docs/man/nut-driver-enumerator.html Also check documentation of ups.conf and upsdrvsvcctl EOF } while [ $# -gt 0 ]; do case "$1" in --help|-h|-help) usage; exit 0 ;; --get-service-framework) echo "${SERVICE_FRAMEWORK}" ; exit 0 ;; --reconfigure) nut_driver_enumerator_full_reconfigure "$@" exit $? ;; --list-devices) upslist_readFile_once && \ if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" >&2 echo "$UPSLIST_FILE" exit 0 fi echo "No devices detected in '$UPSCONF'" >&2 exit 1 ;; --list-services) UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && \ if [ "${#UPSLIST_SVCS_RAW}" != 0 ] ; then echo "=== The currently defined service units are:" >&2 echo "$UPSLIST_SVCS_RAW" exit 0 fi echo "No service units detected" >&2 exit 1 ;; --list-instances) upslist_readSvcs "by user request" && \ if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" >&2 echo "$UPSLIST_SVCS" exit 0 fi echo "No service instances detected" >&2 exit 1 ;; --get-service-for-device) shift get_service_for_device "$@" exit $? ;; --get-device-for-service) shift get_device_for_service "$@" exit $? ;; --list-services-for-devices) shift list_services_for_devices "$@" exit $? ;; --show-configs|--show-device-configs|--show-all-configs|--show-all-device-configs) RES=0 upslist_readFile_once || RES=$? [ "$RES" != 0 ] && { echo "ERROR: upslist_readFile_once () failed with code $RES" >&2; exit $RES; } [ "${#UPSLIST_FILE}" != 0 ] \ || { echo "WARNING: No devices detected in '$UPSCONF'" >&2 ; RES=1 ; } echo "$UPSCONF_DATA" exit $RES ;; --show-config|--show-device-config) [ -z "$2" ] && echo "WARNING: Device name argument empty, will show global config" >&2 DEV="$2" upsconf_getSection "$DEV" exit $? ;; --show-config-value|--show-device-config-value) [ -z "$3" ] && echo "At least one configuration key name argument is required" >&2 && exit 1 [ -z "$2" ] && echo "WARNING: Device name argument empty, will show global config" >&2 DEV="$2" shift 2 upsconf_getValue "$DEV" "$@" exit $? ;; upsconf_debug) # Not public, not in usage() [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 upsconf_debug "$2" exit $? ;; upslist_debug) # Not public, not in usage() upslist_readFile_once || exit upslist_debug exit $? ;; upslist_savednames_find_missing) # Not public, not in usage() upslist_savednames_find_missing exit $? ;; upslist_savednames_find_mismatch) # Not public, not in usage() upslist_savednames_find_mismatch exit $? ;; update_upslist_savednames_find_missing) # Not public, not in usage() update_upslist_savednames_find_missing exit $? ;; hook_findSavedDeviceName) shift ; $hook_findSavedDeviceName "$@" ; exit $? ;; hook_getSavedDeviceName) shift ; $hook_getSavedDeviceName "$@" ; exit $? ;; *) echo "Unrecognized argument: $1" >&2 ; exit 1 ;; esac shift done nut-2.8.3/scripts/upsdrvsvcctl/Makefile.in0000644000200500020050000005663715001555011015547 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/upsdrvsvcctl VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @HAVE_SYSTEMD_TRUE@am__append_1 = nut-driver-enumerator.sh upsdrvsvcctl @HAVE_SYSTEMD_FALSE@@WITH_SOLARIS_SMF_TRUE@am__append_2 = nut-driver-enumerator.sh upsdrvsvcctl subdir = scripts/upsdrvsvcctl ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-driver-enumerator.sh upsdrvsvcctl CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(srcdir)/nut-driver-enumerator.sh.in \ $(srcdir)/upsdrvsvcctl.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README.adoc $(am__append_1) $(am__append_2) \ nut-driver-enumerator.sh.in upsdrvsvcctl.in SPELLCHECK_SRC = README.adoc CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/upsdrvsvcctl/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/upsdrvsvcctl/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-driver-enumerator.sh: $(top_builddir)/config.status $(srcdir)/nut-driver-enumerator.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ upsdrvsvcctl: $(top_builddir)/config.status $(srcdir)/upsdrvsvcctl.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/logrotate/0000755000200500020050000000000015001555411013003 500000000000000nut-2.8.3/scripts/logrotate/nutlogd0000644000200500020050000000110514553676503014340 00000000000000# Log rotation configuration for NUT: # Rotate NUT log file(s) either monthly or when exceeding 5 Mb # # For more information, refer to logrotate(8) manual page: # http://linuxcommand.org/man_pages/logrotate8.html # # To install this file, use: # $ cp nutlogd /etc/logrotate.d/ # $ chmod 644 /etc/logrotate.d/nutlogd # $ chown root.root /etc/logrotate.d/nutlogd # # Log files must have "nut-" prefix and ".log" suffix /var/log/nut-*.log { missingok notifempty size=5M rotate 12 monthly postrotate /usr/bin/killall -HUP upslog endscript } nut-2.8.3/scripts/valgrind/0000755000200500020050000000000015001555411012611 500000000000000nut-2.8.3/scripts/valgrind/valgrind.sh.in0000755000200500020050000000211114777767434015333 00000000000000#!/bin/sh # Copyright (C) 2024-2025 by Jim Klimov # NOTE: If there are system problems to suppress, re-run the test with # --gen-suppressions=all option, and update the .valgrind.supp file. SCRIPTDIR="`dirname "$0"`" SCRIPTDIR="`cd "$SCRIPTDIR" && pwd`" LTEXEC="" [ -n "${LIBTOOL-}" ] || LIBTOOL="`command -v glibtool`" 2>/dev/null [ -n "${LIBTOOL-}" ] || LIBTOOL="`command -v libtool`" 2>/dev/null [ -z "${LIBTOOL}" ] || LTEXEC="${LIBTOOL} --mode=execute " # Allow to run un-parsed "sh ${top_srcdir}/scripts/valgrind/valgrind.sh.in" # with reasonable success: [ -n "${VALGRIND-}" ] || case '@VALGRIND@' in [@]*|none) ;; *) VALGRIND='@VALGRIND@' ;; esac [ -n "${VALGRIND-}" ] || VALGRIND="valgrind" # TODO: Also wrap tool=callgrind e.g. via $0 symlink name? exec ${LTEXEC} \ ${VALGRIND} \ --tool=memcheck --verbose \ --leak-check=full --show-reachable=yes --error-exitcode=1 --show-error-list=yes \ --trace-children=yes --track-fds=yes --show-leak-kinds=all --track-origins=yes \ --suppressions="${SCRIPTDIR}/.valgrind.supp" \ ${VALGRIND_OPTIONS-} \ "$@" nut-2.8.3/scripts/valgrind/.valgrind.supp.in0000644000200500020050000002066614777767434016002 00000000000000{ Memcheck:Leak match-leak-kinds: reachable fun:malloc obj:/usr/bin/dash ... fun:(below main) } { Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:strdup obj:/usr/bin/dash ... fun:(below main) } { Memcheck:Param socketcall.send(msg) fun:send ... } { Memcheck:Free fun:free ... fun:__libc_freeres ... } { Memcheck:Leak match-leak-kinds: reachable fun:malloc fun:pool fun:__static_initialization_and_destruction_0 fun:_GLOBAL__sub_I_eh_alloc.cc ... } { Memcheck:Leak match-leak-kinds: reachable fun:malloc ... fun:_gcry_mpi_init fun:global_init ... } { Memcheck:Leak ... fun:CRYPTO_* ... } { Memcheck:Leak ... fun:SSL_CTX_* ... } { Memcheck:Leak ... fun:OPENSSL_* ... } { Memcheck:Leak fun:*alloc ... fun:_dl_init ... } { Memcheck:Leak fun:*alloc ... fun:_dl_new_object ... } { Memcheck:Leak fun:*alloc ... fun:elf_machine_rela ... } { Memcheck:Leak fun:*alloc ... fun:dl_open_worker ... } { Memcheck:Leak fun:*alloc ... fun:_dlerror_run ... } { Memcheck:Leak ... fun:init_snmp_once ... } { Memcheck:Leak fun:*alloc ... fun:wrap_nut_snmp_sess_open ... } { Memcheck:Leak ... fun:wrap_nut_ipmi_ctx_create ... } { Memcheck:Leak ... fun:wrap_nut_avahi_client_new ... } { # https://forums.freebsd.org/threads/named-semaphore-uninitialized-bytes.84850/ Memcheck:Cond ... fun:sem_open ... } { Memcheck:Cond ... fun:sem_trywait* ... fun:start_thread ... } # Numerous reported leaks seem to be part of CPPUNIT itself, quesce them: { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::ConcretTestFixtureFactory<*>::makeFixture() ... #CppUnit::TestFactoryRegistry::makeTest() fun:_ZN7CppUnit19TestFactoryRegistry8makeTestEv ... } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::SynchronizedObject::SynchronizedObject(CppUnit::SynchronizedObject::SynchronizationObject*) fun:_ZN7CppUnit18SynchronizedObjectC1EPNS0_21SynchronizationObjectE ... } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::TestResult::TestResult(CppUnit::SynchronizedObject::SynchronizationObject*) fun:_ZN7CppUnit10TestResultC1EPNS_18SynchronizedObject21SynchronizationObjectE ... } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::TestRunner::TestRunner() fun:_ZN7CppUnit10TestRunnerC1Ev #CppUnit::TextTestRunner::TextTestRunner(CppUnit::Outputter*) fun:_ZN7CppUnit14TextTestRunnerC1EPNS_9OutputterE fun:main } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::TextTestRunner::TextTestRunner(CppUnit::Outputter*) fun:_ZN7CppUnit14TextTestRunnerC1EPNS_9OutputterE fun:main } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::TestResultCollector::TestResultCollector(CppUnit::SynchronizedObject::SynchronizationObject*) fun:_ZN7CppUnit19TestResultCollectorC1EPNS_18SynchronizedObject21SynchronizationObjectE #CppUnit::TextTestRunner::TextTestRunner(CppUnit::Outputter*) fun:_ZN7CppUnit14TextTestRunnerC1EPNS_9OutputterE fun:main } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::TestSuite::addTest(CppUnit::Test*) fun:_ZN7CppUnit9TestSuite7addTestEPNS_4TestE fun:main } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::TestComposite::TestComposite(std::__cxx11::basic_string, std::allocator > const&) fun:_ZN7CppUnit13TestCompositeC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE ... } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::TestCase::TestCase(std::__cxx11::basic_string, std::allocator > const&) fun:_ZN7CppUnit8TestCaseC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE ... } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #void std::_Function_base::_Base_manager >::_M_create >(std::_Any_data&, std::_Bind&&, std::integral_constant) ###fun:_ZNSt14_Function_base13_Base_managerISt5_BindIFM11ExampleTestFvvEPS2_EEE9_M_createIS7_EEvRSt9_Any_dataOT_St17integral_constantIbLb0EE fun:_ZNSt14_Function_base13_Base_managerISt5_BindIFM11*vvEPS2_EEE9_M_createIS7_EEvRSt9_Any_dataOT_St17integral_constantIbLb0EE ... #CppUnit::TestFactoryRegistry::addTestToSuite(CppUnit::TestSuite*) fun:_ZN7CppUnit19TestFactoryRegistry14addTestToSuiteEPNS_9TestSuiteE } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::ProtectorChain::protect(CppUnit::Functor const&, CppUnit::ProtectorContext const&) fun:_ZN7CppUnit14ProtectorChain7protectERKNS_7FunctorERKNS_16ProtectorContextE #CppUnit::TestResult::protect(CppUnit::Functor const&, CppUnit::Test*, std::__cxx11::basic_string, std::allocator > const&) fun:_ZN7CppUnit10TestResult7protectERKNS_7FunctorEPNS_4TestERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE ... } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm #CppUnit::ProtectorChain::protect() fun:_ZN7CppUnit14ProtectorChainC1Ev #CppUnit::TestResult::TestResult(CppUnit::SynchronizedObject::SynchronizationObject*) fun:_ZN7CppUnit10TestResultC1EPNS_18SynchronizedObject21SynchronizationObjectE #CppUnit::TextTestRunner::TextTestRunner(CppUnit::Outputter*) fun:_ZN7CppUnit14TextTestRunnerC1EPNS_9OutputterE fun:main } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm obj:*libcppunit* #CppUnit::TestResultCollector::TestResultCollector(CppUnit::SynchronizedObject::SynchronizationObject*) fun:_ZN7CppUnit19TestResultCollectorC1EPNS_18SynchronizedObject21SynchronizationObjectE #CppUnit::TextTestRunner::TextTestRunner(CppUnit::Outputter*) fun:_ZN7CppUnit14TextTestRunnerC1EPNS_9OutputterE fun:main } { Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm obj:*libcppunit* #CppUnit::TestPath::TestPath(CppUnit::Test*, std::__cxx11::basic_string, std::allocator > const&) fun:_ZN7CppUnit8TestPathC1EPNS_4TestERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE #CppUnit::TestRunner::run(CppUnit::TestResult&, std::__cxx11::basic_string, std::allocator > const&) fun:_ZN7CppUnit10TestRunner3runERNS_10TestResultERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE #CppUnit::TextTestRunner::run(std::__cxx11::basic_string, std::allocator >, bool, bool, bool) fun:_ZN7CppUnit14TextTestRunner3runENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEbbb fun:main } { ### runner.setOutputter( new CppUnit::CompilerOutputter( ...) ) in main (cpputest.cpp:120) Memcheck:Leak match-leak-kinds: reachable #operator new(unsigned long) fun:_Znwm fun:main } { Memcheck:Leak fun:malloc ... fun:printf ... fun:main } nut-2.8.3/scripts/valgrind/README.adoc0000644000200500020050000000136714777767434014362 00000000000000VALGRIND resources ================== Helper script and suppression file to analyze NUT binaries. Example use-case: ---- :; make -ks -j && LD_LIBRARY_PATH=`pwd`/clients/.libs \ ./scripts/valgrind/valgrind.sh ./tools/nut-scanner/nut-scanner -DDDDDD -m auto ---- Note that the script is generated under `${top_builddir}` by `configure` from a template file located in `${top_srcdir}/scripts/valgrind/valgrind.sh.in`. You might be able to run it directly, falling back to a `valgrind` program in your `PATH`, if any. See also: * link:https://wiki.wxwidgets.org/Valgrind_Suppression_File_Howto[Valgrind Suppression File How-to] - Notably, add `--gen-suppressions=all --error-limit=no` to `valgrind` program options to generate suppression snippets nut-2.8.3/scripts/devd/0000755000200500020050000000000015001555411011725 500000000000000nut-2.8.3/scripts/devd/nut-usb.quirks0000644000200500020050000003350115001555411014504 00000000000000# This file is generated and installed by the Network UPS Tools package. # Homepage: https://www.networkupstools.org/ # Contents should be added to /boot/loader.conf.local (watch out for unique quirk numbers!) # Inspired by 'Notes on USB quirks' under https://forum.netgate.com/topic/183961/nut-package-2-8-1-and-above # and https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/quirk/usb_quirk.c # SNR-UPS-LID-XXXX UPSes - blazer_usb nutdrv_atcl_usb nutdrv_qx hw.usb.quirk.0="0x0001 0x0000 0x0000 0xffff UQ_HID_IGNORE" # Hewlett Packard # e.g. ? - usbhid-ups hw.usb.quirk.1="0x03f0 0x0001 0x0000 0xffff UQ_HID_IGNORE" # T500 - bcmxcp_usb hw.usb.quirk.2="0x03f0 0x1f01 0x0000 0xffff UQ_HID_IGNORE" # T750 - bcmxcp_usb hw.usb.quirk.3="0x03f0 0x1f02 0x0000 0xffff UQ_HID_IGNORE" # HP T750 INTL - usbhid-ups hw.usb.quirk.4="0x03f0 0x1f06 0x0000 0xffff UQ_HID_IGNORE" # HP T1000 INTL - usbhid-ups hw.usb.quirk.5="0x03f0 0x1f08 0x0000 0xffff UQ_HID_IGNORE" # HP T1500 INTL - usbhid-ups hw.usb.quirk.6="0x03f0 0x1f09 0x0000 0xffff UQ_HID_IGNORE" # HP R/T 2200 INTL (like SMART2200RMXL2U) - usbhid-ups hw.usb.quirk.7="0x03f0 0x1f0a 0x0000 0xffff UQ_HID_IGNORE" # HP R1500 G2 and G3 INTL - usbhid-ups hw.usb.quirk.8="0x03f0 0x1fe0 0x0000 0xffff UQ_HID_IGNORE" # HP T750 G2 - usbhid-ups hw.usb.quirk.9="0x03f0 0x1fe1 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.10="0x03f0 0x1fe2 0x0000 0xffff UQ_HID_IGNORE" # HP T1500 G3 - usbhid-ups hw.usb.quirk.11="0x03f0 0x1fe3 0x0000 0xffff UQ_HID_IGNORE" # R/T3000 - usbhid-ups hw.usb.quirk.12="0x03f0 0x1fe5 0x0000 0xffff UQ_HID_IGNORE" # R/T3000 - usbhid-ups hw.usb.quirk.13="0x03f0 0x1fe6 0x0000 0xffff UQ_HID_IGNORE" # various models - usbhid-ups hw.usb.quirk.14="0x03f0 0x1fe7 0x0000 0xffff UQ_HID_IGNORE" # various models - usbhid-ups hw.usb.quirk.15="0x03f0 0x1fe8 0x0000 0xffff UQ_HID_IGNORE" # Eaton # various models - usbhid-ups hw.usb.quirk.16="0x0463 0x0001 0x0000 0xffff UQ_HID_IGNORE" # various models - usbhid-ups hw.usb.quirk.17="0x0463 0xffff 0x0000 0xffff UQ_HID_IGNORE" # Dell # various models - usbhid-ups hw.usb.quirk.18="0x047c 0xffff 0x0000 0xffff UQ_HID_IGNORE" # ST Microelectronics # TS Shara UPSes; vendor ID 0x0483 is from ST Microelectronics - with product IDs delegated to different OEMs - nutdrv_qx hw.usb.quirk.19="0x0483 0x0035 0x0000 0xffff UQ_HID_IGNORE" # USB IDs device table - usbhid-ups hw.usb.quirk.20="0x0483 0xa113 0x0000 0xffff UQ_HID_IGNORE" # Cyber Energy branded devices by CPS - usbhid-ups hw.usb.quirk.21="0x0483 0xa430 0x0000 0xffff UQ_HID_IGNORE" # IBM # 6000 VA LCD 4U Rack UPS; 5396-1Kx - usbhid-ups hw.usb.quirk.22="0x04b3 0x0001 0x0000 0xffff UQ_HID_IGNORE" # Riello (Cypress Semiconductor Corp.) # various models - riello_usb hw.usb.quirk.23="0x04b4 0x5500 0x0000 0xffff UQ_HID_IGNORE" # Minibox # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups hw.usb.quirk.24="0x04d8 0xd004 0x0000 0xffff UQ_HID_IGNORE" # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups hw.usb.quirk.25="0x04d8 0xd005 0x0000 0xffff UQ_HID_IGNORE" # Belkin # F6H375-USB - usbhid-ups hw.usb.quirk.26="0x050d 0x0375 0x0000 0xffff UQ_HID_IGNORE" # F6C550-AVR - usbhid-ups hw.usb.quirk.27="0x050d 0x0551 0x0000 0xffff UQ_HID_IGNORE" # F6C1250-TW-RK - usbhid-ups hw.usb.quirk.28="0x050d 0x0750 0x0000 0xffff UQ_HID_IGNORE" # F6C1500-TW-RK - usbhid-ups hw.usb.quirk.29="0x050d 0x0751 0x0000 0xffff UQ_HID_IGNORE" # F6C900-UNV - usbhid-ups hw.usb.quirk.30="0x050d 0x0900 0x0000 0xffff UQ_HID_IGNORE" # F6C100-UNV - usbhid-ups hw.usb.quirk.31="0x050d 0x0910 0x0000 0xffff UQ_HID_IGNORE" # F6C120-UNV - usbhid-ups hw.usb.quirk.32="0x050d 0x0912 0x0000 0xffff UQ_HID_IGNORE" # F6C800-UNV - usbhid-ups hw.usb.quirk.33="0x050d 0x0980 0x0000 0xffff UQ_HID_IGNORE" # Regulator PRO-USB - usbhid-ups hw.usb.quirk.34="0x050d 0x0f51 0x0000 0xffff UQ_HID_IGNORE" # F6C1100-UNV, F6C1200-UNV - usbhid-ups hw.usb.quirk.35="0x050d 0x1100 0x0000 0xffff UQ_HID_IGNORE" # APC # APC AP9584 Serial->USB kit - usbhid-ups hw.usb.quirk.36="0x051d 0x0000 0x0000 0xffff UQ_HID_IGNORE" # various models - usbhid-ups hw.usb.quirk.37="0x051d 0x0002 0x0000 0xffff UQ_HID_IGNORE" # USB IDs device table - usbhid-ups apc_modbus hw.usb.quirk.38="0x051d 0x0003 0x0000 0xffff UQ_HID_IGNORE" # various 5G models - usbhid-ups hw.usb.quirk.39="0x051d 0x0004 0x0000 0xffff UQ_HID_IGNORE" # Powerware # various models - bcmxcp_usb hw.usb.quirk.40="0x0592 0x0002 0x0000 0xffff UQ_HID_IGNORE" # PW 9140 - usbhid-ups hw.usb.quirk.41="0x0592 0x0004 0x0000 0xffff UQ_HID_IGNORE" # Agiler UPS - blazer_usb nutdrv_qx hw.usb.quirk.42="0x05b8 0x0000 0x0000 0xffff UQ_HID_IGNORE" # Delta UPS # Delta UPS Amplon R Series, Single Phase UPS, 1/2/3 kVA - usbhid-ups hw.usb.quirk.43="0x05dd 0x041b 0x0000 0xffff UQ_HID_IGNORE" # Delta/Minuteman Enterprise Plus E1500RM2U - usbhid-ups hw.usb.quirk.44="0x05dd 0xa011 0x0000 0xffff UQ_HID_IGNORE" # Delta/Minuteman PRO1500RT2U - usbhid-ups hw.usb.quirk.45="0x05dd 0xa0a0 0x0000 0xffff UQ_HID_IGNORE" # Belkin F6C1200-UNV/Voltronic Power UPSes - blazer_usb nutdrv_qx hw.usb.quirk.46="0x0665 0x5161 0x0000 0xffff UQ_HID_IGNORE" # Phoenixtec Power Co., Ltd # Online Yunto YQ450 - bcmxcp_usb blazer_usb nutdrv_qx hw.usb.quirk.47="0x06da 0x0002 0x0000 0xffff UQ_HID_IGNORE" # Mustek Powermust - blazer_usb nutdrv_qx hw.usb.quirk.48="0x06da 0x0003 0x0000 0xffff UQ_HID_IGNORE" # Phoenixtec Innova 3/1 T - blazer_usb nutdrv_qx hw.usb.quirk.49="0x06da 0x0004 0x0000 0xffff UQ_HID_IGNORE" # Phoenixtec Innova RT - blazer_usb nutdrv_qx hw.usb.quirk.50="0x06da 0x0005 0x0000 0xffff UQ_HID_IGNORE" # Phoenixtec Innova T - blazer_usb nutdrv_qx hw.usb.quirk.51="0x06da 0x0201 0x0000 0xffff UQ_HID_IGNORE" # Online Zinto A - blazer_usb nutdrv_qx hw.usb.quirk.52="0x06da 0x0601 0x0000 0xffff UQ_HID_IGNORE" # PROTECT B / NAS - usbhid-ups usbhid-ups hw.usb.quirk.53="0x06da 0xffff 0x0000 0xffff UQ_HID_IGNORE" # iDowell # iDowell - usbhid-ups hw.usb.quirk.54="0x075d 0x0300 0x0000 0xffff UQ_HID_IGNORE" # Cyber Power Systems # 900AVR/BC900D - usbhid-ups hw.usb.quirk.55="0x0764 0x0005 0x0000 0xffff UQ_HID_IGNORE" # Dynex DX-800U?, CP1200AVR/BC1200D, CP825AVR-G, CP1000AVRLCD, CP1000PFCLCD, CP1500C, CP550HG, etc. - usbhid-ups hw.usb.quirk.56="0x0764 0x0501 0x0000 0xffff UQ_HID_IGNORE" # OR2200LCDRM2U, OR700LCDRM1U, PR6000LCDRTXL5U, CP1350EPFCLCD - usbhid-ups hw.usb.quirk.57="0x0764 0x0601 0x0000 0xffff UQ_HID_IGNORE" # Sweex 1000VA - nutdrv_qx richcomm_usb hw.usb.quirk.58="0x0925 0x1234 0x0000 0xffff UQ_HID_IGNORE" # TrippLite # e.g. OMNIVS1000, SMART550USB, ... - tripplite_usb hw.usb.quirk.59="0x09ae 0x0001 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite AVR550U - usbhid-ups hw.usb.quirk.60="0x09ae 0x1003 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite AVR750U - usbhid-ups hw.usb.quirk.61="0x09ae 0x1007 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite ECO550UPS - usbhid-ups hw.usb.quirk.62="0x09ae 0x1008 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite ECO550UPS - usbhid-ups hw.usb.quirk.63="0x09ae 0x1009 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite ECO550UPS - usbhid-ups hw.usb.quirk.64="0x09ae 0x1010 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite SU3000LCD2UHV - usbhid-ups hw.usb.quirk.65="0x09ae 0x1330 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite OMNI1000LCD - usbhid-ups hw.usb.quirk.66="0x09ae 0x2005 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite OMNI900LCD - usbhid-ups hw.usb.quirk.67="0x09ae 0x2007 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.68="0x09ae 0x2008 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite Smart1000LCD - usbhid-ups hw.usb.quirk.69="0x09ae 0x2009 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.70="0x09ae 0x2010 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.71="0x09ae 0x2011 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.72="0x09ae 0x2012 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.73="0x09ae 0x2013 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.74="0x09ae 0x2014 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.75="0x09ae 0x3008 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.76="0x09ae 0x3009 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.77="0x09ae 0x3010 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.78="0x09ae 0x3011 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite smart2200RMXL2U - usbhid-ups hw.usb.quirk.79="0x09ae 0x3012 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.80="0x09ae 0x3013 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.81="0x09ae 0x3014 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.82="0x09ae 0x3015 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite Smart1500LCD (newer unit) - usbhid-ups hw.usb.quirk.83="0x09ae 0x3016 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite AVR750U (newer unit) - usbhid-ups hw.usb.quirk.84="0x09ae 0x3024 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite SmartOnline SU1500RTXL2UA (older unit?) - usbhid-ups hw.usb.quirk.85="0x09ae 0x4001 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite SmartOnline SU6000RT4U? - usbhid-ups hw.usb.quirk.86="0x09ae 0x4002 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite SmartOnline SU1500RTXL2ua - usbhid-ups hw.usb.quirk.87="0x09ae 0x4003 0x0000 0xffff UQ_HID_IGNORE" # e.g. TrippLite SmartOnline SU1000XLA - usbhid-ups hw.usb.quirk.88="0x09ae 0x4004 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.89="0x09ae 0x4005 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.90="0x09ae 0x4006 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.91="0x09ae 0x4007 0x0000 0xffff UQ_HID_IGNORE" # e.g. ? - usbhid-ups hw.usb.quirk.92="0x09ae 0x4008 0x0000 0xffff UQ_HID_IGNORE" # KSTAR under Berkeley Varitronics Systems ID # 6000 VA LCD 4U Rack UPS; 5396-1Kx - usbhid-ups hw.usb.quirk.93="0x09d6 0x0001 0x0000 0xffff UQ_HID_IGNORE" # PowerCOM # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups hw.usb.quirk.94="0x0d9f 0x0001 0x0000 0xffff UQ_HID_IGNORE" # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups hw.usb.quirk.95="0x0d9f 0x0004 0x0000 0xffff UQ_HID_IGNORE" # PowerCOM IMP - IMPERIAL Series - usbhid-ups hw.usb.quirk.96="0x0d9f 0x00a2 0x0000 0xffff UQ_HID_IGNORE" # PowerCOM SKP - Smart KING Pro (all Smart series) - usbhid-ups hw.usb.quirk.97="0x0d9f 0x00a3 0x0000 0xffff UQ_HID_IGNORE" # PowerCOM WOW - usbhid-ups hw.usb.quirk.98="0x0d9f 0x00a4 0x0000 0xffff UQ_HID_IGNORE" # PowerCOM VGD - Vanguard - usbhid-ups hw.usb.quirk.99="0x0d9f 0x00a5 0x0000 0xffff UQ_HID_IGNORE" # PowerCOM BNT - Black Knight Pro - usbhid-ups hw.usb.quirk.100="0x0d9f 0x00a6 0x0000 0xffff UQ_HID_IGNORE" # Unitek Alpha 1200Sx - blazer_usb nutdrv_qx hw.usb.quirk.101="0x0f03 0x0001 0x0000 0xffff UQ_HID_IGNORE" # Liebert # Liebert GXT4 UPS - usbhid-ups hw.usb.quirk.102="0x10af 0x0000 0x0000 0xffff UQ_HID_IGNORE" # Liebert PowerSure PSA UPS - usbhid-ups hw.usb.quirk.103="0x10af 0x0001 0x0000 0xffff UQ_HID_IGNORE" # Liebert PowerSure PST UPS - usbhid-ups hw.usb.quirk.104="0x10af 0x0002 0x0000 0xffff UQ_HID_IGNORE" # Liebert PowerSure PSI 1440 - usbhid-ups hw.usb.quirk.105="0x10af 0x0004 0x0000 0xffff UQ_HID_IGNORE" # Liebert GXT3 - usbhid-ups hw.usb.quirk.106="0x10af 0x0008 0x0000 0xffff UQ_HID_IGNORE" # GE EP series - blazer_usb nutdrv_qx hw.usb.quirk.107="0x14f0 0x00c9 0x0000 0xffff UQ_HID_IGNORE" # Legrand # Legrand Keor SP - usbhid-ups hw.usb.quirk.108="0x1cb0 0x0032 0x0000 0xffff UQ_HID_IGNORE" # Legrand Daker DK / DK Plus - nutdrv_qx hw.usb.quirk.109="0x1cb0 0x0035 0x0000 0xffff UQ_HID_IGNORE" # Legrand Keor PDU - usbhid-ups hw.usb.quirk.110="0x1cb0 0x0038 0x0000 0xffff UQ_HID_IGNORE" # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups hw.usb.quirk.111="0x2341 0x0036 0x0000 0xffff UQ_HID_IGNORE" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups hw.usb.quirk.112="0x2341 0x8036 0x0000 0xffff UQ_HID_IGNORE" # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups hw.usb.quirk.113="0x2a03 0x0036 0x0000 0xffff UQ_HID_IGNORE" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups hw.usb.quirk.114="0x2a03 0x0040 0x0000 0xffff UQ_HID_IGNORE" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups hw.usb.quirk.115="0x2a03 0x8036 0x0000 0xffff UQ_HID_IGNORE" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups hw.usb.quirk.116="0x2a03 0x8040 0x0000 0xffff UQ_HID_IGNORE" # AEG # PROTECT B / NAS - usbhid-ups hw.usb.quirk.117="0x2b2d 0xffff 0x0000 0xffff UQ_HID_IGNORE" # Ever # USB IDs device table - usbhid-ups hw.usb.quirk.118="0x2e51 0x0000 0x0000 0xffff UQ_HID_IGNORE" # USB IDs device table - usbhid-ups hw.usb.quirk.119="0x2e51 0xffff 0x0000 0xffff UQ_HID_IGNORE" # Salicru # https://www.salicru.com/sps-3000-adv-rt2.html - usbhid-ups hw.usb.quirk.120="0x2e66 0x0101 0x0000 0xffff UQ_HID_IGNORE" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups hw.usb.quirk.121="0x2e66 0x0201 0x0000 0xffff UQ_HID_IGNORE" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups hw.usb.quirk.122="0x2e66 0x0202 0x0000 0xffff UQ_HID_IGNORE" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups hw.usb.quirk.123="0x2e66 0x0203 0x0000 0xffff UQ_HID_IGNORE" # https://www.salicru.com/sps-home.html - usbhid-ups hw.usb.quirk.124="0x2e66 0x0300 0x0000 0xffff UQ_HID_IGNORE" # https://www.salicru.com/sps-850-adv-t.html - usbhid-ups hw.usb.quirk.125="0x2e66 0x0302 0x0000 0xffff UQ_HID_IGNORE" # EcoFlow # EcoFlow - usbhid-ups hw.usb.quirk.126="0x3746 0xffff 0x0000 0xffff UQ_HID_IGNORE" # Powervar # Powervar - usbhid-ups hw.usb.quirk.127="0x4234 0x0002 0x0000 0xffff UQ_HID_IGNORE" # Ablerex 625L USB (Note: earlier best-fit was "krauler_subdriver" before PR #1135) - blazer_usb nutdrv_qx hw.usb.quirk.128="0xffff 0x0000 0x0000 0xffff UQ_HID_IGNORE" nut-2.8.3/scripts/devd/Makefile.am0000644000200500020050000000523514777767434013743 00000000000000# Network UPS Tools: scripts/devd if WITH_DEVD devdconfdir = $(devddir) devdconf_DATA = if WITH_USB devdconf_DATA += nut-usb.conf endif endif if WITH_FREEBSD_QUIRKS_DIR freebsdquirks_DATA = nut-usb.quirks endif EXTRA_DIST = README.adoc MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by configure script: DISTCLEANFILES = nut-usb.conf # we should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES += nut-usb.conf.in MAINTAINERCLEANFILES += nut-usb.conf.in.AUTOGEN_WITHOUT MAINTAINERCLEANFILES += nut-usb.quirks # Part of dist tarball, regardless of use for current build: EXTRA_DIST += nut-usb.conf.in nut-usb.quirks SPELLCHECK_SRC = README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked nut-2.8.3/scripts/devd/README.adoc0000644000200500020050000000154414777534446013466 00000000000000NUT USB integration resources for FreeBSD devd ============================================== On FreeBSD, the `devd` subsystem has a similar role to `udev` on Linux. NOTE: Some FreeBSD based systems rely on "quirks" instead. The `devd.conf` file defines actions to perform when devices are plugged in. The `tools/nut-usbinfo.pl` script (under NUT source tree root) generates the `nut-usb.conf.in` here by processing USB macros in all of the drivers. In this case, the defined action for each matching UPS is to change the permissions such that the NUT drivers can access the USB device nodes without requiring root privileges. You may need to restart `devd` and re-plug in the UPS (or reboot) after installation of the file in order to trigger the actions. The format of this configuration file should work with `devd` on FreeBSD 9.0 and 9.1, at the very least. nut-2.8.3/scripts/devd/Makefile.in0000644000200500020050000006557515001555011013730 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/devd VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_DEVD_TRUE@@WITH_USB_TRUE@am__append_1 = nut-usb.conf subdir = scripts/devd ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-usb.conf CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(devdconfdir)" \ "$(DESTDIR)$(freebsdquirksdir)" DATA = $(devdconf_DATA) $(freebsdquirks_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/nut-usb.conf.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ @WITH_DEVD_TRUE@devdconfdir = $(devddir) @WITH_DEVD_TRUE@devdconf_DATA = $(am__append_1) @WITH_FREEBSD_QUIRKS_DIR_TRUE@freebsdquirks_DATA = nut-usb.quirks # Part of dist tarball, regardless of use for current build: EXTRA_DIST = README.adoc nut-usb.conf.in nut-usb.quirks # we should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-usb.conf.in \ nut-usb.conf.in.AUTOGEN_WITHOUT nut-usb.quirks # Generated by configure script: DISTCLEANFILES = nut-usb.conf SPELLCHECK_SRC = README.adoc CLEANFILES = *-spellchecked all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/devd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/devd/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-usb.conf: $(top_builddir)/config.status $(srcdir)/nut-usb.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-devdconfDATA: $(devdconf_DATA) @$(NORMAL_INSTALL) @list='$(devdconf_DATA)'; test -n "$(devdconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(devdconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(devdconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(devdconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(devdconfdir)" || exit $$?; \ done uninstall-devdconfDATA: @$(NORMAL_UNINSTALL) @list='$(devdconf_DATA)'; test -n "$(devdconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(devdconfdir)'; $(am__uninstall_files_from_dir) install-freebsdquirksDATA: $(freebsdquirks_DATA) @$(NORMAL_INSTALL) @list='$(freebsdquirks_DATA)'; test -n "$(freebsdquirksdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(freebsdquirksdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(freebsdquirksdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(freebsdquirksdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(freebsdquirksdir)" || exit $$?; \ done uninstall-freebsdquirksDATA: @$(NORMAL_UNINSTALL) @list='$(freebsdquirks_DATA)'; test -n "$(freebsdquirksdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(freebsdquirksdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(devdconfdir)" "$(DESTDIR)$(freebsdquirksdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-devdconfDATA install-freebsdquirksDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-devdconfDATA uninstall-freebsdquirksDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-devdconfDATA install-dvi install-dvi-am install-exec \ install-exec-am install-freebsdquirksDATA install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am uninstall-devdconfDATA \ uninstall-freebsdquirksDATA .PRECIOUS: Makefile # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/devd/nut-usb.conf.in0000644000200500020050000010205315001555411014517 00000000000000# This file is generated and installed by the Network UPS Tools package. # Homepage: https://www.networkupstools.org/ # SNR-UPS-LID-XXXX UPSes - blazer_usb nutdrv_atcl_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0001"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Hewlett Packard # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # T500 - bcmxcp_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f01"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # T750 - bcmxcp_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f02"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T750 INTL - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f06"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T1000 INTL - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f08"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T1500 INTL - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f09"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP R/T 2200 INTL (like SMART2200RMXL2U) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1f0a"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP R1500 G2 and G3 INTL - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe0"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T750 G2 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe1"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe2"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # HP T1500 G3 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe3"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # R/T3000 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe5"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # R/T3000 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe6"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe7"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x03f0"; match "product" "0x1fe8"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Eaton # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0463"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0463"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Dell # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x047c"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # ST Microelectronics # TS Shara UPSes; vendor ID 0x0483 is from ST Microelectronics - with product IDs delegated to different OEMs - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0483"; match "product" "0x0035"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # USB IDs device table - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0483"; match "product" "0xa113"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Cyber Energy branded devices by CPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0483"; match "product" "0xa430"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # IBM # 6000 VA LCD 4U Rack UPS; 5396-1Kx - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x04b3"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Riello (Cypress Semiconductor Corp.) # various models - riello_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x04b4"; match "product" "0x5500"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Minibox # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x04d8"; match "product" "0xd004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x04d8"; match "product" "0xd005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Belkin # F6H375-USB - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0375"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C550-AVR - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0551"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C1250-TW-RK - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0750"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C1500-TW-RK - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0751"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C900-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0900"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C100-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0910"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C120-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0912"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C800-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0980"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Regulator PRO-USB - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x0f51"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # F6C1100-UNV, F6C1200-UNV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x050d"; match "product" "0x1100"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # APC # APC AP9584 Serial->USB kit - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x051d"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x051d"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # USB IDs device table - usbhid-ups apc_modbus notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x051d"; match "product" "0x0003"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # various 5G models - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x051d"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Powerware # various models - bcmxcp_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0592"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PW 9140 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0592"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Agiler UPS - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x05b8"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Delta UPS # Delta UPS Amplon R Series, Single Phase UPS, 1/2/3 kVA - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x05dd"; match "product" "0x041b"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Delta/Minuteman Enterprise Plus E1500RM2U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x05dd"; match "product" "0xa011"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Delta/Minuteman PRO1500RT2U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x05dd"; match "product" "0xa0a0"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Belkin F6C1200-UNV/Voltronic Power UPSes - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0665"; match "product" "0x5161"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Phoenixtec Power Co., Ltd # Online Yunto YQ450 - bcmxcp_usb blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Mustek Powermust - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0003"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Phoenixtec Innova 3/1 T - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Phoenixtec Innova RT - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Phoenixtec Innova T - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0201"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Online Zinto A - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0x0601"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PROTECT B / NAS - usbhid-ups usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x06da"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # iDowell # iDowell - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x075d"; match "product" "0x0300"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Cyber Power Systems # 900AVR/BC900D - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0764"; match "product" "0x0005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Dynex DX-800U?, CP1200AVR/BC1200D, CP825AVR-G, CP1000AVRLCD, CP1000PFCLCD, CP1500C, CP550HG, etc. - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0764"; match "product" "0x0501"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # OR2200LCDRM2U, OR700LCDRM1U, PR6000LCDRTXL5U, CP1350EPFCLCD - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0764"; match "product" "0x0601"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Sweex 1000VA - nutdrv_qx richcomm_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0925"; match "product" "0x1234"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # TrippLite # e.g. OMNIVS1000, SMART550USB, ... - tripplite_usb notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite AVR550U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1003"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite AVR750U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1007"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite ECO550UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite ECO550UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1009"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite ECO550UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1010"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SU3000LCD2UHV - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x1330"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite OMNI1000LCD - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite OMNI900LCD - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2007"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite Smart1000LCD - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2009"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2010"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2011"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2012"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2013"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x2014"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3009"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3010"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3011"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite smart2200RMXL2U - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3012"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3013"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3014"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3015"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite Smart1500LCD (newer unit) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3016"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite AVR750U (newer unit) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x3024"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SmartOnline SU1500RTXL2UA (older unit?) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SmartOnline SU6000RT4U? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SmartOnline SU1500RTXL2ua - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4003"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. TrippLite SmartOnline SU1000XLA - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4005"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4006"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4007"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # e.g. ? - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09ae"; match "product" "0x4008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # KSTAR under Berkeley Varitronics Systems ID # 6000 VA LCD 4U Rack UPS; 5396-1Kx - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x09d6"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM IMP - IMPERIAL Series - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a2"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM SKP - Smart KING Pro (all Smart series) - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a3"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM WOW - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a4"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM VGD - Vanguard - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a5"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # PowerCOM BNT - Black Knight Pro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0d9f"; match "product" "0x00a6"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Unitek Alpha 1200Sx - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x0f03"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Liebert # Liebert GXT4 UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x10af"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Liebert PowerSure PSA UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x10af"; match "product" "0x0001"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Liebert PowerSure PST UPS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x10af"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Liebert PowerSure PSI 1440 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x10af"; match "product" "0x0004"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Liebert GXT3 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x10af"; match "product" "0x0008"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # GE EP series - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x14f0"; match "product" "0x00c9"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Legrand # Legrand Keor SP - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x1cb0"; match "product" "0x0032"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Legrand Daker DK / DK Plus - nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x1cb0"; match "product" "0x0035"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Legrand Keor PDU - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x1cb0"; match "product" "0x0038"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2341"; match "product" "0x0036"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2341"; match "product" "0x8036"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2a03"; match "product" "0x0036"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2a03"; match "product" "0x0040"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2a03"; match "product" "0x8036"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2a03"; match "product" "0x8040"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # AEG # PROTECT B / NAS - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2b2d"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Ever # USB IDs device table - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e51"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # USB IDs device table - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e51"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Salicru # https://www.salicru.com/sps-3000-adv-rt2.html - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0101"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0201"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0202"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0203"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # https://www.salicru.com/sps-home.html - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0300"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # https://www.salicru.com/sps-850-adv-t.html - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x2e66"; match "product" "0x0302"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # EcoFlow # EcoFlow - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x3746"; match "product" "0xffff"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Powervar # Powervar - usbhid-ups notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x4234"; match "product" "0x0002"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; # Ablerex 625L USB (Note: earlier best-fit was "krauler_subdriver" before PR #1135) - blazer_usb nutdrv_qx notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0xffff"; match "product" "0x0000"; action "chgrp @RUN_AS_GROUP@ /dev/$cdev; chmod g+rw /dev/$cdev"; }; nut-2.8.3/scripts/perl/0000755000200500020050000000000015001555411011745 500000000000000nut-2.8.3/scripts/perl/Nut.pm0000644000200500020050000006420014777534446013023 00000000000000# UPS::Nut - a class to talk to a UPS via the Network Utility Tools upsd. # Original author Kit Peters # Rewritten by Gabor Kiss # Idea to implement TLS:http://www.logix.cz/michal/devel/smtp-cli/smtp-client.pl # ### changelog: made debug messages slightly more descriptive, improved # ### changelog: comments in code # ### changelog: Removed timeleft() function. package UPS::Nut; use strict; use Carp; use FileHandle; use IO::Socket; use IO::Select; use Dumpvalue; my $dumper = Dumpvalue->new; # The following globals dictate whether the accessors and instant-command # functions are created. # ### changelog: tie hash interface and AUTOLOAD contributed by # ### changelog: Wayne Wylupski my $_eol = "\n"; BEGIN { use Exporter (); use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.51; @ISA = qw(Exporter IO::Socket::INET); @EXPORT = qw(); @EXPORT_OK = qw(); %EXPORT_TAGS = (); } sub new { # Author: Kit Peters my $proto = shift; my $class = ref($proto) || $proto; my %arg = @_; # hash of arguments my $self = {}; # _initialize will fill it later bless $self, $class; unless ($self->_initialize(%arg)) { # can't initialize carp "Can't initialize: $self->{err}"; return undef; } return $self; } # accessor functions. Return a value if successful, return undef # otherwise. sub BattPercent { # get battery percentage return shift->GetVar('battery.charge'); } sub LoadPercent { # get load percentage my $self = shift; my $context = shift; $context = "L$context" if $context =~ /^[123]$/; $context = ".$context" if $context; return $self->GetVar("output$context.power.percent"); } sub LineVoltage { # get line voltage my $self = shift; my $context = shift; $context = "L$context-N" if $context =~ /^[123]$/; $context = ".$context" if $context; return $self->GetVar("input$context.voltage"); } sub Status { # get status of UPS return shift->GetVar('ups.status'); } sub Temperature { # get the internal temperature of UPS return shift->GetVar('battery.temperature'); } # control functions: they control our relationship to upsd, and send # commands to upsd. sub Login { # login to upsd, so that it won't shutdown unless we say we're # ok. This should only be used if you're actually connected # to the ups that upsd is monitoring. # Author: Kit Peters # ### changelog: modified login logic a bit. Now it doesn't check to see # ### changelog: if we got OK, ERR, or something else from upsd. It # ### changelog: simply checks for a response beginning with OK from upsd. # ### changelog: Anything else is an error. # # ### changelog: uses the new _send command # my $self = shift; # myself my $user = shift; # username my $pass = shift; # password my $errmsg; # error message, sent to _debug and $self->{err} my $ans; # scalar to hold responses from upsd $self->Authenticate($user, $pass) or return; $ans = $self->_send( "LOGIN $self->{name}" ); if (defined $ans && $ans =~ /^OK/) { # Login successful. $self->_debug("LOGIN successful."); return 1; } if (defined $ans) { $errmsg = "LOGIN failed. Last message from upsd: $ans"; } else { $errmsg = "Network error: $!"; } $self->_debug($self->{err} = $errmsg); return undef; } sub Authenticate { # Announce to the UPS who we are to set up the proper # management level. See upsd.conf man page for details. # Contributor: Wayne Wylupski my $self = shift; # myself my $user = shift; # username my $pass = shift; # password my $errmsg; # error message, sent to _debug and $self->{err} my $ans; # scalar to hold responses from upsd # only attempt authentication if username and password given if (defined $user and defined $pass) { $ans = $self->_send("USERNAME $user"); if (defined $ans && $ans =~ /^OK/) { # username OK, send password $ans = $self->_send("PASSWORD $pass"); return 1 if (defined $ans && $ans =~ /^OK/); } } if (defined $ans) { $errmsg = "Authentication failed. Last message from upsd: $ans"; } else { $errmsg = "Network error: $!"; } $self->_debug($self->{err} = $errmsg); return undef; } sub Logout { # logout of upsd # Author: Kit Peters # ### changelog: uses the new _send command # my $self = shift; if ($self->{srvsock}) { # are we still connected to upsd? my $ans = $self->_send( "LOGOUT" ); close ($self->{srvsock}); delete ($self->{srvsock}); } } # internal functions. These are only used by UPS::Nut internally, so # please don't use them otherwise. If you really think an internal # function should be externalized, let me know. sub _initialize { # Author: Kit Peters my $self = shift; my %arg = @_; my $host = $arg{HOST} || 'localhost'; # Host running upsd and probably drivers my $port = $arg{PORT} || '3493'; # 3493 is IANA assigned port for NUT my $proto = $arg{PROTO} || 'tcp'; # use tcp unless user tells us to my $user = $arg{USERNAME} || undef; # username passed to upsd my $pass = $arg{PASSWORD} || undef; # password passed to upsd my $login = $arg{LOGIN} || 0; # login to upsd on init? $self->{name} = $arg{NAME} || 'default'; # UPS name in etc/ups.conf on $host $self->{timeout} = $arg{TIMEOUT} || 30; # timeout $self->{debug} = $arg{DEBUG} || 0; # debugging? $self->{debugout} = $arg{DEBUGOUT} || undef; # where to send debug messages my $srvsock = $self->{srvsock} = # establish connection to upsd IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port, Proto => $proto ); unless ( defined $srvsock) { # can't connect $self->{err} = "Unable to connect via $proto to $host:$port: $!"; return undef; } $self->{select} = IO::Select->new( $srvsock ); if ($user and $pass) { # attempt login to upsd if that option is specified if ($login) { # attempt login to upsd if that option is specified $self->Login($user, $pass) or carp $self->{err}; } else { $self->Authenticate($user, $pass) or carp $self->{err}; } } # get a hash of vars for both the TIE functions as well as for # expanding vars. $self->{vars} = $self->ListVar; unless ( defined $self->{vars} ) { $self->{err} = "Network error: $!"; return undef; } return $self; } # # _send # # Sends a command to the server and retrieves the results. # If there was a network error, return undef; $! will contain the # error. sub _send { # Contributor: Wayne Wylupski my $self = shift; my $cmd = shift; my @handles; my $result; # undef by default my $socket = $self->{srvsock}; my $select = $self->{select}; @handles = IO::Select->select( undef, $select, $select, $self->{timeout} ); return undef if ( !scalar $handles[1] ); $socket->print( $cmd . $_eol ); @handles = IO::Select->select( $select, undef, $select, $self->{timeout} ); return undef if ( !scalar $handles[0]); $result = $socket->getline; return undef if ( !defined ( $result ) ); chomp $result; return $result; } sub _getline { # Contributor: Wayne Wylupski my $self = shift; my $result; # undef by default my $socket = $self->{srvsock}; my $select = $self->{select}; # Different versions of IO::Socket has different error detection routines. return undef if ( $IO::Socket::{has_error} && $select->has_error(0) ); return undef if ( $IO::Socket::{has_exception} && $select->has_exception(0) ); chomp ( $result = $socket->getline ); return $result; } # Compatibility layer sub Request { goto &GetVar; } sub GetVar { # request a variable from the UPS # Author: Kit Peters my $self = shift; # ### changelog: 8/3/2002 - KP - Request() now returns undef if not # ### changelog: connected to upsd via $srvsock # ### changelog: uses the new _send command # # Modified by Gabor Kiss according to protocol version 1.5+ my $var = shift; my $req = "GET VAR $self->{name} $var"; # build request my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans. Requested $var."; return undef; } elsif ($ans =~ /^VAR/) { my $checkvar; # to make sure the var we asked for is the var we got. my $retval; # returned value for requested VAR (undef, undef, $checkvar, $retval) = split(' ', $ans, 4); # get checkvar and retval from the answer if ($checkvar ne $var) { # did not get expected var $self->{err} = "requested $var, received $checkvar"; return undef; } $retval =~ s/^"(.*)"$/$1/; return $retval; # return the requested value } else { # unrecognized response $self->{err} = "Unrecognized response from upsd: $ans"; return undef; } } sub Set { # Contributor: Wayne Wylupski # ### changelog: uses the new _send command # my $self = shift; my $var = shift; (my $value = shift) =~ s/^"?(.*)"?$/"$1"/; # add quotes if missing my $req = "SET VAR $self->{name} $var $value"; # build request my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^OK/) { return $value; } else { # unrecognized response $self->{err} = "Unrecognized response from upsd: $ans"; return undef; } } sub FSD { # set forced shutdown flag # Author: Kit Peters # ### changelog: uses the new _send command # my $self = shift; my $req = "FSD $self->{name}"; # build request my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { # can't set forced shutdown flag $self->{err} = "Can't set FSD flag. Upsd reports: $ans"; return undef; } elsif ($ans =~ /^OK FSD-SET/) { # forced shutdown flag set $self->_debug("FSD flag set successfully."); return 1; } else { $self->{err} = "Unrecognized response from upsd: $ans"; return undef; } } sub InstCmd { # send instant command to ups # Contributor: Wayne Wylupski my $self = shift; chomp (my $cmd = shift); my $req = "INSTCMD $self->{name} $cmd"; my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { # error reported from upsd $self->{err} = "Can't send instant command $cmd. Reason: $ans"; return undef; } elsif ($ans =~ /^OK/) { # command successful $self->_debug("Instant command $cmd sent successfully."); return 1; } else { # unrecognized response $self->{err} = "Can't send instant command $cmd. Unrecognized response from upsd: $ans"; return undef; } } sub ListUPS { my $self = shift; return $self->_get_list("LIST UPS", 2, 1); } sub ListVar { my $self = shift; my $vars = $self->_get_list("LIST VAR $self->{name}", 3, 2); return $vars unless @_; # return all variables return {map { $_ => $vars->{$_} } @_}; # return selected ones } sub ListRW { my $self = shift; return $self->_get_list("LIST RW $self->{name}", 3, 2); } sub ListCmd { my $self = shift; return $self->_get_list("LIST CMD $self->{name}", 2); } sub ListEnum { my $self = shift; my $var = shift; return $self->_get_list("LIST ENUM $self->{name} $var", 3); } sub _get_list { my $self = shift; my ($req, $valueidx, $keyidx) = @_; my $ans = $self->_send($req); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^BEGIN LIST/) { # command successful my $retval = $keyidx ? {} : []; my $line; while ($line = $self->_getline) { last if $line =~ /^END LIST/; my @fields = split(' ', $line, $valueidx+1); (my $value = $fields[$valueidx]) =~ s/^"(.*)"$/$1/; if ($keyidx) { $retval->{$fields[$keyidx]} = $value; } else { push(@$retval, $value); } } unless ($line) { $self->{err} = "Network error: $!"; return undef; }; $self->_debug("$req command sent successfully."); return $retval; } else { # unrecognized response $self->{err} = "Can't send $req. Unrecognized response from upsd: $ans"; return undef; } } # Compatibility layer sub VarDesc { goto &GetDesc; } sub GetDesc { # Contributor: Wayne Wylupski # Modified by Gabor Kiss according to protocol version 1.5+ my $self = shift; my $var = shift; my $req = "GET DESC $self->{name} $var"; my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^DESC/) { # command successful $self->_debug("$req command sent successfully."); (undef, undef, undef, $ans) = split(' ', $ans, 4); $ans =~ s/^"(.*)"$/$1/; return $ans; } else { # unrecognized response $self->{err} = "Can't send $req. Unrecognized response from upsd: $ans"; return undef; } } # Compatibility layer sub VarType { goto &GetType; } sub GetType { # Contributor: Wayne Wylupski # Modified by Gabor Kiss according to protocol version 1.5+ my $self = shift; my $var = shift; my $req = "GET TYPE $self->{name} $var"; my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^TYPE/) { # command successful $self->_debug("$req command sent successfully."); (undef, undef, undef, $ans) = split(' ', $ans, 4); return $ans; } else { # unrecognized response $self->{err} = "Can't send $req. Unrecognized response from upsd: $ans"; return undef; } } # Compatibility layer sub InstCmdDesc { goto &GetCmdDesc; } sub GetCmdDesc { # Contributor: Wayne Wylupski # Modified by Gabor Kiss according to protocol version 1.5+ my $self = shift; my $cmd = shift; my $req = "GET CMDDESC $self->{name} $cmd"; my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^ERR/) { $self->{err} = "Error: $ans"; return undef; } elsif ($ans =~ /^DESC/) { # command successful $self->_debug("$req command sent successfully."); (undef, undef, undef, $ans) = split(' ', $ans, 4); $ans =~ s/^"(.*)"$/$1/; return $ans; } else { # unrecognized response $self->{err} = "Can't send $req. Unrecognized response from upsd: $ans"; return undef; } } sub DESTROY { # destructor, all it does is call Logout # Author: Kit Peters my $self = shift; $self->_debug("Object destroyed."); $self->Logout(); } sub _debug { # print debug messages to stdout or file # Author: Kit Peters my $self = shift; if ($self->{debug}) { chomp (my $msg = shift); my $out; # filehandle for output if ($self->{debugout}) { # if filename is given, use that $out = new FileHandle ($self->{debugout}, ">>") or warn "Error: $!"; } if ($out) { # if out was set to a filehandle, create nifty timestamp my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); $year = sprintf("%02d", $year % 100); # Y2.1K compliant, even! my $timestamp = join '/', ($mon + 1), $mday, $year; # today $timestamp .= " "; $timestamp .= join ':', $hour, $min, $sec; print $out "$timestamp $msg\n"; } else { print "DEBUG: $msg\n"; } # otherwise, print to stdout } } sub Error { # what was the last thing that went bang? # Author: Kit Peters my $self = shift; if ($self->{err}) { return $self->{err}; } else { return "No error explanation available."; } } sub Master { # check for MASTER level access # Author: Kit Peters # ### changelog: uses the new _send command # # TODO: API change pending to replace MASTER with PRIMARY # (and backwards-compatible alias handling) my $self = shift; my $req = "MASTER $self->{name}"; # build request my $ans = $self->_send( $req ); unless (defined $ans) { $self->{err} = "Network error: $!"; return undef; }; if ($ans =~ /^OK/) { # access granted $self->_debug("MASTER level access granted. Upsd reports: $ans"); return 1; } else { # access denied, or unrecognized reponse $self->{err} = "MASTER level access denied. Upsd responded: $ans"; # ### changelog: 8/3/2002 - KP - Master() returns undef rather than 0 on # ### failure. this makes it consistent with other methods return undef; } } sub AUTOLOAD { # Contributor: Wayne Wylupski my $self = shift; my $name = $UPS::Nut::AUTOLOAD; $name =~ s/^.*:://; # for a change we will only load cmds if needed. if (!defined $self->{cmds} ) { %{$self->{cmds}} = map{ $_ =>1 } @{$self->ListCmd}; } croak "No such InstCmd: $name" if (! $self->{cmds}{$name} ); return $self->InstCmd( $name ); } #------------------------------------------------------------------------- # tie hash interface # # The variables of the array, including the hidden 'numlogins' can # be accessed as a hash array through this method. # # Example: # tie %ups, 'UPS::Nut', # NAME => "myups", # HOST => "somemachine.somewhere.com", # ... # same options as new(); # ; # # $ups{UPSIDENT} = "MyUPS"; # print $ups{MFR}, " " $ups{MODEL}, "\n"; # #------------------------------------------------------------------------- sub TIEHASH { my $class = shift || 'UPS::Nut'; return $class->new( @_ ); } sub FETCH { my $self = shift; my $key = shift; return $self->Request( $key ); } sub STORE { my $self = shift; my $key = shift; my $value = shift; return $self->Set( $key, $value ); } sub DELETE { croak "DELETE operation not supported"; } sub CLEAR { croak "CLEAR operation not supported"; } sub EXISTS { exists shift->{vars}{shift}; } sub FIRSTKEY { my $self = shift; my $a = keys %{$self->{vars}}; return scalar each %{$self->{vars}}; } sub NEXTKEY { my $self = shift; return scalar each %{$self->{vars}}; } sub UNTIE { $_[0]->Logout; } =head1 NAME Nut - a module to talk to a UPS via NUT (Network UPS Tools) upsd =head1 SYNOPSIS use UPS::Nut; $ups = new UPS::Nut( NAME => "myups", HOST => "somemachine.somewhere.com", PORT => "3493", USERNAME => "upsuser", PASSWORD => "upspasswd", TIMEOUT => 30, DEBUG => 1, DEBUGOUT => "/some/file/somewhere", ); if ($ups->Status() =~ /OB/) { print "Oh, no! Power failure!\n"; } tie %other_ups, 'UPS::Nut', NAME => "myups", HOST => "somemachine.somewhere.com", ... # same options as new(); ; print $other_ups{MFR}, " ", $other_ups{MODEL}, "\n"; =head1 DESCRIPTION This is an object-oriented (whoo!) interface between Perl and upsd from the Network UPS Tools package version 1.5 and above (https://www.networkupstools.org/). Note that it only talks to upsd for you in a Perl-ish way. It doesn't monitor the UPS continously. =head1 CONSTRUCTOR Shown with defaults: new UPS::Nut( NAME => "default", HOST => "localhost", PORT => "3493", USERNAME => "", PASSWORD => "", DEBUG => 0, DEBUGOUT => "", ); * NAME is the name of the UPS to monitor, as specified in ups.conf * HOST is the host running upsd * PORT is the port that upsd is running on * USERNAME and PASSWORD are those that you use to login to upsd. This gives you the right to do certain things, as specified in upsd.conf. * DEBUG turns on debugging output, set to 1 or 0 * DEBUGOUT is de thing you do when de s*** hits the fan. Actually, it's the filename where you want debugging output to go. If it's not specified, debugging output comes to standard output. =head1 Important notice This version of UPS::Nut is not compatible with version 0.04. It is totally rewritten in order to talk the new protocol of NUT 1.5+. You should not use this module as a drop-in replacement of previous version from 2002. Allmost all method has changed slightly. =head1 Methods Unlike in version 0.04 no methods return list values but a single reference or undef. =head2 Methods for querying UPS status =over 4 =item Getvar($varname) returns value of the specified variable. Returns undef if variable unsupported. Old method named Request() is also supported for compatibility. =item Set($varname, $value) sets the value of the specified variable. Returns undef if variable unsupported, or if variable cannot be set for some other reason. See Authenticate() if you wish to use this function. =item BattPercent() returns percentage of battery left. Returns undef if we can't get battery percentage for some reason. Same as GetVar('battery.charge'). =item LoadPercent($context) returns percentage of the load on the UPS. Returns undef if load percentage is unavailable. $context is a selector of 3 phase systems. Possibled values are 1, 2, 3, 'L1', 'L2', 'L3'. It should be omitted in case of single phase UPS. =item LineVoltage($context) returns input line (e.g. the outlet) voltage. Returns undef if line voltage is unavailable. $context is a selector of 3 phase systems. Possibled values are 1, 2, 3, 'L1', 'L2', 'L3'. It should be omitted in case of single phase UPS. =item Status() returns UPS status, one of OL or OB. OL or OB may be followed by LB, which signifies low battery state. OL or OB may also be followed by FSD, which denotes that the forced shutdown state ( see UPS::Nut->FSD() ) has been set on upsd. Returns undef if status unavailable. Same as GetVar('ups.status'). =item Temperature() returns UPS internal temperature. Returns undef if internal temperature unavailable. Same as GetVar('battery.temperature'). =back =head2 Other methods These all operate on the UPS specified in the NAME argument to the constructor. =over 4 =item Authenticate($username, $password) With NUT certain operations are only available if the user has the privilege. The program has to authenticate with one of the accounts defined in upsd.conf. =item Login($username, $password) Notify upsd that client is drawing power from the given UPS. It is automatically done if new() is called with USERNAME, PASSWORD and LOGIN parameters. =item Logout() Notify upsd that client is released UPS. (E.g. it is shutting down.) It is automatically done if connection closed. =item Master() Use this to find out whether or not we have MASTER privileges for this UPS. Returns 1 if we have MASTER privileges, returns 0 otherwise. TODO: API change pending to replace MASTER with PRIMARY (and backwards-compatible alias handling) =item ListVar($variable, ...) This is an implementation of "LIST VAR" command. Returns a hash reference to selected variable names and values supported by the UPS. If no variables given it returns all. Returns undef if "LIST VAR" failed. (Note: This method significally differs from the old ListVars() and ListRequest().) =item ListRW() Similar to ListVar() but cares only with read/writeable variables. =item ListEnum($variable) Returns a reference to the list of all possible values of $variable. List is empty if $variable is not an ENUM type. (See GetType().) Returns undef if error occurred. =item ListCmd() Returns a reference to the list of all instant commands supported by the UPS. Returns undef if these are unavailable. This method replaces the old ListInstCmds(). =item InstCmd($command) Send an instant command to the UPS. Returns 1 on success. Returns undef if the command can't be completed. =item FSD() Set the FSD (forced shutdown) flag for the UPS. This means that we're planning on shutting down the UPS very soon, so the attached load should be shut down as well. Returns 1 on success, returns undef on failure. This cannot be unset, so don't set it unless you mean it. =item Error() why did the previous operation fail? The answer is here. It will return a concise, well-written, and brilliantly insightful few words as to why whatever you just did went bang. =item GetDesc($variable) Returns textual description of $variable or undef in case of error. Old method named VarDesc() is also supported for compatibility. =item GetCmdDesc($command) This is like GetDesc() above but applies to the instant commands. Old method named InstCmdDesc() is also supported for compatibility. =item GetType($variable) Returns a string UNKNOWN or constructed one or more words of RW, ENUM and STRING:n (where n is a number). (Seems to be not working perfectly at upsd 2.2.) Old method named VarType() is also supported for compatibility. =item ListUPS() Returns a reference to hash of all available UPS names and descriptions. =back =head1 AUTOLOAD The "instant commands" are available as methods of the UPS object. They are AUTOLOADed when called. For example, if the instant command is FPTEST, then it can be called by $ups->FPTEST. =head1 TIE Interface If you wish to simply query or set values, you can tie a hash value to UPS::Nut and pass as extra options what you need to connect to the host. If you need to exercise an occasional command, you may find the return value of 'tie' useful, as in: my %ups; my $ups_obj = tie %ups, 'UPS::Nut', HOSTNAME=>"firewall"; print $ups{UPSIDENT}, "\n"; $ups_obj->Authenticate( "user", "pass" ); $ups{UPSIDENT} = "MyUPS"; =head1 AUTHOR Original version made by Kit Peters perl@clownswilleatyou.com http://www.awod.com/staff/kpeters/perl/ Rewritten by Gabor Kiss . =head1 CREDITS Developed with the kind support of A World Of Difference, Inc. Many thanks to Ryan Jessen at CyberPower Systems for much-needed assistance. Thanks to Wayne Wylupski for the code to make accessor methods for all supported vars. =head1 LICENSE This module is distributed under the same license as Perl itself. =cut 1; __END__ nut-2.8.3/scripts/Makefile.am0000644000200500020050000000563314777767434013023 00000000000000# Network UPS Tools: scripts (root) EXTRA_DIST = \ README.adoc \ avahi/nut.service.in \ HP-UX/nut-drvctl \ HP-UX/nut-drvctl.sh \ HP-UX/nut-upsd \ HP-UX/nut-upsd.sh \ HP-UX/nut-upsmon \ HP-UX/nut-upsmon.sh \ logrotate/nutlogd \ misc/nut.bash_completion \ misc/osd-notify \ perl/Nut.pm \ RedHat/halt.patch \ RedHat/README.adoc \ RedHat/ups.in \ RedHat/upsd.in \ RedHat/upsmon.in \ Solaris8/S99upsmon \ subdriver/gen-usbhid-subdriver.sh \ subdriver/gen-snmp-subdriver.sh \ upower/95-upower-hid.hwdb \ upower/95-upower-hid.rules \ usb_resetter/README.adoc \ usb_resetter/nut-driver.service \ valgrind/README.adoc \ valgrind/.valgrind.supp.in \ valgrind/valgrind.sh.in \ Windows/halt.c \ Windows/Makefile SUBDIRS = augeas devd hotplug installer python systemd udev ufw Solaris Windows upsdrvsvcctl external_apis SPELLCHECK_SRC = README.adoc RedHat/README.adoc usb_resetter/README.adoc valgrind/README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) $(AM_MAKEFLAGS) -f $(top_builddir)/docs/Makefile MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked RedHat/*-spellchecked usb_resetter/*-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.3/scripts/RedHat/0000755000200500020050000000000015001555411012152 500000000000000nut-2.8.3/scripts/RedHat/halt.patch0000644000200500020050000000241714553676503014070 00000000000000--- /etc/rc.d/init.d/halt Thu Mar 28 00:21:19 2002 +++ halt.new Fri Jan 31 15:29:49 2003 @@ -8,8 +8,17 @@ # Modified for RHS Linux by Damien Neil # +# 2003-01-31 Antonino Albanese +# Modified ups shutdown for new NUT method +# # Set the path. PATH=/sbin:/bin:/usr/bin:/usr/sbin +# load /etc/sysconfig/ups if present I've put the POWERDOWNFLAG +# in there so noboby have to manually modify the shutdown script +if [ -f /etc/sysconfig/ups ]; then + . /etc/sysconfig/ups +fi +UPSCMD=`which upsdrvctl` export NOLOCALE=1 . /etc/init.d/functions @@ -198,10 +208,15 @@ fi if [ "$command" = halt ] ; then - if [ -r /etc/ups/upsmon.conf -a -f /etc/killpower -a -f /etc/sysconfig/ups ] ; then - . /etc/sysconfig/ups - [ "$SERVER" = "yes" -a "$MODEL" != "NONE" -a -n "$MODEL" -a -n "$DEVICE" ] && $MODEL -k $DEVICE - fi +# if [ -r /etc/ups/upsmon.conf -a -f /etc/killpower -a -f /etc/sysconfig/ups ] ; then +# . /etc/sysconfig/ups +# [ "$SERVER" = "yes" -a "$MODEL" != "NONE" -a -n "$MODEL" -a -n "$DEVICE" ] && $MODEL -k $DEVICE +# fi + if [ -n "$POWERDOWNFLAG" -a -n "$UPSCMD" ]; then + if [ -f $POWERDOWNFLAG ]; then + $UPSCMD shutdown + fi + fi fi if [ -x "/sbin/halt.local" ]; then nut-2.8.3/scripts/RedHat/upsd.in0000644000200500020050000000544114777534446013431 00000000000000#!/bin/sh # # chkconfig: 2345 30 90 # # 2022-01-04 Jim Klimov # Updated .in template, double-quoted variable expansions # # 2003-01-31 Antonino Albanese # Removed all old statements # start programs as user nut # new style starting and stopping upsd # added reload option # use of /etc/sysconfig/ups for POWERDOWNFLAG variable retrieving # # 2002-02-07 Nigel Metheringham # made ups.conf pre-eminant, added new upsdrvctl functions, targeted for RH7.2, should # work OK on RH 6.x, 7.x # 2001-10-24 Peter Bieringer # enhancements for new style drivers and controls, tested on a RHL 7.1.93 system # # description: NUT upsd and its drivers directly monitor a ups and \ # make information from it available to other programs # processname: upsd # config: @CONFPATH@/upsd.conf # config: @CONFPATH@/ups.conf PATH="/sbin:/bin:/usr/sbin:/usr/bin" export PATH # Source function library. . /etc/rc.d/init.d/functions # POWERDOWNFLAG *must* match that in upsmon.conf # Loading POWERDOWNFLAG from /etc/sysconfig/ups DRIVERPATH="@DRVPATH@" NUT_SBINDIR="@SBINDIR@" if [ -f /etc/sysconfig/ups ]; then . /etc/sysconfig/ups else POWERDOWNFLAG="@POWERDOWNFLAG@" NUTUSER="@RUN_AS_USER@" fi UPSDCONF="@CONFPATH@/upsd.conf" UPSCONF="@CONFPATH@/ups.conf" if [ -n "$DRIVERPATH" -a -d "$DRIVERPATH" ]; then PATH="$DRIVERPATH:$PATH" fi if [ -n "$NUT_SBINDIR" -a -d "$NUT_SBINDIR" ]; then PATH="$NUT_SBINDIR:$PATH" fi # if there are no config file, bail out [ -f "$UPSDCONF" ] && [ -f "$UPSCONF" ] || exit 0 NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY runcmd() { echo -n "$1 " shift if [ "$BOOTUP" = "color" ]; then $* && echo_success || echo_failure else $* fi echo } # See how we are called. case "$1" in start) # new style drivers uses 'upsdrvctl' echo -n "NUT Starting UPS model drivers: " # starting all drivers as nut user daemon --user "$NUTUSER" "`which upsdrvctl`" start echo if [ $? -eq 0 ]; then echo -n "NUT Starting UPS daemon: " # starting as nut user daemon upsd -u "$NUTUSER" echo touch /var/lock/subsys/upsd fi ;; stop) # new style upsd stop action "NUT Stopping UPS daemon" \ upsd -c stop # new style drivers uses 'upsdrvctl' action "NUT Stopping UPS model drivers" \ upsdrvctl stop rm -f /var/lock/subsys/upsd ;; powerdown) # new style drivers runcmd "NUT powerdown of attached UPS(es)" upsdrvctl shutdown ;; restart) $0 stop $0 start ;; reload) # reloading upsd config files action "NUT Reloading config files" \ upsd -c reload ;; status) # new style drivers action "NUT: checking UPS model drivers" upsdrvctl status status upsd ;; *) echo "Usage: upsd {start|stop|powerdown|restart|reload|status}" exit 1 esac nut-2.8.3/scripts/RedHat/README.adoc0000644000200500020050000000036414777534446013712 00000000000000NUT integration files for older RedHat based Linux distributions ================================================================ Install `ups` in `/etc/rc.d/init.d` The `/etc/sysconfig/ups` is used only to store the `POWERDOWNFLAG` variable nut-2.8.3/scripts/RedHat/upsmon.in0000644000200500020050000000243314777534446013775 00000000000000#!/bin/sh # # chkconfig: 2345 31 89 # # 2022-01-04 Jim Klimov # Updated .in template, double-quoted variable expansions # # 2003-01-31 Antonino Albanese # start program as user nut # new style stopping upsmon # added reload option # # description: upsmon talks to upsd and notifies of ups status changes \ # also shutting systems down if required. # processname: upsmon # config: @CONFPATH@/upsmon.conf PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH # Source function library. . /etc/rc.d/init.d/functions NUT_SBINDIR="@SBINDIR@" if [ -f /etc/sysconfig/ups ]; then . /etc/sysconfig/ups else POWERDOWNFLAG="@POWERDOWNFLAG@" NUTUSER="@RUN_AS_USER@" fi if [ -n "$NUT_SBINDIR" -a -d "$NUT_SBINDIR" ]; then PATH="$NUT_SBINDIR:$PATH" fi NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY # See how we are called. case "$1" in start) action "NUT Starting UPS monitor" upsmon -u "$NUTUSER" touch /var/lock/subsys/upsmon ;; stop) action "NUT Stopping UPS monitor: " \ upsmon -c stop rm -f /var/lock/subsys/upsmon ;; restart) $0 stop $0 start ;; reload) action "NUT Reloading UPS monitor: " \ upsmon -c reload ;; status) status upsmon ;; *) echo "Usage: upsmon {start|stop|restart|reload|status}" exit 1 esac nut-2.8.3/scripts/RedHat/ups.in0000644000200500020050000000015114777534446013256 00000000000000# POWERDOWNFLAG *must* match that in upsmon.conf POWERDOWNFLAG="@POWERDOWNFLAG@" NUTUSER="@RUN_AS_USER@" nut-2.8.3/scripts/python/0000755000200500020050000000000015001555411012324 500000000000000nut-2.8.3/scripts/python/app/0000755000200500020050000000000015001555412013105 500000000000000nut-2.8.3/scripts/python/app/NUT-Monitor-py3qt5.in0000755000200500020050000013771014777767434016663 00000000000000#!@PYTHON3@ # -*- coding: utf-8 -*- # 2009-12-27 David Goncalves - Version 1.2 # Total rewrite of NUT-Monitor to optimize GUI interaction. # Added favorites support (saved to user's home) # Added status icon on the notification area # # 2010-02-26 David Goncalves # Added UPS vars display and the possibility to change values # when user double-clicks on a RW var. # # 2010-05-01 David Goncalves # Added support for PyNotify (if available) # # 2010-05-05 David Goncalves # Added support for command line options # -> --start-hidden # -> --favorite # # NUT-Monitor now tries to detect if there is a NUT server # on localhost and if there is 1 UPS, connects to it. # # 2010-10-06 David Goncalves - Version 1.3 # Added localisation support # # 2015-02-14 Michal Fincham - Version 1.3.1 # Corrected unsafe permissions on ~/.nut-monitor (Debian #777706) # # 2022-02-20 Luke Dashjr - Version 2.0 # Port to Python 3 with PyQt5. # # 2023-11-27 Laurent Bigonville - Version 2.0.1 # Set the DesktopFileName # # 2025-03-15 Jim Klimov - Version 2.0.2 # Revise localisation, inject PACKAGE_VERSION and NUT_WEBSITE_BASE # into the About dialog contents import PyQt5.uic from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * import sys import base64 import os, os.path import stat import platform import time import threading import optparse import configparser import locale import gettext # Try local development/accompanying packaging first, # then system installation sys_path_orig = sys.path.copy() try: # Try "module" path relative to this program script: mod_path = os.path.sep.join([ os.path.dirname(os.path.abspath(os.path.realpath(__file__))), "..", "module"]) ### sys.stderr.write("[D] mod_path: %s\n" % mod_path) if os.path.isfile(os.path.sep.join([mod_path, "PyNUT.py"])): # Insert into the system path at index 1 to ensure that it # resolves after the main script but before anything else: sys.path.insert(1, mod_path) ### sys.stderr.write("[D] sys.path: %s\n" % sys.path) # Try our chances with the default or augmented path import PyNUT except Exception as ignored: # ModuleNotFoundError, path/parsing, et al # Try our chances with the default path: sys.path = sys_path_orig ### sys.stderr.write("[D2] sys.path: %s\n" % sys.path) import PyNUT # We would seek locale files relative to script dir os.chdir(os.path.dirname(os.path.abspath(os.path.realpath(__file__)))) # print(os.getcwd()) class interface : DESIRED_FAVORITES_DIRECTORY_MODE = 0o700 __widgets = {} __callbacks = {} __favorites = {} __favorites_file = None __favorites_path = "" __fav_menu_items = list() __window_visible = True __ui_file = None __connected = False __ups_handler = None __ups_commands = None __ups_vars = None __ups_rw_vars = None __gui_thread = None __current_ups = None def __init__( self, argv ) : # Before anything, parse command line options if any present... opt_parser = optparse.OptionParser() opt_parser.add_option( "-H", "--start-hidden", action="store_true", default=False, dest="hidden", help="Start iconified in tray" ) opt_parser.add_option( "-F", "--favorite", dest="favorite", help="Load the specified favorite and connect to UPS" ) ( cmd_opts, args ) = opt_parser.parse_args() self.__app = QApplication( argv ) try: self.__app.setDesktopFileName("nut-monitor-py3qt5") except Exception as ex: pass self.__ui_file = self.__find_res_file( 'ui', "window1.ui" ) self.__widgets["interface"] = PyQt5.uic.loadUi( self.__ui_file ) self.__widgets["main_window"] = self.__widgets["interface"] self.__widgets["status_bar"] = self.__widgets["interface"].statusbar2 self.__widgets["ups_host_entry"] = self.__widgets["interface"].entry1 self.__widgets["ups_port_entry"] = self.__widgets["interface"].spinbutton1 self.__widgets["ups_refresh_button"] = self.__widgets["interface"].button1 self.__widgets["ups_authentication_check"] = self.__widgets["interface"].checkbutton1 self.__widgets["ups_authentication_frame"] = self.__widgets["interface"].hbox1 self.__widgets["ups_authentication_login"] = self.__widgets["interface"].entry2 self.__widgets["ups_authentication_password"] = self.__widgets["interface"].entry3 self.__widgets["ups_list_combo"] = self.__widgets["interface"].combobox1 self.__widgets["ups_commands_combo"] = self.__widgets["interface"].ups_commands_combo self.__widgets["ups_commands_button"] = self.__widgets["interface"].button8 self.__widgets["ups_connect"] = self.__widgets["interface"].button2 self.__widgets["ups_disconnect"] = self.__widgets["interface"].button7 self.__widgets["ups_params_box"] = self.__widgets["interface"].vbox6 self.__widgets["ups_infos"] = self.__widgets["interface"].notebook1 self.__widgets["ups_vars_tree"] = self.__widgets["interface"].treeview1 self.__widgets["ups_vars_refresh"] = self.__widgets["interface"].button9 self.__widgets["ups_status_image"] = self.__widgets["interface"].image1 self.__widgets["ups_status_left"] = self.__widgets["interface"].label10 self.__widgets["ups_status_right"] = self.__widgets["interface"].label11 self.__widgets["ups_status_time"] = self.__widgets["interface"].label15 self.__widgets["menu_favorites_root"] = self.__widgets["interface"].menu2 self.__widgets["menu_favorites"] = self.__widgets["interface"].menu2 self.__widgets["menu_favorites_add"] = self.__widgets["interface"].menuitem4 self.__widgets["menu_favorites_del"] = self.__widgets["interface"].menuitem5 self.__widgets["progress_battery_charge"] = self.__widgets["interface"].progressbar1 self.__widgets["progress_battery_load"] = self.__widgets["interface"].progressbar2 # Create the tray icon and connect it to the show/hide method... self.__widgets["status_icon"] = QSystemTrayIcon( QIcon( self.__find_res_file( "pixmaps", "on_line.png" ) ) ) self.__widgets["status_icon"].setVisible( True ) self.__widgets["status_icon"].activated.connect( self.tray_activated ) self.__widgets["ups_status_image"].setPixmap( QPixmap( self.__find_res_file( "pixmaps", "on_line.png" ) ) ) # Connect interface callbacks actions self.__widgets["main_window"].destroyed.connect( self.quit ) self.__widgets["interface"].imagemenuitem1.triggered.connect( self.gui_about_dialog ) self.__widgets["interface"].imagemenuitem5.triggered.connect( self.quit ) self.__widgets["ups_host_entry"].textChanged.connect( self.__check_gui_fields ) self.__widgets["ups_authentication_login"].textChanged.connect( self.__check_gui_fields ) self.__widgets["ups_authentication_password"].textChanged.connect( self.__check_gui_fields ) self.__widgets["ups_authentication_check"].stateChanged.connect( self.__check_gui_fields ) self.__widgets["ups_port_entry"].valueChanged.connect( self.__check_gui_fields ) self.__widgets["ups_refresh_button"].clicked.connect( self.__update_ups_list ) self.__widgets["ups_connect"].clicked.connect( self.connect_to_ups ) self.__widgets["ups_disconnect"].clicked.connect( self.disconnect_from_ups ) self.__widgets["ups_vars_refresh"].clicked.connect( self.__gui_update_ups_vars_view ) self.__widgets["menu_favorites_add"].triggered.connect( self.__gui_add_favorite ) self.__widgets["menu_favorites_del"].triggered.connect( self.__gui_delete_favorite ) self.__widgets["ups_vars_tree"].doubleClicked.connect( self.__gui_ups_vars_selected ) # Remove the dummy combobox entry on UPS List and Commands self.__widgets["ups_list_combo"].removeItem( 0 ) # Set UPS vars treeview properties ----------------------------- store = QStandardItemModel( 0, 3, self.__widgets["ups_vars_tree"] ) self.__widgets["ups_vars_tree"].setModel( store ) self.__widgets["ups_vars_tree"].setHeaderHidden( False ) self.__widgets["ups_vars_tree"].setRootIsDecorated( False ) # Column 0 store.setHeaderData( 0, Qt.Horizontal, '' ) # Column 1 store.setHeaderData( 1, Qt.Horizontal, _('Var name') ) # Column 2 store.setHeaderData( 2, Qt.Horizontal, _('Value') ) self.__widgets["ups_vars_tree"].header().setStretchLastSection( True ) self.__widgets["ups_vars_tree"].sortByColumn( 1, Qt.AscendingOrder ) self.__widgets["ups_vars_tree_store"] = store self.__widgets["ups_vars_tree"].setMinimumSize( 0, 50 ) #--------------------------------------------------------------- # UPS Commands combo box creation ------------------------------ ups_commands_height = self.__widgets["ups_commands_combo"].size().height() * 2 self.__widgets["ups_commands_combo"].setMinimumSize(0, ups_commands_height) self.__widgets["ups_commands_combo"].setCurrentIndex( 0 ) self.__widgets["ups_commands_button"].setMinimumSize(0, ups_commands_height) self.__widgets["ups_commands_button"].clicked.connect( self.__gui_send_ups_command ) self.__widgets["ups_commands_combo_store"] = self.__widgets["ups_commands_combo"] #--------------------------------------------------------------- self.gui_init_unconnected() if ( cmd_opts.hidden != True ) : self.__widgets["main_window"].show() # Define favorites path and load favorites if ( platform.system() == "Linux" ) : self.__favorites_path = os.path.join( os.environ.get("HOME"), ".nut-monitor" ) elif ( platform.system() == "Windows" ) : self.__favorites_path = os.path.join( os.environ.get("USERPROFILE"), "Application Data", "NUT-Monitor" ) self.__favorites_file = os.path.join( self.__favorites_path, "favorites.ini" ) self.__parse_favorites() self.gui_status_message( _("Welcome to NUT Monitor") ) if ( cmd_opts.favorite != None ) : if ( cmd_opts.favorite in self.__favorites ) : self.__gui_load_favorite( fav_name=cmd_opts.favorite ) self.connect_to_ups() else : # Try to scan localhost for available ups and connect to it if there is only one self.__widgets["ups_host_entry"].setText( "localhost" ) self.__update_ups_list() if self.__widgets["ups_list_combo"].count() == 1: self.connect_to_ups() def exec( self ) : self.__app.exec() def __find_res_file( self, ftype, filename ) : # print("%s ~ %s => '%s' '%s'\n" % (os.getcwd(), os.path.dirname( sys.argv[0] ), ftype, filename)) filename = os.path.join( ftype, filename ) # We would be in script dir if os.path.exists(filename): return filename # TODO: Skip checking application directory if installed path = os.path.join( os.path.dirname( sys.argv[0] ), filename ) if os.path.exists(path): return path path = QStandardPaths.locate(QStandardPaths.AppDataLocation, filename) if os.path.exists(path): return path raise RuntimeError("Cannot find %s resource %s" % (ftype, filename)) def __find_icon_file( self ) : filename = 'nut-monitor.png' # TODO: Skip checking application directory if installed path = os.path.join( "icons", "256x256", filename ) if os.path.exists(path): return path path = os.path.join( os.path.dirname( sys.argv[0] ), "icons", "256x256", filename ) if os.path.exists(path): return path # Normally icons should be installed to OS location by packaging: path = QStandardPaths.locate(QStandardPaths.GenericDataLocation, os.path.join( "icons", "hicolor", "256x256", "apps", filename ) ) if os.path.exists(path): return path # Fall back to NUT-specific area where `make install` might put them, # e.g. /usr/share/nut/nut-monitor/icons/... or some such, if not the # same location as checked in first attempt above: path = QStandardPaths.locate(QStandardPaths.AppDataLocation, os.path.join( "icons", "hicolor", "256x256", "apps", filename ) ) if os.path.exists(path): return path # No banana! raise RuntimeError("Cannot find %s resource %s" % ('icon', filename)) # Check if correct fields are filled to enable connection to the UPS def __check_gui_fields( self, widget=None ) : # If UPS list contains something, clear it if self.__widgets["ups_list_combo"].currentIndex() != -1 : self.__widgets["ups_list_combo"].clear() self.__widgets["ups_connect"].setEnabled( False ) self.__widgets["menu_favorites_add"].setEnabled( False ) # Host/Port selection if len( self.__widgets["ups_host_entry"].text() ) > 0 : sensitive = True # If authentication is selected, check that we have a login and password if self.__widgets["ups_authentication_check"].isChecked() : if len( self.__widgets["ups_authentication_login"].text() ) == 0 : sensitive = False if len( self.__widgets["ups_authentication_password"].text() ) == 0 : sensitive = False self.__widgets["ups_refresh_button"].setEnabled( sensitive ) if not sensitive : self.__widgets["ups_connect"].setEnabled( False ) self.__widgets["menu_favorites_add"].setEnabled( False ) else : self.__widgets["ups_refresh_button"].setEnabled( False ) self.__widgets["ups_connect"].setEnabled( False ) self.__widgets["menu_favorites_add"].setEnabled( False ) # Use authentication fields... if self.__widgets["ups_authentication_check"].isChecked() : self.__widgets["ups_authentication_frame"].setEnabled( True ) else : self.__widgets["ups_authentication_frame"].setEnabled( False ) self.gui_status_message() #------------------------------------------------------------------- # This method is used to show/hide the main window when user clicks on the tray icon def tray_activated( self, widget=None, data=None ) : if self.__window_visible : self.__widgets["main_window"].hide() else : self.__widgets["main_window"].show() self.__window_visible = not self.__window_visible #------------------------------------------------------------------- # Change the status icon and tray icon def change_status_icon( self, icon="on_line", blink=False ) : self.__widgets["status_icon"].setIcon( QIcon( self.__find_res_file( "pixmaps", "%s.png" % icon ) ) ) self.__widgets["ups_status_image"].setPixmap( QPixmap( self.__find_res_file( "pixmaps", "%s.png" % icon ) ) ) # TODO self.__widgets["status_icon"].set_blinking( blink ) #------------------------------------------------------------------- # This method connects to the NUT server and retrieve availables UPSes # using connection parameters (host, port, login, pass...) def __update_ups_list( self, widget=None ) : host = self.__widgets["ups_host_entry"].text() port = int( self.__widgets["ups_port_entry"].value() ) login = None password = None if self.__widgets["ups_authentication_check"].isChecked() : login = self.__widgets["ups_authentication_login"].text() password = self.__widgets["ups_authentication_password"].text() try : nut_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password ) upses = nut_handler.GetUPSList() ups_list = list(key.decode('ascii') for key in upses.keys()) ups_list.sort() # If UPS list contains something, clear it self.__widgets["ups_list_combo"].clear() for current in ups_list : self.__widgets["ups_list_combo"].addItem( current ) self.__widgets["ups_list_combo"].setCurrentIndex( 0 ) self.__widgets["ups_connect"].setEnabled( True ) self.__widgets["menu_favorites_add"].setEnabled( True ) self.gui_status_message( _("Found {0} devices on {1}").format( len( ups_list ), host ) ) except : error_msg = _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) self.gui_status_message( error_msg ) #------------------------------------------------------------------- # Quit program def quit( self, widget=None ) : # If we are connected to an UPS, disconnect first... if self.__connected : self.gui_status_message( _("Disconnecting from device") ) self.disconnect_from_ups() self.__app.quit() #------------------------------------------------------------------- # Method called when user wants to add a new favorite entry. It # displays a dialog to enable user to select the name of the favorite def __gui_add_favorite( self, widget=None ) : dialog_ui_file = self.__find_res_file( 'ui', "dialog1.ui" ) dialog = PyQt5.uic.loadUi( dialog_ui_file ) # Define interface callbacks actions def check_entry(val): if self.__gui_add_favorite_check_gui_fields(val): dialog.buttonBox.button(QDialogButtonBox.Ok).setEnabled( True ) else: dialog.buttonBox.button(QDialogButtonBox.Ok).setEnabled( False ) dialog.entry4.textChanged.connect( check_entry ) self.__widgets["main_window"].setEnabled( False ) rc = dialog.exec() if rc == QDialog.Accepted : fav_data = {} fav_data["host"] = self.__widgets["ups_host_entry"].text() fav_data["port"] = "%d" % self.__widgets["ups_port_entry"].value() fav_data["ups"] = self.__widgets["ups_list_combo"].currentText() fav_data["auth"] = self.__widgets["ups_authentication_check"].isChecked() if fav_data["auth"] : fav_data["login"] = self.__widgets["ups_authentication_login"].text() fav_data["password"] = base64.b64encode( self.__widgets["ups_authentication_password"].text().encode('ascii') ).decode('ascii') fav_name = dialog.entry4.text() self.__favorites[ fav_name ] = fav_data self.__gui_refresh_favorites_menu() # Save all favorites self.__save_favorites() self.__widgets["main_window"].setEnabled( True ) #------------------------------------------------------------------- # Method called when user wants to delete an entry from favorites def __gui_delete_favorite( self, widget=None ) : dialog_ui_file = self.__find_res_file( 'ui', "dialog2.ui" ) dialog = PyQt5.uic.loadUi( dialog_ui_file ) # Remove the dummy combobox entry on list dialog.combobox2.removeItem( 0 ) favs = list(self.__favorites.keys()) favs.sort() for current in favs : dialog.combobox2.addItem( current ) dialog.combobox2.setCurrentIndex( 0 ) self.__widgets["main_window"].setEnabled( False ) rc = dialog.exec() fav_name = dialog.combobox2.currentText() self.__widgets["main_window"].setEnabled( True ) if ( rc == QDialog.Accepted ) : # Remove entry, show confirmation dialog resp = QMessageBox.question( None, self.__widgets["main_window"].windowTitle(), _("Are you sure that you want to remove this favorite ?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes ) if ( resp == QMessageBox.Yes ) : del self.__favorites[ fav_name ] self.__gui_refresh_favorites_menu() self.__save_favorites() self.gui_status_message( _("Removed favorite '%s'") % fav_name ) #------------------------------------------------------------------- # Method called when user selects a favorite from the favorites menu def __gui_load_favorite( self, fav_name="" ) : if ( fav_name in self.__favorites ) : # If auth is activated, process it before other fields to avoir weird # reactions with the 'check_gui_fields' function. if ( self.__favorites[fav_name].get("auth", False ) ) : self.__widgets["ups_authentication_check"].setChecked( True ) self.__widgets["ups_authentication_login"].setText( self.__favorites[fav_name].get("login","") ) self.__widgets["ups_authentication_password"].setText( self.__favorites[fav_name].get("password","") ) self.__widgets["ups_host_entry"].setText( self.__favorites[fav_name].get("host","") ) self.__widgets["ups_port_entry"].setValue( int( self.__favorites[fav_name].get( "port", 3493 ) ) ) # Clear UPS list and add current UPS name self.__widgets["ups_list_combo"].clear() self.__widgets["ups_list_combo"].addItem( self.__favorites[fav_name].get("ups","") ) self.__widgets["ups_list_combo"].setCurrentIndex( 0 ) # Activate the connect button self.__widgets["ups_connect"].setEnabled( True ) self.gui_status_message( _("Loaded '%s'") % fav_name ) #------------------------------------------------------------------- # Send the selected command to the UPS def __gui_send_ups_command( self, widget=None ) : offset = self.__widgets["ups_commands_combo"].currentIndex() cmd = self.__ups_commands[ offset ].decode('ascii') self.__widgets["main_window"].setEnabled( False ) resp = QMessageBox.question( None, self.__widgets["main_window"].windowTitle(), _("Are you sure that you want to send '%s' to the device ?") % cmd, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes ) self.__widgets["main_window"].setEnabled( True ) if ( resp == QMessageBox.Yes ) : try : self.__ups_handler.RunUPSCommand( self.__current_ups, cmd ) self.gui_status_message( _("Sent '{0}' command to {1}").format( cmd, self.__current_ups ) ) except : self.gui_status_message( _("Failed to send '{0}' ({1})").format( cmd, sys.exc_info()[1] ) ) #------------------------------------------------------------------- # Method called when user clicks on the UPS vars treeview. If the user # performs a double click on a RW var, the GUI shows the update var dialog. def __gui_ups_vars_selected( self, index ) : if True : model = self.__widgets["ups_vars_tree_store"] try : ups_var = model.data( index.siblingAtColumn(1) ).encode('ascii') if ( ups_var in self.__ups_rw_vars ) : # The selected var is RW, then we can show the update dialog cur_val = self.__ups_rw_vars.get(ups_var).decode('ascii') self.__widgets["main_window"].setEnabled( False ) new_val, rc = QInputDialog.getText( None, self.__widgets["main_window"].windowTitle(), _("Enter a new value for the variable.

{0} = {1} (current value)").format( ups_var, cur_val), QLineEdit.Normal, cur_val ) self.__widgets["main_window"].setEnabled( True ) if ( rc ) : try : self.__ups_handler.SetRWVar( ups=self.__current_ups, var=ups_var.decode('ascii'), value=new_val ) self.gui_status_message( _("Updated variable on %s") % self.__current_ups ) # Change the value on the local dict to update the GUI new_val = new_val.encode('ascii') self.__ups_vars[ups_var] = new_val self.__ups_rw_vars[ups_var] = new_val self.__gui_update_ups_vars_view() except : error_msg = _("Error updating variable on '{0}' ({1})").format( self.__current_ups, sys.exc_info()[1] ) self.gui_status_message( error_msg ) else : # User cancelled modification... error_msg = _("No variable modified on %s - User cancelled") % self.__current_ups self.gui_status_message( error_msg ) except : # Failed to get information from the treeview... skip action pass #------------------------------------------------------------------- # Refresh the content of the favorites menu according to the defined favorites def __gui_refresh_favorites_menu( self ) : for current in self.__fav_menu_items : self.__widgets["menu_favorites"].removeAction(current) self.__fav_menu_items = list() items = list(self.__favorites.keys()) items.sort() for current in items : menu_item = QAction( current ) self.__fav_menu_items.append( menu_item ) self.__widgets["menu_favorites"].addAction( menu_item ) menu_item.triggered.connect( lambda: self.__gui_load_favorite( current ) ) if len( items ) > 0 : self.__widgets["menu_favorites_del"].setEnabled( True ) else : self.__widgets["menu_favorites_del"].setEnabled( False ) #------------------------------------------------------------------- # In 'add favorites' dialog, this method compares the content of the # text widget representing the name of the new favorite with existing # ones. If they match, the 'add' button will be set to non sensitive # to avoid creating entries with the same name. def __gui_add_favorite_check_gui_fields( self, fav_name ) : if ( len( fav_name ) > 0 ) and ( fav_name not in list(self.__favorites.keys()) ) : return True else : return False #------------------------------------------------------------------- # Load and parse favorites def __parse_favorites( self ) : if ( not os.path.exists( self.__favorites_file ) ) : # There is no favorites files, do nothing return try : if ( not stat.S_IMODE( os.stat( self.__favorites_path ).st_mode ) == self.DESIRED_FAVORITES_DIRECTORY_MODE ) : # unsafe pre-1.2 directory found os.chmod( self.__favorites_path, self.DESIRED_FAVORITES_DIRECTORY_MODE ) conf = configparser.ConfigParser() conf.read( self.__favorites_file ) for current in conf.sections() : # Check if mandatory fields are present if ( conf.has_option( current, "host" ) and conf.has_option( current, "ups" ) ) : # Valid entry found, add it to the list fav_data = {} fav_data["host"] = conf.get( current, "host" ) fav_data["ups"] = conf.get( current, "ups" ) if ( conf.has_option( current, "port" ) ) : fav_data["port"] = conf.get( current, "port" ) else : fav_data["port"] = "3493" # If auth is defined the section must have login and pass defined if ( conf.has_option( current, "auth" ) ) : if( conf.has_option( current, "login" ) and conf.has_option( current, "password" ) ) : # Add the entry fav_data["auth"] = conf.getboolean( current, "auth" ) fav_data["login"] = conf.get( current, "login" ) try : fav_data["password"] = base64.decodebytes( conf.get( current, "password" ).encode('ascii') ).decode('ascii') except : # If the password is not in base64, let the field empty print(( _("Error parsing favorites, password for '%s' is not in base64\nSkipping password for this entry") % current )) fav_data["password"] = "" else : fav_data["auth"] = False self.__favorites[current] = fav_data self.__gui_refresh_favorites_menu() except : self.gui_status_message( _("Error while parsing favorites file (%s)") % sys.exc_info()[1] ) #------------------------------------------------------------------- # Save favorites to the defined favorites file using ini format def __save_favorites( self ) : # If path does not exists, try to create it if ( not os.path.exists( self.__favorites_file ) ) : try : os.makedirs( self.__favorites_path, mode=self.DESIRED_FAVORITES_DIRECTORY_MODE, exist_ok=True ) except : self.gui_status_message( _("Error while creating configuration folder (%s)") % sys.exc_info()[1] ) save_conf = configparser.ConfigParser() for current in list(self.__favorites.keys()) : save_conf.add_section( current ) for k, v in self.__favorites[ current ].items() : if isinstance( v, bool ) : v = str( v ) save_conf.set( current, k, v ) try : fh = open( self.__favorites_file, "w" ) save_conf.write( fh ) fh.close() self.gui_status_message( _("Saved favorites...") ) except : self.gui_status_message( _("Error while saving favorites (%s)") % sys.exc_info()[1] ) #------------------------------------------------------------------- # Display the about dialog def gui_about_dialog( self, widget=None ) : self.__widgets["main_window"].adjustSize() dialog_ui_file = self.__find_res_file( 'ui', "aboutdialog1.ui" ) dialog = PyQt5.uic.loadUi( dialog_ui_file ) dialog.icon.setPixmap( QPixmap( self.__find_icon_file() ) ) ### sys.stderr.write("gui_about_dialog(): dialog=%s\n" % str(dir(dialog))) ### sys.stderr.write("gui_about_dialog(): label=%s\n" % str(dir(dialog.label))) ### sys.stderr.write("gui_about_dialog(): text=%s\n" % str(dir(dialog.label.text))) s = dialog.label.text() ### sys.stderr.write("gui_about_dialog(): s (original) ='%s'\n" % s) s = _(s) ### sys.stderr.write("gui_about_dialog(): s (localized) ='%s'\n" % s) s = (s .replace('%s%s%s' % ("@", "PACKAGE_VERSION", "@"), '@PACKAGE_VERSION@') .replace('%s%s%s' % ("@", "NUT_WEBSITE_BASE", "@"), '@NUT_WEBSITE_BASE@') ) ### sys.stderr.write("gui_about_dialog(): s (rewritten) ='%s'\n" % s) dialog.label.setText(s) credits_button = QPushButton( dialog ) credits_button.setText( _("C&redits") ) credits_button.setIcon( dialog.style().standardIcon( QStyle.SP_MessageBoxInformation ) ) credits_button.clicked.connect( self.gui_about_credits ) licence_button = QPushButton( dialog ) licence_button.setText( _("&Licence") ) licence_button.clicked.connect( self.gui_about_licence ) dialog.buttonBox.addButton( credits_button, QDialogButtonBox.HelpRole ) dialog.buttonBox.addButton( licence_button, QDialogButtonBox.HelpRole ) self.__widgets["main_window"].setEnabled( False ) dialog.exec() self.__widgets["main_window"].setEnabled( True ) def gui_about_credits( self ) : QMessageBox.about( None, _("Credits"), _(""" Written by: David Goncalves Translated by: David Goncalves - Français Daniele Pezzini - Italiano Alexey Rodionov - Russian """).strip() ) def gui_about_licence( self ) : QMessageBox.about( None, _("Licence"), _(""" Copyright (C) 2010 David Goncalves Copyright (C) since 2010 by NUT Community 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 . """).strip() ) #------------------------------------------------------------------- # Display a message on the status bar. The message is also set as # tooltip to enable users to see long messages. def gui_status_message( self, msg="" ) : text = msg message_id = self.__widgets["status_bar"].showMessage( text.replace("\n", "") ) self.__widgets["status_bar"].setToolTip( text ) #------------------------------------------------------------------- # Display a notification using QSystemTrayIcon with an optional icon def gui_status_notification( self, message="", icon_file="" ) : if ( icon_file != "" ) : icon = QIcon( os.path.abspath( self.__find_res_file( "pixmaps", icon_file ) ) ) else : icon = None self.__widgets["status_icon"].showMessage( "NUT Monitor", message, icon ) #------------------------------------------------------------------- # Connect to the selected UPS using parameters (host,port,login,pass) def connect_to_ups( self, widget=None ) : host = self.__widgets["ups_host_entry"].text() port = int( self.__widgets["ups_port_entry"].value() ) login = None password = None if self.__widgets["ups_authentication_check"].isChecked() : login = self.__widgets["ups_authentication_login"].text() password = self.__widgets["ups_authentication_password"].text() try : self.__ups_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password ) except : self.gui_status_message( _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) ) self.gui_status_notification( _("Error connecting to '{0}'\n{1}").format( host, sys.exc_info()[1] ), "warning.png" ) return # Check if selected UPS exists on server... srv_upses = self.__ups_handler.GetUPSList() self.__current_ups = self.__widgets["ups_list_combo"].currentText() if self.__current_ups.encode('ascii') not in srv_upses : self.gui_status_message( _("Device '%s' not found on server") % self.__current_ups ) self.gui_status_notification( _("Device '%s' not found on server") % self.__current_ups, "warning.png" ) return if not self.__ups_handler.CheckUPSAvailable( self.__current_ups ): self.gui_status_message( _("UPS '{0}' is not reachable").format( self.__current_ups ) ) self.gui_status_notification( _("UPS '{0}' is not reachable").format( self.__current_ups ), "warning.png" ) return self.__connected = True self.__widgets["ups_connect"].hide() self.__widgets["ups_disconnect"].show() self.__widgets["ups_infos"].show() self.__widgets["ups_params_box"].setEnabled( False ) self.__widgets["menu_favorites_root"].setEnabled( False ) self.__widgets["ups_params_box"].hide() commands = self.__ups_handler.GetUPSCommands( self.__current_ups ) self.__ups_commands = list(commands.keys()) self.__ups_commands.sort() # Refresh UPS commands combo box self.__widgets["ups_commands_combo_store"].clear() for desc in self.__ups_commands : # TODO: Style as "%s
%s" self.__widgets["ups_commands_combo_store"].addItem( "%s\n%s" % ( desc.decode('ascii'), commands[desc].decode('ascii') ) ) self.__widgets["ups_commands_combo"].setCurrentIndex( 0 ) # Update UPS vars manually before the thread self.__ups_vars = self.__ups_handler.GetUPSVars( self.__current_ups ) self.__ups_rw_vars = self.__ups_handler.GetRWVars( self.__current_ups ) self.__gui_update_ups_vars_view() # Try to resize the main window... # FIXME: For some reason, calling this immediately doesn't work right QTimer.singleShot(10, self.__widgets["main_window"].adjustSize) # Start the GUI updater thread self.__gui_thread = gui_updater( self ) self.__gui_thread.start() self.gui_status_message( _("Connected to '{0}' on {1}").format( self.__current_ups, host ) ) #------------------------------------------------------------------- # Refresh UPS vars in the treeview def __gui_update_ups_vars_view( self, widget=None ) : if self.__ups_handler : vars = self.__ups_vars rwvars = self.__ups_rw_vars self.__widgets["ups_vars_tree_store"].removeRows(0, self.__widgets["ups_vars_tree_store"].rowCount()) for k,v in vars.items() : if ( k in rwvars ) : icon_file = self.__find_res_file( "pixmaps", "var-rw.png" ) else : icon_file = self.__find_res_file( "pixmaps", "var-ro.png" ) icon = QIcon( icon_file ) item_icon = QStandardItem(icon, '') item_icon.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren) item_var_name = QStandardItem( k.decode('ascii') ) item_var_name.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren) item_var_val = QStandardItem( v.decode('ascii') ) item_var_val.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemNeverHasChildren) self.__widgets["ups_vars_tree_store"].appendRow( (item_icon, item_var_name, item_var_val) ) self.__widgets["ups_vars_tree"].resizeColumnToContents( 0 ) self.__widgets["ups_vars_tree"].resizeColumnToContents( 1 ) def gui_init_unconnected( self ) : self.__connected = False self.__widgets["ups_connect"].show() self.__widgets["ups_disconnect"].hide() self.__widgets["ups_infos"].hide() self.__widgets["ups_params_box"].setEnabled( True ) self.__widgets["menu_favorites_root"].setEnabled( True ) self.__widgets["status_icon"].setToolTip( _("Not connected") ) self.__widgets["ups_params_box"].show() # Try to resize the main window... self.__widgets["main_window"].adjustSize() #------------------------------------------------------------------- # Disconnect from the UPS def disconnect_from_ups( self, widget=None ) : self.gui_init_unconnected() # Stop the GUI updater thread self.__gui_thread.stop_thread() del self.__ups_handler self.gui_status_message( _("Disconnected from '%s'") % self.__current_ups ) self.change_status_icon( "on_line", blink=False ) self.__current_ups = None #----------------------------------------------------------------------- # GUI Updater class # This class updates the main gui with data from connected UPS class gui_updater : __parent_class = None __stop_thread = False def __init__( self, parent_class ) : threading.Thread.__init__( self ) self.__parent_class = parent_class def start( self ) : self.__timer = QTimer() self.__timer.timeout.connect(self.__update) self.__timer.start(1000) def __update( self ) : ups = self.__parent_class._interface__current_ups was_online = True # Define a dict containing different UPS status status_mapper = { b"LB" : "%s" % _("Low batteries"), b"RB" : "%s" % _("Replace batteries !"), b"ALARM" : "%s" % _("Active alarms !"), b"BYPASS" : "Bypass %s" % _("(no battery protection)"), b"ECO" : _("In ECO mode (as defined by vendor)"), b"CAL" : _("Performing runtime calibration"), b"OFF" : "%s (%s)" % ( _("Offline"), _("not providing power to the load") ), b"OVER" : "%s (%s)" % ( _("Overloaded !"), _("there is too much load for device") ), b"TRIM" : _("Triming (UPS is triming incoming voltage)"), b"BOOST" : _("Boost (UPS is boosting incoming voltage)") } if not self.__stop_thread : try : vars = self.__parent_class._interface__ups_handler.GetUPSVars( ups ) self.__parent_class._interface__ups_vars = vars # Text displayed on the status frame text_left = "" text_right = "" status_text = "" text_left += "%s
" % _("Device status :") if ( vars.get(b"ups.status").find(b"OL") != -1 ) : text_right += "%s" % _("Online") if not was_online : self.__parent_class.change_status_icon( "on_line", blink=False ) was_online = True if ( vars.get(b"ups.status").find(b"OB") != -1 ) : text_right += "%s" % _("On batteries") if was_online : self.__parent_class.change_status_icon( "on_battery", blink=True ) self.__parent_class.gui_status_notification( _("Device is running on batteries"), "on_battery.png" ) was_online = False # Check for additionnal information for k,v in status_mapper.items() : if vars.get(b"ups.status").find(k) != -1 : if ( text_right != "" ) : text_right += " - %s" % v else : text_right += "%s" % v # CHRG and DISCHRG cannot be trated with the previous loop ;) if ( vars.get(b"ups.status").find(b"DISCHRG") != -1 ) : text_right += " - %s" % _("discharging") elif ( vars.get(b"ups.status").find(b"CHRG") != -1 ) : text_right += " - %s" % _("charging") status_text += text_right text_right += "
" if ( b"ups.mfr" in vars ) : text_left += "%s

" % _("Model :") text_right += "%s
%s
" % ( vars.get(b"ups.mfr",b"").decode('ascii'), vars.get(b"ups.model",b"").decode('ascii'), ) if ( b"ups.temperature" in vars ) : text_left += "%s
" % _("Temperature :") text_right += "%s
" % int( float( vars.get( b"ups.temperature", 0 ) ) ) if ( b"battery.voltage" in vars ) : text_left += "%s
" % _("Battery voltage :") text_right += "%sv
" % (vars.get( b"battery.voltage", 0 ).decode('ascii'),) self.__parent_class._interface__widgets["ups_status_left"].setText( text_left[:-4] ) self.__parent_class._interface__widgets["ups_status_right"].setText( text_right[:-4] ) # UPS load and battery charge progress bars self.__parent_class._interface__widgets["progress_battery_charge"].setRange( 0, 100 ) if ( b"battery.charge" in vars ) : charge = vars.get( b"battery.charge", "0" ) self.__parent_class._interface__widgets["progress_battery_charge"].setValue( int( float( charge ) ) ) self.__parent_class._interface__widgets["progress_battery_charge"].resetFormat() status_text += "
%s %s%%" % ( _("Battery charge :"), int( float( charge ) ) ) else : self.__parent_class._interface__widgets["progress_battery_charge"].setValue( 0 ) self.__parent_class._interface__widgets["progress_battery_charge"].setFormat( _("Not available") ) # FIXME: Some themes don't draw text, so swap it with a QLabel? self.__parent_class._interface__widgets["progress_battery_load"].setRange( 0, 100 ) if ( b"ups.load" in vars ) : load = vars.get( b"ups.load", "0" ) self.__parent_class._interface__widgets["progress_battery_load"].setValue( int( float( load ) ) ) self.__parent_class._interface__widgets["progress_battery_load"].resetFormat() status_text += "
%s %s%%" % ( _("UPS load :"), int( float( load ) ) ) else : self.__parent_class._interface__widgets["progress_battery_load"].setValue( 0 ) self.__parent_class._interface__widgets["progress_battery_load"].setFormat( _("Not available") ) # FIXME: Some themes don't draw text, so swap it with a QLabel? if ( b"battery.runtime" in vars ) : autonomy = int( float( vars.get( b"battery.runtime", 0 ) ) ) if ( autonomy >= 3600 ) : info = time.strftime( _("%H hours %M minutes %S seconds"), time.gmtime( autonomy ) ) elif ( autonomy > 300 ) : info = time.strftime( _("%M minutes %S seconds"), time.gmtime( autonomy ) ) else : info = time.strftime( _("%M minutes %S seconds"), time.gmtime( autonomy ) ) else : info = _("Not available") self.__parent_class._interface__widgets["ups_status_time"].setText( info ) # Display UPS status as tooltip for tray icon self.__parent_class._interface__widgets["status_icon"].setToolTip( status_text ) except : self.__parent_class.gui_status_message( _("Error from '{0}' ({1})").format( ups, sys.exc_info()[1] ) ) self.__parent_class.gui_status_notification( _("Error from '{0}'\n{1}").format( ups, sys.exc_info()[1] ), "warning.png" ) def stop_thread( self ) : self.__timer.stop() #----------------------------------------------------------------------- # The main program starts here :-) if __name__ == "__main__" : # Init the localisation APP = "NUT-Monitor" DIR = "locale" gettext.bindtextdomain( APP, DIR ) gettext.textdomain( APP ) _ = gettext.gettext for module in ( gettext, ) : module.bindtextdomain( APP, DIR ) module.textdomain( APP ) gui = interface(sys.argv) gui.exec() nut-2.8.3/scripts/python/app/NUT-Monitor-py2gtk2.in0000755000200500020050000013627214777767434017022 00000000000000#!@PYTHON2@ # -*- coding: utf-8 -*- # 2009-12-27 David Goncalves - Version 1.2 # Total rewrite of NUT-Monitor to optimize GUI interaction. # Added favorites support (saved to user's home) # Added status icon on the notification area # # 2010-02-26 David Goncalves # Added UPS vars display and the possibility to change values # when user double-clicks on a RW var. # # 2010-05-01 David Goncalves # Added support for PyNotify (if available) # # 2010-05-05 David Goncalves # Added support for command line options # -> --start-hidden # -> --favorite # # NUT-Monitor now tries to detect if there is a NUT server # on localhost and if there is 1 UPS, connects to it. # # 2010-10-06 David Goncalves - Version 1.3 # Added localisation support # # 2015-02-14 Michal Fincham - Version 1.3.1 # Corrected unsafe permissions on ~/.nut-monitor (Debian #777706) # # 2025-03-15 Jim Klimov - Version 2.0.2 (to align with Python3 variant) # Revise localisation, inject PACKAGE_VERSION and NUT_WEBSITE_BASE # into the About dialog contents import gtk, gtk.glade, gobject import sys import base64 import os, os.path import stat import platform import time import threading import optparse import ConfigParser import locale import gettext if platform.system() == "Windows": import xml.dom.minidom # Try local development/accompanying packaging first, # then system installation sys_path_orig = list(sys.path) try: # Try "module" path relative to this program script: mod_path = os.path.sep.join([ os.path.dirname(os.path.abspath(os.path.realpath(__file__))), "..", "module"]) ### sys.stderr.write("[D] mod_path: %s\n" % mod_path) if os.path.isfile(os.path.sep.join([mod_path, "PyNUT.py"])): # Insert into the system path at index 1 to ensure that it # resolves after the main script but before anything else: sys.path.insert(1, mod_path) ### sys.stderr.write("[D] sys.path: %s\n" % sys.path) # Try our chances with the default or augmented path import PyNUT except Exception as ignored: # ModuleNotFoundError, path/parsing, et al # Try our chances with the default path: sys.path = sys_path_orig ### sys.stderr.write("[D2] sys.path: %s\n" % sys.path) import PyNUT # We would seek locale files relative to script dir os.chdir(os.path.dirname(os.path.abspath(os.path.realpath(__file__)))) # print(os.getcwd()) # Activate threadings on glib gobject.threads_init() class interface : DESIRED_FAVORITES_DIRECTORY_MODE = 0700 __widgets = {} __callbacks = {} __favorites = {} __favorites_file = None __favorites_path = "" __fav_menu_items = list() __window_visible = True __glade_file = None __connected = False __ups_handler = None __ups_commands = None __ups_vars = None __ups_rw_vars = None __gui_thread = None __current_ups = None def __init__( self ) : # Before anything, parse command line options if any present... opt_parser = optparse.OptionParser() opt_parser.add_option( "-H", "--start-hidden", action="store_true", default=False, dest="hidden", help="Start iconified in tray" ) opt_parser.add_option( "-F", "--favorite", dest="favorite", help="Load the specified favorite and connect to UPS" ) ( cmd_opts, args ) = opt_parser.parse_args() # FIXME: tell the system to not guess and definitively use # the `nut-monitor-py2gtk2.desktop` for windowing resources: # g_set_prgname('nut-monitor-py2gtk2') self.__glade_file = os.path.join( "ui", "gui-1.3.glade" ) if os.path.exists(self.__glade_file): self.__resdir = "." else: self.__resdir = os.path.dirname( sys.argv[0] ) self.__glade_file = os.path.join(self.__resdir, "ui", "gui-1.3.glade" ) # If not exists, we bail out in load attempt below if ( platform.system() == "Windows" ) : ### Fails for "fr" and "ru" locales with errors decoding UTF-8 in ### both XML() and xml_new_from_buffer() despite any trickery like ### attempts done below. PRs welcome: # with open(self.__glade_file, 'rb') as f: # doc = f.read() # .decode("cp1250").encode("utf8") # self.__widgets["interface"] = gtk.glade.xml_new_from_buffer( doc, len(doc), "window1", APP ) doc = xml.dom.minidom.parse(self.__glade_file).toxml().encode("utf-8") self.__widgets["interface"] = gtk.glade.xml_new_from_buffer( doc, len(doc), "window1", APP ) else : self.__widgets["interface"] = gtk.glade.XML( self.__glade_file, "window1", APP ) self.__widgets["main_window"] = self.__widgets["interface"].get_widget("window1") self.__widgets["status_bar"] = self.__widgets["interface"].get_widget("statusbar2") self.__widgets["ups_host_entry"] = self.__widgets["interface"].get_widget("entry1") self.__widgets["ups_port_entry"] = self.__widgets["interface"].get_widget("spinbutton1") self.__widgets["ups_refresh_button"] = self.__widgets["interface"].get_widget("button1") self.__widgets["ups_authentication_check"] = self.__widgets["interface"].get_widget("checkbutton1") self.__widgets["ups_authentication_frame"] = self.__widgets["interface"].get_widget("hbox1") self.__widgets["ups_authentication_login"] = self.__widgets["interface"].get_widget("entry2") self.__widgets["ups_authentication_password"] = self.__widgets["interface"].get_widget("entry3") self.__widgets["ups_list_combo"] = self.__widgets["interface"].get_widget("combobox1") self.__widgets["ups_commands_button"] = self.__widgets["interface"].get_widget("button8") self.__widgets["ups_connect"] = self.__widgets["interface"].get_widget("button2") self.__widgets["ups_disconnect"] = self.__widgets["interface"].get_widget("button7") self.__widgets["ups_params_box"] = self.__widgets["interface"].get_widget("vbox6") self.__widgets["ups_infos"] = self.__widgets["interface"].get_widget("notebook1") self.__widgets["ups_vars_tree"] = self.__widgets["interface"].get_widget("treeview1") self.__widgets["ups_vars_refresh"] = self.__widgets["interface"].get_widget("button9") self.__widgets["ups_status_image"] = self.__widgets["interface"].get_widget("image1") self.__widgets["ups_status_left"] = self.__widgets["interface"].get_widget("label10") self.__widgets["ups_status_right"] = self.__widgets["interface"].get_widget("label11") self.__widgets["ups_status_time"] = self.__widgets["interface"].get_widget("label15") self.__widgets["menu_favorites_root"] = self.__widgets["interface"].get_widget("menuitem3") self.__widgets["menu_favorites"] = self.__widgets["interface"].get_widget("menu2") self.__widgets["menu_favorites_add"] = self.__widgets["interface"].get_widget("menuitem4") self.__widgets["menu_favorites_del"] = self.__widgets["interface"].get_widget("menuitem5") self.__widgets["progress_battery_charge"] = self.__widgets["interface"].get_widget("progressbar1") self.__widgets["progress_battery_load"] = self.__widgets["interface"].get_widget("progressbar2") # Create the tray icon and connect it to the show/hide method... self.__widgets["status_icon"] = gtk.StatusIcon() self.__widgets["status_icon"].set_from_file( os.path.join( self.__resdir, "pixmaps", "on_line.png" ) ) self.__widgets["status_icon"].set_visible( True ) self.__widgets["status_icon"].connect( "activate", self.tray_activated ) self.__widgets["ups_status_image"].set_from_file( os.path.join( self.__resdir, "pixmaps", "on_line.png" ) ) # Define interface callbacks actions self.__callbacks = { "on_window1_destroy" : self.quit, "on_imagemenuitem1_activate" : self.gui_about_dialog, "on_imagemenuitem5_activate" : self.quit, "on_entry1_changed" : self.__check_gui_fields, "on_entry2_changed" : self.__check_gui_fields, "on_entry3_changed" : self.__check_gui_fields, "on_checkbutton1_toggled" : self.__check_gui_fields, "on_spinbutton1_value_changed" : self.__check_gui_fields, "on_button1_clicked" : self.__update_ups_list, "on_button2_clicked" : self.connect_to_ups, "on_button7_clicked" : self.disconnect_from_ups, "on_button9_clicked" : self.__gui_update_ups_vars_view, "on_menuitem4_activate" : self.__gui_add_favorite, "on_menuitem5_activate" : self.__gui_delete_favorite, "on_treeview1_button_press_event" : self.__gui_ups_vars_selected } # Connect the callbacks self.__widgets["interface"].signal_autoconnect( self.__callbacks ) # Remove the dummy combobox entry on UPS List and Commands self.__widgets["ups_list_combo"].remove_text( 0 ) # Set UPS vars treeview properties ----------------------------- store = gtk.ListStore( gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_STRING ) self.__widgets["ups_vars_tree"].set_model( store ) self.__widgets["ups_vars_tree"].set_headers_visible( True ) # Column 0 cr = gtk.CellRendererPixbuf() column = gtk.TreeViewColumn( '', cr ) column.add_attribute( cr, 'pixbuf', 0 ) self.__widgets["ups_vars_tree"].append_column( column ) # Column 1 cr = gtk.CellRendererText() cr.set_property( 'editable', False ) column = gtk.TreeViewColumn( _('Var name'), cr ) column.set_sort_column_id( 1 ) column.add_attribute( cr, 'text', 1 ) self.__widgets["ups_vars_tree"].append_column( column ) # Column 2 cr = gtk.CellRendererText() cr.set_property( 'editable', False ) column = gtk.TreeViewColumn( _('Value'), cr ) column.add_attribute( cr, 'text', 2 ) self.__widgets["ups_vars_tree"].append_column( column ) self.__widgets["ups_vars_tree"].get_model().set_sort_column_id( 1, gtk.SORT_ASCENDING ) self.__widgets["ups_vars_tree_store"] = store self.__widgets["ups_vars_tree"].set_size_request( -1, 50 ) #--------------------------------------------------------------- # UPS Commands combo box creation ------------------------------ container = self.__widgets["ups_commands_button"].get_parent() self.__widgets["ups_commands_button"].destroy() self.__widgets["ups_commands_combo"] = gtk.ComboBox() list_store = gtk.ListStore( gobject.TYPE_STRING ) self.__widgets["ups_commands_combo"].set_model( list_store ) cell_renderer = gtk.CellRendererText() cell_renderer.set_property( "xalign", 0 ) self.__widgets["ups_commands_combo"].pack_start( cell_renderer, True ) self.__widgets["ups_commands_combo"].add_attribute( cell_renderer, "markup", 0 ) container.pack_start( self.__widgets["ups_commands_combo"], True ) self.__widgets["ups_commands_combo"].set_active( 0 ) self.__widgets["ups_commands_combo"].show_all() self.__widgets["ups_commands_button"] = gtk.Button( stock=gtk.STOCK_EXECUTE ) container.pack_start( self.__widgets["ups_commands_button"], True ) self.__widgets["ups_commands_button"].show() self.__widgets["ups_commands_button"].connect( "clicked", self.__gui_send_ups_command ) self.__widgets["ups_commands_combo_store"] = list_store #--------------------------------------------------------------- if ( cmd_opts.hidden != True ) : self.__widgets["main_window"].show() # Define favorites path and load favorites if ( platform.system() == "Linux" ) : self.__favorites_path = os.path.join( os.environ.get("HOME"), ".nut-monitor" ) elif ( platform.system() == "Windows" ) : self.__favorites_path = os.path.join( os.environ.get("USERPROFILE"), "Application Data", "NUT-Monitor" ) self.__favorites_file = os.path.join( self.__favorites_path, "favorites.ini" ) self.__parse_favorites() self.gui_status_message( _("Welcome to NUT Monitor") ) if ( cmd_opts.favorite != None ) : if ( self.__favorites.has_key( cmd_opts.favorite ) ) : self.__gui_load_favorite( fav_name=cmd_opts.favorite ) self.connect_to_ups() else : # Try to scan localhost for available ups and connect to it if there is only one self.__widgets["ups_host_entry"].set_text( "localhost" ) self.__update_ups_list() if ( len( self.__widgets["ups_list_combo"].get_model() ) == 1 ) : self.connect_to_ups() # Check if correct fields are filled to enable connection to the UPS def __check_gui_fields( self, widget=None ) : # If UPS list contains something, clear it if self.__widgets["ups_list_combo"].get_active() != -1 : self.__widgets["ups_list_combo"].get_model().clear() self.__widgets["ups_connect"].set_sensitive( False ) self.__widgets["menu_favorites_add"].set_sensitive( False ) # Host/Port selection if len( self.__widgets["ups_host_entry"].get_text() ) > 0 : sensitive = True # If authentication is selected, check that we have a login and password if self.__widgets["ups_authentication_check"].get_active() : if len( self.__widgets["ups_authentication_login"].get_text() ) == 0 : sensitive = False if len( self.__widgets["ups_authentication_password"].get_text() ) == 0 : sensitive = False self.__widgets["ups_refresh_button"].set_sensitive( sensitive ) if not sensitive : self.__widgets["ups_connect"].set_sensitive( False ) self.__widgets["menu_favorites_add"].set_sensitive( False ) else : self.__widgets["ups_refresh_button"].set_sensitive( False ) self.__widgets["ups_connect"].set_sensitive( False ) self.__widgets["menu_favorites_add"].set_sensitive( False ) # Use authentication fields... if self.__widgets["ups_authentication_check"].get_active() : self.__widgets["ups_authentication_frame"].set_sensitive( True ) else : self.__widgets["ups_authentication_frame"].set_sensitive( False ) self.gui_status_message() #------------------------------------------------------------------- # This method is used to show/hide the main window when user clicks on the tray icon def tray_activated( self, widget=None, data=None ) : if self.__window_visible : self.__widgets["main_window"].hide() else : self.__widgets["main_window"].show() self.__window_visible = not self.__window_visible #------------------------------------------------------------------- # Change the status icon and tray icon def change_status_icon( self, icon="on_line", blink=False ) : self.__widgets["status_icon"].set_from_file( os.path.join( self.__resdir, "pixmaps", "%s.png" % icon ) ) self.__widgets["ups_status_image"].set_from_file( os.path.join( self.__resdir, "pixmaps", "%s.png" % icon ) ) self.__widgets["status_icon"].set_blinking( blink ) #------------------------------------------------------------------- # This method connects to the NUT server and retrieve availables UPSes # using connection parameters (host, port, login, pass...) def __update_ups_list( self, widget=None ) : host = self.__widgets["ups_host_entry"].get_text() port = int( self.__widgets["ups_port_entry"].get_value() ) login = None password = None if self.__widgets["ups_authentication_check"].get_active() : login = self.__widgets["ups_authentication_login"].get_text() password = self.__widgets["ups_authentication_password"].get_text() try : nut_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password ) upses = nut_handler.GetUPSList() ups_list = upses.keys() ups_list.sort() # If UPS list contains something, clear it self.__widgets["ups_list_combo"].get_model().clear() for current in ups_list : self.__widgets["ups_list_combo"].append_text( current ) self.__widgets["ups_list_combo"].set_active( 0 ) self.__widgets["ups_connect"].set_sensitive( True ) self.__widgets["menu_favorites_add"].set_sensitive( True ) self.gui_status_message( _("Found {0} devices on {1}").format( len( ups_list ), host ) ) except : error_msg = _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) self.gui_status_message( error_msg ) #------------------------------------------------------------------- # Quit program def quit( self, widget=None ) : # If we are connected to an UPS, disconnect first... if self.__connected : self.gui_status_message( _("Disconnecting from device") ) self.disconnect_from_ups() gtk.main_quit() #------------------------------------------------------------------- # Method called when user wants to add a new favorite entry. It # displays a dialog to enable user to select the name of the favorite def __gui_add_favorite( self, widget=None ) : dialog_interface = gtk.glade.XML( self.__glade_file, "dialog1" ) dialog = dialog_interface.get_widget( "dialog1" ) self.__widgets["favorites_dialog_button_add"] = dialog_interface.get_widget("button3") # Define interface callbacks actions callbacks = { "on_entry4_changed" : self.__gui_add_favorite_check_gui_fields } dialog_interface.signal_autoconnect( callbacks ) self.__widgets["main_window"].set_sensitive( False ) rc = dialog.run() if rc == 1 : fav_data = {} fav_data["host"] = self.__widgets["ups_host_entry"].get_text() fav_data["port"] = "%d" % self.__widgets["ups_port_entry"].get_value() fav_data["ups"] = self.__widgets["ups_list_combo"].get_active_text() fav_data["auth"] = self.__widgets["ups_authentication_check"].get_active() if fav_data["auth"] : fav_data["login"] = self.__widgets["ups_authentication_login"].get_text() fav_data["password"] = base64.b64encode( self.__widgets["ups_authentication_password"].get_text() ) fav_name = dialog_interface.get_widget("entry4").get_text() self.__favorites[ fav_name ] = fav_data self.__gui_refresh_favorites_menu() # Save all favorites self.__save_favorites() dialog.destroy() self.__widgets["main_window"].set_sensitive( True ) #------------------------------------------------------------------- # Method called when user wants to delete an entry from favorites def __gui_delete_favorite( self, widget=None ) : dialog_interface = gtk.glade.XML( self.__glade_file, "dialog2" ) dialog = dialog_interface.get_widget( "dialog2" ) # Remove the dummy combobox entry on list dialog_interface.get_widget("combobox2").remove_text( 0 ) favs = self.__favorites.keys() favs.sort() for current in favs : dialog_interface.get_widget("combobox2").append_text( current ) dialog_interface.get_widget("combobox2").set_active( 0 ) self.__widgets["main_window"].set_sensitive( False ) rc = dialog.run() fav_name = dialog_interface.get_widget("combobox2").get_active_text() dialog.destroy() self.__widgets["main_window"].set_sensitive( True ) if ( rc == 1 ) : # Remove entry, show confirmation dialog md = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("Are you sure that you want to remove this favorite ?") ) resp = md.run() md.destroy() if ( resp == gtk.RESPONSE_YES ) : del self.__favorites[ fav_name ] self.__gui_refresh_favorites_menu() self.__save_favorites() self.gui_status_message( _("Removed favorite '%s'") % fav_name ) #------------------------------------------------------------------- # Method called when user selects a favorite from the favorites menu def __gui_load_favorite( self, fav_name="" ) : if ( self.__favorites.has_key( fav_name ) ) : # If auth is activated, process it before other fields to avoir weird # reactions with the 'check_gui_fields' function. if ( self.__favorites[fav_name].get("auth", False ) ) : self.__widgets["ups_authentication_check"].set_active( True ) self.__widgets["ups_authentication_login"].set_text( self.__favorites[fav_name].get("login","") ) self.__widgets["ups_authentication_password"].set_text( self.__favorites[fav_name].get("password","") ) self.__widgets["ups_host_entry"].set_text( self.__favorites[fav_name].get("host","") ) self.__widgets["ups_port_entry"].set_value( float(self.__favorites[fav_name].get("port",3493.0)) ) # Clear UPS list and add current UPS name self.__widgets["ups_list_combo"].get_model().clear() self.__widgets["ups_list_combo"].append_text( self.__favorites[fav_name].get("ups","") ) self.__widgets["ups_list_combo"].set_active( 0 ) # Activate the connect button self.__widgets["ups_connect"].set_sensitive( True ) self.gui_status_message( _("Loaded '%s'") % fav_name ) #------------------------------------------------------------------- # Send the selected command to the UPS def __gui_send_ups_command( self, widget=None ) : offset = self.__widgets["ups_commands_combo"].get_active() cmd = self.__ups_commands[ offset ] md = gtk.MessageDialog( None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, _("Are you sure that you want to send\n'%s' to the device ?") % cmd ) self.__widgets["main_window"].set_sensitive( False ) resp = md.run() md.destroy() self.__widgets["main_window"].set_sensitive( True ) if ( resp == gtk.RESPONSE_YES ) : try : self.__ups_handler.RunUPSCommand( self.__current_ups, cmd ) self.gui_status_message( _("Sent '{0}' command to {1}").format( cmd, self.__current_ups ) ) except : self.gui_status_message( _("Failed to send '{0}' ({1})").format( cmd, sys.exc_info()[1] ) ) #------------------------------------------------------------------- # Method called when user clicks on the UPS vars treeview. If the user # performs a double click on a RW var, the GUI shows the update var dialog. def __gui_ups_vars_selected( self, widget, event ) : # Check if it's a double click... if ( (event.button == 1) and (event.type == gtk.gdk._2BUTTON_PRESS) ) : treeselection = self.__widgets["ups_vars_tree"].get_selection() (model,iter) = treeselection.get_selected() try : ups_var = model.get_value( iter, 1 ) if ( ups_var in self.__ups_rw_vars ) : # The selected var is RW, then we can show the update dialog dialog_interface = gtk.glade.XML( self.__glade_file, "dialog3" ) dialog = dialog_interface.get_widget( "dialog3" ) lab = dialog_interface.get_widget( "label9" ) lab.set_markup( _("Enter a new value for the variable.\n\n{0} = {1} (current value)").format( ups_var, self.__ups_rw_vars.get(ups_var)) ) str = dialog_interface.get_widget( "entry5" ) str.set_text( self.__ups_rw_vars.get(ups_var) ) self.__widgets["main_window"].set_sensitive( False ) rc = dialog.run() new_val = str.get_text() dialog.destroy() self.__widgets["main_window"].set_sensitive( True ) if ( rc == 1 ) : try : self.__ups_handler.SetRWVar( ups=self.__current_ups, var=ups_var, value=new_val ) self.gui_status_message( _("Updated variable on %s") % self.__current_ups ) # Change the value on the local dict to update the GUI self.__ups_vars[ups_var] = new_val self.__ups_rw_vars[ups_var] = new_val self.__gui_update_ups_vars_view() except : error_msg = _("Error updating variable on '{0}' ({1})").format( self.__current_ups, sys.exc_info()[1] ) self.gui_status_message( error_msg ) else : # User cancelled modification... error_msg = _("No variable modified on %s - User cancelled") % self.__current_ups self.gui_status_message( error_msg ) except : # Failed to get information from the treeview... skip action pass #------------------------------------------------------------------- # Refresh the content of the favorites menu according to the defined favorites def __gui_refresh_favorites_menu( self ) : for current in self.__fav_menu_items : current.destroy() self.__fav_menu_items = list() items = self.__favorites.keys() items.sort() for current in items : menu_item = gtk.MenuItem( current ) menu_item.show() self.__fav_menu_items.append( menu_item ) self.__widgets["menu_favorites"].append( menu_item ) menu_item.connect_object( "activate", self.__gui_load_favorite, current ) if len( items ) > 0 : self.__widgets["menu_favorites_del"].set_sensitive( True ) else : self.__widgets["menu_favorites_del"].set_sensitive( False ) #------------------------------------------------------------------- # In 'add favorites' dialog, this method compares the content of the # text widget representing the name of the new favorite with existing # ones. If they match, the 'add' button will be set to non sensitive # to avoid creating entries with the same name. def __gui_add_favorite_check_gui_fields( self, widget=None ) : fav_name = widget.get_text() if ( len( fav_name ) > 0 ) and ( fav_name not in self.__favorites.keys() ) : self.__widgets["favorites_dialog_button_add"].set_sensitive( True ) else : self.__widgets["favorites_dialog_button_add"].set_sensitive( False ) #------------------------------------------------------------------- # Load and parse favorites def __parse_favorites( self ) : if ( not os.path.exists( self.__favorites_file ) ) : # There is no favorites files, do nothing return try : if ( not stat.S_IMODE( os.stat( self.__favorites_path ).st_mode ) == self.DESIRED_FAVORITES_DIRECTORY_MODE ) : # unsafe pre-1.2 directory found os.chmod( self.__favorites_path, self.DESIRED_FAVORITES_DIRECTORY_MODE ) conf = ConfigParser.ConfigParser() conf.read( self.__favorites_file ) for current in conf.sections() : # Check if mandatory fields are present if ( conf.has_option( current, "host" ) and conf.has_option( current, "ups" ) ) : # Valid entry found, add it to the list fav_data = {} fav_data["host"] = conf.get( current, "host" ) fav_data["ups"] = conf.get( current, "ups" ) if ( conf.has_option( current, "port" ) ) : fav_data["port"] = conf.get( current, "port" ) else : fav_data["port"] = "3493" # If auth is defined the section must have login and pass defined if ( conf.has_option( current, "auth" ) ) : if( conf.has_option( current, "login" ) and conf.has_option( current, "password" ) ) : # Add the entry fav_data["auth"] = conf.getboolean( current, "auth" ) fav_data["login"] = conf.get( current, "login" ) try : fav_data["password"] = base64.decodestring( conf.get( current, "password" ) ) except : # If the password is not in base64, let the field empty print( _("Error parsing favorites, password for '%s' is not in base64\nSkipping password for this entry") % current ) fav_data["password"] = "" else : fav_data["auth"] = False self.__favorites[current] = fav_data self.__gui_refresh_favorites_menu() except : self.gui_status_message( _("Error while parsing favorites file (%s)") % sys.exc_info()[1] ) #------------------------------------------------------------------- # Save favorites to the defined favorites file using ini format def __save_favorites( self ) : # If path does not exists, try to create it if ( not os.path.exists( self.__favorites_file ) ) : try : os.makedirs( self.__favorites_path, mode=self.DESIRED_FAVORITES_DIRECTORY_MODE ) except : self.gui_status_message( _("Error while creating configuration folder (%s)") % sys.exc_info()[1] ) save_conf = ConfigParser.ConfigParser() for current in self.__favorites.keys() : save_conf.add_section( current ) for k, v in self.__favorites[ current ].iteritems() : save_conf.set( current, k, v ) try : fh = open( self.__favorites_file, "w" ) save_conf.write( fh ) fh.close() self.gui_status_message( _("Saved favorites...") ) except : self.gui_status_message( _("Error while saving favorites (%s)") % sys.exc_info()[1] ) #------------------------------------------------------------------- # Display the about dialog def gui_about_dialog( self, widget=None ) : dialog_interface = gtk.glade.XML( self.__glade_file, "aboutdialog1" ) ### sys.stderr.write("gui_about_dialog(): dialog_interface=%s\n" % str(dir(dialog_interface))) ### sys.stderr.write("gui_about_dialog(): dialog_interface.props=%s\n" % str(dir(dialog_interface.props))) ### sys.stderr.write("gui_about_dialog(): dialog_interface.get_data=%s\n" % str(dir(dialog_interface.get_data("label")))) ### sys.stderr.write("gui_about_dialog(): dialog_interface.get_properties=%s\n" % str(dir(dialog_interface.get_properties("label")))) dialog = dialog_interface.get_widget( "aboutdialog1" ) ### sys.stderr.write("gui_about_dialog(): dialog=%s\n" % str(dir(dialog))) ### sys.stderr.write("gui_about_dialog(): label=%s\n" % str(dir(dialog.label))) ### sys.stderr.write("gui_about_dialog(): text=%s\n" % str(dir(dialog.label.text))) ### sys.stderr.write("gui_about_dialog(): text()=%s\n" % str(dir(dialog.label.text()))) s = dialog.get_comments() ### sys.stderr.write("gui_about_dialog(): s (original) ='%s'\n" % s) s = _(s) ### sys.stderr.write("gui_about_dialog(): s (localized) ='%s'\n" % s) s = (s .replace('%s%s%s' % ("@", "PACKAGE_VERSION", "@"), '@PACKAGE_VERSION@') .replace('%s%s%s' % ("@", "NUT_WEBSITE_BASE", "@"), '@NUT_WEBSITE_BASE@') ) ### sys.stderr.write("gui_about_dialog(): s (rewritten) ='%s'\n" % s) dialog.set_comments(s) self.__widgets["main_window"].set_sensitive( False ) dialog.run() dialog.destroy() self.__widgets["main_window"].set_sensitive( True ) #------------------------------------------------------------------- # Display a message on the status bar. The message is also set as # tooltip to enable users to see long messages. def gui_status_message( self, msg="" ) : context_id = self.__widgets["status_bar"].get_context_id("Infos") self.__widgets["status_bar"].pop( context_id ) if ( platform.system() == "Windows" ) : text = msg.decode("cp1250").encode("utf8") else : text = msg message_id = self.__widgets["status_bar"].push( context_id, text.replace("\n", "") ) self.__widgets["status_bar"].set_tooltip_text( text ) #------------------------------------------------------------------- # Display a notification using PyNotify with an optional icon def gui_status_notification( self, message="", icon_file="" ) : # Try to init pynotify try : import pynotify pynotify.init( "NUT Monitor" ) if ( icon_file != "" ) : icon = "file://%s" % os.path.abspath( os.path.join( self.__resdir, "pixmaps", icon_file ) ) else : icon = None notif = pynotify.Notification( "NUT Monitor", message, icon ) notif.show() except : pass #------------------------------------------------------------------- # Let GTK refresh GUI :) def refresh_gui( self ) : while gtk.events_pending() : gtk.main_iteration( False ) return( True ) #------------------------------------------------------------------- # Connect to the selected UPS using parameters (host,port,login,pass) def connect_to_ups( self, widget=None ) : host = self.__widgets["ups_host_entry"].get_text() port = int( self.__widgets["ups_port_entry"].get_value() ) login = None password = None if self.__widgets["ups_authentication_check"].get_active() : login = self.__widgets["ups_authentication_login"].get_text() password = self.__widgets["ups_authentication_password"].get_text() try : self.__ups_handler = PyNUT.PyNUTClient( host=host, port=port, login=login, password=password ) except : self.gui_status_message( _("Error connecting to '{0}' ({1})").format( host, sys.exc_info()[1] ) ) self.gui_status_notification( _("Error connecting to '{0}'\n{1}").format( host, sys.exc_info()[1] ), "warning.png" ) return # Check if selected UPS exists on server... srv_upses = self.__ups_handler.GetUPSList() self.__current_ups = self.__widgets["ups_list_combo"].get_active_text() if not srv_upses.has_key( self.__current_ups ) : self.gui_status_message( _("Device '%s' not found on server") % self.__current_ups ) self.gui_status_notification( _("Device '%s' not found on server") % self.__current_ups, "warning.png" ) return if not self.__ups_handler.CheckUPSAvailable( self.__current_ups ): self.gui_status_message( _("UPS '{0}' is not reachable").format( self.__current_ups ) ) self.gui_status_notification( _("UPS '{0}' is not reachable").format( self.__current_ups ), "warning.png" ) return self.__connected = True self.__widgets["ups_connect"].hide() self.__widgets["ups_disconnect"].show() self.__widgets["ups_infos"].show() self.__widgets["ups_params_box"].set_sensitive( False ) self.__widgets["menu_favorites_root"].set_sensitive( False ) self.__widgets["ups_params_box"].hide() commands = self.__ups_handler.GetUPSCommands( self.__current_ups ) self.__ups_commands = commands.keys() self.__ups_commands.sort() # Refresh UPS commands combo box self.__widgets["ups_commands_combo_store"].clear() for desc in self.__ups_commands : self.__widgets["ups_commands_combo_store"].append( [ "%s\n%s" % ( desc, commands[desc] ) ] ) self.__widgets["ups_commands_combo"].set_active( 0 ) # Update UPS vars manually before the thread self.__ups_vars = self.__ups_handler.GetUPSVars( self.__current_ups ) self.__ups_rw_vars = self.__ups_handler.GetRWVars( self.__current_ups ) self.__gui_update_ups_vars_view() # Try to resize the main window... self.__widgets["main_window"].resize( 1, 1 ) # Start the GUI updater thread self.__gui_thread = gui_updater( self ) self.__gui_thread.start() self.gui_status_message( _("Connected to '{0}' on {1}").format( self.__current_ups, host ) ) #------------------------------------------------------------------- # Refresh UPS vars in the treeview def __gui_update_ups_vars_view( self, widget=None ) : if self.__ups_handler : vars = self.__ups_vars rwvars = self.__ups_rw_vars self.__widgets["ups_vars_tree_store"].clear() for k,v in vars.iteritems() : if ( rwvars.has_key( k ) ) : icon_file = os.path.join( self.__resdir, "pixmaps", "var-rw.png" ) else : icon_file = os.path.join( self.__resdir, "pixmaps", "var-ro.png" ) icon = gtk.gdk.pixbuf_new_from_file( icon_file ) self.__widgets["ups_vars_tree_store"].append( [ icon, k, v ] ) #------------------------------------------------------------------- # Disconnect from the UPS def disconnect_from_ups( self, widget=None ) : self.__connected = False self.__widgets["ups_connect"].show() self.__widgets["ups_disconnect"].hide() self.__widgets["ups_infos"].hide() self.__widgets["ups_params_box"].set_sensitive( True ) self.__widgets["menu_favorites_root"].set_sensitive( True ) self.__widgets["status_icon"].set_tooltip_markup( _("Not connected") ) self.__widgets["ups_params_box"].show() # Try to resize the main window... self.__widgets["main_window"].resize( 1, 1 ) # Stop the GUI updater thread self.__gui_thread.stop_thread() del self.__ups_handler self.gui_status_message( _("Disconnected from '%s'") % self.__current_ups ) self.change_status_icon( "on_line", blink=False ) self.__current_ups = None #----------------------------------------------------------------------- # GUI Updater class # This class updates the main gui with data from connected UPS class gui_updater( threading.Thread ) : __parent_class = None __stop_thread = False def __init__( self, parent_class ) : threading.Thread.__init__( self ) self.__parent_class = parent_class def run( self ) : ups = self.__parent_class._interface__current_ups was_online = True # Define a dict containing different UPS status status_mapper = { "LB" : "%s" % _("Low batteries"), "RB" : "%s" % _("Replace batteries !"), "ALARM" : "%s" % _("Active alarms !"), "BYPASS" : "Bypass %s" % _("(no battery protection)"), "ECO" : _("In ECO mode (as defined by vendor)"), "CAL" : _("Performing runtime calibration"), "OFF" : "%s (%s)" % ( _("Offline"), _("not providing power to the load") ), "OVER" : "%s (%s)" % ( _("Overloaded !"), _("there is too much load for device") ), "TRIM" : _("Triming (UPS is triming incoming voltage)"), "BOOST" : _("Boost (UPS is boosting incoming voltage)") } while not self.__stop_thread : try : vars = self.__parent_class._interface__ups_handler.GetUPSVars( ups ) self.__parent_class._interface__ups_vars = vars # Text displayed on the status frame text_left = "" text_right = "" status_text = "" text_left += "%s\n" % _("Device status :") if ( vars.get("ups.status").find("OL") != -1 ) : text_right += "%s" % _("Online") if not was_online : self.__parent_class.change_status_icon( "on_line", blink=False ) was_online = True if ( vars.get("ups.status").find("OB") != -1 ) : text_right += "%s" % _("On batteries") if was_online : self.__parent_class.change_status_icon( "on_battery", blink=True ) self.__parent_class.gui_status_notification( _("Device is running on batteries"), "on_battery.png" ) was_online = False # Check for additionnal information for k,v in status_mapper.iteritems() : if vars.get("ups.status").find(k) != -1 : if ( text_right != "" ) : text_right += " - %s" % v else : text_right += "%s" % v # CHRG and DISCHRG cannot be trated with the previous loop ;) if ( vars.get("ups.status").find("DISCHRG") != -1 ) : text_right += " - %s" % _("discharging") elif ( vars.get("ups.status").find("CHRG") != -1 ) : text_right += " - %s" % _("charging") status_text += text_right text_right += "\n" if ( vars.has_key( "ups.mfr" ) ) : text_left += "%s\n\n" % _("Model :") text_right += "%s\n%s\n" % ( vars.get("ups.mfr",""), vars.get("ups.model","") ) if ( vars.has_key( "ups.temperature" ) ) : text_left += "%s\n" % _("Temperature :") text_right += "%s\n" % int( float( vars.get( "ups.temperature", 0 ) ) ) if ( vars.has_key( "battery.voltage" ) ) : text_left += "%s\n" % _("Battery voltage :") text_right += "%sv\n" % vars.get( "battery.voltage", 0 ) self.__parent_class._interface__widgets["ups_status_left"].set_markup( text_left[:-1] ) self.__parent_class._interface__widgets["ups_status_right"].set_markup( text_right[:-1] ) # UPS load and battery charge progress bars if ( vars.has_key( "battery.charge" ) ) : charge = vars.get( "battery.charge", "0" ) self.__parent_class._interface__widgets["progress_battery_charge"].set_fraction( float( charge ) / 100.0 ) self.__parent_class._interface__widgets["progress_battery_charge"].set_text( "%s %%" % int( float( charge ) ) ) status_text += "\n%s %s%%" % ( _("Battery charge :"), int( float( charge ) ) ) else : self.__parent_class._interface__widgets["progress_battery_charge"].set_fraction( 0.0 ) self.__parent_class._interface__widgets["progress_battery_charge"].set_text( _("Not available") ) if ( vars.has_key( "ups.load" ) ) : load = vars.get( "ups.load", "0" ) self.__parent_class._interface__widgets["progress_battery_load"].set_fraction( float( load ) / 100.0 ) self.__parent_class._interface__widgets["progress_battery_load"].set_text( "%s %%" % int( float( load ) ) ) status_text += "\n%s %s%%" % ( _("UPS load :"), int( float( load ) ) ) else : self.__parent_class._interface__widgets["progress_battery_load"].set_fraction( 0.0 ) self.__parent_class._interface__widgets["progress_battery_load"].set_text( _("Not available") ) if ( vars.has_key( "battery.runtime" ) ) : autonomy = int( float( vars.get( "battery.runtime", 0 ) ) ) if ( autonomy >= 3600 ) : info = time.strftime( _("%H hours %M minutes %S seconds"), time.gmtime( autonomy ) ) elif ( autonomy > 300 ) : info = time.strftime( _("%M minutes %S seconds"), time.gmtime( autonomy ) ) else : info = time.strftime( _("%M minutes %S seconds"), time.gmtime( autonomy ) ) else : info = _("Not available") self.__parent_class._interface__widgets["ups_status_time"].set_markup( info ) # Display UPS status as tooltip for tray icon self.__parent_class._interface__widgets["status_icon"].set_tooltip_markup( status_text ) except : self.__parent_class.gui_status_message( _("Error from '{0}' ({1})").format( ups, sys.exc_info()[1] ) ) self.__parent_class.gui_status_notification( _("Error from '{0}'\n{1}").format( ups, sys.exc_info()[1] ), "warning.png" ) time.sleep( 1 ) def stop_thread( self ) : self.__stop_thread = True #----------------------------------------------------------------------- # The main program starts here :-) if __name__ == "__main__" : # Init the localisation APP = "NUT-Monitor" DIR = "locale" gettext.bindtextdomain( APP, DIR ) gettext.textdomain( APP ) _ = gettext.gettext for module in ( gettext, gtk.glade ) : module.bindtextdomain( APP, DIR ) module.textdomain( APP ) gui = interface() gtk.main() nut-2.8.3/scripts/python/app/pixmaps/0000755000200500020050000000000015001555412014566 500000000000000nut-2.8.3/scripts/python/app/pixmaps/warning.png0000644000200500020050000000573714553676503016715 00000000000000PNG  IHDR00WbKGDC pHYs oy vpAg00W IDAThYl]u9ΗH)ɲ$kHcTEC^>Zt@X(nEAm_ C -N HELXeR$y>Kd/{{_ks}{_&&z/^Ф xG;4ԕbO"߽|XFgZ//Ԍx/ 5T>p5oe`b&^,~ iygbF1P{1!XF]dh|@c0Ef… $Ȇ*\Itmkz'!Yƭkff5@1_>].45+Aֆtz×p7BsNf088uS5) .x"maSߏKX9j5`D@dEjh\mDâ ! }<aC&fJ f\S9Kia1mE'tj@: icCY,,zL?1U9ms|-M zmC#.b*`yU(5J(S C.iRD_HHHBߥ@x-lyjd)Wο39 eDR lshH´AB$.7kc -[xM k8G),Yʌ-*v H &rH[j!YYW A"01P{ otiK Yݟw"PPqVy)z^&K`*`+ >HP<$>*b `%ƀNb&ƗBRJꗽteW/~cm$/:pCM%gݥ& _u1L4`jRh .*tx6wKJiPqYU3OF5LȴYga뺱o}Tw4#o,Y Nn`A>/k=[lzInooΰ˝ OjA9P`!([) [ `8׫ y4prHy&exd[RM׈oxPy LB6Ht)s҃ 0%hV:V$X^ۤ]E xOyʭ՘&ɼQܝ,PĥhV?J,{x-{)C'dd{ێm=݂p cXH~+(fu !b3k  IKxIJ?|Sf6qڊ`an\nuuS9i7|Sj$d18,&]VPL0c`T˨M X=R]$󜊮< zIY-` ؇NZ6BitoiVgv\6q37Sڟ TJh^mm $k!ƈ~R7V0pF?#Cxkk \3:H ؝Ҽڢq7ou~{4Ai.r,>GGKśSp[plOnmX<^*V:>DֵS=T U[irXh8 TMx[Y*Ne㊱֛v:cؼ-Wى#` e`Pf^cUp9a٪U$)FT_shq e[EWy7ܑ9Lz3"_XF?*bV뉱%Wꏿ_1ϣeWTm, v^HnKt-V|>#=`*~lL){sD/SX140b;tW֧]+nvO1tSc9"8Oy/l]W?> `oK*U[=e`I KtQ(GPBuGq)gѡW%tEXtcreate-date2009-06-25T15:11:27+04:00o%tEXtdate:create2009-08-21T01:23:01+04:00{L%tEXtdate:modify2009-08-21T01:23:01+04:00 %tEXtmodify-date2009-06-25T15:11:27+04:00ޔtEXtSoftwarewww.inkscape.org<IENDB`nut-2.8.3/scripts/python/app/pixmaps/on_line.png0000644000200500020050000000507614553676503016667 00000000000000PNG  IHDR00WsRGBbKGD pHYs  #utIME :-9O IDAThOqUuάHR")EI¥C'N`P  @n>0H\sK 8`Ħ@4HJ,H (Rr\L~U9tBVz=3^UU7||}|]niٟiK<<ɓ'NL=デz(e2ƅ Ν;7~Fڽt[^z%~iFQySN,[ŋW^~ ][YYR:ٳg:}4O=y_ÇtXZZܹs29p̙3={cduu{9^.9gyGt:\r'Oߎ=qc'8?O#U+Yҟs}\enopuaђ9!yr|4Hqϱ>V%cSvoq|k U *(np|bjoA܎t;;j\ɻo_#[/a"}%?`ߑ;!pppq4Z@.r],a=P[KXdRP3zu& \0,щ5!gP̰Rݶn@G U-pg&u S!J9)7g3$I:!LfKb \im& D\@q&01*5cGPqL@A1w<d 0qw#v Q%a85`BnNR hhlfV'+dwjXsOFw[Ƥ1$`nLVD& 8fJmC$4(e* cg̤t~Kۤ$27O}q$Jjd&|Tw;H $1κOHTx07x?&s _!HZ3Hnӆ ;B!HP̝F&1(8Nư15c2ak#EyeY2*\&t !ScuZ`Q|U%v .Fg;!U֍]C{R^ !@3PA>=s9G-rK!2Jqb)vATtKB(E cyAp(1v EQ׸8 "~f255S(5 :eGeG\["ŇPP\rk%@zQBnr,%rw-PH'ٷ(F"3lD@;2)Ԕccc5tq7Oמ9 "GgA!JA1"( ?8,)єҡ@pbݒQ%)]6P _o3{hޠ䏿N:J!BObS^` k 낂DE=lifC걁)*( (onkwo:4 ( OnVnmތV4@)bReΣteF2"A][g= @$(YpVYUB8,]Y٦^Ou&X\7z07;2}bSSmk(h4wںixq5H&[`jPS5L0w ٠DHe5Guv$g,-M(ąI s|H #*NDI(&T&9'&h"Z `l5,KFEz3RUcxLp&VatZ\a&"fdlVFjH^|_ɛ_ff&ұn&IVg3-ʨl?5m@ _<ؑ}y`fw_oT9Zzg+o۵ˋ.'-q6tl']!Z[boޣTڇ#O n0[Ce "o{৭%O||U]tIENDB`nut-2.8.3/scripts/python/app/pixmaps/var-ro.png0000644000200500020050000000116314553676503016443 00000000000000PNG  IHDRasRGBbKGD pHYs"" GtIME 6Y,IDAT8˅kSQ?&归MG:D fM\]R/Һ\L]]By@˻Ř_{s{ KqzzJE~Ph ÇRjjQ š899wuJ2Vחk2n{^\.Fh0잟;Ƙ~/l6n,I+ D}?Z=ϋ(r$ֲK>GUWO?˾}lz^OY13nwkG ;ln9o3"ׅ OVͻ\$Yx*q~1ry*iտϢ*$vPbj5U]<3UR#K(Eb:&yDA")U]G TM[5,tZD # 0"κ`oVlLA c#"ADPj?{3@=uIENDB`nut-2.8.3/scripts/python/app/pixmaps/on_battery.png0000644000200500020050000000551614553676503017411 00000000000000PNG  IHDR00WsRGBbKGD pHYs  #utIME ; IDATh]y}.s梙,Fȷklj ۸-Q ! ~`P J&4ȍDq,i4{9#@3Ѩ>}˳ւ__Q133+/ϫ:uT駟n,,,meG.\>w\ovx;>}o8;;{z||Vx677]7_Y}bcΟ?:^x^3>>< w9<^/wB̉'h6cPUx瘛( 1D熯ܤ^crr7n}gnc @UU !e%ȰV*UUl6ɲ]p)%ztgc! fНC$Zw")%*}<k41c'716٥ּdA|<@y\-굛@Rb0gTHWtTw=(%L衭g8IwxCAbb!R*EHd#= b AفA j(-R)?zpzЪ)RR=R "AL?ZzVC0F\$Υ?'|7XE( R0 EDk`?Caa`@\ĒKpJǀ~O@znYpP%aάG  m[)9ǵm.]6s?6!XJ iL}8wl `bb v8H4n>\Ȉ:nRbf.̼y0>==;J5I&cfgw4WO3 U"=-LFhF X&^CK)J@$^xAQ<='i&er*Kt8x*m¼|GsHMG 56†2zQd^xRѮav!ԯtAG]vwsY7'" -d_K)0~P [*UUdl-l\E+HА҃l|~+z=!ƖB j,75A"D0hPK h+ VUK6yOG).rqBi>Ғ kcFCPVokw3WRH Bk+܌^f9m*P] }&r~reBP\7]ʡmeO$pqIENDB`nut-2.8.3/scripts/python/app/icons/0000755000200500020050000000000015001555411014217 500000000000000nut-2.8.3/scripts/python/app/icons/256x256/0000755000200500020050000000000015001555412015161 500000000000000nut-2.8.3/scripts/python/app/icons/256x256/nut-monitor.png0000644000200500020050000004073414553676503020132 00000000000000PNG  IHDR\rfbKGD IDATxi%yv22 $1e!"(2dʢd&a;²-Ca)bi Pc0f^UdfUVVV{_^^<ѷ2++:[2.p  >9Dx#O 0 xU2>""|c?G| ~ _$?K[$A <9'? tKA/|"ikZXB=F7 %HD* hdG:!MRDL{79A|WqRH<1\"G> `n?8VXX'mz(hH !H!E&"L\`]#t!DC0|w x~ExK_B~OO3$'qKv[Wc k>Fs A$ jH A2͈/E!FR R ty!\0ԟX «^+REq 'N%)%<5D0~{95)Pd~.|`I0$FIjq0$ >Ct?}]Cz=#Iл:[a!E)F?;5`*8"b~QFaj8PR,ZX` jp#Ay#Ⱦ(r+U]˶ w}kZo`R/1Dߐ,z~[Gy"D`+x?A .#< q}/QTy/:q$4Y X bDCdRdR4{亜"cؿQ2xy)L}љ.<#~'D<"{S"n/>D2C4U>D -cq nc°wM.ю8<;qƻ۟ AX@;CsOq ih=fb~'h͡lE_𧷾8<h|shtsYߚ9,>Gљ_FknV{|`Š9w+\)H\V@BR{2]ǧCi2B@h6(Fc q!#4˘[H4D MFᅢ@rTydv?.>f+W:͙#e08 ;*h9$-čqcΣ,`Gs |=(n?}zoޓXVGKhq߄ǰv'r<'-@\[Vu6YEufֳm4^V 7"0P, F'0 9zGsDӈgςP>D NC E `z38eCq UëΠѹV':?tG 8vg"q(f(tٿu<3>' FP7-Pg ih1kZ6-7>QK"H/kJqz(UC}3u]/x@ܜGiøz1f̰?mu&qFHo o+|s^z9"yo^c~̌c8Gqk@m[7 Ko*Ϛ&Dz 2yt$M e0HF@2|>QV9#Cx]f +[􂁛!@:D"=xbJYߝsػ"DRzfϫ̄h.=!4/믖vX. u&9a~籟\xcQx|s:8<!mEROz`J-֌8x X@LjA =GIJ?+N"1HEh?hX~Y\^QP}QfF/tn/-W^Vn%*oYwB/©_@/"\we5$2AR 5HFHG}# It$!~>@:3v>1HCM#ט1EjFzNjS'sQT!Iؚ?9kyb|03<ؚu,‡ǧY[l<5o ~ I Qb¼/L9֮e!͙ocg%&?"uDJӿ$Čwyiaf~I)O ShĠ= "0ĠO ʺr2 xtjCŅ hh~*͗ ` ϱ+` ڃN*XMm! -r,#7$geDX~Czn[_[$ 0Q!M}Au2P0#U z/@&!~:<_ OBH2imx%T$Br$$ E{gA \cPi@WS`|րcS!HYmW'D`LUT}W"2Fd78&_!ILh-|`Wu*=0%zo q[e"ϓ+pA›{ iFtf< -*g -j x U-) 0p " 1R ۇCl@*Χ*g%ʴ 91G 2Jo& t_Z4ədtޚDzf-'^<,P>e&IhF3dFte%U!~&*:"k1N-*x"O/2 z !) Grt u`ƒ3} :%d1<=u}]9'4%H uc>o?6gX 케͜3/DF'}*Ihz5 8*W-Ez$%҄ PyRǜH@ip hK%!*'_uB=O_d}- =49 :4V_*URQn~Dy\~``_scF _C~B6ǔgd% O6jK7M+|+@^IR'3+ HT"M !!Md$)Lgtxp 2{1 = D[2E @tZ[> P#. D'S"EbBm@ry\eu< =E0Ti,L>A c|+|ϗhyL.ռr$R!  $#݆F%% 1D:dx hjb{}"ddI0VLd, wܞ6le M"~OMVj?} 8)T##X B ƛ j 2L7&J4a!@)R$E$WC H&MmѮ3 K?C\Hvtl^]mȓuk^XFp2#|Xa?ws2<cs:&N6=&͢Wg 9D$Ag}Rv!.C=2݃H!=eeKe7]$6cC oӾ} rה nf;[Oi>KH[⇲0e20XG>;)^ϙ/O&"@:!LrSfzOJPaq;F>j-sm> INAs}7ԸXZuɝ r2[Y̋d/:yu="@@jw{i}6|pJ l:bOL?}z˕+FڗqAyz& AU78r%^[O(%꼅*ǚR6 jӵʲe7AjnmGz>Ӵ"D&$GP!R!z>r G+ zw"qq~oc3 o޶b(Lg髈f֥.)O۵Η8/d\`xcsϣШOw`{US+$T ~~~Ux7sŧnN$ B91Xꢅĝ{ vN{RsMMU 8a7tz&T|uU HTfo%k{-md.{[gi[9guֱ~ Ӵw);d IDATPEqS{x)Su,`@9aȭf1mi u o>O di?JwqC5s+E@]]$8!f-so:"] w=mJ$ ũ8WoH)[KŅ/-P_ ||r|*π8mjH[9hWjƈ33p*wT7L9~05KV:SUaVDXf@U=_#s(lr^XzbU)L q @-m}V]H78Q1OYo$@}3s+ܿOb]byQYM.,#e9~O^a/[G` 5obs2Ncz6%o*$*\hm6)OiQ-kpA .̌ou/ MUTw.]o4q6!XbljET3ea ߾xs\Y3Ѭ,l`ɂ$7۶:quÒۿt:Ě|TlZrW{=öP^!:7nE7Y?똙qFm9$);Ppp&!{T`1T@97`6Updo=®5Tֹ3a:Q̶Ug3%'' B},_A#J'wcy:#p-;*U]ԑ,qm\U9;i3=I<ތjS8fNƁan`e7 TE;9n9*׶rVPq*_&Z@m/ӑj@1Z 1u/\] ~W cN4gi<or(Yl{W3$Hdqހ[O{NQmSn108~:;5Uu}V,\NP? K`[@Iwj};[G}o:k;'! ΙNg@eoV t'ENm4ӿ>:q[~پdɫLW'ak;g9[@RW8SUH@^`0,+ʁ$p@ ьzhD]QѵꄲwH_{X~{&lbU,uA77q},nn?jCR=I$ l;lYsj3$ιn>۲P@&z2@C4y ]k҅b;/5 ;YfRoBʦ1m (`&Nb$IC!d~ M5Y.{31<FUjަd DO4Z4⨇uG"SE1Hl{p:7@  VK4"DU ְ;X^w mEtA<)2OP(cfo2~SuG JԷB*[ Z\U=bCDλyଋr{`|̄ o@ Y#F";_i$a//Zr?;wg3eq5z 볚̤ϝ<}13X̪{6xzeKTQ*5c6CbrY X'WtywtN?ʉ>KQ T=FPg+̾iߚf-Wō\M,Kwd ' TU?ΐuB"CzB?b@T"Vy/Q=Yv^ʎ|+(T]7~oT13Lco̿5,c/%,ZҞ~#?I٪,,YAVؼeyq /CL9>48m fS/ry7v7F=B{\?z,{%Y?1ݦ8_L2fF& rR;䟭 u4GzcV*ݞ\aiK)ބ}BQEIn"fF Zݩ  ַ]g<¢BXJW7+&v;('-VMBf[A\̎LBS+vҰݧ[bf`|ޮ.ֱ(h\U1J1]fHnMUR&J97*Z ě@9Nӎu7Dr*9-WwZ0}6Dzs K@ .fFVi&neeErx@kIV"=eJreo3b^vLo<fFhi**n.kѾGSWz\)% ]8VAݎ6!@eg/P2ϮZc\զs-t9YqPs 4K- "ʴwWhNq`\Nc J:P=S )|(Q Ը<ȗl+wk;2mJ]-}eB?Uq!uߦr_af`l*߷@C[J^JrO"|a|I4U/n= e̎ԅ~εnm ܰ~ܻcN;0PlsYDuTI9'xP`}@'B?fFBŝu1sx޴eSJy/MCp߷3\9xwIAfGjG<1]N;נ;eC<*xԋwL+\M-=Gd030(&[W5 lV~QȄ#B II^I;u{(cfz g/na[⾰^U?G?Iƃ~~#׾mS>꫺9v,~g!3#Nʇ,U`-DJ{@;wɿǎTtncf@6-a 9xo}p8OT fGx-xn}? T7=w6Q4/aD T 8$ʂ`6ՙw w,x '}8 =̌c,@ !Y Yd5]֪3[ LNxfZ'g6'_iF~Ř@`Cbޯ*xgEg >̌T{ZxrE%jbIbI |ěT\!qk, ,<'CTGNDŽ@>̌T(R F|SWc0@O2>,q{XɾRoUn0ȇC̎L f_%jf xB{@?; M*lA0A\Ƶϩ+5M]>>9 (&$Æ!]կ%D[wRkyiG6f^״A]WY{i7U3aZ2dXwB|B( ~WP]m3^q:׊ @V1ۀ8N`y׽ !@:~sE& 80F&7P$ _؆Asof;Ҁ9eJ4]|YC @*Q$󣊲 dgO䔹ӦZ B Qk< gۭRTGD)?)33xMj-s=,O7k%4ͣ{'/?RA[#-{iѱ*mUڸ?w_z!eQX_^RD06"•wd"/~zl P(`{Ao_.1,..bc$:wZ-O677m|Mܾ]vw~[gaA*;xP]ײsO]U_p͓'? KyVWװE```1 8ڭ:8B8mŅb}^:COH櫔-l(H.YUa}mO<~?+2k_*J7"烊uw۱s'׶nn]zFx}}ںVŅEZLc``la3f w\>ư.}O= .bii)v ?`0p[7{[Ei?8.[w`BAxwuDQt>.] 8Qll*@ Q.ᩧއs 3xwDi+Wk_~۷WEy:oAwL4ݯ}pz]0  Gh6;h6[X{ D4VVVyΟ'/?.ac3 RJ@/<'+O* 951;~[X>?͏tpxp)9}+++%0n.ω#@*I$M R!شM(L0d,PCN)% 2/u./֩z+?9 FVNNgss󘟟G̾ɎG4+}ow/OI@NKU_j?F#_X^^ki68<.\gGΞM_IOpii X[] qY,`qqsssU$E unmma{{ngmp0[oOOOQni>o/'do8 0vunxܩ'._/' |v 8u6O:װE4MOSB@A{{{.vvvpac`iW)ommoo`zk_L!±%?pG&i㏜;\#?k4VVEJt:hw:h;hZXwQD ٲwE.~pܝ  /w_~׮]UdC88`PIR<i/]: ..-~n=9_]F@@FB܈i7``RA0 JDhp)$FH^k/loo^L {o8 a%8/_?4יj/w"Qɫƛ/\y-$t|.< `p$VefyfsO/-.=jm6ra»"I0_۾{僃ĮIN#x#~nyyyG.>֙om6č80xC!V*wd?|u[ij璽%(6&q}k7mUBLݙ3k'N8ݞ?N686F|h%b|G|羁$iOH'htk4[{{~ݫnHZRŧJOBxv kǹӴG~:_{KK+K sf͹8;<8";FEd1oΐ#Ird$)R%@J9LӴ+R9" dv{{[[;nw"!Q#n?.&̊بGA|xD`Y?)9KVE|SmUDu*?Ep1)}>vMmH#͍yn(wyIDATtW$T*K+׹v[xó8uUmk+Yy_t i<@C"xsD`w[T(u!Y Q)`zTYi>)UI?߸1UWYcs&,bw ۤ]y=ZM۩-%W|Q4m?\Oq7C\|wD;غ`/:/p?~Cv!i{uwMhHs*߸{K+{qu?aGtBE4zu``_8k4^H&!Bԇh0w׃̭<_[Ƅa@apegpvSDQ&ۀ150u0M0Mǘ[{tKE4~0cz/bj3r2v+ELjc=Pk-8ᯢ2-!h⡀QxmS*8 W)ƝIWQC]XLVF=~y.\!RX;RtdY Z;ob(* *iMu"{hM4Dy$d!R7<g2ɗlpkU-&%7\&)þLCԥy (?*PiaT~L_%a,{ /Ȩ"*X;TEp 0nfyH|jq Z7UaOxNH{=dF)@/R@Qq?hl\uSNF$e7e Cں7sGW2sJB8>lFPXDTzn}ؓ'7J頇]+kأbyâ˭Z,T<%~ߢwnw_Q { )PU{/ j pعC"O :@'IA Tw7K dHVFt:$HfW۾y?l连uLޱ~pcXXXgx$^pENoy:EK{sʲYZ\QoP kAc0&4a0A@mX(kk'y9~ <_6'$䑐oF+7TP8az#ᮻG#gΘ'Oz+++lY'ZegY8sdYNv-666իW^8y_^B=2j~;~NF} 377gۭ6 Fy1A$qkf#/cM0οvȽOC@ BBXQ+C \XX;qĩNsV V \`Q *h,Jl#K.^t)˲<3.%+NQ3wDRLefhkyHV-[D9{$UQ\,ʽfaf6P}V;?IENDB`nut-2.8.3/scripts/python/app/icons/48x48/0000755000200500020050000000000015001555412015017 500000000000000nut-2.8.3/scripts/python/app/icons/48x48/nut-monitor.png0000644000200500020050000000330414553676503017760 00000000000000PNG  IHDR00WsRGBbKGD pHYs B(xtIME 7DIDAThߋ\g?9gfgg3ij%)mcV BAU/zEQ Az# P֤"jB5MIfggg&39>slj6,/sμ}~g^8;;?60{u#-fL-UT0 0\AU~Kt>69 _TTZP~67^\y>u*U 1;lޥ,e=7UϨڡWM8ZX-=)Wu<~w(qw5By{GoܾɠsYc~ro.良OSx?S}d7ڀi2S_&B0x{+/{erR3-WgoYpTI6IPZE@B@ٿ2Mm̽\şMLvkչW`!l`% ﱃ?@| Z`qG? zcccDRl<~qgBўs.)7b؟ û~w'/6@^#yWmx,{`w|=?I9rbT-A97Y;oy<YNk~\D@SZm/82cf:8E T a~5j:A<JS>E‹?/rKQk׮}%Jѣa^' # 5N=XkaR277ϑGzZ][{{p|[7l G<}fjX| }qii'xRW"0 C 8I$^G͍fl6Mtvvfn {90_O///begjOjOQNH9Lաx7׮^$0rSy4 ܱvqSg9a{?Dڲkfώe؁؁?Y/~IENDB`nut-2.8.3/scripts/python/app/icons/scalable/0000755000200500020050000000000015001555412015766 500000000000000nut-2.8.3/scripts/python/app/icons/scalable/nut-monitor.svg0000644000200500020050000005556214553676503020757 00000000000000 image/svg+xml Lapo Calamandrei Battery battery recharge power acpi apm nut-2.8.3/scripts/python/app/README.adoc0000644000200500020050000001045714777767434014655 00000000000000NUT-Monitor =========== NUT-Monitor is a graphical application to access and manage UPSes connected to a NUT (Network UPS Tools) server. Dependencies ------------ This application (variants written in Python 2 + GTK2, and in Python 3 + Qt5) uses the python-pynut class (available at http://www.lestat.st), delivered as PyNUT in the NUT source tree. Refer to your OS packaging and/or install custom modules with `pip` (or `pip3`) to get required dependencies (GTK + GObject or Qt5). Path to PyNUT module -------------------- For quick tests (e.g. during development), you can run the clients like this: ---- :; PYTHONPATH=../module/ python2 ./NUT-Monitor-py2gtk2.in ---- or: ---- :; PYTHONPATH=../module/ python3 ./NUT-Monitor-py3qt5.in ---- Localization ------------ For localized UI, on some platforms you can also request the locale with different precision like `export LANG=fr_FR.UTF-8`, `export LANG=it_IT` or `export LANG=ru` (see and feel welcome to improve the choice of languages in `locale` directory); however on some others you are required to use the `xx_YY.UTF-8` spec format. NOTE: Currently, the localization only fully works for Python 2 client, while menu names, dialog field labels, etc. remain in default English wording despite the presence of translations in resource files. PRs to attach them to run-time rendering in the Python 3 client are welcome. Note that some items, like the standard menu items for Preferences or About, can come from the interpreter's default library and so partially cover the interface elements in other languages (e.g. system default) independently of the resources provided with the script or its sources (at least in the Python 2 / GTK2 variant of the UI). Desktop menu integration ------------------------ This component ships both implementation-specific `nut-monitor-py2gtk2.desktop` and `nut-monitor-py3qt5.desktop` files which allows a user to have icons for both variants separately, as well as the legacy-named `nut-monitor.desktop` for running the wrapper script `NUT-Monitor` which picks an implementation best suited for current run-time circumstances. Screenshots ----------- image::screenshots/nut-monitor-1.png[Example of device status overview] image::screenshots/nut-monitor-2.png[Example report of device variables] image::screenshots/nut-monitor-3.png[Example modification of a writable variable] Development/Testing notes ------------------------- As Python2 falls out of favor and packaging scope of different distributions, one where both variants of the script can be tested simultaneously as of 2025 is MSYS2 (on Windows), see linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] for more details about general prerequisites for the NUT build in that environment. Regarding the Python UI support, you would need: ---- :; pacman -Sy mingw-w64-x86_64-python2-pygtk mingw-w64-x86_64-python-pyqt5 ---- This should pull in the interpreters and libraries involved. You may have to add this to your `~/.bashrc` for Python 2 to work properly: ---- PYTHONIOENCODING=UTF-8 export PYTHONIOENCODING ---- To iterate during specifically localization development, you can edit the `.in` template sources of the scripts and the localization files, and (from the `app` directory) run with: ---- :; (cd .. && make `pwd`/app/locale/*/*/*) ; (cd ../../../ && ./config.status \ scripts/python/app/NUT-Monitor-py2gtk2 scripts/python/app/NUT-Monitor-py3qt5) \ && LANG=fr_FR ./NUT-Monitor-py2gtk2 ---- or `..../NUT-Monitor-py3qt5` respectively. NOTE: While `LANG=it` can be useful on MSYS2 for testing that localization does take place, it proved problematic to load `fr` and `ru` resources -- logic buried inside `gtk.glade.XML()` and `gtk.glade.xml_new_from_buffer()` gets the UTF-8 encoded data from `ui/gui-1.3.glade`, but then apparently mangles it inside (possibly in the DLL used by the Python module) to some other encoding, and then fails to parse that as UTF-8 (broken non-ASCII characters in `fr`, crash in `ru`). PRs with fixes would be welcome! Kudos ----- NUT-Monitor and PyNUT (for Python 2 syntax) were originally authored by David Goncalves NUT-Monitor was converted to Python 3 + Qt5 by Luke Dashjr PyNUT was extended, and two variants of NUT-Monitor converged and wrapped for Python 2+3 dual support by Jim Klimov nut-2.8.3/scripts/python/app/nut-monitor.desktop0000644000200500020050000000050314777534446016740 00000000000000[Desktop Entry] Name=NUT Monitor Name[fr]=Moniteur NUT Comment=Network UPS Tools GUI client Comment[fr]=Client graphique pour NUT (Network UPS Tools) Comment[it]=Client grafico per NUT (Network UPS Tools) Categories=System;Monitor;HardwareSettings;Settings Exec=NUT-Monitor Icon=nut-monitor Terminal=false Type=Application nut-2.8.3/scripts/python/app/nut-monitor.appdata.xml0000644000200500020050000000431414777534446017504 00000000000000 nut-monitor.desktop nut-monitor.desktop CC0-1.0 GPL-3.0+ NUT Monitor GUI application to monitor UPS status

NUT Monitor is a GUI application to monitor UPS status, through NUT - Network UPS Tools. NUT is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes.

NUT Monitor provides the following features:

  • Automatically connects to local UPS if there is only one managed
  • Command line options to start hidden, load a favorite, ...
  • System tray (notification area) integration, including notifications
  • Favorites, to store different devices
  • Display all device variables
  • Modify writable variables on UPS and devices
  • Supports English, Russian and French localization (Python2 version only at the moment)

NUT Monitor requires that you have a running NUT system, that you can connect to, either locally or remotely. For more information on NUT: https://www.networkupstools.org/

https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-1.png https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-2.png https://www.lestat.st/_media/informatique/projets/nut-monitor/nut-monitor-3.png https://www.lestat.st/en/informatique/projets/nut-monitor david@lestat.st
nut-2.8.3/scripts/python/app/ui/0000755000200500020050000000000015001555412013522 500000000000000nut-2.8.3/scripts/python/app/ui/aboutdialog1.ui0000644000200500020050000000675114777767434016421 00000000000000 aboutdialog1 About NUT-Monitor true 0 0 0 0 <h1>NUT-Monitor 2.0.2</h1> <p>GUI to manage devices connected to a NUT server.<br/> Provided with NUT version @PACKAGE_VERSION@.</p> <p style=" font-size:8pt;">Copyright (C) 2010 David Goncalves<br/> Copyright (C) since 2010 by NUT Community</p> <p>For more information about NUT (Network UPS Tools)<br/> please visit the project web-site:</p> <p style="margin-bottom: 1.5em"><a href="@NUT_WEBSITE_BASE@">@NUT_WEBSITE_BASE@</a></p> <p>For more information about the GUI please visit<br/> the author's web-site:</p> <p><a href="https://www.lestat.st/en/informatique/projets/nut-monitor">https://www.lestat.st</a></p> Qt::RichText Qt::AlignCenter true true Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse Qt::Horizontal QDialogButtonBox::Ok buttonBox accepted() aboutdialog1 accept() 248 254 157 274 buttonBox rejected() aboutdialog1 reject() 316 260 286 274 nut-2.8.3/scripts/python/app/ui/window1.ui0000644000200500020050000003536514777534446015434 00000000000000 window1 0 0 560 465 NUT Monitor ../../../../../.designer/backup../../../../../.designer/backup NUT Server Qt::AlignCenter 0 0 0 0 65535 3493 Device : None Host / Port : false &Refresh Use authentication 0 0 0 0 Login / Password : QLineEdit::Password QFrame::HLine QFrame::Sunken false C&onnect &Disconnect 0 Device status 0 0 0 0 QFrame::StyledPanel QFrame::Raised 0 0 label Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 label Remaining time : Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Battery charge : Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 24 Device commands : Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 24 Current load : Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::StyledPanel QFrame::Raised N/A Qt::AlignCenter 0 0 QComboBox::AdjustToContents &Execute Device vars QFrame::StyledPanel QFrame::Raised &Refresh 0 0 560 24 &File F&avorites &About &Quit Ctrl+Q false &Add false &Delete nut-2.8.3/scripts/python/app/ui/gui-1.3.glade0000644000200500020050000015335214777767434015570 00000000000000 NUT Monitor center battery True True True _File True True gtk-about True True True True gtk-quit True True True True F_avorites True True gtk-add True False True True gtk-delete True False True True True False 0 True True 0.5 in True 2 True True True 2 3 True 1 Host / Port : GTK_FILL True 1 Device : 1 2 GTK_FILL True True 1 2 True True 5 5 3493 0 65535 1 10 0 True 2 3 GTK_FILL True None 1 2 1 2 gtk-refresh True False True True True 2 3 1 2 GTK_FILL GTK_FILL False False 0 Use authentication True True False True False 1 True False True 1 Login / Password : 0 True True 1 True True False 2 False 2 True False 4 3 0 True gtk-connect True False True True True 0 gtk-disconnect True True True 1 False 1 True NUT Server True label_item False 0 True True True 2 True True gtk-missing-image 6 False 0 True 0 in True 2 2 2 2 True True 1 0 2 label right False 0 True 0 0 2 label 1 label_item 1 0 True 4 2 4 True 1 2 Battery charge : True right GTK_FILL True 1 2 Current load : True right 1 2 GTK_FILL True 1 2 True 1 2 1 2 True 1 2 Remaining time : right 2 3 GTK_FILL True 0 in True True N/A True label_item 1 2 2 3 True 1 2 Device commands : True right 3 4 GTK_FILL True gtk-execute True True True True False False 1 1 2 3 4 False 1 True 2 Device status False tab True 2 True 0 in True 1 1 1 1 True True automatic automatic True True label_item 0 gtk-refresh True True True True False 1 1 True Device vars 1 False tab 1 1 True 2 False 2 5 True center-always normal True 2 True 0 in True 4 4 4 4 True True Enter a name for this favorite <span color="#808080">You cannot re-use a name from another entry</span> True 0 True True False 1 label_item 1 True spread gtk-add 1 True False True True True False False 0 gtk-cancel True True True True False False 1 False end 0 5 True center-always normal True 2 True 0 in True 4 4 4 4 True True Please select the favorite that you want to delete from list... True 0 True 0 <None> False 1 label_item 1 True spread gtk-delete 1 True True True True False False 0 gtk-cancel True True True True False False 1 False end 0 5 True center-always normal True 2 True 0 in True 4 4 4 4 True True 4 True gtk-edit 6 False 4 0 True Enter a new value for the variable. True 2 1 0 True True False 1 label_item 1 True spread gtk-save 1 True True True True False False 0 gtk-cancel True True True True False False 1 False end 0 5 True center-always normal NUT-Monitor 2.0.2 Copyright (c) 2010 David Goncalves, Copyright (c) since 2010 by NUT Community GUI to manage devices connected to a NUT server. Provided with NUT version @PACKAGE_VERSION@. For more information about the GUI please visit the author's web-site: https://www.lestat.st/en/informatique/projets/nut-monitor For more information about NUT (Network UPS Tools) please visit the project web-site: @NUT_WEBSITE_BASE@ @NUT_WEBSITE_BASE@ The Network UPS Tools project Copyright (C) 2010 David Goncalves <david@lestat.st> Copyright (C) since 2010 by NUT Community 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 <http://www.gnu.org/licenses/>. David Goncalves <david@lestat.st> David Goncalves <david@lestat.st> - Français Daniele Pezzini <hyouko@gmail.com> - Italiano Alexey Rodionov <alexey.rodionov@red-soft.ru> - Russian True 2 True spread False end 0 nut-2.8.3/scripts/python/app/ui/dialog1.ui0000644000200500020050000000420414777534446015350 00000000000000 dialog1 0 0 297 133 Dialog true QFrame::StyledPanel QFrame::Raised Enter a name for this favorite<br><br><font color="#808080">You cannot re-use a name from another entry</font> Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() dialog1 accept() 248 254 157 274 buttonBox rejected() dialog1 reject() 316 260 286 274 nut-2.8.3/scripts/python/app/ui/dialog2.ui0000644000200500020050000000440114777534446015350 00000000000000 dialog2 0 0 229 116 Dialog true QFrame::StyledPanel QFrame::Raised Please select the favorite that you want to delete from list... true None Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() dialog2 accept() 248 254 157 274 buttonBox rejected() dialog2 reject() 316 260 286 274 nut-2.8.3/scripts/python/app/locale/0000755000200500020050000000000015001555412014344 500000000000000nut-2.8.3/scripts/python/app/locale/fr/0000755000200500020050000000000015001555412014753 500000000000000nut-2.8.3/scripts/python/app/locale/fr/LC_MESSAGES/0000755000200500020050000000000015001555412016540 500000000000000nut-2.8.3/scripts/python/app/locale/fr/LC_MESSAGES/NUT-Monitor.mo0000644000200500020050000001732514777767434021154 00000000000000JlePAQ %9g< 4 7 & 7 /I y       ' > iX $ b J h   \ & .8 'g !   J ; JV jx+    2FY s0   (!H9jN !#'+S:q6+KAwC(C Yz  v#t!,#NrR&4,M(z$l^o 0   #1K[r@!:KR[v  )@:4 )J >AB, / (8?+"*#63DH E%<!F-57C. 0G&;91=$I'2 Please select the favorite that you want to delete from list... NUT Server (no battery protection)%H hours %M minutes %S seconds%M minutes %S seconds%M minutes %S seconds

NUT-Monitor 2.0.2

GUI to manage devices connected to a NUT server.
Provided with NUT version @PACKAGE_VERSION@.

Copyright (C) 2010 David Goncalves
Copyright (C) since 2010 by NUT Community

For more information about NUT (Network UPS Tools)
please visit the project web-site:

@NUT_WEBSITE_BASE@

For more information about the GUI please visit
the author's web-site:

https://www.lestat.st

Not connectedAre you sure that you want to remove this favorite ?Are you sure that you want to send '%s' to the device ?Battery charge :Battery voltage :Boost (UPS is boosting incoming voltage)Connected to '{0}' on {1}Current load :Device '%s' not found on serverDevice : Device commands :Device is running on batteriesDevice statusDevice status :Device varsDisconnected from '%s'Disconnecting from deviceEnter a name for this favorite You cannot re-use a name from another entry Enter a new value for the variable. Enter a new value for the variable. {0} = {1} (current value)Error connecting to '{0}' {1}Error connecting to '{0}' ({1})Error from '{0}' {1}Error from '{0}' ({1})Error parsing favorites, password for '%s' is not in base64 Skipping password for this entryError updating variable on '{0}' ({1})Error while creating configuration folder (%s)Error while parsing favorites file (%s)Error while saving favorites (%s)F_avoritesFailed to send '{0}' ({1})Found {0} devices on {1}GUI to manage devices connected to a NUT server. Provided with NUT version @PACKAGE_VERSION@. For more information about the GUI please visit the author's web-site: https://www.lestat.st/en/informatique/projets/nut-monitor For more information about NUT (Network UPS Tools) please visit the project web-site: @NUT_WEBSITE_BASE@ Host / Port : Loaded '%s'Login / Password : Low batteriesModel :N/ANo variable modified on %s - User cancelledNoneNot availableOfflineOn batteriesOnlineOverloaded !Performing runtime calibrationRemaining time :Removed favorite '%s'Replace batteries !Saved favorites...Sent '{0}' command to {1}Temperature :Triming (UPS is triming incoming voltage)UPS load :Updated variable on %sUse authenticationValueVar nameWelcome to NUT Monitor_Filechargingdischargingnot providing power to the loadthere is too much load for deviceProject-Id-Version: NUT Monitor Report-Msgid-Bugs-To: PO-Revision-Date: 2013-10-14 22:50+0200 Last-Translator: David Goncalves Language-Team: French Language: fr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Veuillez selectionner le favoris que vous souhaitez supprimer de la liste... Serveur NUT (pas de protection par batteries)%H heures %M minutes %S secondes%M minutes %S secondes%M minutes %S secondes

NUT-Monitor 2.0.2

Interface pour gérer les onduleurs connectés à un serveur NUT.
Fourni avec la version @PACKAGE_VERSION@ du NUT.

Copyright (C) 2010 David Goncalves
Copyright (C) since 2010 by NUT Community

Pour plus d'informations sur NUT (Network UPS Tools)
veuillez consulter le site de l'projet:

@NUT_WEBSITE_BASE@

Pour plus d'informations sur cet GUI
veuillez consulter le site de l'auteur:

https://www.lestat.st

Non connectéVoulez vous vraiement supprimer ce favoris?Voulez vous vraiement envoyer la commande '%s' au périphérique?Charge des batteries :Tension batteries :Compensation (l'onduleur compense le courant d'alimentation)Connecté à '{0}' sur {1}Puissance consommé :'%s' n'existe pas sur le serveurPériphérique :Commandes disponibles :Fonctionnement sur batteriesEtat du périphériqueEtat du périphérique :VariablesDéconnecté de '%s'DéconnectéVeuillez choisir un nom pour ce favoris Vous ne pouvez pas ré-utiliser un nom existant Nouvelle valeur de cette variable. Veuillez saisir la nouvelle valeur de la variable. {0} = {1} (valeure actuelle)Erreur de connexion sur '{0}' {1}Erreur de connexion sur '{0}' ({1})Erreur sur '{0}' {1}Erreur sur '{0}' ({1})Erreur de lecture des favoris sur l'entrée '%s'. Codage incorrect Favoris ignoréErreur de mise à jour sur '{0}' ({1})Erreur de création du dossier de configuration (%s)Erreur de lecture du fichier de favoris (%s)Erreur d'enregistrement des favoris (%s)F_avorisEchec de l'envoi de '{0}' ({1}){0} périphériques trouvés sur {1}Interface pour gérer les onduleurs connectés à un serveur NUT. Fourni avec la version @PACKAGE_VERSION@ du NUT. Pour plus d'informations sur cet GUI veuillez consulter le site de l'auteur: https://www.lestat.st/en/informatique/projets/nut-monitor Pour plus d'informations sur NUT (Network UPS Tools) veuillez consulter le site de l'projet: @NUT_WEBSITE_BASE@ Serveur / Port :Favoris '%s' chargéLogin / Mot de passe :Batteries faiblesModèle :N/DPas de modification sur %s - Opération annuléeAucunNon disponibleHors ligneSur batteriesEn ligneSovraccarico!Calibration des batteriesTemps restant :Favoris '%s' suppriméRemplacer les batteries!Favoris enregistrés...Commande '{0}' envoyée à {1}Température :Régulation (l'onduleur limite le courant d'alimentation)Consommation :Variable modifié sur %sAuthentificationValeurVariableBienvenue dans NUT Monitor_Fichieren chargeen déchargealimentation coupéela puissance demandé est trop importantenut-2.8.3/scripts/python/app/locale/fr/fr.po0000644000200500020050000002626314777767434015707 00000000000000# Italian translations for PACKAGE package. # Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # David Goncalves , 2010. # msgid "" msgstr "" "Project-Id-Version: NUT Monitor\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-14 22:47+0200\n" "PO-Revision-Date: 2013-10-14 22:50+0200\n" "Last-Translator: David Goncalves \n" "Language-Team: French\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: NUT-Monitor:150 msgid "Var name" msgstr "Variable" #: NUT-Monitor:158 msgid "Value" msgstr "Valeur" #: NUT-Monitor:205 msgid "Welcome to NUT Monitor" msgstr "Bienvenue dans NUT Monitor" #: NUT-Monitor:304 #, python-brace-format msgid "Found {0} devices on {1}" msgstr "{0} périphériques trouvés sur {1}" #: NUT-Monitor:307 NUT-Monitor:664 #, python-brace-format msgid "Error connecting to '{0}' ({1})" msgstr "Erreur de connexion sur '{0}' ({1})" #: NUT-Monitor:315 msgid "Disconnecting from device" msgstr "Déconnecté" #: NUT-Monitor:380 msgid "Are you sure that you want to remove this favorite ?" msgstr "Voulez vous vraiement supprimer ce favoris?" #: NUT-Monitor:388 #, python-format msgid "Removed favorite '%s'" msgstr "Favoris '%s' supprimé" #: NUT-Monitor:414 #, python-format msgid "Loaded '%s'" msgstr "Favoris '%s' chargé" #: NUT-Monitor:422 #, python-format msgid "" "Are you sure that you want to send\n" "'%s' to the device ?" msgstr "" "Voulez vous vraiement envoyer la commande\n" "'%s' au périphérique?" #: NUT-Monitor:431 #, python-brace-format msgid "Sent '{0}' command to {1}" msgstr "Commande '{0}' envoyée à {1}" #: NUT-Monitor:434 #, python-brace-format msgid "Failed to send '{0}' ({1})" msgstr "Echec de l'envoi de '{0}' ({1})" #: NUT-Monitor:452 #, python-brace-format msgid "" "Enter a new value for the variable.\n" "\n" "{0} = {1} (current value)" msgstr "" "Veuillez saisir la nouvelle valeur de la variable.\n" "\n" "{0} = {1} (valeure actuelle)" #: NUT-Monitor:466 #, python-format msgid "Updated variable on %s" msgstr "Variable modifié sur %s" #: NUT-Monitor:474 #, python-brace-format msgid "Error updating variable on '{0}' ({1})" msgstr "Erreur de mise à jour sur '{0}' ({1})" #: NUT-Monitor:479 #, python-format msgid "No variable modified on %s - User cancelled" msgstr "Pas de modification sur %s - Opération annulée" #: NUT-Monitor:558 #, python-format msgid "" "Error parsing favorites, password for '%s' is not in base64\n" "Skipping password for this entry" msgstr "" "Erreur de lecture des favoris sur l'entrée '%s'. Codage incorrect\n" "Favoris ignoré" #: NUT-Monitor:567 #, python-format msgid "Error while parsing favorites file (%s)" msgstr "Erreur de lecture du fichier de favoris (%s)" #: NUT-Monitor:578 #, python-format msgid "Error while creating configuration folder (%s)" msgstr "Erreur de création du dossier de configuration (%s)" #: NUT-Monitor:590 msgid "Saved favorites..." msgstr "Favoris enregistrés..." #: NUT-Monitor:593 #, python-format msgid "Error while saving favorites (%s)" msgstr "Erreur d'enregistrement des favoris (%s)" #: NUT-Monitor:665 #, python-brace-format msgid "" "Error connecting to '{0}'\n" "{1}" msgstr "" "Erreur de connexion sur '{0}'\n" "{1}" #: NUT-Monitor:673 NUT-Monitor:674 #, python-format msgid "Device '%s' not found on server" msgstr "'%s' n'existe pas sur le serveur" #: NUT-Monitor:708 #, python-brace-format msgid "Connected to '{0}' on {1}" msgstr "Connecté à '{0}' sur {1}" #: NUT-Monitor:740 msgid "Not connected" msgstr "Non connecté" #: NUT-Monitor:750 #, python-format msgid "Disconnected from '%s'" msgstr "Déconnecté de '%s'" #: NUT-Monitor:772 msgid "Low batteries" msgstr "Batteries faibles" #: NUT-Monitor:773 msgid "Replace batteries !" msgstr "Remplacer les batteries!" #: NUT-Monitor:774 msgid "(no battery protection)" msgstr "(pas de protection par batteries)" #: NUT-Monitor:775 msgid "Performing runtime calibration" msgstr "Calibration des batteries" #: NUT-Monitor:776 msgid "Offline" msgstr "Hors ligne" #: NUT-Monitor:776 msgid "not providing power to the load" msgstr "alimentation coupée" #: NUT-Monitor:777 msgid "Overloaded !" msgstr "Sovraccarico!" #: NUT-Monitor:777 msgid "there is too much load for device" msgstr "la puissance demandé est trop importante" #: NUT-Monitor:778 msgid "Triming (UPS is triming incoming voltage)" msgstr "Régulation (l'onduleur limite le courant d'alimentation)" #: NUT-Monitor:779 msgid "Boost (UPS is boosting incoming voltage)" msgstr "Compensation (l'onduleur compense le courant d'alimentation)" #: NUT-Monitor:792 msgid "Device status :" msgstr "Etat du périphérique :" #: NUT-Monitor:795 msgid "Online" msgstr "En ligne" #: NUT-Monitor:801 msgid "On batteries" msgstr "Sur batteries" #: NUT-Monitor:804 msgid "Device is running on batteries" msgstr "Fonctionnement sur batteries" #: NUT-Monitor:817 msgid "discharging" msgstr "en décharge" #: NUT-Monitor:819 msgid "charging" msgstr "en charge" #: NUT-Monitor:825 msgid "Model :" msgstr "Modèle :" #: NUT-Monitor:829 msgid "Temperature :" msgstr "Température :" #: NUT-Monitor:833 msgid "Battery voltage :" msgstr "Tension batteries :" #: NUT-Monitor:844 gui-1.3.glade.h:11 msgid "Battery charge :" msgstr "Charge des batteries :" #: NUT-Monitor:847 NUT-Monitor:856 NUT-Monitor:868 msgid "Not available" msgstr "Non disponible" #: NUT-Monitor:853 msgid "UPS load :" msgstr "Consommation :" #: NUT-Monitor:862 msgid "%H hours %M minutes %S seconds" msgstr "%H heures %M minutes %S secondes" #: NUT-Monitor:864 msgid "%M minutes %S seconds" msgstr "%M minutes %S secondes" #: NUT-Monitor:866 msgid "%M minutes %S seconds" msgstr "%M minutes %S secondes" #: NUT-Monitor:876 #, python-brace-format msgid "Error from '{0}' ({1})" msgstr "Erreur sur '{0}' ({1})" #: NUT-Monitor:877 #, python-brace-format msgid "" "Error from '{0}'\n" "{1}" msgstr "" "Erreur sur '{0}'\n" "{1}" #: gui-1.3.glade.h:1 msgid "NUT Monitor" msgstr "" #: gui-1.3.glade.h:2 msgid "_File" msgstr "_Fichier" #: gui-1.3.glade.h:3 msgid "F_avorites" msgstr "F_avoris" #: gui-1.3.glade.h:4 msgid "Host / Port : " msgstr "Serveur / Port :" #: gui-1.3.glade.h:5 msgid "Device : " msgstr "Périphérique :" #: gui-1.3.glade.h:6 msgid "None" msgstr "Aucun" #: gui-1.3.glade.h:7 msgid "Use authentication" msgstr "Authentification" #: gui-1.3.glade.h:8 msgid "Login / Password : " msgstr "Login / Mot de passe :" #: gui-1.3.glade.h:9 msgid " NUT Server " msgstr " Serveur NUT " #: gui-1.3.glade.h:10 msgid "label" msgstr "" #: gui-1.3.glade.h:12 msgid "Current load :" msgstr "Puissance consommé :" #: gui-1.3.glade.h:13 msgid "Remaining time :" msgstr "Temps restant :" #: gui-1.3.glade.h:14 msgid "N/A" msgstr "N/D" #: gui-1.3.glade.h:15 msgid "Device commands :" msgstr "Commandes disponibles :" #: gui-1.3.glade.h:16 msgid "Device status" msgstr "Etat du périphérique" #: gui-1.3.glade.h:17 msgid "Device vars" msgstr "Variables" #: gui-1.3.glade.h:18 msgid "" "Enter a name for this favorite\n" "\n" "You cannot re-use a name from another entry\n" msgstr "" "Veuillez choisir un nom pour ce favoris\n" "\n" "Vous ne pouvez pas ré-utiliser un nom existant\n" #: gui-1.3.glade.h:22 msgid "" "\n" "Please select the favorite that you\n" "want to delete from list...\n" msgstr "" "\n" "Veuillez selectionner le favoris que\n" "vous souhaitez supprimer de la liste...\n" #: gui-1.3.glade.h:26 msgid "" msgstr "" #: gui-1.3.glade.h:27 msgid "Enter a new value for the variable.\n" msgstr "Nouvelle valeur de cette variable.\n" #: gui-1.3.glade.h:29 msgid "Copyright (c) 2010 David Goncalves, Copyright (c) after 2010 NUT Community" msgstr "" # NOTE: This plaintext markup of the "comment" is used # in the Python2/GTK2 version of NUT Monitor. # Equivalent "label" text in HTML markup is used in # Python3/Qt5 localization. #: gui-1.3.glade.h:35 msgid "GUI to manage devices connected to a NUT server.\n" "Provided with NUT version @PACKAGE_VERSION@.\n" "\n" "For more information about the GUI please visit\n" "the author's web-site:\n" "https://www.lestat.st/en/informatique/projets/nut-monitor\n" "\n" "For more information about NUT (Network UPS Tools)\n" "please visit the project web-site:\n" "@NUT_WEBSITE_BASE@\n" msgstr "Interface pour gérer les onduleurs connectés à un serveur NUT.\n" "Fourni avec la version @PACKAGE_VERSION@ du NUT.\n" "\n" "Pour plus d'informations sur cet GUI\n" "veuillez consulter le site de l'auteur:\n" "https://www.lestat.st/en/informatique/projets/nut-monitor\n" "\n" "Pour plus d'informations sur NUT (Network UPS Tools)\n" "veuillez consulter le site de l'projet:\n" "@NUT_WEBSITE_BASE@\n" #: gui-1.3.glade.h:46 msgid "

NUT-Monitor 2.0.2

\n" "

GUI to manage devices connected to a NUT server.
\n" "Provided with NUT version @PACKAGE_VERSION@.

\n" "

Copyright (C) 2010 David Goncalves
\n" "Copyright (C) since 2010 by NUT Community

\n" "

For more information about NUT (Network UPS Tools)
\n" "please visit the project web-site:

\n" "

@NUT_WEBSITE_BASE@

\n" "

For more information about the GUI please visit
\n" "the author's web-site:

\n" "

https://www.lestat.st

" msgstr "

NUT-Monitor 2.0.2

\n" "

Interface pour gérer les onduleurs connectés à un serveur NUT.
\n" "Fourni avec la version @PACKAGE_VERSION@ du NUT.

\n" "

Copyright (C) 2010 David Goncalves
\n" "Copyright (C) since 2010 by NUT Community

\n" "

Pour plus d'informations sur NUT (Network UPS Tools)
\n" "veuillez consulter le site de l'projet:

\n" "

@NUT_WEBSITE_BASE@

\n" "

Pour plus d'informations sur cet GUI
\n" "veuillez consulter le site de l'auteur:

\n" "

https://www.lestat.st

" #: gui-1.3.glade.h:58 msgid "https://www.lestat.st" msgstr "" #: gui-1.3.glade.h:59 msgid "" "Copyright (C) 2010 David Goncalves \n" "Copyright (C) since 2010 by NUT Community\n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." msgstr "" nut-2.8.3/scripts/python/app/locale/NUT-Monitor.pot0000644000200500020050000001777214777767434017155 00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: NUT Monitor\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-15 20:35+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: NUT-Monitor:150 msgid "Var name" msgstr "" #: NUT-Monitor:158 msgid "Value" msgstr "" #: NUT-Monitor:205 msgid "Welcome to NUT Monitor" msgstr "" #: NUT-Monitor:304 #, python-brace-format msgid "Found {0} devices on {1}" msgstr "" #: NUT-Monitor:307 NUT-Monitor:664 #, python-brace-format msgid "Error connecting to '{0}' ({1})" msgstr "" #: NUT-Monitor:315 msgid "Disconnecting from device" msgstr "" #: NUT-Monitor:380 msgid "Are you sure that you want to remove this favorite ?" msgstr "" #: NUT-Monitor:388 #, python-format msgid "Removed favorite '%s'" msgstr "" #: NUT-Monitor:414 #, python-format msgid "Loaded '%s'" msgstr "" #: NUT-Monitor:422 #, python-format msgid "" "Are you sure that you want to send\n" "'%s' to the device ?" msgstr "" #: NUT-Monitor:431 #, python-brace-format msgid "Sent '{0}' command to {1}" msgstr "" #: NUT-Monitor:434 #, python-brace-format msgid "Failed to send '{0}' ({1})" msgstr "" #: NUT-Monitor:452 #, python-brace-format msgid "" "Enter a new value for the variable.\n" "\n" "{0} = {1} (current value)" msgstr "" #: NUT-Monitor:466 #, python-format msgid "Updated variable on %s" msgstr "" #: NUT-Monitor:474 #, python-brace-format msgid "Error updating variable on '{0}' ({1})" msgstr "" #: NUT-Monitor:479 #, python-format msgid "No variable modified on %s - User cancelled" msgstr "" #: NUT-Monitor:558 #, python-format msgid "" "Error parsing favorites, password for '%s' is not in base64\n" "Skipping password for this entry" msgstr "" #: NUT-Monitor:567 #, python-format msgid "Error while parsing favorites file (%s)" msgstr "" #: NUT-Monitor:578 #, python-format msgid "Error while creating configuration folder (%s)" msgstr "" #: NUT-Monitor:590 msgid "Saved favorites..." msgstr "" #: NUT-Monitor:593 #, python-format msgid "Error while saving favorites (%s)" msgstr "" #: NUT-Monitor:665 #, python-brace-format msgid "" "Error connecting to '{0}'\n" "{1}" msgstr "" #: NUT-Monitor:673 NUT-Monitor:674 #, python-format msgid "Device '%s' not found on server" msgstr "" #: NUT-Monitor:708 #, python-brace-format msgid "Connected to '{0}' on {1}" msgstr "" #: NUT-Monitor:740 msgid "Not connected" msgstr "" #: NUT-Monitor:750 #, python-format msgid "Disconnected from '%s'" msgstr "" #: NUT-Monitor:772 msgid "Low batteries" msgstr "" #: NUT-Monitor:773 msgid "Replace batteries !" msgstr "" #: NUT-Monitor:774 msgid "(no battery protection)" msgstr "" #: NUT-Monitor:775 msgid "Performing runtime calibration" msgstr "" #: NUT-Monitor:776 msgid "Offline" msgstr "" #: NUT-Monitor:776 msgid "not providing power to the load" msgstr "" #: NUT-Monitor:777 msgid "Overloaded !" msgstr "" #: NUT-Monitor:777 msgid "there is too much load for device" msgstr "" #: NUT-Monitor:778 msgid "Triming (UPS is triming incoming voltage)" msgstr "" #: NUT-Monitor:779 msgid "Boost (UPS is boosting incoming voltage)" msgstr "" #: NUT-Monitor:792 msgid "Device status :" msgstr "" #: NUT-Monitor:795 msgid "Online" msgstr "" #: NUT-Monitor:801 msgid "On batteries" msgstr "" #: NUT-Monitor:804 msgid "Device is running on batteries" msgstr "" #: NUT-Monitor:817 msgid "discharging" msgstr "" #: NUT-Monitor:819 msgid "charging" msgstr "" #: NUT-Monitor:825 msgid "Model :" msgstr "" #: NUT-Monitor:829 msgid "Temperature :" msgstr "" #: NUT-Monitor:833 msgid "Battery voltage :" msgstr "" #: NUT-Monitor:844 gui-1.3.glade.h:11 msgid "Battery charge :" msgstr "" #: NUT-Monitor:847 NUT-Monitor:856 NUT-Monitor:868 msgid "Not available" msgstr "" #: NUT-Monitor:853 msgid "UPS load :" msgstr "" #: NUT-Monitor:862 msgid "%H hours %M minutes %S seconds" msgstr "" #: NUT-Monitor:864 msgid "%M minutes %S seconds" msgstr "" #: NUT-Monitor:866 msgid "%M minutes %S seconds" msgstr "" #: NUT-Monitor:876 #, python-brace-format msgid "Error from '{0}' ({1})" msgstr "" #: NUT-Monitor:877 #, python-brace-format msgid "" "Error from '{0}'\n" "{1}" msgstr "" #: gui-1.3.glade.h:1 msgid "NUT Monitor" msgstr "" #: gui-1.3.glade.h:2 msgid "_File" msgstr "" #: gui-1.3.glade.h:3 msgid "F_avorites" msgstr "" #: gui-1.3.glade.h:4 msgid "Host / Port : " msgstr "" #: gui-1.3.glade.h:5 msgid "Device : " msgstr "" #: gui-1.3.glade.h:6 msgid "None" msgstr "" #: gui-1.3.glade.h:7 msgid "Use authentication" msgstr "" #: gui-1.3.glade.h:8 msgid "Login / Password : " msgstr "" #: gui-1.3.glade.h:9 msgid " NUT Server " msgstr "" #: gui-1.3.glade.h:10 msgid "label" msgstr "" #: gui-1.3.glade.h:12 msgid "Current load :" msgstr "" #: gui-1.3.glade.h:13 msgid "Remaining time :" msgstr "" #: gui-1.3.glade.h:14 msgid "N/A" msgstr "" #: gui-1.3.glade.h:15 msgid "Device commands :" msgstr "" #: gui-1.3.glade.h:16 msgid "Device status" msgstr "" #: gui-1.3.glade.h:17 msgid "Device vars" msgstr "" #: gui-1.3.glade.h:18 msgid "" "Enter a name for this favorite\n" "\n" "You cannot re-use a name from another entry\n" msgstr "" #: gui-1.3.glade.h:22 msgid "" "\n" "Please select the favorite that you\n" "want to delete from list...\n" msgstr "" #: gui-1.3.glade.h:26 msgid "" msgstr "" #: gui-1.3.glade.h:27 msgid "Enter a new value for the variable.\n" msgstr "" #: gui-1.3.glade.h:29 msgid "Copyright (c) 2010 David Goncalves, Copyright (c) after 2010 NUT Community" msgstr "" # NOTE: This plaintext markup of the "comment" is used # in the Python2/GTK2 version of NUT Monitor. # Equivalent "label" text in HTML markup is used in # Python3/Qt5 localization. #: gui-1.3.glade.h:35 msgid "GUI to manage devices connected to a NUT server.\n" "Provided with NUT version @PACKAGE_VERSION@.\n" "\n" "For more information about the GUI please visit\n" "the author's web-site:\n" "https://www.lestat.st/en/informatique/projets/nut-monitor\n" "\n" "For more information about NUT (Network UPS Tools)\n" "please visit the project web-site:\n" "@NUT_WEBSITE_BASE@\n" msgstr "" #: gui-1.3.glade.h:46 msgid "

NUT-Monitor 2.0.2

\n" "

GUI to manage devices connected to a NUT server.
\n" "Provided with NUT version @PACKAGE_VERSION@.

\n" "

Copyright (C) 2010 David Goncalves
\n" "Copyright (C) since 2010 by NUT Community

\n" "

For more information about NUT (Network UPS Tools)
\n" "please visit the project web-site:

\n" "

@NUT_WEBSITE_BASE@

\n" "

For more information about the GUI please visit
\n" "the author's web-site:

\n" "

https://www.lestat.st

" msgstr "" #: gui-1.3.glade.h:58 msgid "https://www.lestat.st" msgstr "" #: gui-1.3.glade.h:59 msgid "" "Copyright (C) 2010 David Goncalves \n" "Copyright (C) since 2010 by NUT Community\n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." msgstr "" nut-2.8.3/scripts/python/app/locale/ru/0000755000200500020050000000000015001555412014772 500000000000000nut-2.8.3/scripts/python/app/locale/ru/ru.po0000644000200500020050000003334414777767434015743 00000000000000# Russian translations for NUT-Monitor. # Copyright (C) 2020 Alexey Rodionov (RED SOFT, Russia) # This file is distributed under the same license as the NUT package. # Alexey Rodionov , 2020 msgid "" msgstr "" "Project-Id-Version: NUT Monitor\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-15 20:35+0200\n" "PO-Revision-Date: 2020-10-08 23:16+0300\n" "Last-Translator: Alexey Rodionov \n" "Language-Team: Russian\n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: NUT-Monitor:150 msgid "Var name" msgstr "Параметр" #: NUT-Monitor:158 msgid "Value" msgstr "Значение" #: NUT-Monitor:205 msgid "Welcome to NUT Monitor" msgstr "Добро пожаловать в NUT Monitor" #: NUT-Monitor:304 #, python-brace-format msgid "Found {0} devices on {1}" msgstr "Найдено {0} устройств на {1}" #: NUT-Monitor:307 NUT-Monitor:664 #, python-brace-format msgid "Error connecting to '{0}' ({1})" msgstr "Ошибка подключения к '{0}' ({1})" #: NUT-Monitor:315 msgid "Disconnecting from device" msgstr "Отключение от устройства" #: NUT-Monitor:380 msgid "Are you sure that you want to remove this favorite ?" msgstr "Вы уверены, что хотите удалить эту закладку ?" #: NUT-Monitor:388 #, python-format msgid "Removed favorite '%s'" msgstr "Закладка '%s' удалена" #: NUT-Monitor:414 #, python-format msgid "Loaded '%s'" msgstr "Загружено '%s'" #: NUT-Monitor:422 #, python-format msgid "" "Are you sure that you want to send\n" "'%s' to the device ?" msgstr "" "Вы уверены, что хотите отправить\n" "'%s' на устройство ?" #: NUT-Monitor:431 #, python-brace-format msgid "Sent '{0}' command to {1}" msgstr "Отправлена команда '{0}' на {1}" #: NUT-Monitor:434 #, python-brace-format msgid "Failed to send '{0}' ({1})" msgstr "Ошибка отправки '{0}' ({1})" #: NUT-Monitor:452 #, python-brace-format msgid "" "Enter a new value for the variable.\n" "\n" "{0} = {1} (current value)" msgstr "" "Введите новое значение параметра.\n" "\n" "{0} = {1} (текущее значение)" #: NUT-Monitor:466 #, python-format msgid "Updated variable on %s" msgstr "Обновлён параметр на %s" #: NUT-Monitor:474 #, python-brace-format msgid "Error updating variable on '{0}' ({1})" msgstr "Ошибка обновления параметра на '{0}' ({1})" #: NUT-Monitor:479 #, python-format msgid "No variable modified on %s - User cancelled" msgstr "Параметр на %s не изменён - отменено пользователем" #: NUT-Monitor:558 #, python-format msgid "" "Error parsing favorites, password for '%s' is not in base64\n" "Skipping password for this entry" msgstr "" "Ошибка разбора закладок, пароль для '%s' не в формате base64\n" "Пропускаем пароль для этой записи" #: NUT-Monitor:567 #, python-format msgid "Error while parsing favorites file (%s)" msgstr "Ошибка при разборе файла закладок (%s)" #: NUT-Monitor:578 #, python-format msgid "Error while creating configuration folder (%s)" msgstr "Ошибка при создании каталога настроек (%s)" #: NUT-Monitor:590 msgid "Saved favorites..." msgstr "Закладки сохранены..." #: NUT-Monitor:593 #, python-format msgid "Error while saving favorites (%s)" msgstr "Ошибка при сохранении закладок (%s)" #: NUT-Monitor:665 #, python-brace-format msgid "" "Error connecting to '{0}'\n" "{1}" msgstr "" "Ошибка подключения к '{0}'\n" "{1}" #: NUT-Monitor:673 NUT-Monitor:674 #, python-format msgid "Device '%s' not found on server" msgstr "Устройство '%s' не найдено на сервере" #: NUT-Monitor:708 #, python-brace-format msgid "Connected to '{0}' on {1}" msgstr "Подключено к '{0}' на {1}" #: NUT-Monitor:740 msgid "Not connected" msgstr "Не подключено" #: NUT-Monitor:750 #, python-format msgid "Disconnected from '%s'" msgstr "Отключено от '%s'" #: NUT-Monitor:772 msgid "Low batteries" msgstr "Низкий заряд" #: NUT-Monitor:773 msgid "Replace batteries !" msgstr "Замените батареи !" #: NUT-Monitor:774 msgid "(no battery protection)" msgstr "(нет защиты батареей)" #: NUT-Monitor:775 msgid "Performing runtime calibration" msgstr "Выполнение калибровки" #: NUT-Monitor:776 msgid "Offline" msgstr "Выключен" #: NUT-Monitor:776 msgid "not providing power to the load" msgstr "не обеспечено должного уровня питания для нагрузки" #: NUT-Monitor:777 msgid "Overloaded !" msgstr "Перегрузка !" #: NUT-Monitor:777 msgid "there is too much load for device" msgstr "слишком большая нагрузка на устройство" #: NUT-Monitor:778 msgid "Triming (UPS is triming incoming voltage)" msgstr "Отсечение (ИБП обрезает входящее напряжение)" #: NUT-Monitor:779 msgid "Boost (UPS is boosting incoming voltage)" msgstr "Повышение (ИБП повышает входящее напряжение)" #: NUT-Monitor:792 msgid "Device status :" msgstr "Статус устройства : " #: NUT-Monitor:795 msgid "Online" msgstr "От сети" #: NUT-Monitor:801 msgid "On batteries" msgstr "От батарей" #: NUT-Monitor:804 msgid "Device is running on batteries" msgstr "Устройство работает от батарей" #: NUT-Monitor:817 msgid "discharging" msgstr "разрядка" #: NUT-Monitor:819 msgid "charging" msgstr "зарядка" #: NUT-Monitor:825 msgid "Model :" msgstr "Модель : " #: NUT-Monitor:829 msgid "Temperature :" msgstr "Температура : " #: NUT-Monitor:833 msgid "Battery voltage :" msgstr "Напряжение батарей :" #: NUT-Monitor:844 gui-1.3.glade.h:11 msgid "Battery charge :" msgstr "Уровень заряда батарей : " #: NUT-Monitor:847 NUT-Monitor:856 NUT-Monitor:868 msgid "Not available" msgstr "Не доступно" #: NUT-Monitor:853 msgid "UPS load :" msgstr "Нагрузка ИБП :" #: NUT-Monitor:862 msgid "%H hours %M minutes %S seconds" msgstr "%H ч.%M мин. %S сек." #: NUT-Monitor:864 msgid "%M minutes %S seconds" msgstr "%M мин. %S сек." #: NUT-Monitor:866 msgid "%M minutes %S seconds" msgstr "%M мин. %S сек." #: NUT-Monitor:876 #, python-brace-format msgid "Error from '{0}' ({1})" msgstr "Ошибка от '{0}' ({1})" #: NUT-Monitor:877 #, python-brace-format msgid "" "Error from '{0}'\n" "{1}" msgstr "" "Ошибка от '{0}'\n" "{1}" #: gui-1.3.glade.h:1 msgid "NUT Monitor" msgstr "NUT Monitor" #: gui-1.3.glade.h:2 msgid "_File" msgstr "_Файл" #: gui-1.3.glade.h:3 msgid "F_avorites" msgstr "_Закладки" #: gui-1.3.glade.h:4 msgid "Host / Port : " msgstr "Хост / Порт : " #: gui-1.3.glade.h:5 msgid "Device : " msgstr "Устройство : " #: gui-1.3.glade.h:6 msgid "None" msgstr "Нет" #: gui-1.3.glade.h:7 msgid "Use authentication" msgstr "Аутентификация" #: gui-1.3.glade.h:8 msgid "Login / Password : " msgstr "Имя / Пароль : " #: gui-1.3.glade.h:9 msgid " NUT Server " msgstr " Сервер NUT " #: gui-1.3.glade.h:10 msgid "label" msgstr "метка" #: gui-1.3.glade.h:12 msgid "Current load :" msgstr "Текущая нагрузка :" #: gui-1.3.glade.h:13 msgid "Remaining time :" msgstr "Время автономной работы : " #: gui-1.3.glade.h:14 msgid "N/A" msgstr "N/A" #: gui-1.3.glade.h:15 msgid "Device commands :" msgstr "Команды устройства : " #: gui-1.3.glade.h:16 msgid "Device status" msgstr "Статус устройства" #: gui-1.3.glade.h:17 msgid "Device vars" msgstr "Параметры устройства" #: gui-1.3.glade.h:18 msgid "" "Enter a name for this favorite\n" "\n" "You cannot re-use a name from another entry\n" msgstr "" "Введите название для этой закладки\n" "\n" "Вы не можете повторно использовать имя другой закладки\n" #: gui-1.3.glade.h:22 msgid "" "\n" "Please select the favorite that you\n" "want to delete from list...\n" msgstr "" "\n" "Укажите закладку, которую Вы\n" "хотите удалить из списка...\n" #: gui-1.3.glade.h:26 msgid "" msgstr "<Нет>" #: gui-1.3.glade.h:27 msgid "Enter a new value for the variable.\n" msgstr "Введите новое значение параметра.\n" #: gui-1.3.glade.h:29 msgid "Copyright (c) 2010 David Goncalves, Copyright (c) after 2010 NUT Community" msgstr "Copyright (c) 2010 David Goncalves, Copyright (c) after 2010 NUT Community" # NOTE: This plaintext markup of the "comment" is used # in the Python2/GTK2 version of NUT Monitor. # Equivalent "label" text in HTML markup is used in # Python3/Qt5 localization. #: gui-1.3.glade.h:35 msgid "GUI to manage devices connected to a NUT server.\n" "Provided with NUT version @PACKAGE_VERSION@.\n" "\n" "For more information about the GUI please visit\n" "the author's web-site:\n" "https://www.lestat.st/en/informatique/projets/nut-monitor\n" "\n" "For more information about NUT (Network UPS Tools)\n" "please visit the project web-site:\n" "@NUT_WEBSITE_BASE@\n" msgstr "Графическая утилита управления устройствами,\n" "подключенными к серверу NUT.\n" "Поставлена как часть NUT версии @PACKAGE_VERSION@.\n" "\n" "Для получения дополнительной информации о самой утилите\n" "пожалуйста посетите веб-сайт автора:\n" "https://www.lestat.st/en/informatique/projets/nut-monitor\n" "\n" "Для получения дополнительной информации о NUT (Network UPS Tools)\n" "пожалуйста посетите веб-сайт проекта:\n" "please visit the project web-site:\n" #: gui-1.3.glade.h:46 msgid "

NUT-Monitor 2.0.2

\n" "

GUI to manage devices connected to a NUT server.
\n" "Provided with NUT version @PACKAGE_VERSION@.

\n" "

Copyright (C) 2010 David Goncalves
\n" "Copyright (C) since 2010 by NUT Community

\n" "

For more information about NUT (Network UPS Tools)
\n" "please visit the project web-site:

\n" "

@NUT_WEBSITE_BASE@

\n" "

For more information about the GUI please visit
\n" "the author's web-site:

\n" "

https://www.lestat.st

" msgstr "

NUT-Monitor 2.0.2

\n" "

Графическая утилита управления устройствами,
" "подключенными к серверу NUT.
\n" "Поставлена как часть NUT версии @PACKAGE_VERSION@.

\n" "

Copyright (C) 2010 David Goncalves
\n" "Copyright (C) since 2010 by NUT Community

\n" "

Для получения дополнительной информации о NUT (Network UPS Tools)
\n" "пожалуйста посетите веб-сайт проекта:

\n" "

@NUT_WEBSITE_BASE@

\n" "

Для получения дополнительной информации о самой утилите
\n" "пожалуйста посетите веб-сайт автора:

\n" "

https://www.lestat.st

" #: gui-1.3.glade.h:58 msgid "https://www.lestat.st" msgstr "https://www.lestat.st" #: gui-1.3.glade.h:59 msgid "" "Copyright (C) 2010 David Goncalves \n" "Copyright (C) since 2010 by NUT Community\n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." msgstr "" "Copyright (C) 2010 David Goncalves \n" "Copyright (C) since 2010 by NUT Community\n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." nut-2.8.3/scripts/python/app/locale/ru/LC_MESSAGES/0000755000200500020050000000000015001555412016557 500000000000000nut-2.8.3/scripts/python/app/locale/ru/LC_MESSAGES/NUT-Monitor.mo0000644000200500020050000002614614777767434021174 00000000000000Ok A  %'M9jg 4! 7V   /   J   9CU t i$9b^\+&.'! (3NJg   +3 8F N[ bo 0 5@Wjpy ! g&&"9K Q \[-%U &bJM!A& 9; !u $ '  .!0!?!6"0"2"*#F#d#E$KN$C$>$%)/%.Y%%(+(C(\(t(( (Z((( )) 1)?))V)/)$)!)&)2*Q*Uk**)*+"+3+.D+ s+}+++ +^+H,CBDLFEO=)&528@/.'I+GMHKJ *A3<">9;! :47 (% #0, 6$N1-? Please select the favorite that you want to delete from list... NUT Server (no battery protection)%H hours %M minutes %S seconds%M minutes %S seconds%M minutes %S seconds

NUT-Monitor 2.0.2

GUI to manage devices connected to a NUT server.
Provided with NUT version @PACKAGE_VERSION@.

Copyright (C) 2010 David Goncalves
Copyright (C) since 2010 by NUT Community

For more information about NUT (Network UPS Tools)
please visit the project web-site:

@NUT_WEBSITE_BASE@

For more information about the GUI please visit
the author's web-site:

https://www.lestat.st

Not connectedAre you sure that you want to remove this favorite ?Are you sure that you want to send '%s' to the device ?Battery charge :Battery voltage :Boost (UPS is boosting incoming voltage)Connected to '{0}' on {1}Copyright (C) 2010 David Goncalves Copyright (C) since 2010 by NUT Community 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 .Copyright (c) 2010 David Goncalves, Copyright (c) after 2010 NUT CommunityCurrent load :Device '%s' not found on serverDevice : Device commands :Device is running on batteriesDevice statusDevice status :Device varsDisconnected from '%s'Disconnecting from deviceEnter a name for this favorite You cannot re-use a name from another entry Enter a new value for the variable. Enter a new value for the variable. {0} = {1} (current value)Error connecting to '{0}' {1}Error connecting to '{0}' ({1})Error from '{0}' {1}Error from '{0}' ({1})Error parsing favorites, password for '%s' is not in base64 Skipping password for this entryError updating variable on '{0}' ({1})Error while creating configuration folder (%s)Error while parsing favorites file (%s)Error while saving favorites (%s)F_avoritesFailed to send '{0}' ({1})Found {0} devices on {1}GUI to manage devices connected to a NUT server. Provided with NUT version @PACKAGE_VERSION@. For more information about the GUI please visit the author's web-site: https://www.lestat.st/en/informatique/projets/nut-monitor For more information about NUT (Network UPS Tools) please visit the project web-site: @NUT_WEBSITE_BASE@ Host / Port : Loaded '%s'Login / Password : Low batteriesModel :N/ANUT MonitorNo variable modified on %s - User cancelledNoneNot availableOfflineOn batteriesOnlineOverloaded !Performing runtime calibrationRemaining time :Removed favorite '%s'Replace batteries !Saved favorites...Sent '{0}' command to {1}Temperature :Triming (UPS is triming incoming voltage)UPS load :Updated variable on %sUse authenticationValueVar nameWelcome to NUT Monitor_Filechargingdischarginghttps://www.lestat.stlabelnot providing power to the loadthere is too much load for deviceProject-Id-Version: NUT Monitor Report-Msgid-Bugs-To: PO-Revision-Date: 2020-10-08 23:16+0300 Last-Translator: Alexey Rodionov Language-Team: Russian Language: ru MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Укажите закладку, которую Вы хотите удалить из списка... Сервер NUT (нет защиты батареей)<Нет>%H ч.%M мин. %S сек.%M мин. %S сек.%M мин. %S сек.

NUT-Monitor 2.0.2

Графическая утилита управления устройствами,
подключенными к серверу NUT.
Поставлена как часть NUT версии @PACKAGE_VERSION@.

Copyright (C) 2010 David Goncalves
Copyright (C) since 2010 by NUT Community

Для получения дополнительной информации о NUT (Network UPS Tools)
пожалуйста посетите веб-сайт проекта:

@NUT_WEBSITE_BASE@

Для получения дополнительной информации о самой утилите
пожалуйста посетите веб-сайт автора:

https://www.lestat.st

Не подключеноВы уверены, что хотите удалить эту закладку ?Вы уверены, что хотите отправить '%s' на устройство ?Уровень заряда батарей : Напряжение батарей :Повышение (ИБП повышает входящее напряжение)Подключено к '{0}' на {1}Copyright (C) 2010 David Goncalves Copyright (C) since 2010 by NUT Community 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 .Copyright (c) 2010 David Goncalves, Copyright (c) after 2010 NUT CommunityТекущая нагрузка :Устройство '%s' не найдено на сервереУстройство : Команды устройства : Устройство работает от батарейСтатус устройстваСтатус устройства : Параметры устройстваОтключено от '%s'Отключение от устройстваВведите название для этой закладки Вы не можете повторно использовать имя другой закладки Введите новое значение параметра. Введите новое значение параметра. {0} = {1} (текущее значение)Ошибка подключения к '{0}' {1}Ошибка подключения к '{0}' ({1})Ошибка от '{0}' {1}Ошибка от '{0}' ({1})Ошибка разбора закладок, пароль для '%s' не в формате base64 Пропускаем пароль для этой записиОшибка обновления параметра на '{0}' ({1})Ошибка при создании каталога настроек (%s)Ошибка при разборе файла закладок (%s)Ошибка при сохранении закладок (%s)_ЗакладкиОшибка отправки '{0}' ({1})Найдено {0} устройств на {1}Графическая утилита управления устройствами, подключенными к серверу NUT. Поставлена как часть NUT версии @PACKAGE_VERSION@. Для получения дополнительной информации о самой утилите пожалуйста посетите веб-сайт автора: https://www.lestat.st/en/informatique/projets/nut-monitor Для получения дополнительной информации о NUT (Network UPS Tools) пожалуйста посетите веб-сайт проекта: please visit the project web-site: Хост / Порт : Загружено '%s'Имя / Пароль : Низкий зарядМодель : N/ANUT MonitorПараметр на %s не изменён - отменено пользователемНетНе доступноВыключенОт батарейОт сетиПерегрузка !Выполнение калибровкиВремя автономной работы : Закладка '%s' удаленаЗамените батареи !Закладки сохранены...Отправлена команда '{0}' на {1}Температура : Отсечение (ИБП обрезает входящее напряжение)Нагрузка ИБП :Обновлён параметр на %sАутентификацияЗначениеПараметрДобро пожаловать в NUT Monitor_Файлзарядкаразрядкаhttps://www.lestat.stметкане обеспечено должного уровня питания для нагрузкислишком большая нагрузка на устройствоnut-2.8.3/scripts/python/app/locale/it/0000755000200500020050000000000015001555412014760 500000000000000nut-2.8.3/scripts/python/app/locale/it/it.po0000644000200500020050000002653414777767434015722 00000000000000# Italian translations for PACKAGE package. # Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Daniele Pezzini , 2013. # msgid "" msgstr "" "Project-Id-Version: NUT Monitor\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-10-14 22:47+0200\n" "PO-Revision-Date: 2013-10-14 22:50+0200\n" "Last-Translator: Daniele Pezzini \n" "Language-Team: Italian\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: NUT-Monitor:150 msgid "Var name" msgstr "Nome della variabile" #: NUT-Monitor:158 msgid "Value" msgstr "Valore" #: NUT-Monitor:205 msgid "Welcome to NUT Monitor" msgstr "Benvenuto in NUT Monitor" #: NUT-Monitor:304 #, python-brace-format msgid "Found {0} devices on {1}" msgstr "Trovati {0} dispositivi su {1}" #: NUT-Monitor:307 NUT-Monitor:664 #, python-brace-format msgid "Error connecting to '{0}' ({1})" msgstr "Errore nel connettersi a '{0}' ({1})" #: NUT-Monitor:315 msgid "Disconnecting from device" msgstr "Disconnessione dal dispositivo in corso" #: NUT-Monitor:380 msgid "Are you sure that you want to remove this favorite ?" msgstr "Sei sicuro di voler rimuovere questo preferito?" #: NUT-Monitor:388 #, python-format msgid "Removed favorite '%s'" msgstr "Il preferito '%s' è stato rimosso" #: NUT-Monitor:414 #, python-format msgid "Loaded '%s'" msgstr "Caricato '%s'" #: NUT-Monitor:422 #, python-format msgid "" "Are you sure that you want to send\n" "'%s' to the device ?" msgstr "" "Sei sicuro di voler inviare il comando\n" "'%s' al dispositivo?" #: NUT-Monitor:431 #, python-brace-format msgid "Sent '{0}' command to {1}" msgstr "Inviato il comando '{0}' a {1}" #: NUT-Monitor:434 #, python-brace-format msgid "Failed to send '{0}' ({1})" msgstr "Errore nell'inviare '{0}' ({1})" #: NUT-Monitor:452 #, python-brace-format msgid "" "Enter a new value for the variable.\n" "\n" "{0} = {1} (current value)" msgstr "" "Inserisci un nuovo valore per la variabile.\n" "\n" "{0} = {1} (valore attuale)" #: NUT-Monitor:466 #, python-format msgid "Updated variable on %s" msgstr "Aggiornata la variabile su %s" #: NUT-Monitor:474 #, python-brace-format msgid "Error updating variable on '{0}' ({1})" msgstr "Errore nell'aggiornare la variabile su '{0}' ({1})" #: NUT-Monitor:479 #, python-format msgid "No variable modified on %s - User cancelled" msgstr "Nessuna variabile modificata su %s - Operazione annullata" #: NUT-Monitor:558 #, python-format msgid "" "Error parsing favorites, password for '%s' is not in base64\n" "Skipping password for this entry" msgstr "" "Errore nel processare i preferiti, la password per '%s' non è in base64\n" "La password per questo preferito verrà saltata" #: NUT-Monitor:567 #, python-format msgid "Error while parsing favorites file (%s)" msgstr "Errore nel processare il file dei preferiti (%s)" #: NUT-Monitor:578 #, python-format msgid "Error while creating configuration folder (%s)" msgstr "Errore nel creare la cartella di configurazione (%s)" #: NUT-Monitor:590 msgid "Saved favorites..." msgstr "Preferiti salvati..." #: NUT-Monitor:593 #, python-format msgid "Error while saving favorites (%s)" msgstr "Errore nel salvare i preferiti (%s)" #: NUT-Monitor:665 #, python-brace-format msgid "" "Error connecting to '{0}'\n" "{1}" msgstr "" "Errore nel connettersi a '{0}'\n" "{1}" #: NUT-Monitor:673 NUT-Monitor:674 #, python-format msgid "Device '%s' not found on server" msgstr "Il dispositivo '%s' non è stato trovato sul server" #: NUT-Monitor:708 #, python-brace-format msgid "Connected to '{0}' on {1}" msgstr "Connesso a '{0}' su {1}" #: NUT-Monitor:740 msgid "Not connected" msgstr "Non connesso" #: NUT-Monitor:750 #, python-format msgid "Disconnected from '%s'" msgstr "Disconnesso da '%s'" #: NUT-Monitor:772 msgid "Low batteries" msgstr "Batterie scariche" #: NUT-Monitor:773 msgid "Replace batteries !" msgstr "Cambia le batterie!" #: NUT-Monitor:774 msgid "(no battery protection)" msgstr "(nessuna protezione dalle batterie)" #: NUT-Monitor:775 msgid "Performing runtime calibration" msgstr "Calibrazione dell'autonomia in esecuzione" #: NUT-Monitor:776 msgid "Offline" msgstr "Spento" #: NUT-Monitor:776 msgid "not providing power to the load" msgstr "non viene fornita alimentazione al carico" #: NUT-Monitor:777 msgid "Overloaded !" msgstr "Sovraccarico!" #: NUT-Monitor:777 msgid "there is too much load for device" msgstr "c'è troppo carico per il dispositivo" #: NUT-Monitor:778 msgid "Triming (UPS is triming incoming voltage)" msgstr "Smorzamento (il gruppo di continuità sta smorzando il voltaggio in ingresso)" #: NUT-Monitor:779 msgid "Boost (UPS is boosting incoming voltage)" msgstr "Potenziamento (il gruppo di continutà sta potenziando il voltaggio in ingresso)" #: NUT-Monitor:792 msgid "Device status :" msgstr "Stato del dispositivo :" #: NUT-Monitor:795 msgid "Online" msgstr "In linea" #: NUT-Monitor:801 msgid "On batteries" msgstr "A batteria" #: NUT-Monitor:804 msgid "Device is running on batteries" msgstr "Il dispositivo sta funzionando a batteria" #: NUT-Monitor:817 msgid "discharging" msgstr "in scarica" #: NUT-Monitor:819 msgid "charging" msgstr "in ricarica" #: NUT-Monitor:825 msgid "Model :" msgstr "Modello :" #: NUT-Monitor:829 msgid "Temperature :" msgstr "Temperatura :" #: NUT-Monitor:833 msgid "Battery voltage :" msgstr "Voltaggio della batteria :" #: NUT-Monitor:844 gui-1.3.glade.h:11 msgid "Battery charge :" msgstr "Carica della batteria :" #: NUT-Monitor:847 NUT-Monitor:856 NUT-Monitor:868 msgid "Not available" msgstr "Non disponibile" #: NUT-Monitor:853 msgid "UPS load :" msgstr "Carico del gruppo di continutà :" #: NUT-Monitor:862 msgid "%H hours %M minutes %S seconds" msgstr "%H ore %M minuti %S secondi" #: NUT-Monitor:864 msgid "%M minutes %S seconds" msgstr "%M minuti %S secondi" #: NUT-Monitor:866 msgid "%M minutes %S seconds" msgstr "%M minuti %S secondi" #: NUT-Monitor:876 #, python-brace-format msgid "Error from '{0}' ({1})" msgstr "Errore da '{0}' ({1})" #: NUT-Monitor:877 #, python-brace-format msgid "" "Error from '{0}'\n" "{1}" msgstr "" "Errore da '{0}'\n" "{1}" #: gui-1.3.glade.h:1 msgid "NUT Monitor" msgstr "" #: gui-1.3.glade.h:2 msgid "_File" msgstr "" #: gui-1.3.glade.h:3 msgid "F_avorites" msgstr "Preferiti" #: gui-1.3.glade.h:4 msgid "Host / Port : " msgstr "Host / Porta :" #: gui-1.3.glade.h:5 msgid "Device : " msgstr "Dispositivo :" #: gui-1.3.glade.h:6 msgid "None" msgstr "Nessuno" #: gui-1.3.glade.h:7 msgid "Use authentication" msgstr "Usa l'autenticazione" #: gui-1.3.glade.h:8 msgid "Login / Password : " msgstr "Utente / Password : " #: gui-1.3.glade.h:9 msgid " NUT Server " msgstr "" #: gui-1.3.glade.h:10 msgid "label" msgstr "etichetta" #: gui-1.3.glade.h:12 msgid "Current load :" msgstr "Carico attuale :" #: gui-1.3.glade.h:13 msgid "Remaining time :" msgstr "Tempo rimasto :" #: gui-1.3.glade.h:14 msgid "N/A" msgstr "N/D" #: gui-1.3.glade.h:15 msgid "Device commands :" msgstr "Comandi del dispositivo :" #: gui-1.3.glade.h:16 msgid "Device status" msgstr "Stato del dispositivo" #: gui-1.3.glade.h:17 msgid "Device vars" msgstr "Variabili del dispositivo" #: gui-1.3.glade.h:18 msgid "" "Enter a name for this favorite\n" "\n" "You cannot re-use a name from another entry\n" msgstr "" "Inserisci un nome per questo preferito\n" "\n" "Non puoi usare lo stesso nome per più preferiti\n" #: gui-1.3.glade.h:22 msgid "" "\n" "Please select the favorite that you\n" "want to delete from list...\n" msgstr "" "\n" "Per favore scegli il preferito che\n" "vuoi cancellare dalla lista...\n" #: gui-1.3.glade.h:26 msgid "" msgstr "" #: gui-1.3.glade.h:27 msgid "Enter a new value for the variable.\n" msgstr "Inserisci un nuovo valore per la variabile.\n" #: gui-1.3.glade.h:29 msgid "Copyright (c) 2010 David Goncalves, Copyright (c) after 2010 NUT Community" msgstr "" # NOTE: This plaintext markup of the "comment" is used # in the Python2/GTK2 version of NUT Monitor. # Equivalent "label" text in HTML markup is used in # Python3/Qt5 localization. #: gui-1.3.glade.h:35 msgid "GUI to manage devices connected to a NUT server.\n" "Provided with NUT version @PACKAGE_VERSION@.\n" "\n" "For more information about the GUI please visit\n" "the author's web-site:\n" "https://www.lestat.st/en/informatique/projets/nut-monitor\n" "\n" "For more information about NUT (Network UPS Tools)\n" "please visit the project web-site:\n" "@NUT_WEBSITE_BASE@\n" msgstr "Interfaccia grafica per gestire dispositivi connessi a un server di NUT.\n" "Fornito con la versione @PACKAGE_VERSION@ del NUT.\n" "\n" "Per maggiori informazioni su GUI\n" "si visiti il sito dell'autore:\n" "https://www.lestat.st/en/informatique/projets/nut-monitor\n" "\n" "Per maggiori informazioni su NUT (Network UPS Tools)\n" "si visiti il sito del progetto:\n" "@NUT_WEBSITE_BASE@\n" #: gui-1.3.glade.h:46 msgid "

NUT-Monitor 2.0.2

\n" "

GUI to manage devices connected to a NUT server.
\n" "Provided with NUT version @PACKAGE_VERSION@.

\n" "

Copyright (C) 2010 David Goncalves
\n" "Copyright (C) since 2010 by NUT Community

\n" "

For more information about NUT (Network UPS Tools)
\n" "please visit the project web-site:

\n" "

@NUT_WEBSITE_BASE@

\n" "

For more information about the GUI please visit
\n" "the author's web-site:

\n" "

https://www.lestat.st

" msgstr "

NUT-Monitor 2.0.2

\n" "Interfaccia grafica per gestire dispositivi connessi a un server di NUT.
\n" "Fornito con la versione @PACKAGE_VERSION@ del NUT.

\n" "

Copyright (C) 2010 David Goncalves
\n" "Copyright (C) since 2010 by NUT Community

\n" "

Per maggiori informazioni su NUT (Network UPS Tools)
\n" "si visiti il sito del progetto:

\n" "

@NUT_WEBSITE_BASE@

\n" "

Per maggiori informazioni su GUI
\n" "si visiti il sito dell'autore:

\n" "

https://www.lestat.st

" #: gui-1.3.glade.h:58 msgid "https://www.lestat.st" msgstr "" #: gui-1.3.glade.h:59 msgid "" "Copyright (C) 2010 David Goncalves \n" "Copyright (C) since 2010 by NUT Community\n" "\n" "This program is free software: you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program. If not, see ." msgstr "" nut-2.8.3/scripts/python/app/locale/it/LC_MESSAGES/0000755000200500020050000000000015001555412016545 500000000000000nut-2.8.3/scripts/python/app/locale/it/LC_MESSAGES/NUT-Monitor.mo0000644000200500020050000001751714777767434021164 00000000000000Ida0A1s%9gw 4 7   / L f u      i+ $ b  ; [ p \ & . ': !b   J  ) =KS+W   , F0T  !<=Cz# "8+zd/;#_wW3 GU)o'v,k"-$Pux24K0# `  9 # *5 >)Lv" T!Tv   )%)%*;GI9=F (/,7 6@&4B)H-A$18C <'>+? #3! D 50:"2E. Please select the favorite that you want to delete from list... (no battery protection)%H hours %M minutes %S seconds%M minutes %S seconds%M minutes %S seconds

NUT-Monitor 2.0.2

GUI to manage devices connected to a NUT server.
Provided with NUT version @PACKAGE_VERSION@.

Copyright (C) 2010 David Goncalves
Copyright (C) since 2010 by NUT Community

For more information about NUT (Network UPS Tools)
please visit the project web-site:

@NUT_WEBSITE_BASE@

For more information about the GUI please visit
the author's web-site:

https://www.lestat.st

Not connectedAre you sure that you want to remove this favorite ?Are you sure that you want to send '%s' to the device ?Battery charge :Battery voltage :Boost (UPS is boosting incoming voltage)Connected to '{0}' on {1}Current load :Device '%s' not found on serverDevice : Device commands :Device is running on batteriesDevice statusDevice status :Device varsDisconnected from '%s'Disconnecting from deviceEnter a name for this favorite You cannot re-use a name from another entry Enter a new value for the variable. Enter a new value for the variable. {0} = {1} (current value)Error connecting to '{0}' {1}Error connecting to '{0}' ({1})Error from '{0}' {1}Error from '{0}' ({1})Error parsing favorites, password for '%s' is not in base64 Skipping password for this entryError updating variable on '{0}' ({1})Error while creating configuration folder (%s)Error while parsing favorites file (%s)Error while saving favorites (%s)F_avoritesFailed to send '{0}' ({1})Found {0} devices on {1}GUI to manage devices connected to a NUT server. Provided with NUT version @PACKAGE_VERSION@. For more information about the GUI please visit the author's web-site: https://www.lestat.st/en/informatique/projets/nut-monitor For more information about NUT (Network UPS Tools) please visit the project web-site: @NUT_WEBSITE_BASE@ Host / Port : Loaded '%s'Login / Password : Low batteriesModel :N/ANo variable modified on %s - User cancelledNoneNot availableOfflineOn batteriesOnlineOverloaded !Performing runtime calibrationRemaining time :Removed favorite '%s'Replace batteries !Saved favorites...Sent '{0}' command to {1}Temperature :Triming (UPS is triming incoming voltage)UPS load :Updated variable on %sUse authenticationValueVar nameWelcome to NUT Monitorchargingdischarginglabelnot providing power to the loadthere is too much load for deviceProject-Id-Version: NUT Monitor Report-Msgid-Bugs-To: PO-Revision-Date: 2013-10-14 22:50+0200 Last-Translator: Daniele Pezzini Language-Team: Italian Language: it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); Per favore scegli il preferito che vuoi cancellare dalla lista... (nessuna protezione dalle batterie)%H ore %M minuti %S secondi%M minuti %S secondi%M minuti %S secondi

NUT-Monitor 2.0.2

Interfaccia grafica per gestire dispositivi connessi a un server di NUT.
Fornito con la versione @PACKAGE_VERSION@ del NUT.

Copyright (C) 2010 David Goncalves
Copyright (C) since 2010 by NUT Community

Per maggiori informazioni su NUT (Network UPS Tools)
si visiti il sito del progetto:

@NUT_WEBSITE_BASE@

Per maggiori informazioni su GUI
si visiti il sito dell'autore:

https://www.lestat.st

Non connessoSei sicuro di voler rimuovere questo preferito?Sei sicuro di voler inviare il comando '%s' al dispositivo?Carica della batteria :Voltaggio della batteria :Potenziamento (il gruppo di continutà sta potenziando il voltaggio in ingresso)Connesso a '{0}' su {1}Carico attuale :Il dispositivo '%s' non è stato trovato sul serverDispositivo :Comandi del dispositivo :Il dispositivo sta funzionando a batteriaStato del dispositivoStato del dispositivo :Variabili del dispositivoDisconnesso da '%s'Disconnessione dal dispositivo in corsoInserisci un nome per questo preferito Non puoi usare lo stesso nome per più preferiti Inserisci un nuovo valore per la variabile. Inserisci un nuovo valore per la variabile. {0} = {1} (valore attuale)Errore nel connettersi a '{0}' {1}Errore nel connettersi a '{0}' ({1})Errore da '{0}' {1}Errore da '{0}' ({1})Errore nel processare i preferiti, la password per '%s' non è in base64 La password per questo preferito verrà saltataErrore nell'aggiornare la variabile su '{0}' ({1})Errore nel creare la cartella di configurazione (%s)Errore nel processare il file dei preferiti (%s)Errore nel salvare i preferiti (%s)PreferitiErrore nell'inviare '{0}' ({1})Trovati {0} dispositivi su {1}Interfaccia grafica per gestire dispositivi connessi a un server di NUT. Fornito con la versione @PACKAGE_VERSION@ del NUT. Per maggiori informazioni su GUI si visiti il sito dell'autore: https://www.lestat.st/en/informatique/projets/nut-monitor Per maggiori informazioni su NUT (Network UPS Tools) si visiti il sito del progetto: @NUT_WEBSITE_BASE@ Host / Porta :Caricato '%s'Utente / Password : Batterie scaricheModello :N/DNessuna variabile modificata su %s - Operazione annullataNessunoNon disponibileSpentoA batteriaIn lineaSovraccarico!Calibrazione dell'autonomia in esecuzioneTempo rimasto :Il preferito '%s' è stato rimossoCambia le batterie!Preferiti salvati...Inviato il comando '{0}' a {1}Temperatura :Smorzamento (il gruppo di continuità sta smorzando il voltaggio in ingresso)Carico del gruppo di continutà :Aggiornata la variabile su %sUsa l'autenticazioneValoreNome della variabileBenvenuto in NUT Monitorin ricaricain scaricaetichettanon viene fornita alimentazione al caricoc'è troppo carico per il dispositivonut-2.8.3/scripts/python/app/nut-monitor-py3qt5.desktop0000644000200500020050000000054614777534446020112 00000000000000[Desktop Entry] Name=NUT Monitor Name[fr]=Moniteur NUT Comment=Network UPS Tools GUI client (Py3Qt5) Comment[fr]=Client graphique pour NUT (Network UPS Tools, Py3Qt5) Comment[it]=Client grafico per NUT (Network UPS Tools, Py3Qt5) Categories=System;Monitor;HardwareSettings;Settings;Qt Exec=NUT-Monitor-py3qt5 Icon=nut-monitor Terminal=false Type=Application nut-2.8.3/scripts/python/app/nut-monitor-py2gtk2.desktop0000644000200500020050000000055314777534446020245 00000000000000[Desktop Entry] Name=NUT Monitor Name[fr]=Moniteur NUT Comment=Network UPS Tools GUI client (Py2Gtk2) Comment[fr]=Client graphique pour NUT (Network UPS Tools, Py2Gtk2) Comment[it]=Client grafico per NUT (Network UPS Tools, Py2Gtk2) Categories=System;Monitor;HardwareSettings;Settings;GTK Exec=NUT-Monitor-py2gtk2 Icon=nut-monitor Terminal=false Type=Application nut-2.8.3/scripts/python/app/screenshots/0000755000200500020050000000000015001555412015445 500000000000000nut-2.8.3/scripts/python/app/screenshots/nut-monitor-2.png0000644000200500020050000012322214777534446020556 00000000000000PNG  IHDRl][1sBIT|dtEXtSoftwaregnome-screenshot> IDATxw|l $*(Rm4UԋV {^׮׎" J6ed)"1ٝ3NݳOO?UeYz9W.˲B!{F lU(5fwb)0 ~3MIq6iB!8(q; YPʎmŊ,\03fY!@2 !BX40t)l`~vAB!8p)[&ᰅiiH oöizlN0EB!( vABt T!P tlZ[8F vϚ,K0Jf#vڎB!h*̰M)R OQ -*axLlAD7./h[̵[nV<]q ***ciӆ$`¢"֭]˪UI˱B! R ӆ+]ݸKqQhﱡBAMVyxJ4xw28昣 :v~q&fXe uQBeYh: Ϡ.x N0lN A\F8aXiu2 t`i8#r6✴JKʛW rc84R Zn7%#5˕hvfnASf<ͨx.d۴vt7,$?g!.n]ElHLE$-=ma$mB!>dYiWgfY xacmא\w̲۶0lp,0|X;"w6n{g2|[N|z"aloc\QFRՑ^3er%vr [^{rs:V8nz!,7tp-Xͫgݍp`)'-?:s[m`Bwt )ֺē}1P9@|E#SBx,[|>?CZƓe1}sa 0*kvp"_kgGp3_o󓝝  PMtժ%ƚ>}Fq \g} WJHEPרojE.G%n*eڟs7eR@"9)"1Ƃֆa'/픅 }SP)+F lf`@qCQ&n'R8'/IcÎRv<6IrBq!E7p(nU!uSJ՟AHM,-h-ֺ2{s<= 8(NhM]8ifmsVlA ߩ-3ٲukN>ŗfbi.e/[zѕ_$K%(QDksk&vQ-oaJ)*.!.ɍ94Q?cHo30 }C3ASmh}~rm/aW)MS.`"9F0vOM/} JO[L;gƟϒ -7߳U! k0a ôe a̠"NI3|ɘcӦlKd;ME8lVønBNinw*((uu 0a?ǵ7A)"SʪY [J)ltǮfhТ5r*%Z,?m:JgH ?MC3EpxJ{˧E5o}?O{:$^RO/F=s KZa&]uNt}B`¦M?VWdOpsbMu*k:U;27"կέpt4 I.vf0 ~z7n\*QVQkVFZe1^l9UL]~Lg;͡%cg H7v9_pImϖ-s=?`nb+iasjmR,uFUh+f?2*07evjk.BѰhVQSixaUe?/mk<ӤʎznQVG*!CY8oQQ~cAeMZu5l5c,wx%Ws'Z Si +z^h:v̠ }ZV}5ϩR} 쳯h6+y?e[_tTJ5 $'x} XJ ˦P$YLꉙF 2vNH*؄BFװ0D']g7ٸ_[QBj<:g52WQ"axǻ++oQRRڣbf9>o^v4fūӮ]3 l%tztcְU-j eK`AE r<2)V5ZaYR3RĪWV ֨5:cDUn*BXll*qH U1GV]&¥^xy;ZG}l3 vGefٺwΙValݺCs~1pvD0">>U̧Y7hB̞]ݒ]-8r rdb|5p(-o17kU6G֜y [θco} hɦǓ>460UpchIPik]yx5_B!vR UOig>ֆeҶ`mE5[@P+GY&h:k} XKq:;0i#xw Pg:cBQ?sgH$QIrl9SgsY7pl ro<. &#r0 ,U-^NSc?:e*J,OqE2"tyǾ܊V5"]|fݗ?#r3n^RTz!Bc)v찣A(&)X> K([;Ug„&:uth'VWa{4֎(/!#Qgt(!.N6Xj6A[DzU䃢VOzpdrSZKf4!PCD݃+̥U2#YZDȌtP\Z )AQQ .{AYAd],HnO":c&+!+Af*BY6lQ K4 sCj)lȓ {(2\8xA,p:P*&T$i lڴ ]J,!BȲ,CN¡0`274) M's|~ ;m`Ca 8v;P`0르 ӾWc !B45e |%l Mfˌ V4 ]ױ l6[)"iB!%ZHT-T])B!B!$lB!M$lB!M\B!Ry %]B!hvl>!BH&BI&BɽÿWn2$W|׋QQ}z62&?ЅqAq+/s/Fqψ47q#3ht`}2_n8 Vt;ӎI]nw"璄MѨ9mr@*u{Aa-C^$h$^mVu23kϧed9 4dJBYqp-5uJywvJu3iTresؙ=oyjrڷ2<,unG|~WCqJhw\}Tڮ'BaB4*#9K9Mxhge),ZRT4M$l7mu%c;#|e\Z =q^_zm _tUbh YmneXo6d23 X wbËSGcU2I(6n,$|#m4.$l҅\thY; ?ՅrǒaD ShƓZL-!~/JWom,\;\!(g66;fr ы$&7pJ&hْU0o؜؝H[|"\=8/LDmAl5 N qbga-b .ɚi x> %hyܕ\}WLdv InӓӮ9E_sw.gS) Zu;KF['WƇOPz#pe͠F LZ9Soqb0q.i}l%B!Ma?eZ!BN6!B&N6!B&N6!B&N6!B&;3+ez),( B![m iץՙmذ8gmڵ'!!qT!@,@Ϧظqmjݮք-o6lNQJaYY5MC?4JՈ'Bq ͉2/*!8(_1[Ւ:]*ra )61" *Ų,~+K.fҥpѺuMiaj!U-&R1+Z*w&ad| ľFUYW߷k!<"ZΦO(Ҹ6eFG-@IbzJƪ%&ZZhy]zBp8̽K˖k=۸"_ s>gqO0,P aʭc_GԬԪl$xO*&Ѫ5mb6}1lv6;nlW5ymDL17<PV_~`\vk{2t7GQIW5l[)+rhLפiTG @G7¢¡@ph~V^fj8RIi@KkN2y% `\sϑ\~敉1gC)ʝES/3&1n=Cy(, s.umtWZEyZ3`U\ujrD~yq{K࡫^M+9!R}ZbA|mD#DJǪ7j}6q8~7?ʊ,tïl}+r[2pT&6ig‰2/[^á^Lfrǒ^ώ{dgep߃Vq\4G|N1hkaCcx,c*zG_A|\i^ӟ;׽ CoSrLx Ṕ}AeqWu'xЭ㹵4SME.V׿6)>إQ *WEV|_Uޜ9[)((xN#2w"bz+6s%W?yQN3/Mz\hiR[';D:{Oζi߱: ?#Lvrl>Ԏ2Zs]q!,OgoomD qCy_ILvC/YQGYft$e >9bɗT1PJG)0 M*{HZ MB+w_&-Y\}cjժx[ xpiVeӀw~}pB{>J.=%ۋ!L,B'ubf-pEm*'r:PeY_JU_VQ!~ _#l[}v>#x/\4Νs`ٱc/h)˲0nw` pP(@7t44,֌(Y l6Papdf^00l6t-2͊xu]L3b:}dzLp8R޲ @T (hU~ԺA躎?aȰ[-Q#CUE]dEZ6iZe!~K)ꫮaZ_~*,Z6mk[k֡S'~u6gH]lYchB!_GPsGiR\9QʤCNƭ5a3 >fJ7Ϸ/@!BT:.m;оc:'$`*+ àc.teϖT!BKl! hxk!BWl6Jl Iopb}!BѸ fwmfъ -Ikޜ}]F!BR~7aY-[ey REE-B!b4 NbRI"y e& ?RZRr@u'mh#BI:5yX^&3a ,Yd;vM!De()߿s@4 g\͛ >! qpޤUBY2 C7Xl$lB!,[IӶ]{RGȬƅyl޼-!>!RRӰ3R7?}]!NܭdnKBR2pH@ i[lcB"eE*ou]{!M-H8$baR$$&~*딴uT* !hlJ)  P,+DU$cB!D5QJ}9Wp}AιB`j=Ϊ((I 9B!ySIA!DD'@!V".QT?;$ȳ#nbG3ֵ[[?֛fs24e&B#U$lelo=g1Wsټ rz' ^ySvvWpbT!|k^sO-\<=؞L4kB_aޚ;JNoe(ʒr]}vWZ|g?3Tw:[AJ&;T3JQ=V } u)"[us&[ 'n+b„ɦWp-Yu⹍qvXk׏!7^lNza CSs&scyp5\yBZOB|l6wW[fū&nZOmGzBu-`o^\p C~g$Ipƕ wVQ5!Mհ{ILtF&5#Tў8s˙ ל:S|7Oo /No>\D/D(] _}3%[˰ciܯ%qZf m3m&ѧD ?_aXN4,t :9T xe*t {4P%9yfw,-멁e讥g ޟi[>$owx3GPQoӽ[>WḓxΗ@謰݌}5&aJ(fğ8hnB!gU,Z53R8{ +)),_|2Oᅲ;zNje~nf}Dj%oY5 si=Hۈ0Odw:~|2}NW[Qw,I'v!np|6Nl?ߪZ6W7O?WD^A[QZ0rlwғi^fpFH7v !MYIځ8Us2I9r#o1\^xy}뤱arT3ɎUinTʢt<ֻ{sY,<(ν du/~(4 t-z׎~-wjZiQ)ԋW̃ -ӈS#ӝl){yyHؔRS[5IRMJrpT,#bQ ;.w `+^ $^iRwB/ ]<߾/fLqŜ?M;,ʏwy'㨳jָ6Hnu i&lVR6&~KIi~VoLx;7˧DΡ5o--u歲q 얅eEˤ J&NɌN| $antc9酪4o+>iF_Y߾fuOZFs~1e+*O, @X^1حB\{B Aq{<lPq.$vAH;~Mg(oޭ1 5_Yӯ gudzi/̕OL'×wķ1`H)7Q}*7?~z`KΓcmB!DxUVC7Mxiۖ$| q)GsGf(̲"dCϔ?XLcm\wka`)bX育|J+ [>t7Um×ޟ3.*bx/i"w[(ME_wt.)v49W[m-,8`&T7zߵ{ZZs,o }&3:Dvqt~-מO3qG243|]vdi$& B.2ƀ7T7(} 9B!%*\2}CλBm=CιB!vĎO!]L!vw!M4C$TyBѴ,{_6{~4I?2MA!t]㉧u$%'}ŧjIr(Ϸp@s:ůBO{latҭrR{IāL!MnyLlκի꜄_!BCvd|ܰ~ e\B!ҭaYV̈́VY{`B!"ˍxh5KLL3B!UC!lv{LؠqGέXN]7ZZiO|b"P8LqQ!HoaƗQB!L)ŊeQ(zMjZ:NMq87C.m0M)ը5O$קBƒǡ0jO4M#+ ֮O|BITr} !՛DoϥUS-MHJJĻ Re7UF'DcS!|T(-|>\u&$&QTTT1oq]SXhLr} !J^4-.wVXɓ ֭[aCYVhItwkPPj0D"קBQs+V`I$$$0׹+FV(Q T;gDU[g3ޑ\ߔ5B9d7u>.~}eEYds 1?RoN(bI,Y=+>lup!—,€ /0θC$oq1 uwެUץSVB!Lԩ?no>l "4Mw]x@#|{}DBl5 y曼,a&Y}-.k|fҧy ʧ o[G#:$>9Pq ?ᶻ6HA1>r?w[FN~ǎb%LW, ~k(OkNJԓFi&ƏϨQhGw'-uYeUU"(K_gX[SS|܃s\*eWlӒiն52U{Hq^M=xgz Cz*]$U짣iv:iV*7NjY 3 +R|NX`WM6AVV+Vٳ8`@W>9ewK&~W P˵#b/9[7SRZ Ja'^dv-CNTg$=P^;j+28,lJ^!+љN43/Gķʊ&S6Tѓj޸T[~P_Óy6O<=,[dPq.$mK4͛7믿СRR)EI0¥Y4r!75VRfb(Kټy# Il0 :P Fvxn'rI{19b@s=ZY|V$zl`~{|یTDV+ח~`|t~m^;מOLyU3{BfLxz ]_lR 8{5Kg2uG!o rRJJIoahi6ݍ㦤ܭ o`Z]*sء nGsId  ^;=>6}3bRv+U]Ǎi*)NYm?{cit '?Uo$:u)wE$GlRKUO: %*dt  N+l޸6;5ZBZ>>_wiOoH;IO!m6-v4d#hxB4&>B4Q ְ9wuG4v̘os\ meelڣ}C~G_nqaʕӧc|p7g.{N{{<~oNDyyĹ\ytzwy8ƜAδI&X}x>- S9\K qɓsfwfwcﱼscKq{!PS LQUq 016єÆCii_l-Oុ}8>.Pߚ'#Z㰵+๷༉Ip#3m˳=2|/W(#NK(K1'Svu͏{ y;9w|9C ۃ,Mܰ9&x6cC88`n7q;0$k,nr$ίrI!\F˓nSc$5QgrI re|Laz:OiM7摉Ws 97c*5g.Mx㤘'S<;9",#ok{vTkB87U?K ۶ACeQiӢ6!Zk؄B[ˬiסcIs8W4 wgܪ֭evВ}h6 @N`RX>3%իm4B!8T68-\MiX%47ʎP"*j{Z`!BN%lmdжMƞ*B!EBB!$lB!M$lB!M$lB!M$lB!MNe&˗/gtԉlv{N!BF ۬Yi۶-|Y6!B.ְ[-[pYgaBwؑ)SйsgRRRB!]a+**vW$kAIII>ʗ˦bs'BR¦Un`0ۅjPpot .Wy;?گOu|g\ v\&»[~-%,B!D$jY 5w\(w|̖n6@:(UADXEQ U"(Fz"Ei"&R723Z|?e9gΜmO9sA/%aҙЈ&ųQJb H_]!lS]ɨłJI^p:Ag^'LK\ִb Goc/#<>wΚ̵!k ]5wM"70u< 2cl_ؐ^l~ҍRJ6fNHscN$ޞ]Y^OJx{ C IDATHI|Gj#gN_] !l>^0k9׊gj͠m֡da/c'.yXhr`%[LjwDj8 c翃^;*Qmm{Z?c(K*;)xq\)ivh^_G!S9i507g&),X˾7Y>_] !Z:8nBs qf- :9YW?{$b&ywG :03ݱۖp]G?-An˦+~À piz:∪t=B?S"0 M/i`mn 86EaT„^,*W3|eRկFe+D KpyLADT3B!ST b`Rv0jfDۓNr6iRP o1ccN~H'|vR{ sD %)ҝOp`W^6EN9V!w*(?.@)toh"3u;tq|W#0e3{}<1QRz ؿn6ŌUus$=%/P -s3s^ KU?B!R%.0]V<{,X昛|O/ro>J>q}` iPih@+B'>)ӟ`ԧeJ %ӛ~˾0ثӎ]dY}) K>wjB!B?jbkޔw7nÜEf+x< {DAx8A@DEEӓRRRhT& !gVKl޴4EQoZX=?/0[,q'-Z]@m[6ل-5ꂦl`1)؂@ élZB!@U+`3 ۍ Wo F)^͋3X,؊mu;frB!DmU+`S͆&cB!5iB!8I&BqM!<'B!yN6!B\aL4GZZ͚5#..̿&BqVպmӦM޽Fǚ5kرc,B!-ldddпL&M6%))͛~V )Bq!U [~~>"XZXVZN("P;gj\O!{j uF_(;8Gf}Qt_"Κ#zKϣF3C U^)SW0tԉk{ fTJ:Bc t]'((v8fz)yžsLayh\?Q^f˂/4e4K !h g-$mW2C>@Ab夒fNPD<&5G[X:4O&smQ֎ĢrI|_QƴAQRfL 0ұ<+/|\q]0UN;̆)|rJ!q< Bφ:ҟx$iI/ßbkLlS6뽧ǫCEH\ sܔ竷qAM4zI_]ϙ.4ua1V_HI1l@IxzAJM䅬̻gmGM<~ƒ- + !8WjisIh=f(;?(y$'h[gWOk>o531q< c`!InwN.0y ӸD&V #:6Wf|<+㙲tt;% g3u2I3֓B9ixҷEٔՀ/ 9)O'|A|\;G-kbv9yuO_=l'Kb#8E2^ /`k}:\q\^!)V#Z1-)LIP*M!9T.QCM`{.!\yجTG- iޝwőzj5L'w2vxo[­fv!lg(Ĕ#kWo`WŃfk݈2YJ~ǁRٻvAiy> ~k4ti*=[;;yzŖ]g7$FPx6Q>^ cޙAIG M; m;v@ 7r-uT\¤qy eU:,)#u&Q40t6C7TgF"԰XB*JaY/sqEztgf>ZrF[~S2)6AL.Ob75]Cy{ ;q es|V߰%%DP«6U)[QvFp=WRi3|AD`y&*&>E/fi$},ˆmˠ|ALPy:3!9t[űO[/>c=m\Tq38/X8!WT b`Rv03(ʄ3ʉ'4  lӤ:V"cc&N,1 ęJSWNqþ<3A,~}^N|u^GE\{čr0>7?YkVrᄮc3 R~]9?6M:*NκL*S>6-%OaeyɽuPEM)z"I5lBP>2 gI&ώbb2 0NV8s>+Q҈>(|W _7ebƪ9ђs_эt/G}OwtF -cPk6NcFd IE4ܜ#K7=-%͟ށ$=x:!vuj>Z=x/[NBx]%hf'!N+"u,L<ѳ~/;BWV+Rbkދ[>g+n7Y[>dPn\p ✪EPwiJYs͌yi3_ޙ.gø 2x5=D}}EWӟ`TTr,OSTό-b/qP]7qn->.{l|8em_#qH t~a'om=RF|[ti+_ֆpXuz'[BJ9{:F˻z{fPpNUK&掝Sy>ܑ3Ƞ֐gG)qмsjK^ ^}'w^Fp3  !8U]{佻W?PlU&v漵."7[Q $ ›qXDx*ONN&**ꜞՕBvb!+6oZEM(7UxVڞGlF-.U̶-֬l6a hMpp)i`6XL PBp0[N$B!jZan\.%nJ]xK(5Jj^ bVlîq8<6 UB!UMQl66B!8פK!<'B!yN6!BlB!9 ؄B!s52Mطoiii4k֌8,2B!YUM6{n5jD\\k֬aǎglB!ZA1L4mڔ$7oNxxY-B!ąV-l8` jbZ)**:k;$B>B!w*`3 {<2Q==?wp|O;84rd]7ѩS':uϰw֑ 7ikXԩȄPSSW0tԉk{ fTJdB*`uv *Ο|c?/,r绬f˧G7\ܤ\4֮EtR(ScY>ݚfvr_}JB!j4Mt+UUx``XrRU3 N'("LiٚVሣ-xeЧ~Y6D(kG bUcy$/q(xx c.iqB4Nd<1ag\(*:yBORfL 0ұz%jƛiNb}`M&J}Њ 8[1p6 L:JABQ}5 AIU( &l:L8h{)A@P&8M -o!ӊ->\VziY:U\j4JgWuOμtQ;}٫(;NκL*S>6-%Oa%*ɤP@?/9%*H'|vނB`OS'<;S;3"㴲PN5!(wnʺSd$lܐ ؄BB>aq7ЅƙI\|”U̜FĆPGI덿R.`y,O/ 3V͑Lm0/i> SV2kQ-#*%÷l_Xѳk̍{5s]n r׫:qq8(u0UC(Խ+egy]\`vE7Z.fҽx3{#<=W5~EuhW3~<_♞xr";ύi;3?-xsv~^9[v!ӷrӭ!R.Qu +ZӔ h1ϗ0m;Ӆl@c׷Vs]7>yg߱/a>jʘ]S-~ $B!.d Efacp~u18%}cZ߿ B!8HӗB!yN6!BlB!9 ؄B!s !Bj4[eo>h֬qqqXd5!B-l6mb4jԈ8֬YÎ;fلB!laKMM%##c2oڴ)III4oޜZH!B#9|&GȺV+Zl8` jbZ)**M!8Dqq14#N,+EEdg&--<6jt|j%j* 8<Om~YoLُ;{AY${t/3GOWekttk~2ɥ]YB7t]6E5( `a6rN_DuM8k!iQU -'\5t"1O<>wΚ̵!j ux)WofNrJ!G'ЁH!q RimCгg@/i82_F!}7w?gp=ޛٛx{rveD^z=m T[~Հ^GΜcXiBV]#ʦ@@mK~m8?WBqFf-PU7 chW z-4Z,X:, W1`;{'Kqay5/b O3izzQSXĉKp39=X;'2wEZzxĤ72u2y#^N2b&*ۮS\D"oS)`₦:QPxԍGFFiϊ&YH=G.Ar 0@EUx @~Z AI5@5PU50)sd((<Ԋ->a9d7W8\[n: XL&.tѩgh:vjwT~e)plޙ8*`"^0F!.rϯaŹ԰ AposqC$`B5EAQ;t IDAT (mlQvv4< L1QRz ؿn+]%m GaJf-ʡE+X{)fduhQ(e*&vB$GGa*fK#KNBVE꺏Yy "AE|W|oHoN5 -Ll-2}{(7\.8BgKqX6EQPPU#bEPtCxV3ҞOY&wK+BXW)r}*8yMO{t90|G.q2ھFT~d1ϗ0m;Ӆl@c"K掝Sy>ܑ3مcxgڳ5C]obcWM*OobЫS+nFR5!Ttu* W1*?ssjbkޔw7nÜEf+x< {DAx8A@DEEU}yb%a5iRRRh׮_] !cf>`a:>χur]BW {~IVP*fۖokf6@u&8S]40 ,&[(!a8v-Z B!7JdJzT+`3 ۍ Wo F)^͋3X,؊mu;f2 [!r Ϧ+  ѪBT6EQlln|~?ޛO!⬪|AْTeB!"ʮ rl5E8}B!3T W>P9 !BO۹c{-ZdSM!x}pJ&Bg**Fk]?:`4}@f͈" !B`*7oѺFikmڴ,ڶmiY.Y !B:]dddпL&jM6%))͛^lB!gUZl8` jbZ)**M!s%j* 8<Omړ?mg?_^ԇB9u{l^  `킧},tP=+?t#a1oH:VJ2n;suƹPBQSe\h˺&_/5 tM8k!iQU_Tb夒fNPD<&Ч~Y6D(kG bQrfF H$yt";0_)6t=:N8y_|ggШ5{QaPeO?˂, >è_ͻ3Ź|%dd. )"ٹl=I_w&zs?/|ExzYFc hITcTlaDE3u~~/q҃4m{cu绔zV#M<66v<2S:}̄Ib<c?h:s>C#l BdT1W׭:& !jSQ(՞ףFϧ%ZidYZa3h!u(YA؃:cv&FOi,Ü'jD#^m 9.*?fҌ\j7L'agd^KlL"S?C b6nz{_oh~}^j>Ÿ=sꃵk:nWuz?4@/,5d]'+WKklM;qc׹-e q Bʋ!py[.n^1TxW+B`ALoú&|A'Op-{mS:V^Gng̪񇁡tqC@l 6zhͳ<ڜ}Vòe[}ȉ)G֮ހ\t0B'^z? wϜ˶T8esb#5|7]č#'rK'Ho]δyV`U=ﱇrϑZ46Z 04Ctljss^Uu;keB31jO{25B04즁7?ooUǧSlD˿.Ua(b~Ƨ˓0M|AM|Pɾ]MvB7EQQU vK Jl $yf;qPCP~r@dρDTbr%H?<Z3q^F>>ݿb<{y L&̊NԇG|,(R,\6_Bp'owt.|Ov )^Gt,WW "ny<;ZaWjT񺝵2 !D5T| dѨz,oU1Pjj(:j`RJա:^Z1ZųziJ;|M&h: XL&.[;ǎT{u}Sn{ Jb宭,]}x.kd4hb∋!<*Up%P}w; B+(;>"*kGrS.ߨ݆F]unQTE5aRX>V;v6$'Q6?\M9o:4j~bbJyN͂Sp uT+JA'yIH/QYrhѽg3~4^ aD0YZT0Joپԇfj+ύo媰*[k> zq&˷en] O3 ]>MVV\OX8?[KznfIt]L +NnoboxOK%?_2Is cMuSAu;eB(- Rʟ+[c:S-DׅǺŎkSB3x5=D}}Eȱ%(ZjyyK4!S LrQ醫ERX,l6Á[p`PUY1@!EQ*VRƲ(b(fb Efaj\wΎ'Bq(bEU5ϔf6]rLB!2EU9|8EU+ͻVt_1T9B=4I&Bq֙M&~%MAyhZ{( p6? ؄B!2UUq8L-lIdϻ p>sPf!B Ntt=6mCvc25ÇvhаͅB!]/Ғ235%Ol6tqQ8Aʫi۷45kF\\M!{EAS-i&vMFc͚5ر !BSU [jj*ɿZgӦMIJJy愇B !B\j–V+VV8!BQˀ0 Up8x~ܩ+`:uĵ3yE*B uje ?A1qUfV;o xۂs8s VtanCyV<F>hx_'ma΄fkv7/=xf6/e_qwFf^}{/aq ^Vaߖ o{7oo$sPҽ=^ k;ٍhsBjNqBv%*?ÿμbAI%W$/8NwpC;gMj5j:Ŕ73bFZ\e'9ͣqO @$ِ8BN)4綡C_|ggШ5{Qay=aN/i82_FG$ޞ]Y^O ̘9`6cGyV7]-E<ޓn&5঒Oxp:.;ݭS<3Kkߞ{*QkvA(S>_1ޑ 'MaeɸNbn=3ћS+i;B3mڌx/Zcs/A۷c3ov$f9bc{AQ 07` Cmn5w<ޑyW툲)?Gۯb_xe$dBv|z\ZO%O(J; ֙ĕSڄ{3J'N^6oɎxuy;% g3u2I3֓<p;⟉2kZ*'0v>zV+gw/eLOX,XH҄`D&,eLz};2oG_Ȏ'zMU=!O{x?99 }i%4 cNm#F[ˆu v3L LHF|5KQLX}J"s_}Janڐʻ~gиM\Ԩ wJE).N_b~^}=!p^绐CtܙnLuUAhY)W!=x˩cҲ [8r)9ªfKpwbѝ9sW(LjHʹPpي7(3 Oܥe,c܋k;=|ӆP8-ˀwKys`'ՏCy}B8V|XϏB5UPfP$Ñʏ-{_*0ei9 C?IL&&tk(todsЙ8ќ|G0Qx5,Z18Å(u .DLDSzjZօ8/(&ڌW^MIT[u#< 3^oF?}̂BUt>]Yn7gG.W[O-l' =#ۖcXfoCh۟'\ 6rmԷU,D5B]?83`uT VT b`Rv0;sbx˻2brk9d`WGSs1ƖN^þ<3A,~}^N|u^)\"3('ڞt |h(<711(̀"'F:$滷gה0GP‹W.IUa.$"*ȁ#}7Q%i4J)Ge(" ("8#T("8q Kā (.""*-mJW=i6-mO{\MXZ?4m>COes<`O'Mb"N.%xkҷ'1ƨEeț\ΟDy8}z}%.Vв0m2bl.^t .L(VKA5}01q]kJ%*tX\2$lB4IT1@1|y?}u_dLMhW{q طf)%8\ŹcMg}!=:5Bh4B[T0J퇯ټYYge2M׋s'_z}zұŴ~ER-%Ĝq9˙r'^wf;c[OqfY'+Vᕗ?`_VGxX:Bcbq`5Ѩet~m#ǣo7w.]{s#{Y̋r0ݢoqtRaHfŕ$qei~d9K*p퇟Vw 3s$>)YJ̙阷wps, a 2`=̛ʇ<ͼ[[0&0a| ?Q:p4jnxaC\3MTVח-dˏ3lE#xS²գ/RY:u\S䅥S7 8nSn[ 8>1*&.fNf|/壛bH?wփHBWg4ݺ}U!s> 8gB0PO[<7/nf~>Gjs״40S6>Pf}ՓLՔcS1uh-ʅw䞳PHO'&1diFD.5eJ!(|rŃ(-)`$&5%"" kq.%Ĝ9Yd) PPՇ0ЀwE\\\ =yO'>vBߞ={ҥsp 7޸kߙE IDAT1'T\ kiѪuB?U?ˣi-vv;PR\Ħ _ׯl6aցRLi`6XL V(.-uzB!Sf.bJQ\ZLRX,EV0l6.=͆jEUVA!ꔰ)jj)1' eCobiv=}q] !cR%B' B!_$lB!["U񷓄M!PRR\E AӉX a[~=۷oy$''駟74B!?Jm&33"^/a:%%%b QjP [ZZ\qL:[n͒%Kh۶-111 +B񏡪*-Ẓ÷؀IRR2p{b5(af'k!!!PXX( B!D##whPaUYfvWĉMCG;=RnkX/Yg3~ٓf_80?7u/J[S7]LϞ=uL]FvB0 auQ0 C>JL]et+8d@p}o}/oVȉLi{)ސN•2f(Kw2I}3bH-&⟣^ ePUv -;58bd=RF^0^ |~p?9-G}EnaDs4>?hQ{WJv)D<+G``kU`x/㞚uìyxÖLˆseѬg4?^1}cQKMsFMgxljk-D1U6t \QC 5j27w3rPcJyg]*pR;#)BWjoз:3BHج$i!Et;nvN&4m[%Qئ}9 L8 *G/$k`㦅6qk w/93b=b HBLڷoύÆ1bD5gfKT@UtLWE1PU0)ef FA1t< Z!4"TKnZFDw9Kƒ3nB-^y/t.RyrU<^ZD?>×a8Z$фFJ_~}kf<.YR/=l 8 yYBimb'ܢQo?|}ΊqѮG?Zf,cު{8|iXh}^[\认FT<߾ag- Ĝq9˙r'^wf;c؋ +[+CY5-u S\fiAыI[ihno*1gcrf/IWGyEԮY˶qiOzRηo`d\dnxٛpp[p 'prss=l "BBBj׀&Q߸P5FE3R^x%+ڃg_˵ L$=AgDƿ)T#jat<{%=eѽW[!,TsyS𔧙7E*h8BK0Y(ft8C|4۝Gi#֙XE9Ե;ࣅ~q-rbh{o@X')[ LMj)Muug"m\eO^9&G#w}:0% d<͸/g_$S&c5%ؔcL1s1Er3(T%SI YZцFMfC!N M8F:Surs]k</DiI vn'1)QXLvy(9p%*$'KVBdĴN>фk.|˸ 4}w={ХK?B!ؽs;СA< P~f3ŽЮ}'Jشհ&1:Q)4 fI%2s*?!B(lӎӏ49#АIα,ֲkTSf.bJQ\ZLR2Y ðlnB|?bÉur0#%p{4P9B t^=`o!gGyT`=?R˷khI4ȸ4;5<@撑[+;唰'IfF]Ԃ^W!9&UOYx/Q)W fc>h:Fx.[(a;ORcΓ稧ǽnp^'g^UH)J7Vi |.c!{sIidX:6sυ-Q'W&!"3b`Y ػ=E1sswz8t|k Jyp@f_~3o#BNBְUm&рuפiTa'"qz-r1("7EZŭAt%hc #RVf$e >Ӷf43EbX#g  _?G:tው<|*~i;Z&_/|k%"[`[2MqhvB>(ɪDA|A|MRo#T[qR:˫QkYPZiHSC*.x^#| ,_1s^:S:`9٘0qľ 5 hΝlKE?9%3z+ d8sr?a79yQaƸ΍6*Lq(jʇ*j،L͠l4J@e߀+?Ԫ !UgEQ1 sKik_)fЩ}oV ^£mī2z[ d 'ܢBր#K&ɮ^S?Y37 K1P˒z7n܈t|*1.p*~7l„_F -GYQUWT K͘kζw:[\}C`qG$2o4X0E[w];B`}G|MDմo{`侗xu (%twծ ˾*JE&MBb9O` Ͻ=O>\nx%%Ox%.uFWUTPN)S>>+f|oh aBvZv l6cX0tU鵐PT \(lFUU tM*K& Nj&SUS} b A5((膎iZy'$4TqQ* wMAUMªKʷ.).bӆkj 5*ײoEQB MCy6|s.?k` QiFtN7TxxoS%Y=Ga nVKE9!B?/ҩ/8PcsP+Y8YY[kY?e(oB!8TP*-{M1|ɚ7Yvv6֠q&lI)߳<(oTa*VC6!BΜϓ*?_VTlcXVR 7hֶ]*~o֯uv$$6Mm}NZF!BSG|\H4 `Ц]jиA6Y=eﯻM2I!*pZlCj.hmjڦvC (B!FUU‚?B!jAα,=B?RZYkcܼ|=ؚXI,0\SxwcL^Y]` UՌWt n`-+B.?_3pAT:+=˹;IM;y&M`)Ȇ838-x 3nDKee!D*O،­G]=&K;s,޻sk) ^]wcؚpEAg~GP~rB a$宬+Y+V')]ŮWbs֔Cn6>3uE0mclFKw؞Өӹ/ԫ_-5RT9GU`UjBWJHD ae|\gxv_9ti @\ FX(Z*afi?8ǨkYz .B!D}\wp M/ΣA2 _r RoC h՗c'ߒqLMӧhMf8񶡆>e/@hٛ_!m}Կ- 2x&Utg r(b>)a&hv5\8!RDuy 0A=IDATl6k m97MMoGH/ % f=ZQPrh,B1zj"PJ -4m3-ė$unKlJZ૱mEr*2:Df\~]/Rl&H9k|ʃk8ǨSYkyssuB!Y$l&{#`fum)*DJ$<3a\Mj(P*& Ct 3 r??\ x)!Ķh{ XYK"pU1Iåj?ڪhP1^JbH3o-VPVё6k:o]2@@4{߼79?sw;{Z(bx;VhLXQѯO择(&Tł/ e+!1$3$8bڎQײ4]B7: 'l!5ݜE x8SG4s8p ^¡ף?/Pjshׯ3au9qbrMpJ|B!D9 ˛B:3'lELz/ 1+z6N1KXTn_Rޔb%MdР˽F!) cYrט\/m8w+H]8G3&3ښ[r|^^8_qٮ7ݛ[@qk9ZB.w|/BL\;:}dbčF{,3r܀9eԄAWa:爫^7p91 =3/^Yz0zf;5Ë?:VsrXM>yS{B!Dm5>V O,=GLm!Bԕ#"ը{tV.!( 9G$kB!D}@kz_KTx8a@ټB!Ŋw.A;ciB!4$lB!qiS`pIENDB`nut-2.8.3/scripts/python/app/screenshots/nut-monitor-3.png0000644000200500020050000015032014777534446020556 00000000000000PNG  IHDRl]19bKGD pHYs  tIME 221 IDATxg\ɖwNueW; `>F"VDJ *D}>,wE%(J PH 78w thuGnUuuUu : U{+oߓ$= GD ̀ǰ#""c 9c"""k@0GB D9 3n,du=ΘnR ;k|)$ Ը{Λ1ƹ뺦iqM4L|J$%sM835MC [aDZ3٬D aC1L':n:f3!܇(,ܹXtJ[t2Tka<:㹮O5!ɈIڮפ 9͓d٬6CQ'eZ2OF|_{78afptK2G}:PTBw%GixwWȊV4wW j: HD +_Bٸ5DCspmGp:i)% ifZ}{F4!|"4 Ht"0Cg@.3Oɘ2΅SbBx2U,cRs''Me9=95hNxx,NVbXU ,PUx+MTAL@'fu[Oȝ;ޓ5{qb2 1bMOhiয়y4+[LD"j̞~{c- 8apq1ߨi+1p̙gBP@ . G4S Sy  y&>&dFܜ8ڝqZr$HT j@ɞ&,GFyZ|G䗗F艮0^_~zga|f3r]ژ Шm'ߪP(/">cfMmLCCC]7L|"%C^*-TRlXM?sΨ=vNܑg.Wړֹ𑜙ZCÃ6io.fX[ -;jC=^Ztz=-) zd&DGt]~ 4< !ڠP(/ *N-]ojjuͲB=ߕU(1\ Lݾ1#L$I0@d@!$(OdZoqx4huYhI f bHWit̳@^#b BBU"DvȲqəDiY 5Bڶe L B'gտqt/sX%H/bM8\88îe %TVrMsoّ)>3PrI٨ieE\~FFm0,2FlSRhf^&9!=l")x"vf/l.oG4t9ev)iT E"3oҴN!]ݝƃzo1e* BEwv42! !fgnha$pwzjfl8nCBP(3Dg8U=$I([A* B<=rkbu  BxEBP(6F+ BNhE BP(VQ՜P( Ņy BPl* BDTP( % BPl TsbC><8yVx3u71to~zE [M?yP[ɯlYfHAf'?Zp$0c % P҉nM<1%#֑'>|X7Nu4(X;Ʃ .{eRBDT0-:wHù_93L K{lFO )#GO>6xC/[v/g @xõL s}.efOlzdWH _]XbՀb`dw2Yޕ(pBy/5ium|oOg<ZWts/;?OȁoL `HLƹ;pѢ 'DsWᧆZw#)Ddrqqa~\# JS*j9?L'Ll<֙'=-޵o"Dд}zWth{c]MzCw 4<Ջ hyN`u+_ʠs?P[|k"jD(gV A JdP(\FӁc.^o:W_t1$oYߥ95&>Z;Q:c}Wn~m瘑qKF>1@QJѦ]42[_cV*} EE"(Imkgg0-TBNXc=^)| -3-,d9P#]̂1b*&/vS?HΞs,F ݴ#-{<#wM>MnjDB= iZWs,83 S)BA%^՝p2,_?o^hs#4sΔ fb V b NkێŅy}9S P|S/99YbĻyHnյHG *Z[w?-o9ƾ&|)o5GOhen߿E1Z oBBݥFX/a9Qa0_Dc _6D44){g[KMHd&ef9EG\JPP8r55OT ƷK)eT)(SdU?)ejP(օjU( BBP(JD BP"P( v""rd EP(Ddi#$Dta~N׵F S( K$e9Hx\M]*"Iw@ $f^ Rkq(Jʄr,Ty%}SL:Tl6& D e )VzP(tu+k%dB! ToR7L"{  b PHDWjŋԓB,AR"%"('Zy@[ "\?s JJCv ߼8fTn(r2)\K.X1Q|/by 2b}MD@As./ݢKxIFB"K.K?ƈda̹]rE|h`Ո"%/'T*N{k.˲J.2$ Rwb{B/R 7cNUiuIx %QDJ>_fCCCpM@K.[t1CEK$95e39A,B֪Vdޯ/~VזSPU'n,LjJ$5;55uՠfolmk$IIR&Wѥ=}+qD~7tw=2:DWQlF%n; "b…A_(Jܘnkl 3AIJD ^s%(V<éd`fv4fD,_/%Cv|16~( ?|$^vɝ+?~t~wXrę (7c '$jނ}?n ~s//y,?#5hKާз|)t}=$y M$$ $@:R񖃧߂~yT&ؾ}On\x&Uyī;@ԃ9dv<3wÑר/g-؜P׏o3ߝqCFmv(Kԫ~#ۅO>M=x$k9Ԩ@!QDDD s߭IDFF$!H0J-RO\p1K3-}J/A+R) 3vxj܉Wk6׆wk.};4O>pgh_}>Uv=Xn >5̧b5uW1Os-hqf$ elwGρ֖B]]A]mTss"Ks \.FdϥK{;.sU.m+nF]*(5@HߖjݥP8[t+F""tYs#H.bS?VB[nImٮuB<\$y`^ʚ#IZAiU7Tp+4,ӨT)6yz!2YQ2rE F $\\Mҩ$׵M~P.||{l}⋪G y(,:w~GsCGQBBt*i*"LOutsfk^~EubO b+iƽʲZ](B>dnsy(<[ED =~׮ajA|6>hŕKTPP`hůAqoH˨xkR:GDд2::fG UQSd]D [ E64&=7\/nUªPrU>WuLVA5u<Ѕm,Ϥ5CPl=pmP~Q|s] cBTO&lc4-LꚦEc5s;:s}WE9UѕtK,Pu*/YlZ~#N-al^lKk1x(VS OGXc"תB<* {+lg IDATQb;(>+m%m?%}:6*lkŅy"0'U6Vx]xP".BuE٩oe-ĥUttUf4M..̫fg<J+A[;cp^b kQX]eh̭ٙ}?UиjYXВui @J95^w. fomXCZ.-?ZxGADSɉmW\zLJ$8 ?y|FZ4}~Pk{jmSkTBIΕFjaai/Sۈn[O4\~C,!h[Dct:U(܀,mLAKU4Qj곙3GP>+R2ƈ 4EAI)(_?o*_qb7JA :ZHg^eN,='X㡢j_6(ITz.lʏBו)*:Zޮ[^Ϭq"vQ"✻ _ Ra.S hR D>blttD_2Pl,jlj:wοc򑷥hKoIDHT]IKpުqs :33?~94i 9}O_A"`jn3@(,kIU]eQt>?`ttk\uQ(@dMMN?-Hi8-T}/>bRY5-O""㏆9gG)TII]/~A%Ղny[%u WϲWͪ͹W+pcǮC[ WA"}Bx9…'`%m_ObK?}թ%= =6Yr]CW.NtVgrq54Q;\u (UpKJ"d =0H ߞovdZAA@*P(6Ki~$\]V+ϫi' |,`n2o/N ܼ޳[uwG0ёj:/yD i%p(˳cհD@ &4͖]zpX#7ޭc Wtg~|[ܡ:$"VAB2q_,>CB tȶB^PAi6D+ykט}#R)@lZ0o%6{XǓɮWt"Z+&wmFС33uƨOoie{Cc@ٿ)S+5zzo֊43}ǭO޿,YKV~ nC*$H5G?Mƨ3rۻ3|}xHW>7?Qr)Bp8n(9Ig9mCBmTLD1xJCs_>Q+.%) AojL:`}7>C7/^9D7S^'#2qAi 9o ϟ/]}VHaIl_tgto7v߉cҠ;}Od¢=yS ]v O /d5ϭꋮQBs2L `O>ҺOlȓ]Nu%إYޛ2YRZZZ,(,ebQq&'}_h A\'W2RKAU( @gK4jtВ_H@nxwi$]].=ǻȂcӐ8Qå/r3^몓NVZ;*#L#m,gLљ}<~=ݔR:Yul4ێCfvqzi<PQ/rBe|L* OPz쁯r@W2򰵽_vrd4F rțeYmmcO pE5Me&ON͌xv3 H>5͚d6K|65sɈZ˜B=+p씐fPTdf"8/k}ny*^f_4pAK<Ͷ4nyRVJ@-Etfqn%gGK.okkծ= o>^C+IH!DRٴSLϟFw?42kZvi ґR /;lHy'Bwr<' aU*^bXDˇ4$ΨDRVӑd֨o4AȞ #L1/j\{<3sz8l:xiXWSHgtΝI'1;^svMن&I8? xG-aF"5I@AI)$I @zddSey 4c-k$mM ߷&n{͇q 3U{GM:c~剆7P]a'*" %%ykHFeYh8r PphqIwwW.qOWl%/dX;u_`5N~݄C$"s/!lMd`#R8ܴÆ4t3-=iZ-Y(l"kD :/tyJDvq.7` 4!|05iWjD,dTZDUЊ-.9Ks+{II.$MϏM{m5{:Nܹ7xq_o?V~SxUou6j8h"~by<&:R.2`Lӑ̤2~Xg$5]=8Iї;LYdll>ք4ivQ,Qٔbk4(.̌6vrvk Iޝo>W^HHn޿%[*:Rxy%~:wѬbo35.3{r ~~3|hɳKW|Ĝ5o;3gv6w/K =l[욛5:p>`ϯNVM֑|77fՌ&ќ#Z-uF%Ԝ+ @\MfDڝ0d6k8p\񶃯ݬ$-["~̞YW]QӲ8ӵTH'>nρȑ ;id1{eϜ={Ưu+ӞOf$v8ݴ{G|ۇO XÁ-wʒ62Uk>8R)dVʹGr|);xo8 G4X<\lnNQ62 g]bXgbꍘ3b:zoٚgq$ r1 @2VޓoO̷uG|`w5ˑ{D<~Տ')ɣ'ķ_O >o9ǐ[2,P9ԥk_;ŧ^p$oSϽÊ(vF(`gn9M..NN?컻k~mUyP<^hB_'TЈ2|1Yd#KAT6)m34M $srݖ"zUcMT#7ViDda  6J"ɬw$v3z62~2XHXVl0,jKL-4C2X+G=Bx81 nYMC[ݻPpRe"I[w-[O zJ)r BI=hL4s4Mc#`q(Fa]|Q@P( \sZWsZUhR%r1r hND"BxQ5_4㜗.u2Jl@K]W ccd۵hy\OxDTP(6a-h\\a&Qwy"z:>:><`s2DssK[, |c}lV]&WkϕXݮ b1<<DYjM #ƈ1D2"/\DKwmutFcQ]7|K.&&...t*^qrupƚe{n] 7U^W ߢUB $j*"lln׿<'n74׏  SQൕł6~nxlLO+ kaٳ#)\`PJobs-:'Og#^-(hgڶcdcS=Q O>[ 9r$":$$% bsz)x% '(*`3a4X!7%ʯPs܉Ѷ ZXfnvf" jZ?tj΅\*X3Uk(ZAbJ."@>("WBO|״%}ŅIi+gVʔJm?ܜ[$Kʝ BI=+]@HD[`4" $BPxiqw|(uOqH,Ut~~#rgo.?}'V|qmrs#s+5*g|t8VP(υ]{7JV}_'vYjwg ~4e٣m!$w{Ok:zbO 447y֜ ݮP(~4t]*C|JXL*Uque>QYzp]+zĥznT( y3+;BH"cMg>x%D'?|ud $ȹ, <$ݙqw~dc~w#mo5T*554IiH!n""Htٺwf;kFw IDATq"<|i:O;R'Apq<ٕSB5B:}q tF t8*p*BhQU&%0փr .c5u wX<֘h^RL-wvoܛIk_ItCg@“} "zU_9労`4ܾ}cz~zKMg?<֠` }Hh`ԭP(6fQnP~7tN` L iV(Igf&m(+زxOl̷Ȇ;Pmk )#UBTNxB)Jp߸\BșC|mmo΅$NU(RB;q!UlʧֹVdd/DDT7nL+ٲw~grSo g SXSo;{x? O}$?ט>؎ bUǠP(9RT[ݢ|6M4ce ZQ0+x~g mQUB،H)ʪ-ܖ&[eU0(}H'ZpBPiyQBؔz<=`ՁE9+e*UЮ?v&'Zk*ME.X۬JKKgcJRŏ+XkgXrSO(WYS"E4WUlR-X n ٙ n7O܆ J\Bʭ4 q!6'dfw]88RK~p[U߻s&Pd"ON[aQ~ofo|}Sx&7ϔP(9\1x_nQ_˝"_ņS}v~[ŵ_Ba ^e.^J~o|uĿ~wW{[ۣkyڬOCƌ++ŴPUXL\a_?y9^aNOKKEOcq2&2d{B^H+Jf-/DDG?JD|ݒ-L&k -O'&K:c^-DWD IQ"Bȭ޼pm}ۻs׮]m9籒;՗}YSX;lMQz{zbAv TiR R7پgi3ΦSf3gf̜NրJ ruip}KgMlgߺ'|s{'~Ai3*H_]19Mjo}gcҎS&?̢J>/<5-\%^#oҮdŢz~z<'t }$}}XqݣaM#tYSؕ;]><;c5%ʟB>X8aY15(m@bP4%z:eحWw繹?ۮu凴F!4hLMMl#lS\;&°LUgj"=yӲaUa|nWVTu_sQ{zߤyk3O[5Oϼ~0OZtI%m=Y3hEllJ$v۱[Jvvi˭-;=Pr>~O6 k<'sqr}njaYh6sb͛q(2f11\C[^)p҄`LAN,e罺on/r_#F_`Y-"%1*ˢ,˲$cB0,^qfn%.jwi%jSos.SpBPGtFqIyIKsxUx6ڄW]dRفWEA%zIapYIdIGtkÖ/EP#KVP|XHㅀ"bjk[6&qRPL0VU ٳtl(>C,7nϞ=VҥÇápww5y7lӣ}(#zqv']RgK%. ]eK\NјdN|XyQP(,wn/Щ+ĢֶVgOE(DbuzSQIXkBX{ݕ31 ^_\2uOVĸh'n ޭ4 B9q[,qC : z} Z^^(ҥKR(Qb2j11  A,h4AcBQ% DYG<%GJ B@[q(T|(1y.W5^XDJu#%E6gʳkYayDis9ՠx0WA ㎁ʎiz&>PNQi .XGkf4 B\oiB}(F6FV s"~Hk!Z~h6]1YӴD ê!5+J~Q) ?uUr_۲ronA*,K~MAP(Mrw.0,ba0 0͏U*==͌(֙45j::$ńƠpP9h +FȘӲZYbDgdch(j2@ ^/IJ1jj xTq 7j\˕AHXP8UJ" !HJx>[^zI`aXajxC:wjݳ.)"I(X,p8 Bp8D"x\$EUUQmSԕ ?}bʗGdPJqi6d졯륭_ƁUO?{Ul {mͿ:7V*,Ao{uۉ7N^8y5wٻM^;nW>-D.z?qp;+xAcO3~q+]=k7E2P:K4\OYՁr 3^M6.d])"N&*+ opfcG=RŐ?#E!'[q8.Q Vkte9͑driMiYF,x#ڌ =iNK.Nov@,䮈+XVg?f q,kETvEQ{XXU6a".\X8eY?N;GCtg^v:}Bu;;}}]/=5u +x ['ɵ@ƯyuZ䉙7uO0׷u]2]k|#;nzn4/zǟ ϫn|3rµKe{vL-k%#sZk5"ZE2J^oNwa9.! #Y\YZ31L,G*Mɰ۬ZW= 3iF!D" bHJqFWfɁ՚\gU a19\^gIs$O*BJ$.F0[tHMŪUArY8V4tHysJzՠ5:i%PyF((Qc,wڥÆ>ޭ[(+5%0Iep&Fy[8-\%^#oҮL~ūO U^[ NP{OK>xab{ͷ\ҬDP IDAT<{rQW-L*W6>"wڷ]mHwϊ S%_/Z,`]FKo_/߳w =Q`y~#3>vh[:h@~ev=rIfl׏my.N\ͥ 0u_RR]uoYYM_F-/}Fpׯ!-$YjwWꣳH;fiozՕKP*Z֛sW>|hާ։װE_O{uw_SvEuՌڔeaAːȮEKޑ͔/k?:v|P90]IrU|9m$?WD'dU% 0 `1QXň$gAzZ7+I"t Zrۧ{^رryVeL-?Pdֵc pؚ_كntزڌn_xcNgDޮ}1jds5dhg3ټrUN1_c`3G^yn C|QI?Œ4k7@ CMWS\3{L[{.)o?9aE,(Q, W-5?/oSBBw X3 oz%T ȖQ=Ě\4\R˞iYwiq9V%ݮP&![|z[1tŭ7]9rqkg΄Vꄮ˽{5t[;!Ng[`IIJܕjKAy,R`02UE^ ~{KwwFoZ̰ #9A}TAPiFFDY]1N^)色ؑ-ENc\3Fr&h_)d Htd"uQ*\ƴ Ⱦ՟EI>O܇*28w rGb9e l:* I=f wڤ:v}} (o!SZf<{c\P e˞csh%  QC٘(o$EQLyvێOlWY5{Ǵ05™Y=Y43񞲰 T+ZYV*Gz Xw1:\_%>⏜XfifQLdG! M,==geDޟ4vgO4CF0⇗|3{.5S^;Wc5[ΑoQYrvXR~^^VV755C=`/3`t)_~Ѳ5I`oAZO}E\l#5RB{nË?.X=& jwBP_QjRuvr99 Nvoq3DoMር{bqTi;K/9(!Y=Ƕ+a[vv2 sl\/`nmd5S Bi?zp~$ۙqÔP=?]pP4e`DPwvX(-[{9C%gʲu;*$I{̏翲c&gՃݡglZ,l6L&ѨZmb6M3$׽h޲!E$~t'*ZP…k,-Sa$_yE ^c1./d_@!~U( I7V(4궪 :{_[ˆ/[ +$qط3)AcuZ,o4됎ᕟ.?V}G9ŕZWO5H^V.oP;{m=ۙ5g7-ܪ5Z>urdt@ݖg[^pu_Q{ϞI9S9#+ZwE"׵M˵7 33>] lz~v|RDFpζh0¾%,XM,*VUY h:H>ug>{+y/+%,VlW?rž >;ȕLf;'xU(, sq۳YcF#ڿE%֡暙94$  *l:D)͋(|qu̷93|-quLt8_EӇO{oތ;G1q?b3òV}|rϟ_}yy>"`= k;hMșWk7{uI)/NH|aHֺɓygmҺ\xmAM;wE=|M{)/+vҮ,p9}rkKzN/ZI3uiG_/|uOଭϺ`ׁTٳ59s{|ώVΩ"i#qs_Gg *cH=b #{xIk:8R`g?2>Z枋7ѕi]^40"9ut jpg`,g_7t3&W)ϽQ]eER Gҵ,ڼ꣧P&{^ 29zœζ2Uݏl;R2^!{o)d JuCm*|]:}|Џ-1x,{wʶXl!|b4 E"$2ѩJӯ>{ҙ}8m oJ詢)K4(IZ )BY*g]ZY"KԙzWUo1BP(#bAYQf_į'(ԓBP(LD&J(HbDQQ!h%pc@)Ϋ_$͆L=0nh:_TMBP('JfjfJX5}m pp7ohCas^}] ]͉;| /P(L5Mr3?ID 7Y"@T6\aXcH)g5];QmQצMyi 0 l|N)V`/~"\;Goʳ/_yvUlp/=5)w%Q/JwT|7UK#IL0֦ oNi o})/=\{3ڡ}?9mܑtY|w8g/I1Bi!X{wtW%H %Q3 iVh"q,P'絉3bPUbCW~q ӝRzVKϽ@7tvjL))WVf\ j%vX .B۲ݖ3Fu|jz?1jZU#GuqvnS(p̦۷AE/r۶.k!TvG"Դ?f"b0{8fx@EJ-0,kYNN.R)usĤ$5&^Cw!5t'%R}UC &!ve=_|'Ob;;J%͜(0Ik l g%1‚ڠ HOܸ~-Pwn5~_?!VUUUmFfVZz*n^w"*r՚ -VG(BW& ΔjRwFpG61 "(5>ϝb;@⇾j{tUob*snE r,XPTT{^!  ܭ{oY6˾y eE cj;*+*83lvشAE \ECf;2RѕkСÏ:G3#:BsOuCXqM8&?x/|~Pn$NOq\v-1yΡejp7?kIr R &m{2B 1Qq⠐Դh4z(!DUTEUIonLgJ8N2G=xw]^r+r4l 'd ץ=?&sР?\«Tkޚ kkSnDjBynݻ36;;6k#_{ɱs$[ %OK6w^}uIH}{'N>ޏ"Koz|\]h B,QMMMڟ qVzZzYYIk= M6"\+AјH:Qhhd/1bu6Kl3{CRw./>uɿdv.?(/1E TUUQEQTUŪh7aO(X,V#X!1VEeQhkn'7nAYg[dgæ>4ïځZ~]3'ѫ߿?UK̚2 u r5ֵwS7,r[rG3ZQ!b>z?65 ""j DAM#mk6‚Tt(j]BϳF=}0YH=Q]߾b7)Mh svʎQ=gܦn}γr+>~[ }k̤xH/Z5>Q(g2% ^  !@&QNGM̿l).W+vEfHkWD1gw>xc]lܗG8=ew*_{ߺ3s=^!bj}{O[׮%낝Fٖ(՛Pb!@:Ll BVt^)ɧF,ķ{Rl/(WȽ wN0"TJy>>oWouok=s[n7~Սp{^<&źŸ6 m kUw5d۲=±E:y|s_[[ŎHVE2JLć{DELK&]qሑ9d{2Nvv[a-x`͡R[ 㮀ܱ8kHO;x7}~]Wpj8K.nfFfOK3;LƝ=KS`nz@ 7;&*3jK5g:yB~6;s]aEކ`u)]f_éd#AŻKFYTRL Ik}=8G/8gyўUp,#ks^9m["$t*B%,Ő!V4(C (kM10Bde6P6m> ؠ/R+虯Wfvv]9̈́/*ljg6U~s՚eYvhߖcvz{lnbR: j: yI>y0]wٷ+QzǶ7\ǿl}uULMbzIJZ1QPW =0DspQi%tn~FP #YXԝ{fåmo.To}t4x}a ?ɢI^F99gto-Su<4Xz\1L~m[X\tpO^萣_Mj08ZbER)֝ɃLgv ?ߋ_ٞM7wScJAKW?XE8-#zJ}uJP F͔,@f' "b\mEI7x) r&S{emSE !@HV* B$N'zZ-Q BP7FA JIٹTD) BF P@5+:\DEBP(YiT(B)D) Bi1OL-B "AQ+N<%@0%IR( \^^zmhFz=F>9m‚ I` x^b2 } {M^B@UA|]Bp( $mcYɜJAH+xI8U{ТڗjݟǾ6_9Q{3Bc~'!e]KET$INGz]Y(*:r͖3(Krrri%J^ Xlݲg1 ˰߶u`AKTUjmgVՓ)DU 2'5Ieq/'cvq] $>4vnǹC"Z>]=^әB+V"j5jݦ$ˋ WjZ(HzqQXM<3'I䰧RP(aO'߽nxRVEW$D|noA"*OR>}ޜܶubu_ ^j{OԞJ[ymxh%Jv)nJlZK7<55JmB͋"z0hC0,cY9!(B 2iPP0Q`YPHO.3;L6M Vhj"AImV+/[V+J^?^9Ѹ t=T_PwzvLJL+V"Djcu(!DQ$A U:!$KR  HP("*5Y-&-R^hJM1<Q cޛI_D-ګz^{gه`dQ]A"WqrUT{āa{z{-r;kD|?NfVVVVU]Sy2Ns"_|!% L4+b $P͊1rI.`t⩄]x#Un1_v|V,j<=ǻ3Qf}3e̴R΅IJ\*@"aV#@8#\)EdT#ȝbTĎ&R1(\af<3f{ {oVOӤowr9.Kv L\+5aD#t@ogTfrhZ:bdz:hƘWAӠM#5DǮFynM6C)Tcme|ϹNv-n>|i>|2:ǎ_ApLUePUW#C%h1Ce˰ u֦:B(|`a,J/EDHvd=<3pz$1 %3DL#Q7)RY)$)] $JЯPQڮ.aKg'H Tz%O Jv* iդ:i%:cؑu9(`oLS*BßRf%ܼg'sLigs'2df C+Dk. u(z>TV9U B7e#eMz8w~|Kb%{:{ GK2խq Y.ؚb1˴InZ[6 edQԠRx|RQ-45-7pfOχύB(ŁrI,C)PJ!ycrRdYMlϿG?@t+Sok\B,ak?>s81w? M^ړ:;=W/v;'"j܋_+ [G.͐S~W}>{*…(GfET7FPrTZ*e PTrds`.n @WVL/NN *t˳9N#ΧD]z>s%.GBh\/ Kinvt( gl=.~i@xQ Ԉ"?=IP~Tr =Hh´]XM?W2@z-TB-` l2(h۷FD[RԌܭjj?k-&;]!~o{$N_?߭( 62Rs28FcP7ޭE>~B`>umI]q|"ڿn?>3N#;s희x.vio~MTb[htZ<칉IOx@oLz^<+ϜYx,K?6͚u)Olߺ޸?6J[ztd493c] jDtD~Y:e*oo/&Ԟ-D-WrcG"̌%bAe1LozY%CZC \hWlov$О[#G٬a?4oc=o~Q%3J__D|+>OW3@0޽1W>ݓEͿKo'D|* Ui]'|Ou?a aO٧䏤ؤ3l P\O~;2ozᣟ:v|Y\q|n.|={ftc7ZXzw_xTQ47/~[mMTDkF\I/QJdzc"peGjT6=E9сS#ߛNDta$4pfŻ:zbQ]#%%[ )k]6as=5Qb Ќg=N rɗ4K':!}t$h@WJ'.To/nQJdzcJW.2=P3ߗc}uqS#(Z:l_:0OR wJeebj5ؼ9 lXog۶cXloH7>}뢖}~| +/X}M'~7;ҥ _X)$)"0ќB%pS@AɘwTi)D T@TWKuEL@?8l^#"vXaRv[ ^kY_]e豰v*Qv/!J)R(%8R(%rƘ$Vs\I }R^M % IԉDhTӴH$r%o湣OhoFq!DT;@)GMf384GlD\{K-޻dA[?/Coѽ4=HT2tK(\%3vp @;oЇo!!Qi:w噙FC~a֏e'q RTfJ艁RJVYFxR⚪DţD)TӢRYÕRn"buSAuCܹ94xǗE{G-ms'IO_%&^#{/}/??D(]RڳЃ~oRƲq~-4@^4w<|0<"U[wwtMT;Wzc|^>w332+uPw7zlmL7^^]"J D fP/2${k_<8ZfG5k\SxBR5+i DPAFhJ(ݷoq=]?|m:4::nدFw^}ؙ_t[w\1o HzzUK=G9"Iyܗ/OU\{xϯO[~I ;wJz#Կ|6G_ٷs%?_|gߞS@[h%>~|?~/\ns_~f6(IXLzuůEKG<>m2-k*QubP*\aMg%P6TjPx6\.u]aem>Z5܇~?>Hӛnz71=oy?NٍG~ (J9e3DƷ>BLcА8BpW\Ep0Mp8ڔ@toҲ&*:x14QF)a}RJH8G)%0Q+͆ʗSհ> Ȓban=zqvcW~ DUذjxУr*Jξ ^BH)=sǶmyTdҍZ#m]>y04`@%띻B%RC{Ň޵grODRɡ_ݲZ/c IDATYG/: 50Uwb#5܆AhS;; r,A6n,)!ao׉_[7>{xqjJUѵFyڎ#z.B]e0 sff gBN! +EV7I V/%̘kT*QʖSΑlGR0˜B݊t y֝:vn 0D H(i/?=QC/ܰQUDţkD`pppvfRaZQM7!约UCP~H!1zQS^+ d y7o̓mٶa [U[ o/tBRSClU*QZ!QvLVͰa8\HimD"Y˘ȃ )D83SՕkBs9Om]N٧YOJ)D7nڲEU*B$ F$wJ2] Dc"ẾQ]@{/KEP F)\h}>e9X|NF#fƝuc[n߲uzU%*\{se]DۮP3ڕr!K "HnKJbfSɸIx %c&)aXGga+b $P͊1rIQpKb̈.(b խX* H\*k);1\p[ ׬UPPXzV]eּb'0\@ hcL,+s 7nߵu[sE/,rM Zٞcɍ;6u&Z +HoԭUrG3$+9nCBۋrٸcRF@؅\Y6n~ .0r(((\<چB]KhD5]uM״Lb0t0tu]'AUߡŲ ᗅiL] %-{435rA+Ɯ2Z&̧dõlu$[7!ȝR([ɹFw@g"jo4ӟтreɞގT2r^dRJM0(((\[t@}׏jmH $b07HfYڱTr Z̐v2,hޮ“B(|`a,Eu=@ !(A-rlPp3GGӄtm7@(AR"/Qsl2BYWAAT%%Q.4^FTXȗLgW0SF՝@ZF)f(ѳ)P3peo( C]+Fݔ %j%{:{ GK2p wS Rx̤bPE W;k6vG"O%1q㉔rzj(c-KYQ<=U.J+,)X5Tr^6TJgsݝFOs5M2+g}q@2BX$ss"K3*<)\ѸDB~z.(r=ōE3 pm)\]w-(" .lwvvr."-jĤ'jfg7&=/gNpЬD<{h͍If: GSY'\@ho]o\}KˏIvFWV_p2΍MA DМ׹ȗ&G9afk0â,&<Tz3YtijfW\5G֣+Dd3Pז^ jY뺖e-V'[,;RX( t"¤3G #@5+!(W.BoH ]++pNH7^KO -rpЈgz6DM@/VbV_):/b[dŅ TAAᚡ G!Qqk0973 HK9I T[ۡv>_M ZR MP!%s3u U^:W ~enqA筸! jUΣ ̹x MĢr.VcK X$ٹ2hPRTAA*6ObM;,ZJb*U\LJ*((\݊yNsHUaمQ*kR 7R.١E%p!٨Pom $\H(å(DDRb3ꅄ5@m0VxbnGCf|bbm.4- 5 X89OaX0+!RJ(]~\f˪D/o!i?X Y1 / r eR Wh[ChLD{uRlJ%ĵ /sοɶ9ȠMEkHij-)NaebUq6g[sn VLC9ZAb6p~JtdQRBH]=zwD/}&\R嵚`ubqSB%HB#̯-]J\s.%D.nq>JM =HڷаD)%-t>_mRzR\h$-Rdm%5BZ RIRH)R0МXϹqΕ` hwHJUcPPɅzr*b}Z3κؤhBU/:/DKhgfgd<S MünV[$‚XR2T@) MUie<_6Z|q[JT͉*(\e$2R _gBiAϔ^^:љh`gWJŒHO'b)fC-R΅n! T,V|̌rPDb%Z;o#EDTJ'jP5Nm$=( ULTwGqcL2HTA9ӥHtHF` ,Ǥo,uϫ_J1u<.B 0hD(B\BS{:ύ/}i,4bx1ΞSeoP'*f2ӹ0eP+-PĈFB~ffC]1(Q[MM< &AAWO%gO҂ϯ$VT5ωC 3<LRp9H1#4ErKͧ(YAIKUJt0$PhQxulМBمHҨrSJD"/͕j@=Ț^ceB-sn͵ iōC@oޡ== v`[]Pw)jB].&.Yf/lΑPcB¥mΙm$QX,m]A՜¾_=Dp"-fHrPgmDqt c8){BP^VޚGg nKљ!QwSq\/ghέ.^|bJ *UPJXK3Zz|Y+.i9siɂ˃2%UzH4Vݳ\s=i["5疿.( C+/}rϖ(,@mV S 6m\Rd ъ¢9 -ʜpũw)&6SK ]xl¬^*Jn\KLVa ^Jl,#E bzqvrHP)[͹fwwq>%r4u:HL/L-dW_-BAz*Vi($DW]"PRB)U$peJaKDr1RKBivB0mIBR\8# jtV&&=T3=1yT G}z"[Z~H3*b޶"2΍MAz%tK1$Iңf]KVm5q9B bn"Q4YnʜpIt!_B " nsmѪ8Db__(F ("#(Eˎ"lz 55s<F70HhP͊wuĢFJKRB׺l <Jz$ћ /*'|@ߴx]i+15i^!e9%rnڦ[ [9'p޹-]hY] @_,Xi)DsɅ(tB(a'0ӑEvyPxW}]v>_M ZR N ) OrՔ+;0\Zk]JNOiT[gswJ^G}\12 >^[LvvfR)Jt>$*BHB d)R"gIQB^$5Ї)7hbmvH ^Aei J6 m>{d"0LK4D D*:OV82vn;< K_`.ӈ/ٜ(QZkH.4bdЫ n4T.g'YkZ".駦UGWpy7MЪ"Q2/DN ڈx<EWm WaR/F gP$zUV痡նb QE 0.Mm:V$z(-Ŵ4ɞw=oU$p(m>^S$$](q R(ѐFU]+(\sD˄%jU|>RVSJo4."y@4u]EM\x.Q-lAAAa<-ֈؽ{ׁ- w^]CrX43d2b&1 9^F̹ \̘zUݻw:љh`gWJŒHO'b)fn1_v|V,j<=ǻ3Qf}3e̴R΅ ~T,.ڑ顾wfgr%D$SF;R%q PSg* ̈:|"'2ι݉f ">؟5ĜfT=~/\2B=7:ЁcarZVd֥-s<3]sJ 0J CFtZ_+4տ'ޗfUY  V'i~@9{UeoP'*f2ӹ0eP+yՎB;7e"ԙ<>RNݴ#)e/ E5dBOvvŝY F4if}>Y˳0v6WTƞO=sc}tnXeԘ ٽi]&;2Zgr?]/m0\4xBMV}4:".+'/TϨp taViZ7r4-jEzz{+G_Fqɴj[- HG*(((-*74]?Ǯ<J4HjUȣ *mMMߏ~I5+N, rU$DCp((+%֗]u%vc2*kG.%PJ-+O?u 4#5jCW*6UPP*fP^ssբ$Z* !l~XX .*BUPP"Ĺ*4/Vk$##53=Y.r$ZzH2p"KQE(iӄ JkXN"CXnKLvrb|AJ`Utm_cHŵ +@YMXݤ!U4]k[@Dl? C/M;T.%l)K !4YHĥӳՕE.-+\Jz^cp \fc%aork6^BoeD ͹HH'(TժT$"bYhPRONN !bѨrjzfuUuz{j+%P(k*.w-Ik3 ά FT~*VQՏ 0#ш8!DLxUn Ez*Лޜ@꙯vߘ~Y!QޘsG}~|T5.<.C DB"CI~85 kU+(,MBo<0tbHl2#}XֻؑW_߫u7n;ȑ1{ ,xڲҹ3rx\jJhgS(%$ơ!9A+8r0T-*lAsm*ѐC[.$ȁT =u!\xTa2M)\.MӚ53}#ܸޔ+{9ȿO(yXTDZ$G ܝ$+;hEY1bmVM+LǷWO<|vHcj kגd&BĐ('"uَm\X=Q")(@D+(T+.ɢ;-%ZdԔ`-bmUAaͣsxdKcnD)\ BΉ`Hng?ĉWnl~>t{M̿ȈEDnk:rK_HݍPAa'Z9) "PZ|G_Fq_:pݮ<ϭ୩yUUPcXMbX*_(CL+BȄRj&p!xN(#ʀs)iZ eVʼn)c(<@,sQ X=R$''0C'zBa/|qqǮ<(GÍE՘J*(h%uK"a$hj0 5g; ?).N7\ǹQPIMrVMQn%3 jSTPhd"L,zT((\ d޵j$y Ẕ#Iנ5m4`kS}.jdèJAyj^)UϩyUs/~ŷWlkWBKQH(E@\t}M33x9R@" \ CaZܐPH}!4}L&vu:y]==d \eUPPPPF \GjTH9ΙS'wn2;=9rLS*!if]=vuSPPPPPXRZ.UA((((((3t,A|.Hj7{Ц-[YAAAAAay bT|O*4g:'[DFϜ*%7]'@S#ݛ{ иs n˝ZtsO˻he;n)ͷ=ϔEbF$mvP3B)136lmyEGn(C߹;:HǺ[7d4'jm=)(((\;~'~$*׻bpYtЕ|4ݶ=;2ϜsƆwϖF;eT%VٳΚ zѡ]Yv§\;37k~$bɃv:q1ߩcޝ7R[︣{jd|ԙhu uh||>VWh,ي@JDiOV9FbхlmP%^s%̊j:r=}X}-1jcgK$(Ŷںϥgm1>|d2Q'GE@r-[HʼnL-` ")Ay4)((\UKLSGG@^0zI'=%gcE'OWb}i$Fv};ulѮs?gYf}>~ő&<âDDze[ .>KޘN- @wX(f`v,m[i7bxkM::]1Q"ƕ3,Mwp칞f(]WB $S|(,@ύxu[eU}x*[\Qxقd~anJt*((\( !7P7mֽv}/%uזDRq>Ӈ':v$ϏyIi?zgHd=:\Ӧ#~H@Tߎ;o=ѱ{]7g}ГO,=I- ihCn܃M-&}OoN?/zur3vvux 7ܶ5 +^woߔ{i7DϦⱲ#!,'MnmwTmYUoM1l۔W;yp8sm˥CY4YqH3 i(96IBaX1J])1])!iE4MAzA3-RR(=@ LUfB=2[R塠pIIt)"73$S: _φsJ^0LS D=Gu F.eŭDIENDB`nut-2.8.3/scripts/python/app/screenshots/nut-monitor-1.png0000644000200500020050000013253114777534446020560 00000000000000PNG  IHDRl][1sBIT|dtEXtSoftwaregnome-screenshot> IDATxw|^ݥH "bڱbŮ+b"H{M!R"BLv=X~:KYE(bú_\,B!B>WQdR eY/_Pf3p:GB! ²p29dZVvlP?0F8d u,BqluCćjmx БnB!ıKA2 -NNGt8Mk:`H7Q!BmQ^BaY&i0u_~îG TјZAV F|l,AM-$'D`+m';= n@VF&5\NZDЌB[`M7~YRNwRio;^D_MNZx#oEd !GeYhuZ e)dI-hlA-IQƖl&!!le)20h)8,k߱ o3Hb폌ɻkwYDdR4aldg8o{vSZrۛxV>ܪ\Qy6?ep܃cm N;&=4&ۛănw3l,$gFsi{듬םn<\O~}43 SHxg$GDP?4$ců-´*ZˆV5vFЯyc>Ft:@4q:6l@NnvM^cSNPcpX+*BQzFK+>t(z=\,AKFqOhXDWZq 䳱 5a<7{Y'R*|~ :EhQQQ=ev,3NR,yg|QNdžY01N3!oNNE &qB!D͔R'l@1 kkc:vVxCp8L3[_D0 c24)]\@hbse0nP(|@ki_rrrjxf4LgL`ft|g21*UU|])MSX!9UXd5 }Nw4,)=n(\}S\T8v =# %]}Эk(toxlmi3rڽv+We&s2s1Q"\% !>6m~C\>KqsF4ۊ+ocY屋FSB巿7oAݻgNc*^5ց挛@nsW25VڤZ b;U ~Yw!Mb{[㸂ٌN@i$Om$E{| M ;zؕ;Da>K.4 ىYS^$/S`ⷩk0\ !bJΜh7&FY -N^ٜKP/ŤҎznQTGʓSRcyye {Ҫ*a;ցr70q,^y.}ZJnX%Uc7 k%WWQ5U)k/qM&nP[}CfWIzTn 5 ='H}7X ˦PETYLjH VE C'$lB!!Φ0],/@Myj&jh"471t[YlztFjFAAn qi׫u~?[.^Ph *`WY8riY:a=:yiuJz*@ Ekf4*FVL *͸L 2&V+1, 3PHtr<­X㪊]{u5cn@WeB!8T9$j٘K}UGjG{7YN…^xyw3lCK4f(nyZL0 +_-6F81fYDFFqқ|!M) 3gv:sgOb=]9qwm`|"| !Q[h+ecaBYdΟ cm߀?Mz4[I֘W ;B!ߡf2&pëqO@Y84R6g4 Q Ɯ"H;VIlFvNII8J4M󑝛GTX}1N^nnWijc(ph|WyDSĸuv}2O85ڰ~Q~1\aY JUnƦi ?AGNCÙ?gຫ杫\,U1 3r\eZwu37Q>Γɏq5 + J)^z!BR AjA(&&X>" >K(nn+BaaVZOh%V6bh]@rV~k+&ND(l>%kl nQu CXa?InU'WMaN)1>°@^:5Bv~Ӄ/76 Bfa!xZdЊ*.gHwyyaTD2E9 EA~p{3_n: 5W!Bβ,AOD !?%(~biƦ1 gxA,RSSq:%TPIK `ΝvXb !BEe <8*YɔaՐ=riIN^ !I|2)#$PӽGIs0@?cxW4@weO8ƽˬӸi [t#/hNlB)I؄M$61ZHz{ѰG @z';^=!>\Xِp>=WuE_=-YnI=s7dMz%:gX!ĿU󖭫`az}5w wxGq=ܹ|Zw'Q^^ztO]=uzJ+bl@ޜu,^ŀ^}[e@lÜ>Z2wt.wĩbӆux!4Mf"HHH@mΝNl\,6c_q]6=#_֓moegVY[,0Av[M)]p^E g+0b 0yٕwMCiEvG#t9)jb0g6‰Eցĩ"aA;!ı }NvIfg1qq8 !. Oyo {MF$Ŏ;'҆rؖJD¦(\6GGtq5,\nlI=SI6 fkFY%={9v.˗lpu禆u@q*)BRiahҼ%7#7'=ߛKtlNS5!ġE+8ŵyi6[uObϴzZgmҳmA$l\U؝e@1;o~ߌTsV/;n2ԍ>q:6!ā R 1 ]5!!93Yji#V?OdN ؉mҙsn< 7E_sۆ/LyB-N 8{pwx"Eg͈ݰwP#.}Ss>Ǖ_`!8f8L˅ihK-P) S^!q=\,!BQI&BQI&BQI&BQI&BQxgf,^/99B!ġVz*wdIhZ}i5&l۷o#Af͉*BqRE gرFT[ڄ-kO&6Cy(U5MC>4b'Bq,Ay^TziTpFh޲5֬"+k {ŭ-';FMZUyd !BRr[ŤFMgOa \WQ;QܭW5B!8V @J)'UMڜN'pڸ&lULP f5iBTkNm\%˸;tsⰨ'UP]@u,Ӭ6^ [5UbvUmDI qګ;6ӺEVX% !1GQUAsJRkZYVU=l%(WL bYc͚UY0}ueZv#BqEUS F*$a+JP4[\Vi[m߮G^y<7nDsO7lʗAHG-XPỤ*sPzYD*C}!E0= gxx"3u08g\4 O^6jnR:w97ePK̇w?IorgGǑn0ػS|율~C{*VBٴ鿑瞏f'""ߏaӹry^Ldy/VP||Ʌr63{^~3z0$G@'G^AϫBQ?zHBdhTۗ_}mFG7ܼ¡@pْ0"U:8bs%֣=)p|jNL| xUޟ=~i~pg4wa;ƽ-6{<9a-\?9n»+ޚܩ8Zn8_sȅt91n% Dp iMۚF@Ɍ7yQ9z? Zmap4s~ixz=C0''8\.[M .;;_;!UJ7*υG/WI GY%s., ݰ[JUo|燊Sn0J->'KH wi=M䭅e;#yf,T~_.~ϵF[ ?4<5{"/whg>>'/1*X_'xj\G"-/0~~ok];/?QLx=mʣOrﰴڶ|r,?p?+{oswg'iSMY.V6U)J࠮UXV*dlr奫JdžzSFAP܋_˶[% +)MD |U2)WwFa.g/3P=q|iXI޲_Y=gh%Ԋ̒<Di&zSEl O-vLd$e U8U/JhB)0ԁ^tP%^ɰWYKiQcO?OC{"=@͓eKݗBZ}Bg'f ( {۫y/짏yG5E#Ԇɇx0, M?QxxlX Aw(n) Vͤ =3{2 \ &"#[C[,*[r_Jq4J.,;_R8+RY%p?*S%y !.o >>A(*Y;\.ⱛ7fāp*_ͱt(Uۤ9DwBnVjKF~9Ym"ϼ6=AHߍ7dkX-~NJHZP"t"n˦JڡY%v+ڦNao&Yf4%kjhٺ\} !F%%TM*SAUIjRezX(Kat-˪Q\*".8vEVmLRbIIONA5 4oT(_x"kO:;מ狼V-B3VDcvAtAN)䯛Of錤~ρ4Kl$/`4|;O~ٌvU5mӈzmVQh|޻fF} gKǡޝA<⟧|he8KNg{Tqt; L6uӧO~@8EU6}Oװ_s]Y(fkwpSF#Fq+x8t ܼ >* i;1ia҇"| knb#Gxݧ^n^W:YRcibO sa>ʈeky6͸ۢӻO2û幋`g>*!D]i,4ܫM[hJi.{q_8s (*޹$zR嗯ʨG?τ [&]:wQٳgznV.u|$Jl6;6{j)˲0nw` pP(@7t44,U\,Ql6t]GØy еmiū_ueF̰Y6ϷW}iPJÁ(*sGҏj s]u]ױLkN4a岿jJPUmWr/iZ!QK)od鲥lܸs璕QG]Ӵd ^($ `0*k`aL3\p8L8MWTT@jm@AqP~/QҳVHŻ*#ُDK'nTa+RUiQ!ja3\tuЁ:҄^R}nXM8uǎHd Q|{O ]V^+.Z>퀮-]Gœ5Ud[y95[Bq6SFꑔP˔ !14/(_VJZJkZ s,u`8N$*2BFV2Z2wrԒ*7B!8TSC+˗Tm*NJٳYmjؼ~z Re#fOՊWu,[,% "D IDATB!UUW(͓*^\&M[m֢U+79fҲu[SU(Z-F!B*GPkGisPʤEVƭ6a3 y/o@!BT:.M[мe"0f aвUZj϶T!BJl! wi!BqXl6 lQ1dpb%B!2 Af.bbrUh$֫GTtnB!1K) GڮXEмyJ)\ss Us!Bqxhf':&8䢃ܜmBaAmBuH7G!u-7;kWӵ{Oe,"=mVy֒ !V۶ҩkwn Y C7XvuYV%#= [xl4 gD'2*H7G!Dn6*J)_(NvlFf͉CӥWb׮4h$mB!,eY%pu,QHQD$> t .>Mؽ{7-%aBQG-&l?*6M8$baRDEDzm#!F+JvD)0 `0prL0%Ba% B.78^O%o8 !lP$HpU=JzzK26!u19$|6hHCBkHa4q՗ѿo-k}wןb`7"&>i5qCXʛ9B!MQ{ǎfssG!|[^+/<̙ =Wޜ~x:y%;j̃GYgV|I|Μ| &;^2=7__Aۮ{aHI؄Bqs`st$Ļ&'ԽwU 3n'3aWٜ4׹1~؛:cɸz 5^F30g{1K>}.CZjV"f% f@beH=,30f<Ũ1qf&݇zek;{[Eo>Ήo{C VWg{ q 4;w6s2 䧱z|:OmAjE IpiGE)BlHt]HUS}B2-%-ԉy/o=۶4ƽmwC:EƩuQh,5WuHm${9>n*Ó1'SpLXԐ?qg4kmUnSglFH2~?z\5|ydĺ>j{uNJ*ʇE{fӾCv-IgȨGb-gi*?R`% nzD㧵yeϟd+D\_eN" ˲5:ˆdwd:ʐqBUjYr(k3~_uZDvi##7 i'g<" :>+׵D&})Ͻ{]Xi mŭ7Cq̢環eq?⩏ X'6] zH!Xô5$cG|l3fbn*M%&23sfz J"/eguVqWR\̚[":pY}KYe *heSXIs[m-J=^:g]-,0;oGr?q)I(2%kNA c&# Z]1vE:c.BF7$¬x.n(}nDӨs?n}"I&<#>G17h[L}jc>g2oj~~_oOТ晴\:CG($t7m~r7C8j@>L/ҞsႥcyУht.OwT+s5;ay_As8fUަ, u=lpAyPoLcvasIf)<ͻ:m:.hY7$`#+64׎:Eg @YI&]hi [sa|&O_AaWsY,#CG˰4KRzho|:WIx7Qn͉SW~ M!D7jgMǏԟIYb-Z&P_xa$6mO߁'.^*|䗩 XCR:Aw'ɠ/{I'S]N(mO.`]VUpj$ھWU}}ʿ?[ ]kՍ,dF@?I7\B{fȴe;k8bmkŁtFq:w|{ !$lGPՄY9͛6H&9lP[{]< 7(BFcYU]C#AB\t >9B!:=ٲoe=Bu2$zDɐh] \!D]g'IvKx̙5ܜ#Q9!Gx<4nڜXl9D\}#ݶc&!zHh٦\tpI,Bv;`unx !BnWtm߶# !B֦]G4Mò/a+*,$anB!~qܸܞ+W.a+{ B_¡62M!M!M!M!_$n vRV!u1)l".FF䁋.;eyHotv'?1]CXcӖ'$s&ϯXV*~ܸ> ǯ϶nQs78\BLV..' M|58zvi@vhZO4Mp>5+_4 dHjRS, _VfkNDcXINCA1:BG:l5̅#F &/ͧK|o4 ox{·,Cj kOc#7D+\L.>Oour_Om(|[ϙ6.R e%V3Zᩚxo+D/mfAWҗ۪ycl6噀ng1bD/P^>Wg6F!wU]Q,bvr\yB}c, Ʒ?#e\T5ώ@ ϼ7gJx$}ݯw'~<4Y|Wt&J &Ƴ !8܎ 4'M!ذA0'?eAfC]| 7d3fN]i[ әCPPż[L]k9zd.g^]51'Ь"8^~Uv \)_瓥H ]} g)7]}t1ؽxбJN1R< t֚;$Al5 Jo_̚=Rѧ" 'BgW1k4OKUR0XJ^z{p سj1{eȃ1qv |iovixar܅;XW}i W."ZKCgl Q{ :#vU)%XӶdݿigAjhkihy~/[W lACEA6/ݎJ'I0*"(ϫu +y! M sy]o`i-{*6|<L"m"+4kOmKK+o.~W}{B!c>a|yDai^6O'V(GϬns n0Cڸ|R D%Gd#'X3:Whߖ3LpVߋ blqYSe=fY>}@]xl@wJIh=YJ_w4$V0;:9n"˛ m]|*zF_T]wdyPsqhJmD7]4`f:?MN`n#zCIygN. #}EIWe0eA:69:rqӈzMkO#[?2h|v= Vm:Z@K%MBQc,&^)?>^֕M3٠\VЍ+XDHVy McNhyϗa2v@GI;me v09EEYt4KD3$9mZ {E=wV=gIL|ƀ9)r K9eIb|l_ЗōΏ#Ckb|[YW?*3"]3Լc$;e{ۯen5KpDI f7 &"g 3f 9v2K#,g/8'")Й75Q>g1h3mr٠el@" POefE@dQl,& wMIv.MY^IT!Kx8羻8~qFE}N\07'`rtvX{BkZq>8h8nQi9'7m#ol:1BY g|C^'YG1L՜αܱFS+͈BY]VI9 >jzݓIlMtәڝFah'?E>g=hcظݎf K(/:M#8 !'{ ,=w'Impesz4ɖr#1U`z \yk"Dzٙ_] $U?y_5~3ixE\3b1:h0t$LIW߫r96,r-g,*OI'tlH1B4t&^w*'La7HqûYUi[I$9t#b^ѥs|D;sfxtkpjH7}7=^޽8חF7o2KH[CiPYyX_DE_ɥ_“ܘ'IHWan"2%Qn&erb[b8Z7ugV'vggz7FBY?|=ϷkW a*ѱG)B 6iL'[7=WčoC!dY/ڴ/BM! 4,I {{{B!cpHT'm./w]6Eu{q4B@6!(#7<ћkp !G !Bq !Bq !Bq6O00 g㣨>lI6BGVTT]ZQzEAPAc/\AEAE, (%!fD/ݙ3IT0pp$<>˲px~?uQCtWqH v-I2>^gnZ*^%3mls 3bz˥w>"K3G]́LjO–3yʢ5#c q#Ex>(K䵼;|$SS@ IDAT{M([ ?5*cvE{Nrec#v%u|:1>{o}'oD;yx 5V v~* ׶ B!vnܼ\TKw=ȇ&{jfN\;.3NNmd6N+K܏15=+g R4[;| Ռt|۫F1H>fYg@c l?5zC6v@3]ra9]’XN63ӆ}h"1.i/n0^fF)=YX.O]ٵ-B{v;ieŚeѩc'bB1(ETDJ")# 7RY *QtB\aŪ,mM7k!Y_f&Tc9|[|#ne\5u/,)ߧdC±7r cX{%c~]hqэ\7;嗏)(gmY!z$d/#3}N╯qYMp~ܸc=+58e)#F Xn}s5.3 @;Ey/cn{(?phBoO $Q<4}5? <{ 5cW 9[ya!wVgeBQlG.Ͱ(jMEfyTVVPP1A 4cĦp"MW<;Y?Z&|6Gٺ 8@NۜB&-[rJQV'Wשr`aRe^g7;u*: *}:P> ֜z*ş, ؁dX_n ҫX[BX4:~(tw@1,0L]v?WwrtJc;[-P]l,ǰiesq$6 \rx#ocď7mQ1&xo<_'"Ȯ޿]LB!jہu\Z )娠CLytޒfDƠ4 JcX\/O_pE)1^n_Aju8-3t鐌)gbū K'N-]F$D VQ,L(PA\zPFsCPv)IYilͭk߇"O1}Qs S16ktK҇|2e'\ډRXd:-F*YdgbNXFmGbv4I";ѳo'-t{Ɖ|RpPo1 20{{vsӔ};$6<|BʣȥL%t>!R_%x P(RxxxZ43%R HhˡM`* 3fXTlzUױ?=3m5|9:2_s}9$gfOMOMW<ϡEiK,}U>0NI{ Y*=<[:q;#v?; /k:+Ԗ1qVz:ɼĢqhI[wh3MJ"fbѭ{6o;SΣ?u"3m]Su8a2Lr]0M>}qmك}GX'p0O0)//36 qٴG䮎RlK zu? DoF ]xoywɭp!BNݸS63'omΑNr^Cmy^{!>)q?w_Hͭ\z^|FDa%> t2_9]ݿ͟VgeBQ+5uڰ~קH@;61* yhFi ,4hC`0s5&`e4,^3ٍsHHHK#BQ_,Ҷ}G•|WuP.*SQl"(l<:y A)POkЀChQGY!ba(A S<4 &Q548ūŐ>lB!uILU5-czk. XTE\Q@)JaMB!uSL@DD R̙_¶46.JykwMDilQ`+[yکn5M!neb+pT*DqЦ'; Ԭ^VOG&Q6TxFu_6!B}O4uUuvKE !"&xhT ÷,!Bvi*oD=p'XCpqpP85M@QEl4aOyY|W|f0 !8{9MV97ı+h"/."Zsٸ蓾נȫk19!ck=uw}j1\ULKsq5py^٪KxⅩϭ,w!WuKnVlqD 2L5ә0%/+HlMsa1 HwP!أI  iVr0(X[Jƴ we aX耉MRf:NӴ0ak(;o 򓰃IU.\t} |z@37-WeM>g&rxWY[#f@|Bnyv4w/pO_8s{طj'o fmq~zV]vt=6],^ZH?:PccoD E7N2oBSC&LxYС&v\qr[j]HcRs2&@U3r8?ݼށkxy]8aӪ ^u oQn}h"kfRW2ZW/ Oljp1eZrE\'_2W֙Ԁ.gqߪ.~NB!ݯP@ЏiMS& #&ak}`5)4&`ò(CqĖtx9 ѣyla>ZO}W>uʳ_W81^#ˍ7wBZb|PZOg(YOg#滺ir4ɭ2lk$қ9?>`ȅ/\pMw &Egͅ'5\|@`K-r=rf3~_"ի$&kSg̖T._[\!Df>O;ht(6U|W6\\\</̳q3ߏOHj'f90J~fFEcx>dEs0/ؓA;쳈o՛s%`\jOlI۶ϿZ ܸc82kJO#O4`"3-Ulk=vMΑJ73}+ϻg^G׏gyШ?4Jlk?UſFAa! n7ZE@(nHP`0OWlge)mL]v?Wwi#6?[/}F Ư Xi3xקķǙWriJq2[YV.e.kJcO5J' H=v ֗+WT]\O+SSkz+¡1Ѽ0lejh?aQb_Fߖ$.>e:7OM~ l|6OA};;)+j m"bϲ} p0 W),ħL5 Z5 :؋(YdgއmWyB+=1UEЕ@J/Ϟ硉atI ȈQȱ4vYN"B׾DbqbCs,z ~sZn Qkw){ ܢo?r VToah;2ئ]TL幛5* 4G3TnxBZl b6q%ȋBc %6m[\!DDL&& > қ%lXR$by&gVu\0-DK ((QLxWyկXq(^x9—xgbMHM `,CۢLbGcϋw\]o,qsl~wÌ /k>y~F΍HMMydq}i1R燦rˀV$^z#ǛlsNҦ&}eKŲϘ~.͏9f -w/NYL`<=!Uoˤ~ `[L}Z,!i=L UxX5aEsٸ㸻kF9kut*.jeK^C,|ftxWN[w*p,zʭ\sl&\q^|1{0MC˙. m&Һǥ~~;vXC^]O:6k0å$u9ͷffv^湷?瀜Pnz8kQ:p-Y4t<ׂ{Ni@3Xn& *!4!g03qH'<ů1[qEw1[/qcrt\ 6ʔBSS'؟H8k! 33cCPj,$B&]E-h9KE8GMGF bUOc9<LvY éqLy!{cmpe}ULa-4`h^MO4U4N q1~nyDK0]Ea<}OB!<| CfzPA<KRxnuȃIse\!BL]=hBiʼn,g6hY41ծL "VxB!?, < ⏹<+8?7 *EAa.Ճ3B!NuPæQ9v6>[=S&SPG6i]km< P di*!Bش(p]e)<\GM4Ǝz9 &5p5uGdn]7yߦqrݍcAllB!Dyxb!Bԉ2-ea}A!um]=y_"JKKh}I!kiĆ"=3 4wx^ğSҥKz1++KXB!˴PX̬וUM:дY 2m lիVg?~gAC'.B\ǎRYRL)ٓY{ضMNf#mUX Kk$id5i[Y* wBR(eKbZ:yW1z3qq$%ls}繬\ /8t\]B! F;iV%%!1زO}Paa!?aTU֤%NYᦰ&B[ZDFFK~X69el}PYi1O3I,Gn}I!ا9 2Yw6gBvY붨mIhmGHB!>MWU^hU6[`ӥ3ϥcX*CO瀤.{nΆpcGsz}[q8&IKv vqy}FgsnK :3aeCů8./ 5ۙWsr7a]U M<<~k$YyJi;|Ķ=w͉ndxG IDAT޺&>:TS>I`1MLD3P} *D 7a$"K%K "sm𪭖s"FY~p#x]/Z>*s$D= zP-c]3}粏3[uS={(w~&c>sdؐ[嚑Doˍp̭,l+1^!k'<~pK‚;t#"~ϥrD^%_:z_؃ [~}>0[aPFքh0<b`3b89K|<82Qw#3Xn};YIp &ɱUav\/Q4w =ֿ#>Uo7ۦ̥J̡qH2S//[I蔰ui,?NhKw(UfcN8hZ&Zx[ KGZ6}>eYqq>|-:'6$SWC˯B#.O45Z+v5CGCZ޲?[ٽVN;%Ğ#;j,K'D<<F l"ј@vf4]|Ĭ9=>~W?[HJqV]w)+-nRV.e)5ߌݓs<4YUtrRx/ԖpJ#؍/&hC\˦D)Y[J1b2miZh>lB4U@{ ZirVv PN's*?L$p.DY`~G.WQ ukDg nZeZ |13\&7:Pm6K ȈQȩ]GHJ7#cHs~{`k[KLBP~pa锷9Dn]<6Z6$>+{9bM@G(Pm}ڙVu]<&D4/5?fdupsr\j%f#3Ƒ-U?N~?sBmyڭnaۅvPPP@AA>~7'~JqQt0Vq ! xuX(r)Ŷ&>-))v4vx2#靵7^յ7bj+"SoڗMu)]ϼ%ynk٢$dޛeҌTaV|Wh?w]:̚yÊ-7MGxl\f[2}6ۦ5oe_2t$N7!*yc~x4>l^%_7nٝrc螗pƼTw=3z++r;Э[ӟm}~OnZ΄FpKeh3=.S`۲v\^xkA`;E6R{pÐ"O/T[pC9MmB-2wt-GmU~rlA7>od=܂<~/NNkwyuO6ߟ5JmTB!Pu;_bDqp.B!j!B!8 lB! 6!BN V-idf5aW  >&#=PNbC]41$Q֮Ym4iVQذtFMVverpI}B)X[O !XڄBEٍs[K\\ʟ*HKO-+D.uqKT̝Q߷P!s~ۼ&5lbܟfSYv..qd$'nLBSB!\(-Vt8n q;[l_MBh;;Xl!UŇZK}E![~Ja lƻv:]5:g\ĿlL.1ll 7v69!8{9* ~ǵwÌ.D nE)1A)?7TVrڽW1Xk^ymfĈoóo+fkyu~?./h*ßWw#Y: )Jm7}_J3.bmH5KY<=6VV^\/n&l귶'1s=/Q.^t ,?r;I>htx gݗss.9?=o∶}V9tп$ ƶߤ{\`e?H?ҨRI=ܮGoQ|L붪ڬ&Cbi߮Kiy\WʾɣcvArS8mf-+Cpism {[NGJ9/;G`Fi|MZP[nAc4M4=o l(V!bĜL;`?JՊ-kOr@A[^r5'7ka`{7E>L7-~j}:fq?Զ[+~ 7_2*o㞚xe <7o:?bӶW'x0~X;y,y4[Wy1ws߸MøwȭrH7ƍᮟCN&<ӯ%j'<9!F߮s={(w~&c>sbc_yp^B)Nbr%*1 Of ޞ1`8{)X+_gQ~Τoj4ʟS[n,je=^͇ljm AJ\DZ.#B]W6HFh7=zב$l[QG dX$V9n2 {#ҥ1t!q i,:'!ZaЙ3ïs<>ܝĬ$TrXͪ2rLge)أ 1&4;|Lk; ݩ+[=m& <ϫ.{EfL{5v M$ 0[Tqwxx_^J4].ޘKq #^3msM) >6^'fm͚'R(\-~n%E[aToĥedĨX,'pI|zoZJC5\m5꫱ĕNGv2y |A|fu2 1U$iOaM$*11-]lXYFLoݒọ7ȝǚp H)NA lB4@m WB8Y⽌~[+0w{1Kg≯lRYŌY(*coZwAA}h[4SShyeTX p]. 38-ֿ-q([:oчjq ! xCѮ}^ 'گ^ͥvaVTy,8Jv.{VbEBlSx{anG7!ݣ_^0htةxP"_{rr&<7_*Cq)ߎLoDnYLf0o~30OMK&VBMrqjs×pƼTw=3z++r[y黹({qD ?voQ\[nd3*Ū*_02 HMQ/dc ['B90K4Z'>l&2tsBae@d#LЪjEg6 6Hɬ !uʲ|$&`k|K`ۇi#QsĚSɝ~_@82-̘qZqQrt}I!J) $8vH`yʤi4}:J)K@!NiZ.v4% gחB!?;+ !B&BI`B!h>heTVTw1Bmwb[>9] !B11Ć6m/?w}$B!ew>lB! 6!BN?HYWw1Υl:* Bl续W]Ү\}Qkos|,N{?RUwu?^Ƥۆ1{!^MS:^.}tzgc@f-7;Cg-;.ǒs3?N.ӟ| ;sϣ_`77f7xzT ?=+;l_Ӟe3_*zUtO\.o_)rn;;(\ʥ z/t(bW "{" tP{!]K;F/%[fg{gH ׹=$=NexC4%o2z-|ʄx97JPHM[_IC Oc&U4$" :+{kCYW߲;(d]Ӣ~1mcf=BdyX?sQ@Hg|m0i\1֡sHٴq*"k>mj`ج=kWGcQ=g2sOuNHM fBϡCWI6A./m9ML3&Ifv,d?8ZWS9u/s'ټZmV1|~rо$Ykқu! [^-K`n(d<+f(OI:t-ҟ+|( H|,u3ayyP0z֓+yH62rL.DϺ(grp|>E׏F;-/ى1i \kHZ= %2oQbj{/>@H ̸X*Ta vC裗 FCl9q77B6Y*V-y7?N%`oP/X%l{T tv2TR7߯bF@vPRx;QH9_OkPw0yRbaڢz敟1iG"*Np؛ONQM^%3b3z7g5 j>^e?pr?Ž.f$ vQOqȽ'3SSfJ,5f#ڊᱱ]<;eT -.qpy{q)|)mIwrʟ?!%Ɏur _a@3z.{@%y X@!ѥىe_%zUz׳pb<O)$ 35HUWpG j۩E;xxx hiXi?oOڋۿqv]W16c=}Ά2+LLlci :=\P *æY98O:s n֭5"I2!(4$-dq$_*DT#CC+3Kgn@-q8(OF 5e缜L 6?߆ax K{>blju,|W"},D@=O8 0$_u ɮ6ţ^2 hJzÎNx.-׻*Ed%5: ^Y6'3o8{u}g.k43׶NwۂJs_'"N9<;< IDATʵ$|4)VKDEoۋENVBx@X0%[U\Kk(L2 ~ɝ0o8\L9  /`h?&z2^>/{аbIP.s=m S~eи uCRbX3m6c\bD;IвH@-W-79- )}e ֝F8ϵFVɲz pqv.ޑ?A."BIW1o6E S tMEC+ 0ǼɒJLoHyiX IN}<\= l/=1h+*jk_dPX90A4.^V Wċd5f/{:D#sSWt&?Ot\!5*+!Ț4{A:rMT/}ccf2ec->_\zx&cUC^Ҙ5( x{ \޶_.+4QJd nى+Y{] "ib(*W1$W xKi꜖Ӥ7]֥a%O)ѻZ87l9Afoe~_0{@5_2JgZELZe.Dfy끔}Kۖ"-%lkXw~]>dd|,!aT A9<,VŌdF%~)2S[sfgLo\BjPmr1irNTqA~̤іClsN}z?փ~xƘ;q\ҫk%\D%jwQ6Fڟ,:d\n srUZ՟d12a:*3` MZ~!%W&}?84/?ODn<$/ŐUN69+ފg^ŷV{aBmƻWbNʩ``%sD ywseϺLT nMZ<;AˈnOugΖ^tZ+NDt,LuGN2ڄG2&{&ׯeT d+}jgsn.R} #d0}voXn4ٗWŧid"d @g,?s*4h_ƦX_@ -yJ>y탾̜-sJt) q7Y& _Rp23,JN$SJ9\$@g㨷ku-<nԉV @pwqԬǓtvSLsV6hf䗫4{k@ =P*OviL?d-:Ap_ A! EdaLqy]a)0(gN"@ (!`+;2 @ 7@ r&@p# 6@ a @ AeMSINN&1!svG $$1 ARos# 2 qs3P12FG $mڕ+\xU]͍ߎ0(q1:UiZ$Ih$I x.u*ժs b  )wDa+$&&^)"XӴBhV qԛ~~>b qׄw)wDx(l ^/khQoԡy\ܰX,BW{f;" 2qQI AazftN+})nJ[Q }V RS3f mB{^R\Q!0@ (LѺ5Lf̢Ʉ0(y{\D#@ )ط̶[G8*[@,|T[@  =^lMd 6en[%vxc)mhJ,-#sˉLzi SPkd>lr}Oe_q|Em۷|w4cCUX_Ź3x,#=%oߦq/NWۂ{׿#`+hv{M!v&·<Τj⫗ZW?~NL5-!~H)$yh\I2{+B㝶xEu k+/- W@pQkIII:|NGHK?J aQ4MsjX_euPqYӹ~#?*W=CCLiHFBrGia .ż lw^ĉTXcǏSfMBBBJ9IIaQn/BW(R(c k$& h[ހDzl@;Ĉv8l9r4 ___? wD@qu.D(^Ƥ7Oj`:9ˮ֮%L'^.Hj:XK VnD&bsY3cYlj\;{/PXW0 u)8cMlb3g0vXN8q67n{!<<UUH'33UUX"wFU;^d2c~塨:ϣx[>$wB񗞥]%w|Jj}/  )ZyU-&eВc,|s8CbL1}fg yӬHY>8<@ѻI^ߑa#S:}^aƷփ_ &  [nH#B~"3g2gF#㥗^Vdd^G;e1/,Eh6[PUIPJXAfF&IIIq1G2qѵAU A2mM7G7Jz6뺣V2.|;_o}RoSU/a )97S>s^ƧaoFL|^uw:w>O8\k zmKc1hre^~I89Zvv6̙3}c.~wnF-عs'kFe$IݝcǎQzu2239vaaa=vVZE  %:o|͐λa4}dfF p?=00|?xo3k9'`B E ^`L}٧'̈{;a㫙5v]4zsߓح*R1?RB.>I<*)G~f5칒Q2g}b~fBϡCWI6A./m9ML3&KO2c!ӗɘL<Тڝ z82iVA]0(^·6p$N#^ۼy̬3ϒ>ЭJO5V ʆ2oU#ק+^s/PZU>dvyqkN]HfصkժUC$9Bxx8YYf:ڕz '>c錼āCs/lwyųQW?!&1 0 44-Zp1=BfMQUUFffڵkJffR lh3Nz&$Lh11͇1sr_?ed|Oڌb֏+;Wc_sDЕQA蜤Qܔ&8JTRVU㐡=c{ډ纮cdߙl:NF7&C))W4RnA>}&>.@^9A:vRJD\WGu?0ڷ$&X* FjbL*Rr _d\eə@SH:&M+$Srȣ i ڽ@/t)Gm g2 $zu@h永p1nxMuXA>HHrѺN`z?i&N\lE\\F$t:H@@-<Ǝ_L}&nv`5GFJ4t-)H;Ck>Xw=T/tOg- vEKIDT臘*}$$(=JZ܂`Oxz6vᾑpS;7Wp(Hgds:6 ɷX@R6Ztt9)#I.\Oζa%-dq$_*DT#C[Ug͞zJZ\;T`}t`LLqQqZ MI]3FkZѰ`IAI\&4T0ㅂ(JUiK -of,ZUʕ7QܼfbX6 EKSaz[S, V\\P۵٣g>(؆-oh,~hX7Z:tI'(R&LyoV%aˠqsiꆤİflt@vm|id_#-{]v'ӨS|}2F[plE@ &IO1l*9v'tuvv6fшb%++ UU`0QmyUCUU fEQ!a(BPPZ1}gݍM6LYNϞ/\w`' ϱq$(޸8 hR ?Y~%Gºӭ5R2HJ-gjh4|;8YJGnSNI !!.DZ">^7t5Lͤ5]wd%nǼ?^ ЗoM̛{rVR׉Z,xzb53o'_x<iޑ?3gRVL73wU*e` sF\e.Hj&- Yqboޕ_,\yҎ,OfZ6 O"Rڡ]쿔^>DŽUs6{qSPbu!6w垳cG|'u cv6oʖ[{N"##Q+񸸸bU$K.ѴiGt$FŒ9IwqnhV~3Acٛmxӧh͑3tT3ggC6BmdD+2ƒο oHḇk㥓@熗vKl2M|rxTcOw2/ĥXBʮ(Sҏ`~˥k͘ğ_e 6͜sW6Qp$ g++aN>%K1dӷos$It2:wa_`78]YԶNn[\zs9FFfM9y11dgeAJHHHzT~deeѱCxdYFаh,m9Ie=NyT6kNwMQTeYFe$4UE0ggwqbvFi~JPXKkam?v #ޚXHq!xy{mI;?G!}m/Uā <9XāoṾTӱg(xl6#ĵRQI?DlPnEçJC"2}SrPL'Y-GC_L}*dΝÔ ~w$xK <w8Q9ɿRTlMJ^ M|.&=,|(qL.~Śz{իOdR^ۗ\]"gsiD; xJvyILL$88Xf35k ыݻy\xZXV')j2*$|qלm1xJk%GVFuGPud}r{Jr'if\s?J9Yy Xr~=I|6,^72Y(R>~Y@ulwK5Z㱣#y駹<O]Q4P9z?Ͽ8>C4g=kň XO3ȱy"{ Ǽ[oi:EŧB5/#4CJX~¨Ffj ly_ɸY+ Z]ƚ&0'1$iۤ u%x:̙yYvߓux@])G/IDATM)3+aM#q]5)a;!S8z"('nzj5WB/#MC?o)t!)1UzʗX[hNJJ*UTFZJ_տ#`+؆giy 28#oDfi344] GCɒ@DKxS#@bK|:VSI>~0y!2xԦqF6Ʀl9׆*/mLf v*87is~.~hif2hĚIN߫: IH^ggDJ&C݇VprvT90^MjO䏣\"V1Z{ޭfgD2^ᖥ >3s+|OW-7$*kZ{]V''!xY5P3Zd~Uţ Dҭlhr y2{YL5LḓW$ٗrt9i=> q;?GVFk$s^~ كJH՚,LjfIvW~A]!orX@ Z¬;8?ƠWQ)e5cw:9|4%{d%/ı埱lq%jw~AO5#@6`Zz81.W), V@ V,5f_ɱpڵ";݅xKePb61u۾˷s2mdG b]V@M?aã|88c;5%/o0e\Ձ$2ujԹnhc.獴g(moW$K&?bּoġ"hr@xAqԂrYR8}+%2ܫѥ|_l4iV06xw%X'N£գ3I5z#BY9_Dc?0ow2*)Ly k&1;-'LOƼe1[r,^%;m3>zöo9QRYn5R.@  }pdz:4lbRډzm]0:tQxנIy&)Z FGjTi370fA(8eG]jD>5XU|xp><̛.C6laQ9.w -WnTA43ƿ³xߛt  {?X ڠ==E0/^PRT؎w>ow/RV*Ii2~W3mF\m!Ih" J6UkRWRCJx)oFd+v͍p"`JM 6+O2*xi̞yť!kxCO :7u]E^SIMEI}728x1==UlَLN≋KcP^<!~%(*yh!4J`Q@vIO$ 5ՕӼ;~i'`zJS w:-IK9 %_W =Cק3nSdt :@ ,#.Hd(D;Krn\@ fPSjJ~ޒz8w v\`!jg _SQz:& L dqa*ujNBy_'.ABjA?TQx:˳Qd#!F48P: u/""=ymoN|&F>ʦk9h׭un[Sv|<Bݐ֎9+Qk)Q iqHށXq%V Aicousxԡӑ\[)Wlt1ػKt j֞J1V+i2koӂ[j۰5ֲ`i,p4mesSkßĹd\ufcI+6>Hĵ,ztk/f/ xqgyv ebV-Gp-k~ eVm}N'Y; :a>(.3Wpٯ1nߨS KF& ɕYsEjQnܱc֋di$bDj>XqY,fŴJ9@ SjJnS}ߡ#Lp|VS"Z~ēmC:3LfA 2OC |'\3>52Ѣr)<;͙ zdn?-)Vr՚ܘT W]~ bM$ ;1T7D@.: nWAR<4K/ǒu֎d'<ƼBf U;$K(UPL|dzt 3juܗRSJqSAzm#[Lm!AI1z6ZQE%,5ث]&`o-n_KTp7`ʪ # # License: GPLv2+ # Currently we have issues using localization for py3qt5 variant, # so if both seem functional, the wrapper would call py2gtk2: case "${PREFER_PY2-}" in true|false) ;; "") PREFER_PY2=true ;; *) echo "Unsupported value of PREFER_PY2='$PREFER_PY2', defaulting to 'true'" >&2 PREFER_PY2=true ;; esac # Detect which variant of NUT-Monitor we can run on the local system: [ -s "$0"-py2gtk2 -a -x "$0"-py2gtk2 ] && PYTHON_PY2GTK2_SHEBANG="`head -1 "$0"-py2gtk2 | sed 's,^#!,,'`" || PYTHON_PY2GTK2_SHEBANG="" [ -s "$0"-py3qt5 -a -x "$0"-py3qt5 ] && PYTHON_PY3QT5_SHEBANG="`head -1 "$0"-py3qt5 | sed 's,^#!,,'`" || PYTHON_PY3QT5_SHEBANG="" SCRIPTDIR="`dirname "$0"`" && SCRIPTDIR="`cd "$SCRIPTDIR" && pwd`" || SCRIPTDIR="./" PYTHON_PY2GTK2="" for P in "$PYTHON2" "$PYTHON_PY2GTK2_SHEBANG" "python2" "python" ; do if [ -n "$P" ] \ && (command -v $P) >/dev/null 2>/dev/null \ && $P -c "import re,glob,codecs,gtk,gtk.glade,gobject,ConfigParser" >/dev/null 2>/dev/null \ ; then PYTHON_PY2GTK2="$P" echo "PYTHON_PY2GTK2 is usable as: $PYTHON_PY2GTK2" >&2 break fi done PYTHON_PY3QT5="" for P in "$PYTHON3" "$PYTHON_PY3QT5_SHEBANG" "python3" "python" ; do if [ -n "$P" ] \ && (command -v $P) >/dev/null 2>/dev/null \ && $P -c "import re,glob,codecs,PyQt5.uic,configparser" >/dev/null 2>/dev/null \ ; then PYTHON_PY3QT5="$P" echo "PYTHON_PY3QT5 is usable as: $PYTHON_PY3QT5" >&2 break fi done for P in "$PYTHON_PY2GTK2" "$PYTHON_PY3QT5" ; do [ -n "$P" ] || continue # If running from source tree... if ! $P -c "import PyNUT" >/dev/null 2>/dev/null \ && PYTHONPATH="${SCRIPTDIR}/../module" $P -c "import PyNUT" >/dev/null 2>/dev/null \ ; then PYTHONPATH="${SCRIPTDIR}/../module" export PYTHONPATH fi done if [ -n "$PYTHON_PY2GTK2" ] && [ -n "$PYTHON_PY3QT5" ] ; then if $PREFER_PY2 ; then echo "Starting $0-py2gtk2 variant..." >&2 exec $PYTHON_PY2GTK2 "$0"-py2gtk2 "$@" else echo "Starting $0-py3qt5 variant..." >&2 exec $PYTHON_PY3QT5 "$0"-py3qt5 "$@" fi else if [ -n "$PYTHON_PY2GTK2" ] ; then echo "Starting $0-py2gtk2 variant..." >&2 exec $PYTHON_PY2GTK2 "$0"-py2gtk2 "$@" fi if [ -n "$PYTHON_PY3QT5" ] ; then echo "Starting $0-py3qt5 variant..." >&2 exec $PYTHON_PY3QT5 "$0"-py3qt5 "$@" fi fi echo "ERROR: No usable Python interpreter version (with needed modules) was found" >&2 exit 1 nut-2.8.3/scripts/python/module/0000755000200500020050000000000015001555412013612 500000000000000nut-2.8.3/scripts/python/module/test_nutclient.py.in0000755000200500020050000001513414777767434017620 00000000000000#!@PYTHON@ # -*- coding: utf-8 -*- # This source code is provided for testing/debuging purpose ;) import PyNUT import sys import os if __name__ == "__main__" : NUT_HOST = os.getenv('NUT_HOST', '127.0.0.1') NUT_PORT = int(os.getenv('NUT_PORT', '3493')) NUT_USER = os.getenv('NUT_USER', None) NUT_PASS = os.getenv('NUT_PASS', None) NUT_DEBUG = ("true" == os.getenv('DEBUG', 'false') or os.getenv('NUT_DEBUG_LEVEL', None) is not None) # Account "unexpected" failures (more due to coding than circumstances) # e.g. lack of protected access when no credentials were passed is okay failed = [] print( "PyNUTClient test..." ) #nut = PyNUT.PyNUTClient( debug=True, port=NUT_PORT ) #nut = PyNUT.PyNUTClient( login=NUT_USER, password=NUT_PASS, debug=True, host=NUT_HOST, port=NUT_PORT ) nut = PyNUT.PyNUTClient( login=NUT_USER, password=NUT_PASS, debug=NUT_DEBUG, host=NUT_HOST, port=NUT_PORT ) #nut = PyNUT.PyNUTClient( login="upsadmin", password="upsadmin", debug=True, port=NUT_PORT ) print( 80*"-" + "\nTesting 'GetUPSList' :") result = nut.GetUPSList( ) print( "\033[01;33m%s\033[0m\n" % result ) # [dummy] # driver = dummy-ups # desc = "Test device" # port = /src/nut/data/evolution500.seq print( 80*"-" + "\nTesting 'GetUPSVars' for 'dummy' (should be registered in upsd.conf) :") result = nut.GetUPSVars( "dummy" ) print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'CheckUPSAvailable' :") result = nut.CheckUPSAvailable( "dummy" ) print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'GetUPSCommands' :") result = nut.GetUPSCommands( "dummy" ) print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'GetRWVars' :") result = nut.GetRWVars( "dummy" ) print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'RunUPSCommand' (Test front panel) :") try : result = nut.RunUPSCommand( "UPS1", "test.panel.start" ) if (NUT_USER is None): raise AssertionError("Secure operation should have failed due to lack of credentials, but did not") except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex if (NUT_USER is None and ex == 'ERR USERNAME-REQUIRED'): result = result + "\n(anticipated error: no credentials were provided)" else: if (ex != 'ERR CMD-NOT-SUPPORTED' and (NUT_USER is not None and ex != 'ERR ACCESS-DENIED') ): result = result + "\nTEST-CASE FAILED" failed.append('RunUPSCommand') print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'SetUPSVar' (set ups.id to test):") try : result = nut.SetRWVar( "UPS1", "ups.id", "test" ) if (NUT_USER is None): raise AssertionError("Secure operation should have failed due to lack of credentials, but did not") except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex if (NUT_USER is None and ex == 'ERR USERNAME-REQUIRED'): result = result + "\n(anticipated error: no credentials were provided)" else: if (ex != 'ERR VAR-NOT-SUPPORTED' and (NUT_USER is not None and ex != 'ERR ACCESS-DENIED') ): result = result + "\nTEST-CASE FAILED" failed.append('SetUPSVar') print( "\033[01;33m%s\033[0m\n" % result ) # testing who has an upsmon-like log-in session to a device print( 80*"-" + "\nTesting 'ListClients' for 'dummy' (should be registered in upsd.conf) before test client is connected :") try : result = nut.ListClients( "dummy" ) except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex result = result + "\nTEST-CASE FAILED" failed.append('ListClients-dummy-before') print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'ListClients' for missing device (should raise an exception) :") try : result = nut.ListClients( "MissingBogusDummy" ) except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex if (ex == 'ERR UNKNOWN-UPS'): result = result + "\n(anticipated error: bogus device name was tested)" else: result = result + "\nTEST-CASE FAILED" failed.append('ListClients-MissingBogusDummy') print( "\033[01;33m%s\033[0m\n" % result ) loggedIntoDummy = False print( 80*"-" + "\nTesting 'DeviceLogin' for 'dummy' (should be registered in upsd.conf; current credentials should have an upsmon role in upsd.users) :") try : result = nut.DeviceLogin( "dummy" ) if (NUT_USER is None): raise AssertionError("Secure operation should have failed due to lack of credentials, but did not") loggedIntoDummy = True except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex if (NUT_USER is None and ex == 'ERR USERNAME-REQUIRED'): result = result + "\n(anticipated error: no credentials were provided)" else: if (NUT_USER is not None and ex != 'ERR ACCESS-DENIED'): result = result + "\nTEST-CASE FAILED" failed.append('DeviceLogin-dummy') print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'ListClients' for None (should list all devices and sessions to them, if any -- e.g. one established above) :") try : result = nut.ListClients( ) if (type(result) is not dict): raise TypeError("ListClients() did not return a dict") else: if (loggedIntoDummy): if (len(result) < 1): raise ValueError("ListClients() returned an empty dict where at least one client was expected on b'dummy'") if (type(result[b'dummy']) is not list): raise TypeError("ListClients() did not return a dict whose b'dummy' keyed value is a list") if (len(result[b'dummy']) < 1): raise ValueError("ListClients() returned a dict where at least one client was expected on b'dummy' but none were reported") except : ex = str(sys.exc_info()[1]) result = "EXCEPTION: " + ex result = result + "\nTEST-CASE FAILED" failed.append('ListClients-dummy-after') print( "\033[01;33m%s\033[0m\n" % result ) print( 80*"-" + "\nTesting 'PyNUT' instance teardown (end of test script)" ) # No more tests AFTER this line; add them above the teardown message if (len(failed) > 0): print ( "SOME TEST CASES FAILED in an unexpected manner: %s" % failed ) sys.exit(1) nut-2.8.3/scripts/python/module/Makefile.in0000644000200500020050000006625515001555011015610 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/python/module (PyNUTClient) # See also: .github/workflows/PyNUTClient.yml # Note: this Makefile is focused on PyPI publication # The usual autotools stuff including clean-up is in parent dir # (to allow easier mixing of the module and app, if/when desired) # # NOTE: Due to PEP-0625, the versioned tarball and directory names # must be normalized to lower-case, as achieved by setup.py(.in). # The module name remains camel-cased as it always was. VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = scripts/python/module ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = PyNUT.py setup.py test_nutclient.py CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/PyNUT.py.in \ $(srcdir)/setup.py.in $(srcdir)/test_nutclient.py.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = tox.ini MANIFEST.in GENERATED_DIST = dist build *.egg-info GENERATED_SRC = PyNUTClient README.txt LICENSE-GPL3 # These are normally generated by a NUT build, but if we want to iterate # specifically PyNUTClient packaging - `make veryclean dist` should do it here: GENERATED_PY = test_nutclient.py PyNUT.py setup.py MAINTAINERCLEANFILES = Makefile.in .dirstamp .pypi-tools* all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/python/module/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/python/module/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): PyNUT.py: $(top_builddir)/config.status $(srcdir)/PyNUT.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ setup.py: $(top_builddir)/config.status $(srcdir)/setup.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ test_nutclient.py: $(top_builddir)/config.status $(srcdir)/test_nutclient.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-local dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: all all-am check check-am check-local clean clean-generic \ clean-libtool clean-local cscopelist-am ctags-am distclean \ distclean-generic distclean-libtool distclean-local distdir \ dvi dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am .PRECIOUS: Makefile # Non-maintainers can at most generate the source layout for python setuptools # (having only shell scripting as a prerequisite suffices for that) all: PyNUTClient check-local: @echo "You may want to set up a NUT data server and run 'make tox' here: `pwd`" # NOT tying into "make check" because a lot of stars must align for this test: tox: dist .pypi-tools-tox tox # (Re-)generate files normally made by `configure` from .in templates # No touch-files here, intended for manual use in developer iterations py-in: $(GENERATED_PY) redist: clean py-in dist $(GENERATED_DIST): .pypi-dist # NOTE: We only clean .pypi-tools* in MAINTAINERCLEANFILES to avoid regular # re-detection of the probably unchanging environment! clean-local: rm -rf $(GENERATED_SRC) $(GENERATED_DIST) rm -f .pypi-src .pypi-dist* veryclean: clean rm -f $(GENERATED_PY) # Python test envs take a while to populate, so maybe better not clean # them too enthusiastically. Can revise (move to "clean-local") later, # if this choice proves a problem. distclean-local: rm -rf .tox rm -f $(GENERATED_PY) PyNUTClient: .pypi-src # Tagged releases should only have three blocks of digits separated by dots upload publish: +@echo " PYPI Checking upload type for module version '$(NUT_SOURCE_GITREV_NUMERIC)'" ; \ case x"`echo "$(NUT_SOURCE_GITREV_NUMERIC)" | tr -d '[0-9]'`" in \ x..) echo " PYPI ...release"; $(MAKE) $(AM_MAKEFLAGS) upload-pypi ;; \ x*) echo " PYPI ...testing"; $(MAKE) $(AM_MAKEFLAGS) upload-testpypi ;; \ esac # README.txt is also a part of module standard expectations .pypi-src: test_nutclient.py.in PyNUT.py.in setup.py.in README.adoc Makefile $(top_srcdir)/LICENSE-GPL3 @echo " PYPI Generate PyPI module source" @rm -rf $(GENERATED_SRC) "$@" @mkdir -p PyNUTClient @for S in "$(srcdir)"/*.py.in ; do \ B="`basename "$${S}" .in`" ; \ if test x"$${B}" = xsetup.py ; then \ if ! test -s "$${B}" ; then \ sed -e "s/[@]NUT_SOURCE_GITREV_NUMERIC[@]/$(NUT_SOURCE_GITREV_NUMERIC)/" < "$(srcdir)/$${B}.in" > "$${B}" || exit ; \ fi ; \ continue; \ fi; \ if test -s "$${B}" ; then \ cp -pf "$${B}" PyNUTClient/ || exit ; \ continue; \ fi ; \ sed -e "s,[@]PYTHON[@],@PYTHON@," < "$(srcdir)/$${B}.in" > "PyNUTClient/$${B}" || exit ; \ if test -x "$(srcdir)/$${B}.in" ; then chmod +x "PyNUTClient/$${B}"; fi ; \ done ; \ cp -pf "$(srcdir)/README.adoc" README.txt || exit ; \ cp -pf "$(top_srcdir)/LICENSE-GPL3" . || exit ; \ echo "from . import PyNUT" > PyNUTClient/__init__.py || exit @touch "$@" .pypi-tools-python: @echo " PYPI Checking that PYTHON variable is defined and usable: $(PYTHON)" @test -n "$(PYTHON)" && command -v $(PYTHON) @touch "$@" .pypi-tools-dist-wheel: .pypi-tools-python @echo " PYPI Prepare PyPI tools to generate a distribution (wheel)" @$(PYTHON) -m pip install wheel @touch "$@" .pypi-tools-dist-build: .pypi-tools-python @echo " PYPI Prepare PyPI tools to generate a distribution (build)" @$(PYTHON) -m pip install build @touch "$@" .pypi-tools-tox: .pypi-tools-python @echo " PYPI Prepare Python multi-environment testing tools (tox)" @$(PYTHON) -m pip install tox @touch "$@" # Install via OS packaging or pip? # https://twine.readthedocs.io/en/stable/ .pypi-tools-upload: .pypi-tools-python @echo " PYPI Prepare PyPI tools and resources to upload a distribution (twine)" @$(PYTHON) -m pip install twine @command -v twine @test -s $(HOME)/.pypirc @touch "$@" # Using pypa/setuptools .pypi-dist: .pypi-src +@$(MAKE) $(AM_MAKEFLAGS) .pypi-dist-pip-build || \ $(MAKE) $(AM_MAKEFLAGS) .pypi-dist-obsolete || \ $(MAKE) $(AM_MAKEFLAGS) .pypi-dist-pip-wheel @touch "$@" # The most modern approach as of 2023 .pypi-dist-pip-build: .pypi-tools-dist-build .pypi-src @echo " PYPI Generate PyPI module distribution (using 'build' module)" @rm -rf $(GENERATED_DIST) "$@" @$(PYTHON) -m build --skip-dependency-check --no-isolation @touch "$@" # Using "setup.py" directly causes warnings about its deprecation # While "pip" distribution generator also uses it internally, # it "knows what it's doing" and goes quietly about its work :) # Does not support "sdis" though. Oh well. .pypi-dist-pip-wheel: .pypi-tools-dist-wheel .pypi-src @echo " PYPI Generate PyPI module distribution (using 'pip wheel')" @rm -rf $(GENERATED_DIST) "$@" @$(PYTHON) -m pip wheel --no-deps -w dist . @touch "$@" .pypi-dist-obsolete: .pypi-tools-dist-wheel .pypi-src @echo " PYPI Generate PyPI module distribution (using setup.py directly)" @rm -rf $(GENERATED_DIST) "$@" @$(PYTHON) setup.py sdist bdist_wheel @touch "$@" # These need $HOME/.pypirc prepared with credentials (API tokens) from # https://pypi.org/manage/account/ and https://test.pypi.org/manage/account/ # TODO: .asc/.sig files for releases? upload-pypi: .pypi-dist .pypi-tools-upload @echo " PYPI Upload PyPI module distribution to production/release PyPI repository" @twine upload dist/* upload-testpypi: .pypi-dist .pypi-tools-upload @echo " PYPI Upload PyPI module distribution to testing/staging PyPI repository" @twine upload -r testpypi dist/* # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/python/module/MANIFEST.in0000644000200500020050000000002014777534446015307 00000000000000include tox.ini nut-2.8.3/scripts/python/module/tox.ini0000644000200500020050000000171314777534446015076 00000000000000# Configuration for Python test environment manager # https://tox.wiki/en/latest/user_guide.html # # Note that to run `test_nutclient.py` you must prepare a running NUT data # server (upsd) with a connected driver. You can use a dummy-ups driver for # that, see e.g. NUT tests/NIT/nit.sh for how the test beds are prepared. # Further you may need to export `NUT_HOST` and `NUT_PORT` (if not default), # and a `NUT_USER` and `NUT_PASS` for tests with logged-in session behaviors. # Then just run `tox` (may have to `pip install tox` first though). [tox] envlist = py2{6,7} py3{5,5,6,7,8,9,10,11,12,13} [testenv] setenv = PYTHONPATH = {toxinidir}:{toxinidir}/PyNUTClient # On my system, some but not all Python versions complained about lack of # "distutils.cmd" etc. in the prepared virtual environments. Can this help? commands_pre = python -m pip install -U pip commands = python PyNUTClient/test_nutclient.py #py.test --basetemp={envtmpdir} nut-2.8.3/scripts/python/module/Makefile.am0000644000200500020050000001365415001552635015603 00000000000000# Network UPS Tools: scripts/python/module (PyNUTClient) # See also: .github/workflows/PyNUTClient.yml # Note: this Makefile is focused on PyPI publication # The usual autotools stuff including clean-up is in parent dir # (to allow easier mixing of the module and app, if/when desired) # # NOTE: Due to PEP-0625, the versioned tarball and directory names # must be normalized to lower-case, as achieved by setup.py(.in). # The module name remains camel-cased as it always was. # Non-maintainers can at most generate the source layout for python setuptools # (having only shell scripting as a prerequisite suffices for that) all: PyNUTClient check-local: @echo "You may want to set up a NUT data server and run 'make tox' here: `pwd`" # NOT tying into "make check" because a lot of stars must align for this test: tox: dist .pypi-tools-tox tox EXTRA_DIST = tox.ini MANIFEST.in NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ PYTHON = @PYTHON@ GENERATED_DIST = dist build *.egg-info GENERATED_SRC = PyNUTClient README.txt LICENSE-GPL3 # These are normally generated by a NUT build, but if we want to iterate # specifically PyNUTClient packaging - `make veryclean dist` should do it here: GENERATED_PY = test_nutclient.py PyNUT.py setup.py # (Re-)generate files normally made by `configure` from .in templates # No touch-files here, intended for manual use in developer iterations py-in: $(GENERATED_PY) redist: clean py-in dist $(GENERATED_DIST): .pypi-dist # NOTE: We only clean .pypi-tools* in MAINTAINERCLEANFILES to avoid regular # re-detection of the probably unchanging environment! clean-local: rm -rf $(GENERATED_SRC) $(GENERATED_DIST) rm -f .pypi-src .pypi-dist* veryclean: clean rm -f $(GENERATED_PY) # Python test envs take a while to populate, so maybe better not clean # them too enthusiastically. Can revise (move to "clean-local") later, # if this choice proves a problem. distclean-local: rm -rf .tox rm -f $(GENERATED_PY) MAINTAINERCLEANFILES = Makefile.in .dirstamp .pypi-tools* PyNUTClient: .pypi-src # Tagged releases should only have three blocks of digits separated by dots upload publish: +@echo " PYPI Checking upload type for module version '$(NUT_SOURCE_GITREV_NUMERIC)'" ; \ case x"`echo "$(NUT_SOURCE_GITREV_NUMERIC)" | tr -d '[0-9]'`" in \ x..) echo " PYPI ...release"; $(MAKE) $(AM_MAKEFLAGS) upload-pypi ;; \ x*) echo " PYPI ...testing"; $(MAKE) $(AM_MAKEFLAGS) upload-testpypi ;; \ esac # README.txt is also a part of module standard expectations .pypi-src: test_nutclient.py.in PyNUT.py.in setup.py.in README.adoc Makefile $(top_srcdir)/LICENSE-GPL3 @echo " PYPI Generate PyPI module source" @rm -rf $(GENERATED_SRC) "$@" @mkdir -p PyNUTClient @for S in "$(srcdir)"/*.py.in ; do \ B="`basename "$${S}" .in`" ; \ if test x"$${B}" = xsetup.py ; then \ if ! test -s "$${B}" ; then \ sed -e "s/[@]NUT_SOURCE_GITREV_NUMERIC[@]/$(NUT_SOURCE_GITREV_NUMERIC)/" < "$(srcdir)/$${B}.in" > "$${B}" || exit ; \ fi ; \ continue; \ fi; \ if test -s "$${B}" ; then \ cp -pf "$${B}" PyNUTClient/ || exit ; \ continue; \ fi ; \ sed -e "s,[@]PYTHON[@],@PYTHON@," < "$(srcdir)/$${B}.in" > "PyNUTClient/$${B}" || exit ; \ if test -x "$(srcdir)/$${B}.in" ; then chmod +x "PyNUTClient/$${B}"; fi ; \ done ; \ cp -pf "$(srcdir)/README.adoc" README.txt || exit ; \ cp -pf "$(top_srcdir)/LICENSE-GPL3" . || exit ; \ echo "from . import PyNUT" > PyNUTClient/__init__.py || exit @touch "$@" .pypi-tools-python: @echo " PYPI Checking that PYTHON variable is defined and usable: $(PYTHON)" @test -n "$(PYTHON)" && command -v $(PYTHON) @touch "$@" .pypi-tools-dist-wheel: .pypi-tools-python @echo " PYPI Prepare PyPI tools to generate a distribution (wheel)" @$(PYTHON) -m pip install wheel @touch "$@" .pypi-tools-dist-build: .pypi-tools-python @echo " PYPI Prepare PyPI tools to generate a distribution (build)" @$(PYTHON) -m pip install build @touch "$@" .pypi-tools-tox: .pypi-tools-python @echo " PYPI Prepare Python multi-environment testing tools (tox)" @$(PYTHON) -m pip install tox @touch "$@" # Install via OS packaging or pip? # https://twine.readthedocs.io/en/stable/ .pypi-tools-upload: .pypi-tools-python @echo " PYPI Prepare PyPI tools and resources to upload a distribution (twine)" @$(PYTHON) -m pip install twine @command -v twine @test -s $(HOME)/.pypirc @touch "$@" # Using pypa/setuptools .pypi-dist: .pypi-src +@$(MAKE) $(AM_MAKEFLAGS) .pypi-dist-pip-build || \ $(MAKE) $(AM_MAKEFLAGS) .pypi-dist-obsolete || \ $(MAKE) $(AM_MAKEFLAGS) .pypi-dist-pip-wheel @touch "$@" # The most modern approach as of 2023 .pypi-dist-pip-build: .pypi-tools-dist-build .pypi-src @echo " PYPI Generate PyPI module distribution (using 'build' module)" @rm -rf $(GENERATED_DIST) "$@" @$(PYTHON) -m build --skip-dependency-check --no-isolation @touch "$@" # Using "setup.py" directly causes warnings about its deprecation # While "pip" distribution generator also uses it internally, # it "knows what it's doing" and goes quietly about its work :) # Does not support "sdis" though. Oh well. .pypi-dist-pip-wheel: .pypi-tools-dist-wheel .pypi-src @echo " PYPI Generate PyPI module distribution (using 'pip wheel')" @rm -rf $(GENERATED_DIST) "$@" @$(PYTHON) -m pip wheel --no-deps -w dist . @touch "$@" .pypi-dist-obsolete: .pypi-tools-dist-wheel .pypi-src @echo " PYPI Generate PyPI module distribution (using setup.py directly)" @rm -rf $(GENERATED_DIST) "$@" @$(PYTHON) setup.py sdist bdist_wheel @touch "$@" # These need $HOME/.pypirc prepared with credentials (API tokens) from # https://pypi.org/manage/account/ and https://test.pypi.org/manage/account/ # TODO: .asc/.sig files for releases? upload-pypi: .pypi-dist .pypi-tools-upload @echo " PYPI Upload PyPI module distribution to production/release PyPI repository" @twine upload dist/* upload-testpypi: .pypi-dist .pypi-tools-upload @echo " PYPI Upload PyPI module distribution to testing/staging PyPI repository" @twine upload -r testpypi dist/* nut-2.8.3/scripts/python/module/PyNUT.py.in0000644000200500020050000004554014777767434015534 00000000000000#!@PYTHON@ # -*- coding: utf-8 -*- # Copyright (C) 2008 David Goncalves # # 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 . # 2008-01-14 David Goncalves # PyNUT is an abstraction class to access NUT (Network UPS Tools) server. # # 2008-06-09 David Goncalves # Added 'GetRWVars' and 'SetRWVar' commands. # # 2009-02-19 David Goncalves # Changed class PyNUT to PyNUTClient # # 2010-07-23 David Goncalves - Version 1.2 # Changed GetRWVars function that fails is the UPS is not # providing such vars. # # 2011-07-05 René Martín Rodríguez - Version 1.2.1 # Added support for FSD, HELP and VER commands # # 2012-02-07 René Martín Rodríguez - Version 1.2.2 # Added support for LIST CLIENTS command # # 2014-06-03 george2 - Version 1.3.0 # Added custom exception class, fixed minor bug, added Python 3 support. # # 2021-09-27 Jim Klimov - Version 1.4.0 # Revise strings used to be byte sequences as required by telnetlib # in Python 3.9, by spelling out b"STR" or str.encode('ascii'); # the change was also tested to work with Python 2.7, 3.4, 3.5 and # 3.7 (to the extent of accompanying test_nutclient.py at least). # # 2022-08-12 Jim Klimov - Version 1.5.0 # Fix ListClients() method to actually work with current NUT protocol # Added DeviceLogin() method # Added GetUPSNames() method # Fixed raised PyNUTError() exceptions to carry a Python string # (suitable for Python2 and Python3), not byte array from protocol, # so exception catchers can process them naturally (see test script). # # 2023-01-18 Jim Klimov - Version 1.6.0 # Added CheckUPSAvailable() method originally by Michal Hlavinka # from 2013-01-07 RedHat/Fedora packaging # # 2024-07-01 Jim Klimov - Version 1.7.0 # Re-arranged dependency on telnetlib module (deprecated/removed # since Python 3.11/3.13), so we can fall back on a privately # stashed copy until a better solution is developed. # # 2025-01-31 cgar - Version 1.8.0 # Removed telnetlib dependency. Switched to using socket directly. import socket class PyNUTError( Exception ) : """ Base class for custom exceptions """ class PyNUTClient : """ Abstraction class to access NUT (Network UPS Tools) server """ __debug = None # Set class to debug mode (prints everything useful for debuging...) __host = None __port = None __login = None __password = None __timeout = None __srv_handler = None __recv_leftover = b'' __version = "1.8.0" __release = "2025-02-07" def __init__( self, host="127.0.0.1", port=3493, login=None, password=None, debug=False, timeout=5 ) : """ Class initialization method host : Host to connect (default to localhost) port : Port where NUT listens for connections (default to 3493) login : Login used to connect to NUT server (default to None for no authentication) password : Password used when using authentication (default to None) debug : Boolean, put class in debug mode (prints everything on console, default to False) timeout : Timeout used to wait for network response """ self.__debug = debug if self.__debug : print( "[DEBUG] Class initialization..." ) print( "[DEBUG] -> Host = %s (port %s)" % ( host, port ) ) print( "[DEBUG] -> Login = '%s' / '%s'" % ( login, password ) ) self.__host = host self.__port = port self.__login = login self.__password = password self.__timeout = timeout self.__connect() # Try to disconnect cleanly when class is deleted ;) def __del__( self ) : """ Class destructor method """ try : self.__srv_handler.send( b"LOGOUT\n" ) except : pass def __read_until(self, finished_reading_data): data = self.__recv_leftover while True: data_end_index = data.find(finished_reading_data) if data_end_index == -1: data += self.__srv_handler.recv(50) # nut_telnetlib.py uses 50 else: break data_end_index += len(finished_reading_data) if data_end_index == len(data): self.__recv_leftover = b'' else: self.__recv_leftover = data[data_end_index:] data = data[:data_end_index] return data def __connect( self ) : """ Connects to the defined server If login/pass was specified, the class tries to authenticate. An error is raised if something goes wrong. """ if self.__debug : print( "[DEBUG] Connecting to host" ) self.__srv_handler = socket.create_connection( (self.__host, self.__port), self.__timeout ) if self.__login != None : self.__srv_handler.send( ("USERNAME %s\n" % self.__login).encode('ascii') ) result = self.__read_until( b"\n" ) if result[:2] != b"OK" : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) if self.__password != None : self.__srv_handler.send( ("PASSWORD %s\n" % self.__password).encode('ascii') ) result = self.__read_until( b"\n" ) if result[:2] != b"OK" : if result == b"ERR INVALID-ARGUMENT\n" : # Quote the password (if it has whitespace etc) # TODO: Escape special chard like NUT does? self.__srv_handler.send( ("PASSWORD \"%s\"\n" % self.__password).encode('ascii') ) result = self.__read_until( b"\n" ) if result[:2] != b"OK" : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) else: raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def GetUPSList( self ) : """ Returns the list of available UPS from the NUT server The result is a dictionary containing 'key->val' pairs of 'UPSName' and 'UPS Description' Note that fields here are byte sequences (not locale-aware strings) which is of little concern for Python2 but is important in Python3 (e.g. when we use "str" type `ups` variables or check their "validity"). """ if self.__debug : print( "[DEBUG] GetUPSList from server" ) self.__srv_handler.send( b"LIST UPS\n" ) result = self.__read_until( b"\n" ) if result != b"BEGIN LIST UPS\n": raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) result = self.__read_until( b"END LIST UPS\n" ) ups_list = {} for line in result.split( b"\n" ) : if line[:3] == b"UPS" : ups, desc = line[4:-1].split( b'"' ) ups_list[ ups.replace( b" ", b"" ) ] = desc return( ups_list ) def GetUPSNames( self ) : """ Returns the list of available UPS names from the NUT server as strings The result is a set of str objects (comparable with ups="somename" and useful as arguments to other methods). Helps work around Python2/Python3 string API changes. """ if self.__debug : print( "[DEBUG] GetUPSNames from server" ) self_ups_list = [] for b in self.GetUPSList(): self_ups_list.append(b.decode('ascii')) return self_ups_list def GetUPSVars( self, ups="" ) : """ Get all available vars from the specified UPS The result is a dictionary containing 'key->val' pairs of all available vars. """ if self.__debug : print( "[DEBUG] GetUPSVars called..." ) self.__srv_handler.send( ("LIST VAR %s\n" % ups).encode('ascii') ) result = self.__read_until( b"\n" ) if result != ("BEGIN LIST VAR %s\n" % ups).encode('ascii') : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) ups_vars = {} result = self.__read_until( ("END LIST VAR %s\n" % ups).encode('ascii') ) offset = len( ("VAR %s " % ups ).encode('ascii') ) end_offset = 0 - ( len( ("END LIST VAR %s\n" % ups).encode('ascii') ) + 1 ) for current in result[:end_offset].split( b"\n" ) : var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" ) data = current[ offset: ].split( b'"' )[1] ups_vars[ var ] = data return( ups_vars ) def CheckUPSAvailable( self, ups="" ) : """ Check whether UPS is reachable Just tries to contact UPS with a safe command. The result is True (reachable) or False (unreachable) """ if self.__debug : print( "[DEBUG] CheckUPSAvailable called..." ) self.__srv_handler.send( ("LIST CMD %s\n" % ups).encode('ascii') ) result = self.__read_until( b"\n" ) if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') : return False self.__read_until( ("END LIST CMD %s\n" % ups).encode('ascii') ) return True def GetUPSCommands( self, ups="" ) : """ Get all available commands for the specified UPS The result is a dict object with command name as key and a description of the command as value """ if self.__debug : print( "[DEBUG] GetUPSCommands called..." ) self.__srv_handler.send( ("LIST CMD %s\n" % ups).encode('ascii') ) result = self.__read_until( b"\n" ) if result != ("BEGIN LIST CMD %s\n" % ups).encode('ascii') : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) ups_cmds = {} result = self.__read_until( ("END LIST CMD %s\n" % ups).encode('ascii') ) offset = len( ("CMD %s " % ups).encode('ascii') ) end_offset = 0 - ( len( ("END LIST CMD %s\n" % ups).encode('ascii') ) + 1 ) for current in result[:end_offset].split( b"\n" ) : var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" ) # For each var we try to get the available description try : self.__srv_handler.send( ("GET CMDDESC %s %s\n" % ( ups, var )).encode('ascii') ) temp = self.__read_until( b"\n" ) if temp[:7] != b"CMDDESC" : raise PyNUTError else : off = len( ("CMDDESC %s %s " % ( ups, var )).encode('ascii') ) desc = temp[off:-1].split(b'"')[1] except : desc = var ups_cmds[ var ] = desc return( ups_cmds ) def GetRWVars( self, ups="" ) : """ Get a list of all writable vars from the selected UPS The result is presented as a dictionary containing 'key->val' pairs """ if self.__debug : print( "[DEBUG] GetUPSVars from '%s'..." % ups ) self.__srv_handler.send( ("LIST RW %s\n" % ups).encode('ascii') ) result = self.__read_until( b"\n" ) if ( result != ("BEGIN LIST RW %s\n" % ups).encode('ascii') ) : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) result = self.__read_until( ("END LIST RW %s\n" % ups).encode('ascii') ) offset = len( ("VAR %s" % ups).encode('ascii') ) end_offset = 0 - ( len( ("END LIST RW %s\n" % ups).encode('ascii') ) + 1 ) rw_vars = {} try : for current in result[:end_offset].split( b"\n" ) : var = current[ offset: ].split( b'"' )[0].replace( b" ", b"" ) data = current[ offset: ].split( b'"' )[1] rw_vars[ var ] = data except : pass return( rw_vars ) def SetRWVar( self, ups="", var="", value="" ): """ Set a variable to the specified value on selected UPS The variable must be a writable value (cf GetRWVars) and you must have the proper rights to set it (maybe login/password). """ self.__srv_handler.send( ("SET VAR %s %s %s\n" % ( ups, var, value )).encode('ascii') ) result = self.__read_until( b"\n" ) if ( result == b"OK\n" ) : return( "OK" ) else : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def RunUPSCommand( self, ups="", command="" ) : """ Send a command to the specified UPS Returns OK on success or raises an error """ if self.__debug : print( "[DEBUG] RunUPSCommand called..." ) self.__srv_handler.send( ("INSTCMD %s %s\n" % ( ups, command )).encode('ascii') ) result = self.__read_until( b"\n" ) if ( result == b"OK\n" ) : return( "OK" ) else : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def DeviceLogin( self, ups="") : """ Establish a login session with a device (like upsmon does) Returns OK on success or raises an error USERNAME and PASSWORD must have been specified earlier in the session (once) and upsd.conf should permit that user with one of `upsmon` role types. Note there is no "device LOGOUT" in the protocol, just one for general end of connection. """ if self.__debug : print( "[DEBUG] DeviceLogin called..." ) if ups is None or (ups not in self.GetUPSNames()): if self.__debug : print( "[DEBUG] DeviceLogin: %s is not a valid UPS" % ups ) raise PyNUTError( "ERR UNKNOWN-UPS" ) self.__srv_handler.send( ("LOGIN %s\n" % ups).encode('ascii') ) result = self.__read_until( b"\n" ) if ( result.startswith( ("User %s@" % self.__login).encode('ascii')) and result.endswith (("[%s]\n" % ups).encode('ascii')) ): # User dummy-user@127.0.0.1 logged into UPS [dummy] # Read next line then result = self.__read_until( b"\n" ) if ( result == b"OK\n" ) : return( "OK" ) else : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def FSD( self, ups="") : """ Send FSD command Returns OK on success or raises an error NOTE: API changed since NUT 2.8.0 to replace MASTER with PRIMARY (and backwards-compatible alias handling) """ if self.__debug : print( "[DEBUG] PRIMARY called..." ) self.__srv_handler.send( ("PRIMARY %s\n" % ups).encode('ascii') ) result = self.__read_until( b"\n" ) if ( result != b"OK PRIMARY-GRANTED\n" ) : if self.__debug : print( "[DEBUG] Retrying: MASTER called..." ) self.__srv_handler.send( ("MASTER %s\n" % ups).encode('ascii') ) result = self.__read_until( b"\n" ) if ( result != b"OK MASTER-GRANTED\n" ) : if self.__debug : print( "[DEBUG] Primary level functions are not available" ) raise PyNUTError( "ERR ACCESS-DENIED" ) if self.__debug : print( "[DEBUG] FSD called..." ) self.__srv_handler.send( ("FSD %s\n" % ups).encode('ascii') ) result = self.__read_until( b"\n" ) if ( result == b"OK FSD-SET\n" ) : return( "OK" ) else : raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) def help(self) : """ Send HELP command """ if self.__debug : print( "[DEBUG] HELP called..." ) self.__srv_handler.send( b"HELP\n" ) return self.__read_until( b"\n" ) def ver(self) : """ Send VER command """ if self.__debug : print( "[DEBUG] VER called..." ) self.__srv_handler.send( b"VER\n" ) return self.__read_until( b"\n" ) def ListClients( self, ups = None ) : """ Returns the list of connected clients from the NUT server The result is a dictionary containing 'key->val' pairs of 'UPSName' and a list of clients """ if self.__debug : print( "[DEBUG] ListClients from server: %s" % ups ) # If (!ups) we use this list below to recurse: self_ups_list = self.GetUPSNames() if ups and (ups not in self_ups_list): if self.__debug : print( "[DEBUG] ListClients: %s is not a valid UPS" % ups ) raise PyNUTError( "ERR UNKNOWN-UPS" ) if ups: self.__srv_handler.send( ("LIST CLIENT %s\n" % ups).encode('ascii') ) else: # NOTE: Currently NUT does not support just listing all clients # (not providing an "ups" argument) => NUT_ERR_INVALID_ARGUMENT self.__srv_handler.send( b"LIST CLIENT\n" ) result = self.__read_until( b"\n" ) if ( (ups and result != ("BEGIN LIST CLIENT %s\n" % ups).encode('ascii')) or (ups is None and result != b"BEGIN LIST CLIENT\n") ): if ups is None and (result == b"ERR INVALID-ARGUMENT\n") : # For ups==None, list all upses, list their clients if self.__debug : print( "[DEBUG] Recurse ListClients() because it did not specify one UPS to query" ) ups_list = {} for ups in self_ups_list : # Update "ups_list" dict with contents of recursive call return ups_list.update(self.ListClients(ups)) return( ups_list ) # had a seemingly valid arg, but no success: if self.__debug : print( "[DEBUG] ListClients from server got unexpected result: %s" % result ) raise PyNUTError( result.replace( b"\n", b"" ).decode('ascii') ) if ups: result = self.__read_until( ("END LIST CLIENT %s\n" % ups).encode('ascii') ) else: # Should not get here with current NUT: result = self.__read_until( b"END LIST CLIENT\n" ) ups_list = {} for line in result.split( b"\n" ): ###print( "[DEBUG] ListClients line: '%s'" % line ) if line[:6] == b"CLIENT" : ups, host = line[7:].split(b' ') ups.replace(b' ', b'') host.replace(b' ', b'') if not ups in ups_list: ups_list[ups] = [] ups_list[ups].append(host) return( ups_list ) nut-2.8.3/scripts/python/module/README.adoc0000644000200500020050000002736314777767434015366 00000000000000Introduction ============ The PyNUT module provides an abstraction class `PyNUTClient` written in Python, which allows to connect to a NUT (Network UPS Tools) server and execute different commands without an application developer needing to know the NUT communication protocol. It also includes a small self-test application as a consumer of the module. The project was originally started in 2008 by David Goncalves at https://www.lestat.st/informatique/projets/pynut and was soon added to the main NUT codebase and further evolved there. The `PyNUTClient` class was born from another project the original author had -- a graphical application to monitor and manage the UPSes connected to a NUT server. It is now known as `NUT-Monitor` and is also provided along with NUT sources. With that GUI application being written in Python too, it was decided to split the project in two parts (the PyNUT class + GUI application, serving as model + view) in order to keep the two parts independent. That class was subsequently renamed to `PyNUTClient` since version 1.1 of the original project, allowing to develop other classes nearby later. It is published to PyPI repository as link:https://pypi.org/project/PyNUTClient/[PyNUTClient] and so should be installable with `pip` tooling. Note that the file name of the distribution tarball is lower-cased per PEP-0625 requirements, while the module name is camel-cased historically. Currently the module is regularly tested to work with Python interpreter versions 2.7, 3.4, 3.5, 3.7, 3.11 and 3.13. [NOTE] ====== Text fields returned by methods are byte sequences (not locale-aware strings), except NUT protocol error codes quoted into `PyNUTError` exceptions which are decoded into strings as originally `ascii` text. This is of little concern for Python 2, but is important in Python 3. The `ups` argument to methods is handled as a string, so conversion may be needed to compare with names returned in the lists and dictionaries, e.g.: ---- strUps = bUps.decode('ascii') bUps = strUps.encode('ascii') ---- Only the names returned by `GetUPSNames()` method specifically are converted into string type. Since Python 3 support was added just recently, module code may later be converted to use string types like `str` or `unicode` in the returned dictionaries and sets instead, if the community deems this to be more idiomatic. Examples below *do not* specify the `b'some text'` markup that would be pedantically correct (for Python 3 at least). ====== .List of methods in the class ------ class PyNUTClient : def __init__( self, host='127.0.0.1', port=3493, login=None, password=None, debug=False, timeout=5 ) : def help( self ) : def ver( self ) : def DeviceLogin( self, ups="" ) : def FSD( self, ups="" ) : def CheckUPSAvailable( self, ups="" ) : def GetRWVars( self, ups='' ) : def GetUPSCommands( self, ups='' ) : def GetUPSList( self ) : def GetUPSNames( self ) : def GetUPSVars( self, ups='' ) : def ListClients( self, ups = None ) : def RunUPSCommand( self, ups='', command='' ) : def SetRWVar( self, ups='', var='', value='' ) : ------ The module also provides the `PyNUTError` class to represent any exceptions raised by `PyNUTClient` logic. Documentation ------------- Although the original project was written in French, for the reasons of general distribution with NUT, all of its code is commented in English. While this file contains the description from https://www.lestat.st/informatique/projets/pynut the class `PyNUTClient` is compatible with the Python module PyDOC, so you can type `pydoc PyNUT` to obtain succinct documentation on your current version of the module. For more examples see the provided test script and the NUT-Monitor application in the NUT sources. Commands below are listed in alphabetic order. __init__ ~~~~~~~~ When you initialize the class instance, it performs the connection to the NUT data server or raises a Python exception from the `__connect()` method called internally. help ~~~~ Sends the `HELP` command to the NUT data server and returns whatever bits of wisdom it has to offer. ver ~~~ Sends the `VER` command to the NUT data server and returns its self-reported identification such as version, product or distribution it may be bundled with. Note that the NUT client interactions should not rely on reported versions, but follow the protocol as defined. DeviceLogin ~~~~~~~~~~~ Establish a "client" session with the specified UPS. This uses credentials specified earlier to `__init__()` this class instance, and on server side (in `upsd.users` file) these credentials must have one of `upsmon` roles. The command should return `OK` if everything went well, or raise an exception in case of failure, such as invalid or insufficiently privileged credentials. Note there is no `DeviceLogout()`, just the general connection termination. FSD ~~~ Send the FSD (Forced ShutDown) command to the specified UPS. The command should return `OK` if everything went well, or raise an exception in case of failure, such as that this server does not allow to manage that UPS as a "primary" (or "master" before NUT 2.8.0). CheckUPSAvailable ~~~~~~~~~~~~~~~~~ Returns a boolean state whether the specified UPS is recognized and available (`True`), or is not (`False`). Internally, requests a listing of commands supported by the device name, and evaluates the server response. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='server', login='upsadmin', password='upspass' ) result = ups.CheckUPSAvailable( ups='ups1' ) print( result ) >> True ----- See also: `GetUPSCommands()` GetRWVars ~~~~~~~~~ Returns a list of modifiable variables on the specified UPS, as a dictionary of "variable"-"current value" pairs. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='server', login='upsadmin', password='upspass' ) result = ups.GetRWVars( ups='ups1' ) print( result ) >> {'battery.date': '10/25/07', 'ups.id': 'test'} ----- See also: `GetUPSVars()`, `SetRWVar()` GetUPSCommands ~~~~~~~~~~~~~~ Returns a list of commands supported by the specified UPS. Note that certain commands are not usable without first getting necessary rights on the NUT data server. The result is presented as a dictionary of "command"-"English description" pairs. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='server', login='upsadmin', password='upspass' ) result = ups.GetRWVars( ups='ups1' ) print( result ) >> {'test.battery.start' : 'Start a battery test', 'calibrate.stop' : 'Stop run time calibration', 'shutdown.stayoff' : 'Turn off the load and remain off', 'test.battery.stop' : 'Stop the battery test', 'test.panel.start' : 'Start testing the UPS panel', 'calibrate.start' : 'Start run time calibration', 'load.off' : 'Turn off the load immediately', 'test.failure.start' : 'Start a simulated power failure', 'shutdown.return' : 'Turn off the load and return when power is back'} ----- See also: `RunUPSCommand()` GetUPSList ~~~~~~~~~~ Returns the list of UPSes represented by the NUT server, as a dictionary of "name"-"description" pairs. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='server', login='upsadmin', password='upspass' ) result = ups.GetUPSList() print( result ) >> {'UPS1': 'Smart UPS 3000 File server', 'UPS2': 'Smart UPS 1000 Serveur de mail'} ----- GetUPSNames ~~~~~~~~~~~ Returns just the list of available UPS names from the NUT server. The result is a set of `str` objects (comparable with `ups="somename"` and useful as arguments to other methods). Helps work around Python2/Python3 string API changes (where `b'string' != 'string'` and not even a type comparable to it), and is primarily used as a helper internally in some methods. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='Serveur', login='upsadmin', password='upspass' ) result = ups.GetUPSNames() print( result ) >> ['UPS1', 'UPS2'] ----- GetUPSVars ~~~~~~~~~~ Returns a list of all variables on the specified UPS, as a dictionary of "variable"-"current value" pairs. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='Serveur', login='upsadmin', password='upspass' ) result = ups.GetUPSVars( ups='UPS1' ) print( result ) >> {'input.transfer.high' : '253', 'battery.charge' : '100.0', 'ups.mfr' : 'APC', 'battery.voltage.nominal' : '024', 'input.transfer.reason' : 'S', 'ups.test.interval' : '1209600', 'input.transfer.low' : '208', 'output.voltage' : '234.0', 'driver.version' : '2.2.1-', 'battery.charge.restart' : '00', 'ups.id' : 'test', 'driver.parameter.pollinterval' : '2', 'driver.parameter.port' : '/dev/ttyS0', 'battery.voltage' : '27.10', 'ups.test.result' : 'NO', 'ups.status' : 'OL', 'battery.date' : '10/25/07', 'ups.model' : 'Smart-UPS SC1000', 'ups.serial' : 'XXXXXXXXXXXX', 'output.voltage.nominal' : '230', 'ups.mfr.date' : '10/25/07', 'driver.version.internal' : '1.99.8', 'input.voltage' : '234.0', 'battery.runtime.low' : '120', 'input.sensitivity' : 'H', 'ups.load' : '001.9', 'driver.name' : 'apcsmart', 'input.voltage.maximum' : '234.0', 'input.frequency' : '50.00', 'ups.delay.shutdown' : '060', 'ups.delay.start' : '000', 'input.voltage.minimum' : '232.0', 'input.quality' : 'FF', 'battery.runtime' : '29040', 'ups.firmware' : '737.3.I', 'battery.alarm.threshold' : '0'} ----- See also: `GetRWVars()` ListClients ~~~~~~~~~~~ Returns the list of connected clients (such as the `NUT-Monitor` application or an `upsmon` service) from the NUT server, for a particular UPS or all of them by default. The result is a dictionary containing "upsname"-"client list" pairing 'UPSName' and a list of clients for each device if the information was retrieved from the NUT data server successfully, or an exception is raised otherwise. RunUPSCommand ~~~~~~~~~~~~~ Executes the specified command on the specified UPS. It should be one of the commands returned by the `GetUPSCommands()` function. Note that certain commands are not usable without first getting necessary rights on the NUT data server. The command should return `OK` if everything went well, or raise an exception in case of failure. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='Serveur', login='upsadmin', password='upspass' ) result = ups.RunUPSCommand( ups='UPS1', command='test.panel.start' ) print( result ) >> OK ----- See also: `GetUPSCommands()` SetRWVar ~~~~~~~~ This method adjusts the value of a writable NUT variable on the specified UPS. It should be one of the variables listed by the `GetRWVars()` method. Note that you may need to first get necessary rights on the NUT data server. The command should return `OK` if everything went well, or raise an exception in case of failure. .Example ----- import PyNUT ups = PyNUT.PyNUTClient( host='Serveur', login='upsadmin', password='upspass' ) result = ups.SetRWVar( ups='UPS1', var='battery.date', value='06/17/08' ) print( result ) >> OK ----- See also: `GetRWVars()` nut-2.8.3/scripts/python/module/setup.py.in0000644000200500020050000000406414777767434015711 00000000000000""" The setup.py file for PyNUTClient """ # Based on https://medium.com/@VersuS_/automate-pypi-releases-with-github-actions-4c5a9cfe947d # See also .github/workflows/PyNUTClient.yml for active packaging steps from setuptools import setup, find_packages import codecs import os here = os.path.abspath(os.path.dirname(__file__)) # README.txt appears from README.adoc during package or CI build with codecs.open(os.path.join(here, "README.txt"), encoding="utf-8") as fh: long_description = "\n" + fh.read() setup( name = "pynutclient", ### "PyNUTClient" lower-cased due to PEP-0625 version = '@NUT_SOURCE_GITREV_NUMERIC@', author = "The Network UPS Tools project", license = "GPL-3.0-or-later", license_files = ('LICENSE-GPL3',), author_email = "jimklimov+nut@gmail.com", description = "Python client bindings for NUT", url = "https://github.com/networkupstools/nut/tree/master/scripts/python/module", long_description_content_type = "text/plain", # NOTE: No asciidoc so far, see https://packaging.python.org/en/latest/specifications/core-metadata/ long_description = long_description, packages = find_packages(), #py_modules = ['PyNUT'], package_dir = {'PyNUT': 'PyNUTClient'}, #data_files = [('', ['tox.ini'])], #scripts = ['PyNUTClient/test_nutclient.py', 'PyNUTClient/__init__.py'], python_requires = '>=2.6', keywords = ['pypi', 'cicd', 'python', 'nut', 'Network UPS Tools'], classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Operating System :: Unix", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows" ] ) nut-2.8.3/scripts/python/Makefile.in0000644000200500020050000015124215001555011014312 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/python VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_NUT_MONITOR_PY2GTK2_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_1 = $(NUT_MONITOR_PY2GTK2) @WITH_NUT_MONITOR_PY2GTK2_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_2 = $(NUT_MONITOR_PY2GTK2_GENERATED_SCRIPT) @WITH_NUT_MONITOR_PY3QT5_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_3 = $(NUT_MONITOR_PY3QT5) @WITH_NUT_MONITOR_PY3QT5_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_4 = $(NUT_MONITOR_PY3QT5_GENERATED_SCRIPT) @WITH_NUT_MONITOR_TRUE@@WITH_PYNUT_APP_TRUE@am__append_5 = $(PYNUT_COMMON) $(PYNUT_GENERATED_NOEXEC) @WITH_NUT_MONITOR_TRUE@@WITH_PYNUT_APP_TRUE@am__append_6 = $(PYNUT_GENERATED_SCRIPT) subdir = scripts/python ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(nutmonitordir)" \ "$(DESTDIR)$(pynut_py2_sitedir)" \ "$(DESTDIR)$(pynut_py3_sitedir)" \ "$(DESTDIR)$(pynut_py_sitedir)" "$(DESTDIR)$(sysbindir)" \ "$(DESTDIR)$(nutmonitordir)" "$(DESTDIR)$(pynut_py2_sitedir)" \ "$(DESTDIR)$(pynut_py3_sitedir)" \ "$(DESTDIR)$(pynut_py_sitedir)" SCRIPTS = $(nobase_nutmonitor_SCRIPTS) $(pynut_py2_site_SCRIPTS) \ $(pynut_py3_site_SCRIPTS) $(pynut_py_site_SCRIPTS) \ $(sysbin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(nobase_nutmonitor_DATA) $(pynut_py2_site_DATA) \ $(pynut_py3_site_DATA) $(pynut_py_site_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ # Recognize settings from configure.ac (for make install handling) nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ # Note: this may be "desktop-file-install" to use in e.g. # packaging postinstall scripts for tighter OS integration; # note also the icon files, etc. that may want symlinks to # system-defined locations. For examples please see e.g. # https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=nut-monitor #nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ SUBDIRS = module NUT_MONITOR_PY2GTK2 = \ app/ui/gui-1.3.glade \ app/nut-monitor-py2gtk2.desktop NUT_MONITOR_PY2GTK2_TEMPLATE = \ app/NUT-Monitor-py2gtk2.in NUT_MONITOR_PY2GTK2_GENERATED_SCRIPT = \ app/NUT-Monitor-py2gtk2 NUT_MONITOR_PY3QT5 = \ app/ui/aboutdialog1.ui \ app/ui/dialog1.ui \ app/ui/dialog2.ui \ app/ui/window1.ui \ app/nut-monitor-py3qt5.desktop NUT_MONITOR_PY3QT5_TEMPLATE = \ app/NUT-Monitor-py3qt5.in NUT_MONITOR_PY3QT5_GENERATED_SCRIPT = \ app/NUT-Monitor-py3qt5 NUT_MONITOR_COMMON = \ README.adoc \ app/nut-monitor.appdata.xml \ app/icons/48x48/nut-monitor.png \ app/icons/64x64/nut-monitor.png \ app/icons/256x256/nut-monitor.png \ app/icons/scalable/nut-monitor.svg \ app/README.adoc \ app/screenshots/nut-monitor-1.png \ app/screenshots/nut-monitor-2.png \ app/screenshots/nut-monitor-3.png \ app/pixmaps/on_battery.png \ app/pixmaps/on_line.png \ app/pixmaps/var-ro.png \ app/pixmaps/var-rw.png \ app/pixmaps/warning.png \ app/locale/fr/LC_MESSAGES/NUT-Monitor.mo \ app/locale/it/LC_MESSAGES/NUT-Monitor.mo \ app/locale/ru/LC_MESSAGES/NUT-Monitor.mo # Reserved for shipping additional modules or scripts "as is" PYNUT_COMMON_CODE = PYNUT_COMMON_MISC = \ module/README.adoc PYNUT_COMMON = $(PYNUT_COMMON_CODE) $(PYNUT_COMMON_MISC) # Note: we both distribute and install the generated *.mo translation files # so they are listed above and not in NUT_MONITOR_COMMON_TEMPLATE NUT_MONITOR_COMMON_TEMPLATE = \ app/locale/NUT-Monitor.pot \ app/locale/fr/fr.po \ app/locale/it/it.po \ app/locale/ru/ru.po PYNUT_TEMPLATE = \ module/setup.py.in \ module/PyNUT.py.in \ module/test_nutclient.py.in PYNUT_GENERATED_NOEXEC = \ module/PyNUT.py PYNUT_GENERATED_SCRIPT = \ module/test_nutclient.py # For now, we have a "dispatcher" script and applet manifest, # to select a functional choice of the GUI client, if possible: NUT_MONITOR_DISPATCHER_NOEXEC = \ app/nut-monitor.desktop NUT_MONITOR_DISPATCHER_SCRIPT = \ app/NUT-Monitor ################################################################# # `make dist` tarball contents: EXTRA_DIST = $(NUT_MONITOR_DISPATCHER_NOEXEC) \ $(NUT_MONITOR_DISPATCHER_SCRIPT) $(NUT_MONITOR_COMMON) \ $(NUT_MONITOR_COMMON_TEMPLATE) $(PYNUT_COMMON) \ $(PYNUT_TEMPLATE) $(NUT_MONITOR_PY2GTK2) \ $(NUT_MONITOR_PY2GTK2_TEMPLATE) $(NUT_MONITOR_PY3QT5) \ $(NUT_MONITOR_PY3QT5_TEMPLATE) ################################################################# # `make install` handling (nobase_ to keep tree structure): # Make py2/py3-only builds, delivered preferred symlinks, etc. optional @WITH_NUT_MONITOR_TRUE@nutmonitordir = $(nut_with_nut_monitor_dir) @WITH_NUT_MONITOR_TRUE@nobase_nutmonitor_DATA = \ @WITH_NUT_MONITOR_TRUE@ $(NUT_MONITOR_DISPATCHER_NOEXEC) \ @WITH_NUT_MONITOR_TRUE@ $(NUT_MONITOR_COMMON) $(am__append_1) \ @WITH_NUT_MONITOR_TRUE@ $(am__append_3) $(am__append_5) @WITH_NUT_MONITOR_TRUE@nobase_nutmonitor_SCRIPTS = \ @WITH_NUT_MONITOR_TRUE@ $(NUT_MONITOR_DISPATCHER_SCRIPT) \ @WITH_NUT_MONITOR_TRUE@ $(am__append_2) $(am__append_4) \ @WITH_NUT_MONITOR_TRUE@ $(am__append_6) # Note lack of "$<" below - it is a non-portable GNU Make extension # The POT-Creation-Date: is removed by current python gettext builder to avoid # "spurious" changes that do not benefit (otherwise unmodified) contents; see: # https://github.com/sphinx-doc/sphinx/pull/3490 # https://github.com/sphinx-doc/sphinx/issues/3443 # Note that OUTFILE may be in builddir (not necessarily same as srcdir) @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ACT_MSGFMT = { \ @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ $(GREP) -v -E '^.?POT-Creation-Date: ' < "$${SRCFILE}" > "$${OUTFILE}.tmpsrc" && \ @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ $(MSGFMT) -o "$${OUTFILE}" "$${OUTFILE}.tmpsrc" && \ @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ rm -f "$${OUTFILE}.tmpsrc" ; \ @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@} @WITH_NUT_MONITOR_TRUE@sysbindir = $(BINDIR) @WITH_NUT_MONITOR_TRUE@sysbin_SCRIPTS = NUT-Monitor # These are dumped into site-packages directly, right? @WITH_PYNUT_PY_TRUE@pynut_py_sitedir = $(PYTHON_SITE_PACKAGES) @WITH_PYNUT_PY_TRUE@pynut_py_site_DATA = $(PYNUT_GENERATED_NOEXEC) @WITH_PYNUT_PY_TRUE@pynut_py_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) $(PYNUT_COMMON_CODE) @WITH_PYNUT_PY2_TRUE@pynut_py2_sitedir = $(PYTHON2_SITE_PACKAGES) @WITH_PYNUT_PY2_TRUE@pynut_py2_site_DATA = $(PYNUT_GENERATED_NOEXEC) @WITH_PYNUT_PY2_TRUE@pynut_py2_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) $(PYNUT_COMMON_CODE) @WITH_PYNUT_PY3_TRUE@pynut_py3_sitedir = $(PYTHON3_SITE_PACKAGES) @WITH_PYNUT_PY3_TRUE@pynut_py3_site_DATA = $(PYNUT_GENERATED_NOEXEC) @WITH_PYNUT_PY3_TRUE@pynut_py3_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) $(PYNUT_COMMON_CODE) ################################################################# SPELLCHECK_SRC = \ README.adoc \ app/README.adoc \ module/README.adoc CLEANFILES = *-spellchecked */*-spellchecked ################################################################# MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-recursive .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/python/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/python/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-nobase_nutmonitorSCRIPTS: $(nobase_nutmonitor_SCRIPTS) @$(NORMAL_INSTALL) @list='$(nobase_nutmonitor_SCRIPTS)'; test -n "$(nutmonitordir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(nutmonitordir)'"; \ $(MKDIR_P) "$(DESTDIR)$(nutmonitordir)" || exit 1; \ fi; \ $(am__nobase_strip_setup); \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e "s|$$srcdirstrip/||" -e 'h;s|[^/]*$$||; s|^$$|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ case $$type in \ d) echo " $(MKDIR_P) '$(DESTDIR)$(nutmonitordir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(nutmonitordir)/$$dir" || exit $$?;; \ f) \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(nutmonitordir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(nutmonitordir)$$dir" || exit $$?; \ } \ ;; esac \ ; done uninstall-nobase_nutmonitorSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(nobase_nutmonitor_SCRIPTS)'; test -n "$(nutmonitordir)" || exit 0; \ $(am__nobase_strip_setup); \ files=`$(am__nobase_strip) \ -e 'h;s,.*/,,;$(transform);x;s|[^/]*$$||;G;s,\n,,'`; \ dir='$(DESTDIR)$(nutmonitordir)'; $(am__uninstall_files_from_dir) install-pynut_py2_siteSCRIPTS: $(pynut_py2_site_SCRIPTS) @$(NORMAL_INSTALL) @list='$(pynut_py2_site_SCRIPTS)'; test -n "$(pynut_py2_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py2_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py2_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pynut_py2_sitedir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pynut_py2_sitedir)$$dir" || exit $$?; \ } \ ; done uninstall-pynut_py2_siteSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(pynut_py2_site_SCRIPTS)'; test -n "$(pynut_py2_sitedir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(pynut_py2_sitedir)'; $(am__uninstall_files_from_dir) install-pynut_py3_siteSCRIPTS: $(pynut_py3_site_SCRIPTS) @$(NORMAL_INSTALL) @list='$(pynut_py3_site_SCRIPTS)'; test -n "$(pynut_py3_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py3_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py3_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pynut_py3_sitedir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pynut_py3_sitedir)$$dir" || exit $$?; \ } \ ; done uninstall-pynut_py3_siteSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(pynut_py3_site_SCRIPTS)'; test -n "$(pynut_py3_sitedir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(pynut_py3_sitedir)'; $(am__uninstall_files_from_dir) install-pynut_py_siteSCRIPTS: $(pynut_py_site_SCRIPTS) @$(NORMAL_INSTALL) @list='$(pynut_py_site_SCRIPTS)'; test -n "$(pynut_py_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pynut_py_sitedir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pynut_py_sitedir)$$dir" || exit $$?; \ } \ ; done uninstall-pynut_py_siteSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(pynut_py_site_SCRIPTS)'; test -n "$(pynut_py_sitedir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(pynut_py_sitedir)'; $(am__uninstall_files_from_dir) install-sysbinSCRIPTS: $(sysbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sysbin_SCRIPTS)'; test -n "$(sysbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sysbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sysbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sysbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sysbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sysbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sysbin_SCRIPTS)'; test -n "$(sysbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sysbindir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nobase_nutmonitorDATA: $(nobase_nutmonitor_DATA) @$(NORMAL_INSTALL) @list='$(nobase_nutmonitor_DATA)'; test -n "$(nutmonitordir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(nutmonitordir)'"; \ $(MKDIR_P) "$(DESTDIR)$(nutmonitordir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(nutmonitordir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(nutmonitordir)/$$dir"; }; \ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(nutmonitordir)/$$dir'"; \ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(nutmonitordir)/$$dir" || exit $$?; }; \ done uninstall-nobase_nutmonitorDATA: @$(NORMAL_UNINSTALL) @list='$(nobase_nutmonitor_DATA)'; test -n "$(nutmonitordir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(nutmonitordir)'; $(am__uninstall_files_from_dir) install-pynut_py2_siteDATA: $(pynut_py2_site_DATA) @$(NORMAL_INSTALL) @list='$(pynut_py2_site_DATA)'; test -n "$(pynut_py2_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py2_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py2_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pynut_py2_sitedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pynut_py2_sitedir)" || exit $$?; \ done uninstall-pynut_py2_siteDATA: @$(NORMAL_UNINSTALL) @list='$(pynut_py2_site_DATA)'; test -n "$(pynut_py2_sitedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pynut_py2_sitedir)'; $(am__uninstall_files_from_dir) install-pynut_py3_siteDATA: $(pynut_py3_site_DATA) @$(NORMAL_INSTALL) @list='$(pynut_py3_site_DATA)'; test -n "$(pynut_py3_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py3_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py3_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pynut_py3_sitedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pynut_py3_sitedir)" || exit $$?; \ done uninstall-pynut_py3_siteDATA: @$(NORMAL_UNINSTALL) @list='$(pynut_py3_site_DATA)'; test -n "$(pynut_py3_sitedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pynut_py3_sitedir)'; $(am__uninstall_files_from_dir) install-pynut_py_siteDATA: $(pynut_py_site_DATA) @$(NORMAL_INSTALL) @list='$(pynut_py_site_DATA)'; test -n "$(pynut_py_sitedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pynut_py_sitedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pynut_py_sitedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pynut_py_sitedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pynut_py_sitedir)" || exit $$?; \ done uninstall-pynut_py_siteDATA: @$(NORMAL_UNINSTALL) @list='$(pynut_py_site_DATA)'; test -n "$(pynut_py_sitedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pynut_py_sitedir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(SCRIPTS) $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(nutmonitordir)" "$(DESTDIR)$(pynut_py2_sitedir)" "$(DESTDIR)$(pynut_py3_sitedir)" "$(DESTDIR)$(pynut_py_sitedir)" "$(DESTDIR)$(sysbindir)" "$(DESTDIR)$(nutmonitordir)" "$(DESTDIR)$(pynut_py2_sitedir)" "$(DESTDIR)$(pynut_py3_sitedir)" "$(DESTDIR)$(pynut_py_sitedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) @WITH_NUT_MONITOR_FALSE@install-data-hook: @WITH_NUT_MONITOR_FALSE@uninstall-hook: clean: clean-recursive clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-nobase_nutmonitorDATA \ install-nobase_nutmonitorSCRIPTS install-pynut_py2_siteDATA \ install-pynut_py2_siteSCRIPTS install-pynut_py3_siteDATA \ install-pynut_py3_siteSCRIPTS install-pynut_py_siteDATA \ install-pynut_py_siteSCRIPTS install-sysbinSCRIPTS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-nobase_nutmonitorDATA \ uninstall-nobase_nutmonitorSCRIPTS \ uninstall-pynut_py2_siteDATA uninstall-pynut_py2_siteSCRIPTS \ uninstall-pynut_py3_siteDATA uninstall-pynut_py3_siteSCRIPTS \ uninstall-pynut_py_siteDATA uninstall-pynut_py_siteSCRIPTS \ uninstall-sysbinSCRIPTS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: $(am__recursive_targets) install-am install-data-am \ install-strip uninstall-am .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool clean-local \ cscopelist-am ctags ctags-am distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-data-hook install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man \ install-nobase_nutmonitorDATA install-nobase_nutmonitorSCRIPTS \ install-pdf install-pdf-am install-ps install-ps-am \ install-pynut_py2_siteDATA install-pynut_py2_siteSCRIPTS \ install-pynut_py3_siteDATA install-pynut_py3_siteSCRIPTS \ install-pynut_py_siteDATA install-pynut_py_siteSCRIPTS \ install-strip install-sysbinSCRIPTS installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-hook uninstall-nobase_nutmonitorDATA \ uninstall-nobase_nutmonitorSCRIPTS \ uninstall-pynut_py2_siteDATA uninstall-pynut_py2_siteSCRIPTS \ uninstall-pynut_py3_siteDATA uninstall-pynut_py3_siteSCRIPTS \ uninstall-pynut_py_siteDATA uninstall-pynut_py_siteSCRIPTS \ uninstall-sysbinSCRIPTS .PRECIOUS: Makefile # Craft locale subdirs with "xx_YY.UTF-8" patterned names, # and similarly alias the "*.po" files inside, as needed # by some platforms but not others to find these files. install-data-hook-app-locale-symlinks: @cd "$(DESTDIR)$(nutmonitordir)/app/locale" && \ for L in fr it ru ; do \ UTF8_NAME="$$L"_"`echo "$$L" | tr '[a-z]' '[A-Z]'`".UTF-8 || exit ; \ UTF8_POFILE="$${L}/$${UTF8_NAME}.po" || exit ; \ UTF8_SUBDIR="$${UTF8_NAME}" || exit ; \ rm -f "$${UTF8_POFILE}" || true ; rm -f "$${UTF8_SUBDIR}" || true ; \ $(LN_S) "$$L".po "$${UTF8_POFILE}" || exit ; \ $(LN_S) "$$L" "$${UTF8_SUBDIR}" || exit ; \ done uninstall-hook-app-locale-symlinks: @RES=0 ; \ cd "$(DESTDIR)$(nutmonitordir)/app/locale" && \ for L in fr it ru ; do \ UTF8_NAME="$$L"_"`echo "$$L" | tr '[a-z]' '[A-Z]'`".UTF-8 || exit ; \ UTF8_POFILE="$${L}/$${UTF8_NAME}.po" || exit ; \ UTF8_SUBDIR="$${UTF8_NAME}" || exit ; \ rm -f "$${UTF8_POFILE}" || RES=$$? ; \ rm -f "$${UTF8_SUBDIR}" || RES=$$? ; \ done ; \ exit $$RES # Runs after the rest of automake install goals @WITH_NUT_MONITOR_TRUE@install-data-hook: install-data-hook-app-locale-symlinks # Not separated into data/exec # TOTHINK: Do we only want to call this recipe when uninstalling a NUT build # that could have installed NUT-Monitor in the first place, or in any case? @WITH_NUT_MONITOR_TRUE@uninstall-hook: uninstall-hook-app-locale-symlinks @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@app/locale/fr/LC_MESSAGES/NUT-Monitor.mo: $(abs_builddir)/app/locale/fr/LC_MESSAGES/NUT-Monitor.mo @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@$(abs_builddir)/app/locale/fr/LC_MESSAGES/NUT-Monitor.mo: app/locale/fr/fr.po @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ @$(MKDIR_P) "$(builddir)/app/locale/fr/LC_MESSAGES" @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ SRCFILE="$?"; OUTFILE="$@"; $(ACT_MSGFMT) @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@app/locale/it/LC_MESSAGES/NUT-Monitor.mo: $(abs_builddir)/app/locale/it/LC_MESSAGES/NUT-Monitor.mo @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@$(abs_builddir)/app/locale/it/LC_MESSAGES/NUT-Monitor.mo: app/locale/it/it.po @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ @$(MKDIR_P) "$(builddir)/app/locale/it/LC_MESSAGES" @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ SRCFILE="$?"; OUTFILE="$@"; $(ACT_MSGFMT) @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@app/locale/ru/LC_MESSAGES/NUT-Monitor.mo: $(abs_builddir)/app/locale/ru/LC_MESSAGES/NUT-Monitor.mo @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@$(abs_builddir)/app/locale/ru/LC_MESSAGES/NUT-Monitor.mo: app/locale/ru/ru.po @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ @$(MKDIR_P) "$(builddir)/app/locale/ru/LC_MESSAGES" @HAVE_MSGFMT_TRUE@@WITH_NUT_MONITOR_TRUE@ SRCFILE="$?"; OUTFILE="$@"; $(ACT_MSGFMT) # Dummy redirector for /usr/bin/... presence @WITH_NUT_MONITOR_TRUE@NUT-Monitor: Makefile @WITH_NUT_MONITOR_TRUE@ @echo '#!/bin/sh' > "$@" @WITH_NUT_MONITOR_TRUE@ @echo 'exec "$(nutmonitordir)/app/NUT-Monitor" "$$@"' >> "$@" # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ clean-local: $(AM_V_at)rm -rf *.pyc __pycache__ */*.pyc */__pycache__ */*/*.pyc */*/__pycache__ $(AM_V_at)rm -f NUT-Monitor module/setup.py # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/python/Makefile.am0000644000200500020050000002411414777767434014337 00000000000000# Network UPS Tools: scripts/python SUBDIRS = module # Recognize settings from configure.ac (for make install handling) nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ # Note: this may be "desktop-file-install" to use in e.g. # packaging postinstall scripts for tighter OS integration; # note also the icon files, etc. that may want symlinks to # system-defined locations. For examples please see e.g. # https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=nut-monitor #nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ BINDIR = @BINDIR@ NUT_MONITOR_PY2GTK2 = \ app/ui/gui-1.3.glade \ app/nut-monitor-py2gtk2.desktop NUT_MONITOR_PY2GTK2_TEMPLATE = \ app/NUT-Monitor-py2gtk2.in NUT_MONITOR_PY2GTK2_GENERATED_SCRIPT = \ app/NUT-Monitor-py2gtk2 NUT_MONITOR_PY3QT5 = \ app/ui/aboutdialog1.ui \ app/ui/dialog1.ui \ app/ui/dialog2.ui \ app/ui/window1.ui \ app/nut-monitor-py3qt5.desktop NUT_MONITOR_PY3QT5_TEMPLATE = \ app/NUT-Monitor-py3qt5.in NUT_MONITOR_PY3QT5_GENERATED_SCRIPT = \ app/NUT-Monitor-py3qt5 NUT_MONITOR_COMMON = \ README.adoc \ app/nut-monitor.appdata.xml \ app/icons/48x48/nut-monitor.png \ app/icons/64x64/nut-monitor.png \ app/icons/256x256/nut-monitor.png \ app/icons/scalable/nut-monitor.svg \ app/README.adoc \ app/screenshots/nut-monitor-1.png \ app/screenshots/nut-monitor-2.png \ app/screenshots/nut-monitor-3.png \ app/pixmaps/on_battery.png \ app/pixmaps/on_line.png \ app/pixmaps/var-ro.png \ app/pixmaps/var-rw.png \ app/pixmaps/warning.png \ app/locale/fr/LC_MESSAGES/NUT-Monitor.mo \ app/locale/it/LC_MESSAGES/NUT-Monitor.mo \ app/locale/ru/LC_MESSAGES/NUT-Monitor.mo # Reserved for shipping additional modules or scripts "as is" PYNUT_COMMON_CODE = PYNUT_COMMON_MISC = \ module/README.adoc PYNUT_COMMON = $(PYNUT_COMMON_CODE) $(PYNUT_COMMON_MISC) # Note: we both distribute and install the generated *.mo translation files # so they are listed above and not in NUT_MONITOR_COMMON_TEMPLATE NUT_MONITOR_COMMON_TEMPLATE = \ app/locale/NUT-Monitor.pot \ app/locale/fr/fr.po \ app/locale/it/it.po \ app/locale/ru/ru.po # Craft locale subdirs with "xx_YY.UTF-8" patterned names, # and similarly alias the "*.po" files inside, as needed # by some platforms but not others to find these files. install-data-hook-app-locale-symlinks: @cd "$(DESTDIR)$(nutmonitordir)/app/locale" && \ for L in fr it ru ; do \ UTF8_NAME="$$L"_"`echo "$$L" | tr '[a-z]' '[A-Z]'`".UTF-8 || exit ; \ UTF8_POFILE="$${L}/$${UTF8_NAME}.po" || exit ; \ UTF8_SUBDIR="$${UTF8_NAME}" || exit ; \ rm -f "$${UTF8_POFILE}" || true ; rm -f "$${UTF8_SUBDIR}" || true ; \ $(LN_S) "$$L".po "$${UTF8_POFILE}" || exit ; \ $(LN_S) "$$L" "$${UTF8_SUBDIR}" || exit ; \ done uninstall-hook-app-locale-symlinks: @RES=0 ; \ cd "$(DESTDIR)$(nutmonitordir)/app/locale" && \ for L in fr it ru ; do \ UTF8_NAME="$$L"_"`echo "$$L" | tr '[a-z]' '[A-Z]'`".UTF-8 || exit ; \ UTF8_POFILE="$${L}/$${UTF8_NAME}.po" || exit ; \ UTF8_SUBDIR="$${UTF8_NAME}" || exit ; \ rm -f "$${UTF8_POFILE}" || RES=$$? ; \ rm -f "$${UTF8_SUBDIR}" || RES=$$? ; \ done ; \ exit $$RES PYNUT_TEMPLATE = \ module/setup.py.in \ module/PyNUT.py.in \ module/test_nutclient.py.in PYNUT_GENERATED_NOEXEC = \ module/PyNUT.py PYNUT_GENERATED_SCRIPT = \ module/test_nutclient.py # For now, we have a "dispatcher" script and applet manifest, # to select a functional choice of the GUI client, if possible: NUT_MONITOR_DISPATCHER_NOEXEC = \ app/nut-monitor.desktop NUT_MONITOR_DISPATCHER_SCRIPT = \ app/NUT-Monitor ################################################################# # `make dist` tarball contents: EXTRA_DIST = \ $(NUT_MONITOR_DISPATCHER_NOEXEC) $(NUT_MONITOR_DISPATCHER_SCRIPT) \ $(NUT_MONITOR_COMMON) $(NUT_MONITOR_COMMON_TEMPLATE) \ $(PYNUT_COMMON) $(PYNUT_TEMPLATE) EXTRA_DIST += $(NUT_MONITOR_PY2GTK2) $(NUT_MONITOR_PY2GTK2_TEMPLATE) EXTRA_DIST += $(NUT_MONITOR_PY3QT5) $(NUT_MONITOR_PY3QT5_TEMPLATE) ################################################################# # `make install` handling (nobase_ to keep tree structure): # Make py2/py3-only builds, delivered preferred symlinks, etc. optional if WITH_NUT_MONITOR nutmonitordir = $(nut_with_nut_monitor_dir) nobase_nutmonitor_DATA = $(NUT_MONITOR_DISPATCHER_NOEXEC) $(NUT_MONITOR_COMMON) nobase_nutmonitor_SCRIPTS = $(NUT_MONITOR_DISPATCHER_SCRIPT) # Runs after the rest of automake install goals install-data-hook: install-data-hook-app-locale-symlinks # Not separated into data/exec # TOTHINK: Do we only want to call this recipe when uninstalling a NUT build # that could have installed NUT-Monitor in the first place, or in any case? uninstall-hook: uninstall-hook-app-locale-symlinks if HAVE_MSGFMT # Note lack of "$<" below - it is a non-portable GNU Make extension # The POT-Creation-Date: is removed by current python gettext builder to avoid # "spurious" changes that do not benefit (otherwise unmodified) contents; see: # https://github.com/sphinx-doc/sphinx/pull/3490 # https://github.com/sphinx-doc/sphinx/issues/3443 # Note that OUTFILE may be in builddir (not necessarily same as srcdir) ACT_MSGFMT = { \ $(GREP) -v -E '^.?POT-Creation-Date: ' < "$${SRCFILE}" > "$${OUTFILE}.tmpsrc" && \ $(MSGFMT) -o "$${OUTFILE}" "$${OUTFILE}.tmpsrc" && \ rm -f "$${OUTFILE}.tmpsrc" ; \ } app/locale/fr/LC_MESSAGES/NUT-Monitor.mo: $(abs_builddir)/app/locale/fr/LC_MESSAGES/NUT-Monitor.mo $(abs_builddir)/app/locale/fr/LC_MESSAGES/NUT-Monitor.mo: app/locale/fr/fr.po @$(MKDIR_P) "$(builddir)/app/locale/fr/LC_MESSAGES" SRCFILE="$?"; OUTFILE="$@"; $(ACT_MSGFMT) app/locale/it/LC_MESSAGES/NUT-Monitor.mo: $(abs_builddir)/app/locale/it/LC_MESSAGES/NUT-Monitor.mo $(abs_builddir)/app/locale/it/LC_MESSAGES/NUT-Monitor.mo: app/locale/it/it.po @$(MKDIR_P) "$(builddir)/app/locale/it/LC_MESSAGES" SRCFILE="$?"; OUTFILE="$@"; $(ACT_MSGFMT) app/locale/ru/LC_MESSAGES/NUT-Monitor.mo: $(abs_builddir)/app/locale/ru/LC_MESSAGES/NUT-Monitor.mo $(abs_builddir)/app/locale/ru/LC_MESSAGES/NUT-Monitor.mo: app/locale/ru/ru.po @$(MKDIR_P) "$(builddir)/app/locale/ru/LC_MESSAGES" SRCFILE="$?"; OUTFILE="$@"; $(ACT_MSGFMT) endif HAVE_MSGFMT if WITH_NUT_MONITOR_PY2GTK2 nobase_nutmonitor_DATA += $(NUT_MONITOR_PY2GTK2) nobase_nutmonitor_SCRIPTS += $(NUT_MONITOR_PY2GTK2_GENERATED_SCRIPT) endif WITH_NUT_MONITOR_PY2GTK2 if WITH_NUT_MONITOR_PY3QT5 nobase_nutmonitor_DATA += $(NUT_MONITOR_PY3QT5) nobase_nutmonitor_SCRIPTS += $(NUT_MONITOR_PY3QT5_GENERATED_SCRIPT) endif WITH_NUT_MONITOR_PY3QT5 if WITH_PYNUT_APP nobase_nutmonitor_DATA += $(PYNUT_COMMON) $(PYNUT_GENERATED_NOEXEC) nobase_nutmonitor_SCRIPTS += $(PYNUT_GENERATED_SCRIPT) endif WITH_PYNUT_APP sysbindir = $(BINDIR) sysbin_SCRIPTS = NUT-Monitor # Dummy redirector for /usr/bin/... presence NUT-Monitor: Makefile @echo '#!/bin/sh' > "$@" @echo 'exec "$(nutmonitordir)/app/NUT-Monitor" "$$@"' >> "$@" endif WITH_NUT_MONITOR # These are dumped into site-packages directly, right? if WITH_PYNUT_PY pynut_py_sitedir = $(PYTHON_SITE_PACKAGES) pynut_py_site_DATA = $(PYNUT_GENERATED_NOEXEC) pynut_py_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) $(PYNUT_COMMON_CODE) endif if WITH_PYNUT_PY2 pynut_py2_sitedir = $(PYTHON2_SITE_PACKAGES) pynut_py2_site_DATA = $(PYNUT_GENERATED_NOEXEC) pynut_py2_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) $(PYNUT_COMMON_CODE) endif if WITH_PYNUT_PY3 pynut_py3_sitedir = $(PYTHON3_SITE_PACKAGES) pynut_py3_site_DATA = $(PYNUT_GENERATED_NOEXEC) pynut_py3_site_SCRIPTS = $(PYNUT_GENERATED_SCRIPT) $(PYNUT_COMMON_CODE) endif ################################################################# SPELLCHECK_SRC = \ README.adoc \ app/README.adoc \ module/README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked */*-spellchecked ################################################################# MAINTAINERCLEANFILES = Makefile.in .dirstamp clean-local: $(AM_V_at)rm -rf *.pyc __pycache__ */*.pyc */__pycache__ */*/*.pyc */*/__pycache__ $(AM_V_at)rm -f NUT-Monitor module/setup.py nut-2.8.3/scripts/python/README.adoc0000644000200500020050000000521414777767434014070 00000000000000Python NUT Client files ----------------------- This directory contains various NUT Client related Python scripts, written by David Goncalves, and released under GPL v3. module ~~~~~~ This directory contains `PyNUT.py`, which is a Python abstraction class to access NUT data server(s). You can use it in Python programs to access NUT's `upsd` data server in a simple way, without having to know the NUT protocol. The same module should work for Python 2 and Python 3. To import it into Python programs you have to use the following line (case sensitive): import PyNUT This module provides a `(PyNUT.)PyNUTClient` class that can be used to connect and get data from an `upsd` data server. To install the `PyNUT` module on Debian/Ubuntu, copy it to: `/usr/share/python-support/python-pynut/` For quick tests, just make sure its directory is exported in `PYTHONPATH` environment variable. This directory also contains `test_nutclient.py`, which is a `PyNUT` test program and it also serves as a code example. For this to be fully functional, you will need to adapt the login, password and upsname to fit your configuration. A NUT data server should be running for the test program to verify connection and protocol support. For one practical example, you can research `tests/NIT/nit.sh` in NUT sources. app ~~~ This directory contains the `NUT-Monitor` UI application, which uses the `PyNUT` class, along with its own resources. NOTE: Do not mistake it for `nut-monitor` service for the `upsmon` client in some distributions' NUT packaging. There are two closely related separate implementations, for Python 2 with GTK2 and for Python 3 with Qt5. Both can be installed at the same time, if your distribution has not yet outlawed the obsolete Python 2 interpreters. To install it, you will either need to keep the files together, or to install: - Depending on the Python version(s) your system has, put `NUT-Monitor-py2gtk2` and/or `NUT-Monitor-py3qt5` to `/usr/bin/`, `/usr/X11R6/bin/` or something like that (optionally making a simple `NUT-Monitor` symlink to the preferred implementation version or using the provided wrapper script), - `ui/*.glade` (for `NUT-Monitor-py2gtk2`) or `ui/*.ui` (for `NUT-Monitor-py3qt5`) files to `/usr/share/nut-monitor/`, - `nut-monitor.png` to something like `/usr/share/pixmaps/`, - finally, `nut-monitor-py2gtk2.desktop` and/or `nut-monitor-py3qt5.desktop` (optionally symlinked as `nut-monitor.desktop`) to `/usr/share/applications/` The `PyNUT` module can be kept nearby, or must be installed as a "site" or "vendor" provided script into your Python modules location. See the wrapper scripts of the app for more technical details. nut-2.8.3/scripts/udev/0000755000200500020050000000000015001555412011747 500000000000000nut-2.8.3/scripts/udev/nut-usbups.rules.in0000644000200500020050000004134715001555411015505 00000000000000# This file is generated and installed by the Network UPS Tools package. ACTION=="remove", GOTO="nut-usbups_rules_end" SUBSYSTEM=="usb_device", GOTO="nut-usbups_rules_real" SUBSYSTEM=="usb", GOTO="nut-usbups_rules_real" GOTO="nut-usbups_rules_end" LABEL="nut-usbups_rules_real" # SNR-UPS-LID-XXXX UPSes - blazer_usb nutdrv_atcl_usb nutdrv_qx ATTR{idVendor}=="0001", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # Hewlett Packard # e.g. ? - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # T500 - bcmxcp_usb ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f01", MODE="664", GROUP="@RUN_AS_GROUP@" # T750 - bcmxcp_usb ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f02", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T750 INTL - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f06", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T1000 INTL - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f08", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T1500 INTL - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f09", MODE="664", GROUP="@RUN_AS_GROUP@" # HP R/T 2200 INTL (like SMART2200RMXL2U) - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1f0a", MODE="664", GROUP="@RUN_AS_GROUP@" # HP R1500 G2 and G3 INTL - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe0", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T750 G2 - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe1", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe2", MODE="664", GROUP="@RUN_AS_GROUP@" # HP T1500 G3 - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe3", MODE="664", GROUP="@RUN_AS_GROUP@" # R/T3000 - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe5", MODE="664", GROUP="@RUN_AS_GROUP@" # R/T3000 - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe6", MODE="664", GROUP="@RUN_AS_GROUP@" # various models - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe7", MODE="664", GROUP="@RUN_AS_GROUP@" # various models - usbhid-ups ATTR{idVendor}=="03f0", ATTR{idProduct}=="1fe8", MODE="664", GROUP="@RUN_AS_GROUP@" # Eaton # various models - usbhid-ups ATTR{idVendor}=="0463", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # various models - usbhid-ups ATTR{idVendor}=="0463", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # Dell # various models - usbhid-ups ATTR{idVendor}=="047c", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # ST Microelectronics # TS Shara UPSes; vendor ID 0x0483 is from ST Microelectronics - with product IDs delegated to different OEMs - nutdrv_qx ATTR{idVendor}=="0483", ATTR{idProduct}=="0035", MODE="664", GROUP="@RUN_AS_GROUP@" # USB IDs device table - usbhid-ups ATTR{idVendor}=="0483", ATTR{idProduct}=="a113", MODE="664", GROUP="@RUN_AS_GROUP@" # Cyber Energy branded devices by CPS - usbhid-ups ATTR{idVendor}=="0483", ATTR{idProduct}=="a430", MODE="664", GROUP="@RUN_AS_GROUP@" # IBM # 6000 VA LCD 4U Rack UPS; 5396-1Kx - usbhid-ups ATTR{idVendor}=="04b3", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # Riello (Cypress Semiconductor Corp.) # various models - riello_usb ATTR{idVendor}=="04b4", ATTR{idProduct}=="5500", MODE="664", GROUP="@RUN_AS_GROUP@" # Minibox # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups ATTR{idVendor}=="04d8", ATTR{idProduct}=="d004", MODE="664", GROUP="@RUN_AS_GROUP@" # openUPS Intelligent UPS (minimum required firmware 1.4) - usbhid-ups ATTR{idVendor}=="04d8", ATTR{idProduct}=="d005", MODE="664", GROUP="@RUN_AS_GROUP@" # Belkin # F6H375-USB - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0375", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C550-AVR - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0551", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C1250-TW-RK - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0750", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C1500-TW-RK - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0751", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C900-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0900", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C100-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0910", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C120-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0912", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C800-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0980", MODE="664", GROUP="@RUN_AS_GROUP@" # Regulator PRO-USB - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="0f51", MODE="664", GROUP="@RUN_AS_GROUP@" # F6C1100-UNV, F6C1200-UNV - usbhid-ups ATTR{idVendor}=="050d", ATTR{idProduct}=="1100", MODE="664", GROUP="@RUN_AS_GROUP@" # APC # APC AP9584 Serial->USB kit - usbhid-ups ATTR{idVendor}=="051d", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # various models - usbhid-ups ATTR{idVendor}=="051d", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # USB IDs device table - usbhid-ups apc_modbus ATTR{idVendor}=="051d", ATTR{idProduct}=="0003", MODE="664", GROUP="@RUN_AS_GROUP@" # various 5G models - usbhid-ups ATTR{idVendor}=="051d", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # Powerware # various models - bcmxcp_usb ATTR{idVendor}=="0592", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # PW 9140 - usbhid-ups ATTR{idVendor}=="0592", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # Agiler UPS - blazer_usb nutdrv_qx ATTR{idVendor}=="05b8", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # Delta UPS # Delta UPS Amplon R Series, Single Phase UPS, 1/2/3 kVA - usbhid-ups ATTR{idVendor}=="05dd", ATTR{idProduct}=="041b", MODE="664", GROUP="@RUN_AS_GROUP@" # Delta/Minuteman Enterprise Plus E1500RM2U - usbhid-ups ATTR{idVendor}=="05dd", ATTR{idProduct}=="a011", MODE="664", GROUP="@RUN_AS_GROUP@" # Delta/Minuteman PRO1500RT2U - usbhid-ups ATTR{idVendor}=="05dd", ATTR{idProduct}=="a0a0", MODE="664", GROUP="@RUN_AS_GROUP@" # Belkin F6C1200-UNV/Voltronic Power UPSes - blazer_usb nutdrv_qx ATTR{idVendor}=="0665", ATTR{idProduct}=="5161", MODE="664", GROUP="@RUN_AS_GROUP@" # Phoenixtec Power Co., Ltd # Online Yunto YQ450 - bcmxcp_usb blazer_usb nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # Mustek Powermust - blazer_usb nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0003", MODE="664", GROUP="@RUN_AS_GROUP@" # Phoenixtec Innova 3/1 T - blazer_usb nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # Phoenixtec Innova RT - blazer_usb nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0005", MODE="664", GROUP="@RUN_AS_GROUP@" # Phoenixtec Innova T - blazer_usb nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0201", MODE="664", GROUP="@RUN_AS_GROUP@" # Online Zinto A - blazer_usb nutdrv_qx ATTR{idVendor}=="06da", ATTR{idProduct}=="0601", MODE="664", GROUP="@RUN_AS_GROUP@" # PROTECT B / NAS - usbhid-ups usbhid-ups ATTR{idVendor}=="06da", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # iDowell # iDowell - usbhid-ups ATTR{idVendor}=="075d", ATTR{idProduct}=="0300", MODE="664", GROUP="@RUN_AS_GROUP@" # Cyber Power Systems # 900AVR/BC900D - usbhid-ups ATTR{idVendor}=="0764", ATTR{idProduct}=="0005", MODE="664", GROUP="@RUN_AS_GROUP@" # Dynex DX-800U?, CP1200AVR/BC1200D, CP825AVR-G, CP1000AVRLCD, CP1000PFCLCD, CP1500C, CP550HG, etc. - usbhid-ups ATTR{idVendor}=="0764", ATTR{idProduct}=="0501", MODE="664", GROUP="@RUN_AS_GROUP@" # OR2200LCDRM2U, OR700LCDRM1U, PR6000LCDRTXL5U, CP1350EPFCLCD - usbhid-ups ATTR{idVendor}=="0764", ATTR{idProduct}=="0601", MODE="664", GROUP="@RUN_AS_GROUP@" # Sweex 1000VA - nutdrv_qx richcomm_usb ATTR{idVendor}=="0925", ATTR{idProduct}=="1234", MODE="664", GROUP="@RUN_AS_GROUP@" # TrippLite # e.g. OMNIVS1000, SMART550USB, ... - tripplite_usb ATTR{idVendor}=="09ae", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite AVR550U - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1003", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite AVR750U - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1007", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite ECO550UPS - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1008", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite ECO550UPS - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1009", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite ECO550UPS - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1010", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SU3000LCD2UHV - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="1330", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite OMNI1000LCD - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2005", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite OMNI900LCD - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2007", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2008", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite Smart1000LCD - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2009", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2010", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2011", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2012", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2013", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="2014", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3008", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3009", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3010", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3011", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite smart2200RMXL2U - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3012", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3013", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3014", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3015", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite Smart1500LCD (newer unit) - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3016", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite AVR750U (newer unit) - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="3024", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SmartOnline SU1500RTXL2UA (older unit?) - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4001", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SmartOnline SU6000RT4U? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4002", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SmartOnline SU1500RTXL2ua - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4003", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. TrippLite SmartOnline SU1000XLA - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4004", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4005", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4006", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4007", MODE="664", GROUP="@RUN_AS_GROUP@" # e.g. ? - usbhid-ups ATTR{idVendor}=="09ae", ATTR{idProduct}=="4008", MODE="664", GROUP="@RUN_AS_GROUP@" # KSTAR under Berkeley Varitronics Systems ID # 6000 VA LCD 4U Rack UPS; 5396-1Kx - usbhid-ups ATTR{idVendor}=="09d6", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM Vanguard and BNT-xxxAP - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM IMP - IMPERIAL Series - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a2", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM SKP - Smart KING Pro (all Smart series) - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a3", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM WOW - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a4", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM VGD - Vanguard - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a5", MODE="664", GROUP="@RUN_AS_GROUP@" # PowerCOM BNT - Black Knight Pro - usbhid-ups ATTR{idVendor}=="0d9f", ATTR{idProduct}=="00a6", MODE="664", GROUP="@RUN_AS_GROUP@" # Unitek Alpha 1200Sx - blazer_usb nutdrv_qx ATTR{idVendor}=="0f03", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # Liebert # Liebert GXT4 UPS - usbhid-ups ATTR{idVendor}=="10af", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # Liebert PowerSure PSA UPS - usbhid-ups ATTR{idVendor}=="10af", ATTR{idProduct}=="0001", MODE="664", GROUP="@RUN_AS_GROUP@" # Liebert PowerSure PST UPS - usbhid-ups ATTR{idVendor}=="10af", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # Liebert PowerSure PSI 1440 - usbhid-ups ATTR{idVendor}=="10af", ATTR{idProduct}=="0004", MODE="664", GROUP="@RUN_AS_GROUP@" # Liebert GXT3 - usbhid-ups ATTR{idVendor}=="10af", ATTR{idProduct}=="0008", MODE="664", GROUP="@RUN_AS_GROUP@" # GE EP series - blazer_usb nutdrv_qx ATTR{idVendor}=="14f0", ATTR{idProduct}=="00c9", MODE="664", GROUP="@RUN_AS_GROUP@" # Legrand # Legrand Keor SP - usbhid-ups ATTR{idVendor}=="1cb0", ATTR{idProduct}=="0032", MODE="664", GROUP="@RUN_AS_GROUP@" # Legrand Daker DK / DK Plus - nutdrv_qx ATTR{idVendor}=="1cb0", ATTR{idProduct}=="0035", MODE="664", GROUP="@RUN_AS_GROUP@" # Legrand Keor PDU - usbhid-ups ATTR{idVendor}=="1cb0", ATTR{idProduct}=="0038", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2341", ATTR{idProduct}=="0036", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2341", ATTR{idProduct}=="8036", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2a03", ATTR{idProduct}=="0036", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2a03", ATTR{idProduct}=="0040", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2a03", ATTR{idProduct}=="8036", MODE="664", GROUP="@RUN_AS_GROUP@" # Arduino Leonardo, Leonardo ETH and Pro Micro - usbhid-ups ATTR{idVendor}=="2a03", ATTR{idProduct}=="8040", MODE="664", GROUP="@RUN_AS_GROUP@" # AEG # PROTECT B / NAS - usbhid-ups ATTR{idVendor}=="2b2d", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # Ever # USB IDs device table - usbhid-ups ATTR{idVendor}=="2e51", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" # USB IDs device table - usbhid-ups ATTR{idVendor}=="2e51", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # Salicru # https://www.salicru.com/sps-3000-adv-rt2.html - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0101", MODE="664", GROUP="@RUN_AS_GROUP@" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0201", MODE="664", GROUP="@RUN_AS_GROUP@" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0202", MODE="664", GROUP="@RUN_AS_GROUP@" # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0203", MODE="664", GROUP="@RUN_AS_GROUP@" # https://www.salicru.com/sps-home.html - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0300", MODE="664", GROUP="@RUN_AS_GROUP@" # https://www.salicru.com/sps-850-adv-t.html - usbhid-ups ATTR{idVendor}=="2e66", ATTR{idProduct}=="0302", MODE="664", GROUP="@RUN_AS_GROUP@" # EcoFlow # EcoFlow - usbhid-ups ATTR{idVendor}=="3746", ATTR{idProduct}=="ffff", MODE="664", GROUP="@RUN_AS_GROUP@" # Powervar # Powervar - usbhid-ups ATTR{idVendor}=="4234", ATTR{idProduct}=="0002", MODE="664", GROUP="@RUN_AS_GROUP@" # Ablerex 625L USB (Note: earlier best-fit was "krauler_subdriver" before PR #1135) - blazer_usb nutdrv_qx ATTR{idVendor}=="ffff", ATTR{idProduct}=="0000", MODE="664", GROUP="@RUN_AS_GROUP@" LABEL="nut-usbups_rules_end" nut-2.8.3/scripts/udev/nut-ipmipsu.rules.in0000644000200500020050000000027714553676503015670 00000000000000# This file is generated and installed by the Network UPS Tools package. # It sets the correct device permissions for nut-ipmipsu driver. KERNEL=="ipmi*", MODE="664", GROUP="@RUN_AS_GROUP@" nut-2.8.3/scripts/udev/README.adoc0000644000200500020050000000332414777534446013505 00000000000000Udev script for NUT USB and IPMI drivers ======================================== Arnaud Quette v1.0, 31 July 2014 (start date) This document introduces the Linux `udev` script for NUT USB drivers (`usbhid-ups`, `nutdrv_qx`, `bcmxcp_usb`, `tripplite_usb`, ...) and IPMI driver (`nut-ipmipsu`). These are needed on Linux systems running `udev` (recommended as of Linux kernel 2.6.3, and mandatory as of 2.6.14 and higher). This script ensures that the right privileges are set on the USB and IPMI device nodes to allow the NUT driver to operate (i.e. allowing the `nut` user to read AND write to the hardware device). Note that the old style `hotplug` files, available in the `scripts/hotplug` directory, are not needed anymore if your kernel supports `udev`. Installation ------------ For most users, these files will be automatically installed in `/etc/udev` (or `/lib/udev`) upon `make install`, if that directory exists and if the feature (USB and/or IPMI driver support) has been enabled at `configure` time. You can specify an alternate directory with: ---- :; ./configure --with-udev-dir=DIR ---- Manual installation ------------------- To install them manually, copy the rules file(s) to `/etc/udev/rules.d` (or `/lib/udev/rules.d` on newer systems) using the following command(s): ---- :; cp -f nut-usbups.rules /etc/udev/rules.d/62-nut-usbups.rules :; cp -f nut-ipmipsu.rules /etc/udev/rules.d/52-nut-ipmipsu.rules ---- You will need to refresh the bus to avoid a reboot for these rules to be active. You can do so using: ---- :; udevadm trigger --subsystem-match=usb_device ---- For USB devices, you can then plug your UPS USB cord, or unplug/re-plug it to refresh the device permission, and start NUT. nut-2.8.3/scripts/udev/Makefile.am0000644000200500020050000000555414777767434013770 00000000000000# Network UPS Tools: scripts/udev if WITH_UDEV udevrulesdir = $(udevdir)/rules.d udevrules_DATA = if WITH_USB udevrules_DATA += 62-nut-usbups.rules endif if WITH_IPMI udevrules_DATA += 52-nut-ipmipsu.rules endif endif EXTRA_DIST = README.adoc 62-nut-usbups.rules: nut-usbups.rules cp nut-usbups.rules $@ 52-nut-ipmipsu.rules: nut-ipmipsu.rules cp nut-ipmipsu.rules $@ MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by configure script: DISTCLEANFILES = nut-usbups.rules nut-ipmipsu.rules CLEANFILES = 62-nut-usbups.rules 52-nut-ipmipsu.rules # We should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES += nut-usbups.rules.in nut-usbups.rules.in.AUTOGEN_WITHOUT # Part of dist tarball, regardless of use for current build: EXTRA_DIST += nut-usbups.rules.in SPELLCHECK_SRC = README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) $(AM_MAKEFLAGS) -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES += *-spellchecked nut-2.8.3/scripts/udev/Makefile.in0000644000200500020050000006451115001555011013736 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/udev VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_UDEV_TRUE@@WITH_USB_TRUE@am__append_1 = 62-nut-usbups.rules @WITH_IPMI_TRUE@@WITH_UDEV_TRUE@am__append_2 = 52-nut-ipmipsu.rules subdir = scripts/udev ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = nut-ipmipsu.rules nut-usbups.rules CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(udevrulesdir)" DATA = $(udevrules_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/nut-ipmipsu.rules.in \ $(srcdir)/nut-usbups.rules.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ @WITH_UDEV_TRUE@udevrulesdir = $(udevdir)/rules.d @WITH_UDEV_TRUE@udevrules_DATA = $(am__append_1) $(am__append_2) # Part of dist tarball, regardless of use for current build: EXTRA_DIST = README.adoc nut-usbups.rules.in # We should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-usbups.rules.in \ nut-usbups.rules.in.AUTOGEN_WITHOUT # Generated by configure script: DISTCLEANFILES = nut-usbups.rules nut-ipmipsu.rules CLEANFILES = 62-nut-usbups.rules 52-nut-ipmipsu.rules *-spellchecked SPELLCHECK_SRC = README.adoc all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/udev/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/udev/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): nut-ipmipsu.rules: $(top_builddir)/config.status $(srcdir)/nut-ipmipsu.rules.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ nut-usbups.rules: $(top_builddir)/config.status $(srcdir)/nut-usbups.rules.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-udevrulesDATA: $(udevrules_DATA) @$(NORMAL_INSTALL) @list='$(udevrules_DATA)'; test -n "$(udevrulesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(udevrulesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(udevrulesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(udevrulesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(udevrulesdir)" || exit $$?; \ done uninstall-udevrulesDATA: @$(NORMAL_UNINSTALL) @list='$(udevrules_DATA)'; test -n "$(udevrulesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(udevrulesdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(udevrulesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-udevrulesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-udevrulesDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip install-udevrulesDATA installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-udevrulesDATA .PRECIOUS: Makefile 62-nut-usbups.rules: nut-usbups.rules cp nut-usbups.rules $@ 52-nut-ipmipsu.rules: nut-ipmipsu.rules cp nut-ipmipsu.rules $@ # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) $(AM_MAKEFLAGS) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) $(AM_MAKEFLAGS) -f $(top_builddir)/docs/Makefile $(AM_MAKEFILE) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/subdriver/0000755000200500020050000000000015001555411013010 500000000000000nut-2.8.3/scripts/subdriver/gen-snmp-subdriver.sh0000755000200500020050000004133614777767434017062 00000000000000#!/usr/bin/env bash # # an auxiliary script to produce a "stub" snmp-ups subdriver from # SNMP data from a real agent or from dump files # # Version: 0.16 # # See also: docs/snmp-subdrivers.txt # # Copyright (C) # 2011 - 2012 Arnaud Quette # 2015 - 2022 Eaton (author: Arnaud Quette ) # 2011 - 2024 Jim Klimov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # TODO: # - Prepend sysDescription (.1.3.6.1.2.1.1.1.0) to have some more visibility # - extend to SNMP v3 (auth.) usage() { echo "Usage: $0 [options] [file]" echo "Options:" echo " -h, --help -- show this message and quit" echo " -n name -- subdriver name (use natural capitalization)" echo " -M DIRLIST -- colon separated list of directories to also search for MIBs" echo " -k -- keep temporary files (for debugging)" echo "" echo "mode 1: get SNMP data from a real agent" echo " -H host_address -- SNMP host IP address or name" echo " -c community -- SNMP v1 community name (default: public)" echo " -s XXXX -- override SNMP OID entry point (sysOID). Ex: '.1.3.6.1.4.1.534.10'" echo "" echo "mode 2: get data from files (snmpwalk dumps of 'sysOID' subtree)" echo " -s XXXX -- SNMP OID entry point (sysOID). Ex: '.1.3.6.1.4.1.534.6.6.7'" echo " file1 file2 -- read from files instead of an host (using Net SNMP)" echo " file1: numeric SNMP walk (snmpwalk -On ... )" echo " file2: string SNMP walk (snmpwalk -Os ... )" echo "" echo "mode 3: get data from 1 file (numeric snmpwalk dump of the whole SNMP tree)" echo " The sysOID is extracted from the dump, and only the pointed subtree is used" echo " A MIB file MUST be provided, and is used to produce the string SNMP walk" echo " file1 -- read from file instead of an host (using Net SNMP)" echo " file1: numeric SNMP walk (snmpwalk -On ... )" echo "" echo "Notes:" echo " For both modes, prefer to copy the specific MIB file(s) for your device in the $0 script directory" echo " So that it is automatically taken into account for the string name resolution of OIDs" echo " Otherwise, use \"-M.\" option" echo "" echo "Example:" echo "mode 1: $0 -H 192.168.0.1 -n mibname -c mycommunity" echo "mode 2: (using sysOID .1.3.6.1.4.1.534.6.6.7)" echo " snmpwalk -On -v1 -c mycommunity 192.168.0.1 .1.3.6.1.4.1.534.6.6.7 2>/dev/null 1> numeric-walk-file" echo " snmpwalk -Os -v1 -m ALL -M+. -c mycommunity 192.168.0.1 .1.3.6.1.4.1.534.6.6.7 2>/dev/null 1> string-walk-file" echo " $0 -s .1.3.6.1.4.1.534.6.6.7 numeric-walk-file string-walk-file" echo "mode 3:" echo " snmpwalk -On -v1 -c mycommunity 192.168.0.1 .1 2>/dev/null 1> numeric-walk-file" echo " $0 numeric-walk-file" echo "" echo " You may alos need to install additional packages:" echo " - 'snmp' package (on Debian) for the base commands (snmpget, snmpwalk, snmptranslate)" echo " - 'snmp-mibs-downloader' package (on Debian) to get all standard MIBs" } # variables DRIVER="" KEEP="" HOSTNAME="" MIBS_DIRLIST="+." COMMUNITY="public" DEVICE_SYSOID="" SYSOID="" MODE=0 # constants NAME=gen-snmp-subdriver TMPDIR="${TEMPDIR:-/tmp}" SYSOID_NUMBER=".1.3.6.1.2.1.1.2.0" DEBUG="`mktemp "$TMPDIR/$NAME-DEBUG.XXXXXX"`" DFL_NUMWALKFILE="`mktemp "$TMPDIR/$NAME-NUMWALK.XXXXXX"`" DFL_STRWALKFILE="`mktemp "$TMPDIR/$NAME-STRWALK.XXXXXX"`" TMP_NUMWALKFILE="`mktemp "$TMPDIR/$NAME-TMP-NUMWALK.XXXXXX"`" TMP_STRWALKFILE="`mktemp "$TMPDIR/$NAME-TMP-STRWALK.XXXXXX"`" get_snmp_data() { # 1) get the sysOID (points the mfr specif MIB), apart if there's an override if [ -z "$SYSOID" ] then SYSOID="`snmpget -On -v1 -c "$COMMUNITY" -Ov "$HOSTNAME" "$SYSOID_NUMBER" | cut -d' ' -f2`" echo "sysOID retrieved: ${SYSOID}" else echo "Using the provided sysOID override ($SYSOID)" fi DEVICE_SYSOID="$SYSOID" OID_COUNT=0 while (test "$OID_COUNT" -eq 0) do # 2) get the content of the mfr specif MIB echo "Retrieving SNMP information. This may take some time" snmpwalk -On -v1 -c "$COMMUNITY" "$HOSTNAME" "$SYSOID" 2>/dev/null 1> "$DFL_NUMWALKFILE" snmpwalk -Os -v1 -m ALL -M"$MIBS_DIRLIST" -c "$COMMUNITY" "$HOSTNAME" "$SYSOID" 2>/dev/null 1> "$DFL_STRWALKFILE" # 3) test return value of the walk, and possibly ramp-up the path to get something. # The sysOID mechanism only works if we're pointed somehow in the right direction # i.e. doesn't work if sysOID is .1.3.6.1.4.1.705.1 and data is at .1.3.6.1.4.1.534... # Ex: sysOID = ".1.X.Y.Z" # try with ".1.X.Y.Z", if fails try with .1.X.Y", if fails try with .1.X"... OID_COUNT="`cat $NUMWALKFILE | wc -l`" if [ $OID_COUNT -eq 0 ]; then # ramp-up the provided sysOID by removing the last .x part SYSOID=${SYSOID%.*} echo "Warning: sysOID provided no data! Trying with a level up using $SYSOID" fi done return $OID_COUNT } generate_C() { # create file names, lowercase LDRIVER="`echo "$DRIVER" | tr A-Z a-z`" UDRIVER="`echo "$DRIVER" | tr a-z A-Z`" # keep dashes in name for files CFILE="$LDRIVER-mib.c" HFILE="$LDRIVER-mib.h" # but replace with underscores for the structures and defines LDRIVER="`echo "$LDRIVER" | tr - _`" UDRIVER="`echo "$UDRIVER" | tr - _`" # generate header file # NOTE: with <<-EOF leading TABs are all stripped echo "Creating $HFILE" cat > "$HFILE" <<-EOF /* ${HFILE} - subdriver to monitor ${DRIVER} SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ${UDRIVER}_MIB_H #define ${UDRIVER}_MIB_H #include "main.h" #include "snmp-ups.h" extern mib2nut_info_t ${LDRIVER}; #endif /* ${UDRIVER}_MIB_H */ EOF # generate source file # create heading boilerblate # NOTE: with <<-EOF leading TABs are all stripped echo "Creating $CFILE" cat > "$CFILE" <<-EOF /* ${CFILE} - subdriver to monitor ${DRIVER} SNMP devices with NUT * * Copyright (C) * 2011 - 2016 Arnaud Quette * * Note: this subdriver was initially generated as a "stub" by the * gen-snmp-subdriver script. It must be customized! * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "${HFILE}" #define ${UDRIVER}_MIB_VERSION "0.01" #define ${UDRIVER}_SYSOID "${DEVICE_SYSOID}" /* To create a value lookup structure (as needed on the 2nd line of the example * below), use the following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t onbatt_info[] = { * info_lkp_default(1, "OB"), * info_lkp_default(2, "OL"), * info_lkp_sentinel * }; */ /* ${UDRIVER} Snmp2NUT lookup table */ static snmp_info_t ${LDRIVER}_mib[] = { /* Data format: * snmp_info_default(info_type, info_flags, info_len, OID, dfl, flags, oid2info), * * info_type: NUT INFO_ or CMD_ element name * info_flags: flags to set in addinfo * info_len: length of strings if ST_FLAG_STRING, multiplier otherwise * OID: SNMP OID or NULL * dfl: default value * flags: snmp-ups internal flags (FIXME: ...) * oid2info: lookup table between OID and NUT values * * Example: * snmp_info_default("input.voltage", 0, 0.1, ".1.3.6.1.4.1.705.1.6.2.1.2.1", "", SU_INPUT_1, NULL), * snmp_info_default("ups.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.705.1.7.3.0", "", SU_FLAG_OK | SU_STATUS_BATT, onbatt_info), * * To create a value lookup structure (as needed on the 2nd line), use the * following kind of declaration, outside of the present snmp_info_t[]: * static info_lkp_t onbatt_info[] = { * info_lkp_default(1, "OB"), * info_lkp_default(2, "OL"), * info_lkp_sentinel * }; */ /* standard MIB items; if the vendor MIB contains better OIDs for * this (e.g. with daisy-chain support), consider adding those here */ EOF # Same file, indented text (TABs not stripped): cat >> "$CFILE" < /dev/null if [ $? -eq 0 ]; then ST_FLAG_TYPE="ST_FLAG_STRING" SU_INFOSIZE="SU_INFOSIZE" else ST_FLAG_TYPE="0" SU_INFOSIZE="1" fi # get the matching numeric OID NUM_OID="`sed -n "${LINENB}p" "${NUMWALKFILE}" | cut -d' ' -f1`" printf "\t/* ${FULL_STR_OID} */\n\tsnmp_info_default(\"unmapped.${STR_OID}\", ${ST_FLAG_TYPE}, ${SU_INFOSIZE}, \"${NUM_OID}\", NULL, SU_FLAG_OK, NULL),\n" done < "${STRWALKFILE}" >> "${CFILE}" # append footer (TABs not stripped): cat >> "$CFILE" <&2 exit 1 fi done # check that the needed parameters are provided, depending on the mode if [ -z "$NUMWALKFILE" ]; then # mode 1: directly get SNMP data from a real agent echo "Mode 1 selected" MODE=1 NUMWALKFILE="$DFL_NUMWALKFILE" STRWALKFILE="$DFL_STRWALKFILE" # check if Net SNMP is available if [ -z "`command -v snmpget`" -o -z "`command -v snmpwalk`" ] && \ [ -z "`which snmpget`" -o -z "`which snmpwalk`" ]; then echo "Net SNMP not found! snmpget and snmpwalk commands are required." >&2 exit 1 fi # hostname is also mandatory while [ -z "$HOSTNAME" ]; do printf "\n\tPlease enter the SNMP host IP address or name.\n" read -p "SNMP host IP name or address: " HOSTNAME < /dev/tty if echo "$HOSTNAME" | grep -E -q '[^a-zA-Z0-9.-]'; then echo "Please use only letters, digits, dash and period character" HOSTNAME="" fi done # get data from the agent get_snmp_data else # no string walk provided, so mode 3 if [ -z "$STRWALKFILE" ]; then # mode 3: get data from 1 file, # Filter according to sysOID on the specific subtree # Generate the numeric SNMP walk using this output # then use snmptranslate to get the string OIDs and generated the string SNMP walk echo "Mode 3 selected" MODE=3 RAWWALKFILE="$NUMWALKFILE" NUMWALKFILE="$DFL_NUMWALKFILE" STRWALKFILE="$DFL_STRWALKFILE" # check for actual file existence if [ ! -f "$RAWWALKFILE" ]; then echo "SNMP walk dump file is missing on disk. Try --help for more info." >&2 exit 1 fi # Extract the sysOID # Format is "1.3.6.1.2.1.1.2.0 = OID: 1.3.6.1.4.1.4555.1.1.1" DEVICE_SYSOID="`grep 1.3.6.1.2.1.1.2.0 "$RAWWALKFILE" | cut -d' ' -f4`" if [ -n "$DEVICE_SYSOID" ]; then echo "Found sysOID $DEVICE_SYSOID" else echo "SNMP sysOID is missing in file. Try --help for more info." >&2 exit 1 fi # Switch to the entry point, and extract the subtree # Extract the numeric walk echo -n "Extracting numeric SNMP walk..." grep "$DEVICE_SYSOID" "$RAWWALKFILE" | grep -E -v "1.3.6.1.2.1.1.2.0" 2>/dev/null 1> "$NUMWALKFILE" echo " done" # Create the string walk from a translation of the numeric one echo -n "Converting string SNMP walk..." while IFS=' = ' read NUM_OID OID_VALUE do STR_OID="`snmptranslate -Os -m ALL -M+. "$NUM_OID" 2>/dev/null`" # Uncomment the below line to get debug logs #echo "Got: $STR_OID = $OID_VALUE" printf "." echo "$STR_OID = $OID_VALUE" >> "$STRWALKFILE" done < "$NUMWALKFILE" echo " done" else # mode 2: get data from files echo "Mode 2 selected" MODE=2 # get sysOID value from command line, if needed while [ -z "$SYSOID" ]; do echo " Please enter the value of sysOID, as displayed by snmp-ups. For example '.1.3.6.1.4.1.2254.2.4'. You can get it using: snmpget -v1 -c XXX $SYSOID_NUMBER" read -p "Value of sysOID: " SYSOID < /dev/tty if echo "$SYSOID" | grep -E -q '[^0-9.]'; then echo "Please use only the numeric form, with dots and digits" SYSOID="" fi done # check for actual files existence if [ ! -f "$NUMWALKFILE" -o ! -f "$STRWALKFILE" ]; then echo "SNMP walk dump files are missing on disk. Try --help for more info." >&2 exit 1 fi fi fi # delete temporary files: this is called just before exiting. cleanup () { rm -f "$DEBUG $DFL_NUMWALKFILE $TMP_NUMWALKFILE $DFL_STRWALKFILE $TMP_STRWALKFILE" } if [ -n "$KEEP" ]; then trap cleanup EXIT fi # prompt use for name of driver while [ -z "$DRIVER" ]; do echo " Please enter a name for this driver. Use only letters and numbers. Use natural (upper- and lowercase) capitalization, e.g., 'Belkin', 'APC'." read -p "Name of subdriver: " DRIVER < /dev/tty if echo "$DRIVER" | grep -E -q '[^a-zA-Z0-9]'; then echo "Please use only letters and digits" DRIVER="" fi done # remove blank and "End of MIB" lines grep -E -e "^[[:space:]]?$" -e "End of MIB" -v "${NUMWALKFILE}" > "${TMP_NUMWALKFILE}" grep -E -e "^[[:space:]]?$" -e "End of MIB" -v "${STRWALKFILE}" > "${TMP_STRWALKFILE}" NUMWALKFILE="${TMP_NUMWALKFILE}" STRWALKFILE="${TMP_STRWALKFILE}" # FIXME: sanity checks (! -z contents -a same `wc -l`) NUM_OID_COUNT="`cat "$NUMWALKFILE" | wc -l`" STR_OID_COUNT="`cat "$STRWALKFILE" | wc -l`" echo "SNMP OIDs extracted = $NUM_OID_COUNT / $NUM_OID_COUNT" generate_C # Display the remaining tasks cat < debuginfo 2>&1 # # Usage: cat debuginfo | gen-usbhid-subdriver.sh # # See also: docs/hid-subdrivers.txt usage() { echo "Usage: $0 [options] [file] < debuginfo" echo "with data prepared by a driver walk:" echo " drivers/usbhid-ups -s ups -DD -u root -x vendorid=XXXX -x productid=XXXX \\" echo " -x port=auto -x explore -d1 > debuginfo 2>&1" echo "Options:" echo " -h, --help -- show this message and quit" echo " -n name -- driver name (use natural capitalization)" echo " -v XXXX -- vendor id (learned from debuginfo by default)" echo " -p XXXX -- product id (learned from debuginfo by default)" echo " -k -- keep temporary files (for debugging)" echo " file -- read from file instead of stdin" } DRIVER="" VENDORID="" PRODUCTID="" KEEP="" while [ $# -gt 0 ]; do if [ $# -gt 1 -a "$1" = "-n" ]; then DRIVER="$2" shift 2 elif [ $# -gt 1 -a "$1" = "-v" ]; then VENDORID="$2" shift 2 elif [ $# -gt 1 -a "$1" = "-p" ]; then PRODUCTID="$2" shift 2 elif [ "$1" = "-k" ]; then KEEP=yes shift elif echo "$1" | grep -qv '^-'; then FILE="$1" shift elif [ "$1" = "--help" -o "$1" = "-h" ]; then usage exit 0 else echo "Illegal option $1. Try --help for more info." >&2 exit 1 fi done # delete temporary files: this is called just before exiting. cleanup () { rm -f "$DEBUG" "$UTABLE" "$USAGES" "$SUBST" "$SEDFILE" "$NEWUTABLE" } if [ -z "$KEEP" ]; then trap cleanup EXIT fi NAME=gen-usbhid-subdriver TMPDIR="${TEMPDIR:-/tmp}" DEBUG=`mktemp "$TMPDIR/$NAME-DEBUG.XXXXXX"` UTABLE=`mktemp "$TMPDIR/$NAME-UTABLE.XXXXXX"` USAGES=`mktemp "$TMPDIR/$NAME-USAGES.XXXXXX"` SUBST=`mktemp "$TMPDIR/$NAME-SUBST.XXXXXX"` SEDFILE=`mktemp "$TMPDIR/$NAME-SEDFILE.XXXXXX"` NEWUTABLE=`mktemp "$TMPDIR/$NAME-NEWUTABLE.XXXXXX"` # save standard input to a file if [ -z "$FILE" ]; then FILE="$DEBUG" cat > "$DEBUG" fi # prompt use for name of driver while [ -z "$DRIVER" ]; do echo " Please enter a name for this driver. Use only letters and numbers. Use natural (upper- and lowercase) capitalization, e.g., 'Belkin', 'APC'." read -p "Name of subdriver: " DRIVER < /dev/tty if echo $DRIVER | grep -E -q '[^a-zA-Z0-9]'; then echo "Please use only letters and digits" DRIVER="" fi done # try to determine product and vendor id, if not specified by user [ -n "$VENDORID" ] || VENDORID=`cat "$FILE" | sed -n 's/.*- VendorID: \([0-9a-fA-F]*\).*/\1/p' | tail -1` [ -n "$PRODUCTID" ] || PRODUCTID=`cat "$FILE" | sed -n 's/.*- ProductID: \([0-9a-fA-F]*\).*/\1/p' | tail -1` # prompt for productid, vendorid if necessary if [ -z "$VENDORID" ]; then read -p "Vendor ID: " VENDORID < /dev/tty fi if [ -z "$PRODUCTID" ]; then read -p "Product ID: " PRODUCTID < /dev/tty fi LDRIVER=`echo $DRIVER | tr A-Z a-z` UDRIVER=`echo $DRIVER | tr a-z A-Z` CFILE="$LDRIVER-hid.c" HFILE="$LDRIVER-hid.h" # extract Usage Table cat "$FILE" | sed -n 's/.*Path: \([^,][^,]*\), Type:.*/\1/p' > "$UTABLE" # extract Usage codes cat "$UTABLE" | tr '.' $'\n' | sort -u > "$USAGES" # make up dummy names for unknown usages count=0 cat "$USAGES" | grep -E '[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]' |\ while read U; do count=`expr $count + 1` echo "$U $UDRIVER$count" done > "$SUBST" # create an sed script for substitutions cat "$SUBST" | sed 's/\(.*\) \(.*\)/s!\1!\2!g;/' > "$SEDFILE" # create modified usage table sed -f "$SEDFILE" < "$UTABLE" > "$NEWUTABLE" # generate header file echo "Creating $HFILE" cat > "$HFILE" < * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ${UDRIVER}_HID_H #define ${UDRIVER}_HID_H #include "usbhid-ups.h" extern subdriver_t ${LDRIVER}_subdriver; #endif /* ${UDRIVER}_HID_H */ EOF # generate source file echo "Creating $CFILE" cat > "$CFILE" < * 2005 - 2006 Peter Selinger * 2008 - 2009 Arjen de Korte * 2013 Charles Lepple * * TODO: Add year and name for new subdriver author (contributor) * Mention in docs/acknowledgements.txt if this is a vendor contribution * * Note: this subdriver was initially generated as a "stub" by the * gen-usbhid-subdriver script. It must be customized. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "usbhid-ups.h" #include "${HFILE}" #include "main.h" /* for getval() */ #include "usb-common.h" #define ${UDRIVER}_HID_VERSION "${DRIVER} HID 0.1" /* FIXME: experimental flag to be put in upsdrv_info */ /* ${DRIVER} */ #define ${UDRIVER}_VENDORID 0x${VENDORID} /* USB IDs device table */ static usb_device_id_t ${LDRIVER}_usb_device_table[] = { /* ${DRIVER} */ { USB_DEVICE(${UDRIVER}_VENDORID, 0x${PRODUCTID}), NULL }, /* Terminating entry */ { 0, 0, NULL } }; /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* ${UDRIVER} usage table */ static usage_lkp_t ${LDRIVER}_usage_lkp[] = { EOF cat "$SUBST" | sed 's/\(.*\) \(.*\)/\t{ "\2",\t0x\1 },/' >> "$CFILE" cat >> "$CFILE" <> "$CFILE" <> "$CFILE" <Product; } static const char *${LDRIVER}_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "${DRIVER}"; } static const char *${LDRIVER}_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int ${LDRIVER}_claim(HIDDevice_t *hd) { int status = is_usb_device_supported(${LDRIVER}_usb_device_table, hd); switch (status) { case POSSIBLY_SUPPORTED: /* by default, reject, unless the productid option is given */ if (getval("productid")) { return 1; } possibly_supported("${DRIVER}", hd); return 0; case SUPPORTED: return 1; case NOT_SUPPORTED: default: return 0; } } subdriver_t ${LDRIVER}_subdriver = { ${UDRIVER}_HID_VERSION, ${LDRIVER}_claim, ${LDRIVER}_utab, ${LDRIVER}_hid2nut, ${LDRIVER}_format_model, ${LDRIVER}_format_mfr, ${LDRIVER}_format_serial, fix_report_desc, /* may optionally be customized, see cps-hid.c for example */ }; EOF cat </dev/null 2>&1 && CLIENT="yes" fi SHUTDOWN_TIMER=-1 if [ -f "$CONFIG_IPP" ]; then . "$CONFIG_IPP" fi do_start() { if [ "$SERVER" = "yes" ]; then echo "Starting UPS driver controller: \c" ( upsdrvctl start >/dev/null 2>&1 && success || failure ) || \ RETVAL=$? echo "Starting upsd: \c" ( upsd $UPSD_OPTIONS >/dev/null 2>&1 && success || failure ) || \ RETVAL=$? echo "Cancel pending UPS powercycle, if any: \c" if [ -x "${NUT_DIR}/init" ]; then ( "${NUT_DIR}/init" > /dev/null 2>&1 && success || failure ) || \ true #RETVAL=$? fi fi if [ "$CLIENT" = "yes" ]; then echo "Starting UPS monitor: \c" if [ "$SHUTDOWN_TIMER" -gt -1 ]; then # This host wants early shutdown support, must be root ( upsmon -p >/dev/null 2>&1 && success || failure ) || \ RETVAL=$? else ( upsmon >/dev/null 2>&1 && success || failure ) || \ RETVAL=$? fi fi [ "$RETVAL" = 0 ] && touch "${NUT_LOCK_FILE}" } do_stop() { if test -e "${NUT_RUN_DIR}/upsmon.pid" ; then echo "Stopping UPS monitor: \c" PID="`cat "${NUT_RUN_DIR}/upsmon.pid"`" ( kill $PID && success || failure ) || \ RETVAL=$? rm "${NUT_RUN_DIR}/upsmon.pid" fi if [ "$SERVER" = "yes" ]; then if test -e "${NUT_RUN_DIR}/upsd.pid" ; then echo "Stopping upsd: \c" PID="`cat "${NUT_RUN_DIR}/upsd.pid"`" ( kill -9 $PID && success || failure ) || \ RETVAL=$? rm "${NUT_RUN_DIR}/upsd.pid" fi echo "Shutting down UPS driver controller: \c" ( upsdrvctl stop > /dev/null 2>&1 && success || failure ) || \ RETVAL=$? fi [ "$RETVAL" = 0 ] && rm -f "${NUT_LOCK_FILE}" } do_restart() { do_stop waitmore=5 while [ -n "`ls ${NUT_RUN_DIR}/`" -a "$waitmore" -ge 1 ] do sleep 1 waitmore="`expr $waitmore - 1`" done do_start } do_reload() { # FIXME: upsd and upsmon always return 0 # => can't tell if reload was successful if [ "$SERVER" = "yes" ]; then echo "Reloading upsd" upsd -c reload || \ RETVAL=$? fi echo "Reloading upsmon" upsmon -c reload || \ RETVAL=$? } RETVAL=0 # See how we are called. case "$1" in start) do_start ;; stop) do_stop ;; restart) do_restart ;; try-restart) [ -f "${NUT_LOCK_FILE}" ] && do_restart || true ;; reload) do_reload ;; force-reload) do_restart ;; status) RETVAL_UPSD=0 if [ "$SERVER" = "yes" ]; then RETVAL_UPSD=1 if test -f "${NUT_LOCK_FILE}" -o -s "${NUT_RUN_DIR}/upsd.pid" ; then PID_UPSD="`cat "${NUT_RUN_DIR}/upsd.pid"`" && \ test -n "$PID_UPSD" && \ test -d "/proc/${PID_UPSD}" && \ echo "upsd is running with PID $PID_UPSD" && \ RETVAL_UPSD=0 fi if [ "$RETVAL_UPSD" != 0 ]; then echo "upsd is NOT running!" >&2 RETVAL=1 fi fi RETVAL_UPSMON=1 if test -s "${NUT_RUN_DIR}/upsmon.pid" ; then PID_UPSMON="`cat "${NUT_RUN_DIR}/upsmon.pid"`" && \ test -n "$PID_UPSMON" && \ test -d "/proc/${PID_UPSMON}" && \ echo "upsmon is running with PID $PID_UPSMON" && \ RETVAL_UPSMON=0 elif rpm -q nut-client >/dev/null 2>&1; then : # default error remains in place - package present, service not running else RETVAL_UPSMON=0 fi if [ "$RETVAL_UPSMON" != 0 ]; then echo "upsmon isn't running" >&2 RETVAL=1 fi ;; *) echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}" RETVAL=3 esac exit $RETVAL nut-2.8.3/scripts/installer/aix/ipp-os-shutdown.conf.sample0000644000200500020050000000233114602463167020723 00000000000000# # ipp-os-shutdown.conf # # Settings that specify typical shutdown commands for various supported OSes # Version for AIX # # The program which executes an OS shutdown, maybe including flags that # disable its interactive mode CMD_SHUTDOWN="/usr/sbin/shutdown" # Depending on OS and hardware support, "poweroff" option may tell the # host's power source units to cut off their power to the motherboard, # and "halt" may sit forever at the "OS is stopped" prompt or equivalent. # NOTE: Yes, according to AIX man pages, the letters are not matched # with the tag-words: "-p" leaves the machine halted and powered-on, # and "-h" tries to kill power in the end. SDFLAG_POWEROFF="-h" SDFLAG_REBOOT="-r" SDFLAG_HALT="-p" # The flag for quick stop (shorter service stop timeouts and fewer/no # logs, or outright go to kill remaining processes) SDFLAG_UNGRACEFUL="-F" # Trigger a shutdown without delay SDFLAG_INSTANT="+0" ## Filename to store the PID of a pending shutdown ## If this file is absent, the shutdown can not be canceled (killed) ## If the "${SHUTDOWN_PIDFILE}.irreversible" exists and points to running PID ## then the new shutdown can not be queued (caller must cancel old one first) SHUTDOWN_PIDFILE="/var/run/nut/shutdown.pid" nut-2.8.3/scripts/installer/common_EN/0000755000200500020050000000000015001555411014652 500000000000000nut-2.8.3/scripts/installer/common_EN/license.txt0000644000200500020050000004310314553676503016777 00000000000000 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. nut-2.8.3/scripts/installer/common_EN/install.res0000644000200500020050000001565614602463167017004 00000000000000You must be root to install IPP - Unix. Unable to determine your system. Please specify your system like, "\"./install.sh \"" Valid systems are SOLINT SOLARI HPUX AIX6 No serial device detected. Press Enter to continue. This is not a number, please enter a valid number. Welcome to IPP - Unix! To install IPP - Unix, press y and then press and fill in the configuration items as they are presented to you. NOTE: If you already have IPP - Unix installed and you do not wish to re-install it, select (N)o to stop IPP - Unix installation. Continue IPP - Unix installation? (y/n) Version The install path name for this software is: License Agreement: Do you accept all terms of the preceding license Agreement? If you do not accept the terms, then the Setup will close. To install IPP - Unix, you must accept this agreement. Do you accept all terms of the preceding license Agreement? (y/n) Install failed! IPP - Unix was successfully installed on your system. WARNING: IPP - Unix was NOT successfully installed on your system. Installing package. Removing old package. Installation error, please see install.log. =============================================================================== IPP - Unix configuration - Select installation option: IPP - Unix UPS Server Configuration We will scan your network to find available IPP - Unix UPS Server. Please enter the first IP to scan (e.g. 192.168.0.0) then the last IP to scan (e.g. 192.168.0.255) or nothing if you want to scan only one address. Enter first IP to scan : Enter last IP to scan : Scanning... No IPP - Unix UPS Server available ! Press Enter to continue. Please choose the UPS protecting this machine: 0. Go back Select UPS Manager Password The UPS manager password is used to secure the shut-off of UPS. Please enter the IPP - Unix UPS Server password, this cannot be empty (characters will not appear when typed): Re-enter the IPP - Unix UPS Server password (characters will not appear): Please review your configuration Managing UPS for local use only Managing UPS and allow remote clients Connecting to remote IPP - Unix UPS Servers Configured UPS devices: Minimum number of supplies needed: Early shutdown timeout, minutes (-1 for disabled feature): UPS Shutoff delay, seconds: UPS Shutoff and power-cycling enforcement (empty for auto): Is this correct ? (y/n) How is your UPS connected to this host ? 1. Serial Connection (COM port) 2. Network adapter 0. Go back Enter selection 0-2: Verify Detection Do you want Setup to automatically look for a serially connected UPS? 1. Yes 2. No 0. Go back Enter selection 0-2: Choose serial device 0. Go back Enter selection: Manually choose serial device Please enter the device name (in the form /dev/name) of the serial port on which the UPS is connected (Make sure "ipp" user and/or "ipp" group have read/write access to the entered /dev file). Enter device name (/dev/name): No serial UPS found on this device. Press Enter to continue. Network Configuration We are scanning your network to find available network UPS. Enter first IP to scan : Enter last IP to scan : Please enter the community name of your SNMP device (note that you have to enter a read/write community name to change UPS settings and allow shut-off of the UPS.) Scanning... No network UPS available ! Press Enter to continue. Please choose the UPS protecting this machine: 0. Go back Scan for more UPS Starting IPP - Unix service. LanSafe installation detected. Proceeding to uninstallation. Netwatch installation detected. Proceeding to uninstallation. Older IPP-Unix installation detected. Proceeding to uninstallation with its method script first. Shut-off UPS Do you want your UPS to be shut-off after a system shut-down due to power failure ? (y/n) Enter Power Failure Settings Shutting down the operating system and programs on this computer takes (in second): Shutting down the operating system and programs on this computer takes (in second) - Note that this value may be ignored if you have set-up a greater value on your device: Do you want to directly manage an UPS (via serial link or network) or connect to a remote IPP - Unix UPS Server ? 1. Direct management 2. Connect to remote IPP - Unix UPS Server Enter selection: Network connectivity Do you want this IPP for Unix instance to be reachable over the network as an UPS Server for the power device(s) it manages (i.e. allow IPP - Unix clients to connect to it) ? 1. No remote access 2. Act as a server for managed UPS Enter selection: Currently configured UPS 1. Continue with this configuration 2. Add another UPS 3. Remove an UPS 0. Go back Enter selection: Minimum supplies required Give the number of power supplies that must be receiving power to keep this system running (minimum 1): Enter the number of the UPS you wish to remove No such UPS Network device login/password Enter login for network device: Enter password for network device (characters will not appear): Re-enter password for network device (characters will not appear): Passwords are different, please try again. Power Failure Settings Note that the shutdown duration (the time left for your system to shutdown before the UPS shuts-off) is set on the IPP - Unix UPS Server side. Push Enter key to continue... Automatic or manual network device setup Do you want to scan your network for available devices or directly enter an IP address ? 1. Scan network 2. Enter IP 0. Go back Enter selection: Network device IP Please enter your network device IP: Do you want to "enforce" or "forbid" this host to always power-cycle the UPS as part of powerfail shutdown, or should it depend on other setup and run-time situation? Please enter "enforce" ("e"), "forbid" ("f") or "auto" (empty line); if unsure - default to "auto": Unexpected string was entered, please try again. Do you want to enable early shutdown timer ("-1" or empty for usual late shutdown to maximize uptime, 0 or more for minutes (recommended 5+ minutes then) spent ONBATT with less than MINSUPPLIES power sources known protected, before beginning to shut down)? Please enter a number of minutes for early shutdown timer (either "-1", or 0 or more); if unsure - default to "-1": nut-2.8.3/scripts/installer/nutconf-dummy0000755000200500020050000000464514602463167015500 00000000000000#!/bin/sh # Script to fake nutconf, for integration purpose # FIXME: to be completed! # there must be at least 1 option! if [ $# -lt 1 ] ; then echo "Error: no options provided!"; exit 1; fi case $1 in --system) ;; --mode) #standalone,netserver,netclient,controlled,manual,none ;; --is-configured) # return "yes" / "no" + retval 0 / 1 if nut is configured or not ;; # --scan-?options?) # FIXME: call nutscan?? --scan-snmp) echo "SNMP:driver=\"snmp-ups\",port=\"166.99.224.106\",desc=\"Evolution\",mibs=\"mge\",community=\"public\"" echo "SNMP:driver=\"snmp-ups\",port=\"166.99.224.155\",desc=\"Eaton ePDU AM 1P IN:IEC309 32A OUT:20xC13, 4xC19\",mibs=\"eaton_epdu\",community=\"public\"" echo "SNMP:driver=\"snmp-ups\",port=\"166.99.224.111\",desc=\"Eaton 5P\",mibs=\"mge\",community=\"public\"" echo "SNMP:driver=\"snmp-ups\",port=\"166.99.224.149\",desc=\"PW104MA0UC34\",mibs=\"aphel_revelation\",community=\"public\"" ;; --restart) # FIXME: restart NUT services after configuration ;; --reload) # FIXME: reload NUT services after configuration ;; --get-devices) #get the list of devices name ;; --get-device) # FIXME: ;; --set-device) # FIXME: [=] [[=]] ;; --new-device) # FIXME: [] ;; --del-devices) # FIXME: ;; --del-device) # FIXME: []: either remove a field or the entire device entry ;; --get-users) # FIXME: ;; --get-user) # FIXME: ;; --set-user) # FIXME: [=] ;; --new-user) # FIXME: ... needs completion with upsmon master slave/instcmd/set ;; --del-user) # FIXME: ;; # --?generic-{s,g}etter? # FIXME: set or get a global or local param (need discussion) # upsd.conf/maxage, statepath, listen, maxconn, certfile # ups.conf/chroot, driverpath, maxstartdelay, pollinterval, user # ups.conf/drivers specific (see scripts/augeas/) # --?security-option?: I let M speak about the best way to configure NSS / OpenSSL --get-monitors) # FIXME:get the list of monitored systems (names only, but may also use a verbose flag to display details) ;; --get-monitor) # FIXME:: details... ;; --set-monitor) # FIXME:TBD ;; --new-monitor) # FIXME:TBD ;; --get-notifycmds) # FIXME: ;; --get-notifycmd) # FIXME: ;; *) echo "nutconf Unknown option ($1)"; #exit 1; esac nut-2.8.3/scripts/installer/make_package.sh0000755000200500020050000000412114777767434015702 00000000000000#!/usr/bin/env bash # make_package.sh # Copyright (c) 2013-2015, by Eaton (R) Corporation. All rights reserved. # Unlike what the name implies, this script prepares tarballs for each # supported platform, including a separately prepared platform package # with compiled NUT and adds third-party libs and Eaton IPP - Unix # scripts for better taste ;) . ./version.sh || exit $? rm -Rf package mkdir package # NOTE: Originally this pulled installer sources (separate from NUT code base) # If this script were to be modernized, it could be prudent to `make package` # in NUT sources for each platform, to create the package file(s) tarballed # below for end-user along with the interactive installer delivery. #git pull --all # [ $? = 0 ] && git merge upstream/master || exit $? # NOTE: See README.adoc about expected subdirectory contents with binary files NAME="ipp-solaris-$IPP_VERSION.sparc" mkdir "package/$NAME" FILE_LIST="`find . -type f -name '*' | egrep -v '.svn|.git|./nutconf-dummy|./make_package.sh|nut/|(un|)install.log|package/|aix|hpux|solint'`" cp --parents -r $FILE_LIST "package/$NAME" cd package tar cpvf "$NAME.tar" "$NAME" gzip -9 "$NAME.tar" cd .. NAME="ipp-solaris-$IPP_VERSION.x86" mkdir "package/$NAME" FILE_LIST="`find . -type f -name '*' | egrep -v '.svn|.git|./nutconf-dummy|./make_package.sh|nut/|(un|)install.log|package/|aix|hpux|solari/'`" cp --parents -r $FILE_LIST "package/$NAME" cd package tar cpvf "$NAME.tar" "$NAME" gzip -9 "$NAME.tar" cd .. NAME="ipp-hpux-$IPP_VERSION.parisc" mkdir "package/$NAME" FILE_LIST="`find . -type f -name '*' | egrep -v '.svn|.git|./nutconf-dummy|./make_package.sh|nut/|(un|)install.log|package/|aix|solint|solari/|solcmn/'`" cp --parents -r $FILE_LIST "package/$NAME" cd package tar cpvf "$NAME.tar" "$NAME" gzip -9 "$NAME.tar" cd .. NAME="ipp-aix-$IPP_VERSION.powerpc" mkdir "package/$NAME" FILE_LIST="`find . -type f -name '*' | egrep -v '.svn|.git|./nutconf-dummy|./make_package.sh|nut/|(un|)install.log|package/|hpux|solint|solari/|solcmn/'`" cp --parents -r $FILE_LIST "package/$NAME" cd package tar cpvf "$NAME.tar" "$NAME" gzip -9 "$NAME.tar" cd .. nut-2.8.3/scripts/installer/uninstall-ipp0000755000200500020050000001452514602463167015470 00000000000000#!/bin/sh # uninstall.sh # Copyright (c) 2013-2016, by Eaton (R) Corporation. All rights reserved. # A shell script which uninstalls IPP - Unix # It stops daemons and removes the native package # PATH="$PATH:/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb:/usr/ccs/bin:/usr/xpg4/bin:/usr/xpg6/bin" export PATH NUT_PACKAGE_SOLARI="NUT_solaris_sparc_package2.6.5.local" NUT_PACKAGE_SOLINT="NUT_solaris_i386_package2.6.5.local" cd "`dirname "$0"`" #configuration data C_MODE="standalone" C_HOSTNAME="localhost" C_CONNECTIVITY="serial" C_DEVICE="" C_PASSWORD="" # /dev/tty user & group used on the supported systems case "`uname -s`" in "SunOS") TTY_OWNER="root:root" ;; "AIX") TTY_OWNER="root:system" ;; "HP-UX") TTY_OWNER="bin:bin" ;; *) # Safe fallback for unsupported systems TTY_OWNER="root:root" ;; esac DO_UNINSTALL="" ADMIN_FILE="/tmp/ipp_admin_file" UNINSTALL_TMP="/tmp" LOG_FILE="$UNINSTALL_TMP/uninstall.log" get_parameters() { case "$1" in English) lang=EN ;; # Japanese) # lang=JP # ;; SOLARI) SYSTEM="$1" ;; SOLINT) SYSTEM="$1" ;; HPUX) SYSTEM="$1" ;; AIX) SYSTEM="$1" ;; DO_UNINSTALL) DO_UNINSTALL="OK" ;; esac } check_locale_language() { set `locale` >/dev/null 2>&1 case "$1" in LANG=en_US) lang=EN ;; LANG=C) lang=EN ;; esac } compute_SYSTEM () { set `uname -a` case "$1" in SunOS) case "$3" in 5.*) case "$5" in i86pc) SYSTEM=SOLINT ;; *) SYSTEM=SOLARI ;; esac ;; *) SYSTEM="Unknown System" ;; esac ;; HP-UX) SYSTEM=HPUX ;; AIX) case "$4" in 6) SYSTEM=AIX ;; 7) SYSTEM=AIX ;; *) SYSTEM="This AIX version is not supported" ;; esac ;; *) SYSTEM="Unknown System" ;; esac compute_system } compute_system () { case "$SYSTEM" in SOLINT) system=solint ;; SOLARI) system=solari ;; HPUX) system=hpux ;; AIX) system=aix ;; *) echo echo "Please specify your system like './install.sh '" echo "Valid systems are SOLINT SOLARI HPUX AIX" echo exit 1 ;; esac } create_admin_file () { echo basedir=default > "$ADMIN_FILE" echo runlevel=quit >> "$ADMIN_FILE" echo conflict=nocheck >> "$ADMIN_FILE" echo setuid=nocheck >> "$ADMIN_FILE" echo action=nocheck >> "$ADMIN_FILE" echo partial=nocheck >> "$ADMIN_FILE" echo instance=unique >> "$ADMIN_FILE" echo idepend=quit >> "$ADMIN_FILE" echo rdepend=quit >> "$ADMIN_FILE" echo space=quit >> "$ADMIN_FILE" } restore_ttys () { for tty in `find /dev/tty* -user ipp`; do chown "$TTY_OWNER" "$tty" chmod 622 "$tty" done } killall_ps () { kill -9 `ps -e | awk "/ $1\$/ { print \$1; }"` } killall_nut () { killall_ps upsd >/dev/null 2>/dev/null killall_ps upsmon >/dev/null 2>/dev/null killall_ps bcmxcp >/dev/null 2>/dev/null killall_ps mge-shut >/dev/null 2>/dev/null killall_ps snmp-ups >/dev/null 2>/dev/null } uninstall_files () { rm -f "$LOG_FILE" > /dev/null 2>&1 touch "$LOG_FILE" echo echo "`date`: Uninstalling IPP - Unix" | tee -a "$LOG_FILE" echo case "$system" in solari) /etc/init.d/nut stop >> "$LOG_FILE" 2>&1 sleep 5 killall_nut create_admin_file restore_ttys pkgrm -n -a "$ADMIN_FILE" NUT >> "$LOG_FILE" 2>&1 rm -f "$ADMIN_FILE" #uninstall additional libraries ;; solint) /etc/init.d/nut stop >> "$LOG_FILE" 2>&1 sleep 5 killall_nut create_admin_file restore_ttys pkgrm -n -a "$ADMIN_FILE" NUT >> "$LOG_FILE" 2>&1 rm -f "$ADMIN_FILE" #uninstall additional libraries ;; hpux) /sbin/init.d/nut-drvctl stop >> "$LOG_FILE" 2>&1 /sbin/init.d/nut-upsd stop >> "$LOG_FILE" 2>&1 /sbin/init.d/nut-upsmon stop >> "$LOG_FILE" 2>&1 sleep 5 killall_nut restore_ttys swremove NUT >> "$LOG_FILE" 2>&1 #uninstall additional libraries ;; aix) /etc/rc.d/init.d/ups stop >> "$LOG_FILE" 2>&1 sleep 5 killall_nut restore_ttys rm -rf "$instpath/share/man" >> "$LOG_FILE" 2>&1 rpm -e nut >> "$LOG_FILE" 2>&1 rpm -e nut-client >> "$LOG_FILE" 2>&1 #uninstall additional libraries ;; *) echo "Installation error, please see $LOG_FILE." exit 1 ;; esac rm -f "$instpath/bin/uninstall"* >> "$LOG_FILE" 2>&1 rm -f "$instpath/init" >> "$LOG_FILE" 2>&1 rm -f "$instpath/shutdown" >> "$LOG_FILE" 2>&1 rm -f "$instpath/sbin/ipp-os-shutdown" >> "$LOG_FILE" 2>&1 rm -f "$instpath/sbin/ipp-host-shutdown.sample" >> "$LOG_FILE" 2>&1 rm -f "$instpath/bin/ipp-notifier.sh" >> "$LOG_FILE" 2>&1 rm -f "$instpath/bin/ipp-status" >> "$LOG_FILE" 2>&1 rm -f "$instpath/share/string.sh" >> "$LOG_FILE" 2>&1 rm -f "$instpath/share/install.res" >> "$LOG_FILE" 2>&1 rm -f "$instpath/etc/ipp.conf.sample" >> "$LOG_FILE" 2>&1 rm -Rf "$instpath/lib" >> "$LOG_FILE" 2>&1 rm -Rf "$instpath/xbin" >> "$LOG_FILE" 2>&1 rm -f "$instpath/bin/ipp-wrapper" >> "$LOG_FILE" 2>&1 } remove_profile_settings () { if /usr/bin/test -e /etc/profile; then awk ' BEGIN { echo = 1; } /^##### IPP - Unix settings begin #####$/ { echo = 0; } /^##### IPP - Unix settings end #####$/ { echo = 1; next; } { if (echo) print $0; } ' /etc/profile > /tmp/profile.tmp.$$ mv /tmp/profile.tmp.$$ /etc/profile fi } main () { # Setup some globals instpath=/usr/local/ups ret=TRUE # Must check parameters SYSTEM="" lang="" if [ "$1" != "" ] ; then get_parameters $1 fi if [ "$2" != "" ] ; then get_parameters $2 fi if [ "$3" != "" ] ; then get_parameters $3 fi if [ ! "$DO_UNINSTALL" = "OK" ];then cp -f "$instpath/bin/uninstall-ipp" "$UNINSTALL_TMP" chmod 744 "$UNINSTALL_TMP/uninstall-ipp" exec "$UNINSTALL_TMP/uninstall-ipp" DO_UNINSTALL $1 $2 $3 exit fi compute_SYSTEM # Get language locale if [ "$lang" = "" ]; then check_locale_language if [ -z "$lang" ]; then lang=EN fi fi who="`whoami 2>/dev/null`" if [ "$who" != 'root' ]; then #work around in case no whoami is present who="`id -u 2>/dev/null`" if [ "$who" != '0' ]; then who="`id 2>/dev/null | grep -w '0' | grep -w root`" if [ -z "$who" ]; then echo "You must be root to uninstall IPP - Unix." exit 1 fi fi fi uninstall_files remove_profile_settings # Say goodbye echo "---------------------------------------------------------------" echo " IPP - Unix was successfully uninstalled from your system." echo "---------------------------------------------------------------" } main $1 $2 $3 nut-2.8.3/scripts/installer/Makefile.in0000644000200500020050000005762415001555011014777 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/installer VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = scripts/installer ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = \ README.adoc \ make_package.sh \ version.sh \ install.sh \ uninstall-lsnw.sh \ uninstall-ipp \ nutconf-dummy \ common_EN/license.txt \ common_EN/install.res \ common/solaris_init \ common/ipp-shutdown-daemon.sh \ common/README_ipp-os-shutdown.adoc \ common/ipp-status \ common/ipp.conf \ common/ipp-wrapper \ common/ipp-event.sh \ common/string.sh \ common/ipp-host-shutdown.sample \ common/shutdown \ common/ipp-notifier.sh \ common/ipp-os-shutdown \ common/init \ common/aix_init \ aix/ipp-os-shutdown.conf.sample \ aix/aix_init \ hpux/ipp-os-shutdown.conf.sample \ solcmn/solaris_init \ solcmn/ipp-os-shutdown.conf.sample SPELLCHECK_SRC = README.adoc common/README_ipp-os-shutdown.adoc CLEANFILES = *-spellchecked */*-spellchecked common_EN/license.txt MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/installer/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/installer/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ clean-local cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # Originally an Eaton license was used, changed along with donation of sources # to NUT project. Having the file name populated helps keep the scripts as is. common_EN/license.txt: $(top_srcdir)/LICENSE-GPL2 $(MKDIR_P) '$(@D)' cp -pf '$?' '$@' nut: rm -f "$@" $(LN_S) $(top_srcdir) "$@" # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Remove "nut" if it is a symlink to the source tree clean-local: if test -L nut || test -h nut ; then rm -f nut ; fi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/installer/version.sh0000644000200500020050000000002514602463167014752 00000000000000IPP_VERSION="1.40-5" nut-2.8.3/scripts/installer/solcmn/0000755000200500020050000000000015001555411014273 500000000000000nut-2.8.3/scripts/installer/solcmn/solaris_init0000755000200500020050000000431114602463167016653 00000000000000#!/sbin/sh # ups: Starts and stops the Network UPS Tools 2.6.5 built for IPP - Unix 1.40-4 on Solaris # Customizations copyright (c) 2015-2017, by Eaton (R) Corporation. All rights reserved. NUT_DIR="/usr/local/ups" NUT_RUN_DIR="/var/state/ups" NUT_LOCK_FILE="/var/locks/ups" NUT_CFG_DIR="" for D in "$NUT_DIR/etc" "/etc/nut" "/etc/ups" ; do if [ -d "$D" ] && [ -f "$D/ups.conf" ] && [ -f "$D/ipp.conf" ] ; then NUT_CFG_DIR="$D" break fi done unset D CONFIG_IPP="$NUT_CFG_DIR/ipp.conf" # Note: $NUT_DIR/xbin holds the wrappers to run NUT binaries with co-bundled # third party libs and hopefully without conflicts induced for the OS binaries PATH="$NUT_DIR/xbin:$NUT_DIR/sbin:$NUT_DIR/bin:$PATH" export PATH # Do not normally mangle the LD_LIBRARY_PATH - it can impact system tools too #LD_LIBRARY_PATH="$NUT_DIR/lib:/usr/lib:/lib:$LD_LIBRARY_PATH" #export LD_LIBRARY_PATH SHUTDOWN_TIMER=-1 if [ -f "$CONFIG_IPP" ]; then . "$CONFIG_IPP" fi ups_stop () { echo "in ups stop function" pkill -n upsmon pkill -n upsd upsdrvctl stop > /dev/null 2>&1 towait=5 while \ pgrep netxml-ups > /dev/null || \ pgrep snmp-ups > /dev/null || \ pgrep upsd > /dev/null || \ pgrep upsmon > /dev/null \ ; do sleep 1 towait="`expr $towait - 1`" if [ "$towait" -le 0 ] ; then echo "warning: some daemons did not die" break fi done # If the user changed ups.conf definitions and then asks for # a NUT restart, the old instance of a driver might not die # with obsolete knowledge of upsdrvctl LIST="`ls -1 ${NUT_RUN_DIR}/*.pid | grep -v /shutdown.pid 2>/dev/null`" if [ -n "$LIST" ]; then echo "in ups stop function: killing some left-over daemons:" echo "$LIST" kill -15 `cat $LIST` > /dev/null 2>&1 sleep 5 fi } ups_start () { echo "in ups start function" upsdrvctl start #> /dev/null 2>&1 upsd #> /dev/null 2>&1 if [ "$SHUTDOWN_TIMER" -gt -1 ]; then # This host wants early shutdown support, must be root upsmon -p #> /dev/null 2>&1 else upsmon #> /dev/null 2>&1 fi "$NUT_DIR"/init #> /dev/null 2>&1 } case $1 in 'start') ups_start ;; 'stop') ups_stop ;; 'restart') ups_stop ups_start ;; *) echo "" echo "Usage: '$0' {start | stop | restart }" echo "" exit 64 ;; esac exit $? nut-2.8.3/scripts/installer/solcmn/ipp-os-shutdown.conf.sample0000644000200500020050000000232414602463167021437 00000000000000# # ipp-os-shutdown.conf # # Settings that specify typical shutdown commands for various supported OSes # Version for Solaris (x86, SPARC) # # The program which executes an OS shutdown, maybe including flags that # disable its interactive mode CMD_SHUTDOWN="/usr/sbin/shutdown -y" # Depending on OS and hardware support, "poweroff" option may tell the # host's power source units to cut off their power to the motherboard, # and "halt" may sit forever at the "OS is stopped" prompt or equivalent. SDFLAG_POWEROFF="-i 5" SDFLAG_REBOOT="-i 6" SDFLAG_HALT="-i 0" # The flag for quick stop (shorter service stop timeouts and fewer/no # logs, or outright go to kill remaining processes) # NOTE: In Solaris, there are very ungraceful options for `poweroff`, # `halt` and `reboot` programs - but they are not exposed in `shutdown`. SDFLAG_UNGRACEFUL="-g 0" # Trigger a shutdown without delay SDFLAG_INSTANT="-g 0" ## Filename to store the PID of a pending shutdown ## If this file is absent, the shutdown can not be canceled (killed) ## If the "${SHUTDOWN_PIDFILE}.irreversible" exists and points to running PID ## then the new shutdown can not be queued (caller must cancel old one first) SHUTDOWN_PIDFILE="/var/state/ups/shutdown.pid" nut-2.8.3/scripts/installer/uninstall-lsnw.sh0000755000200500020050000000541414602463167016271 00000000000000#!/bin/sh # Script to detect and uninstall Lansafe / Netwatch # AQU notes: # - default install path: /usr/Powerware/LanSafe (for all systems) # - may be expanded to PSP OS_NAME="`uname -s`" detect_psp() { case $OS_NAME in HP-UX) PSP_INITSCRIPT_FN="/sbin/init.d/ls.init" ;; AIX) PSP_INITSCRIPT_FN="`grep psp /etc/inittab 2>/dev/null | cut -d':' -f4 | cut -d' ' -f1`" ;; SunOS) PSP_INITSCRIPT_FN="/etc/init.d/ls.init" ;; *) #echo "$OS_NAME is not managed!" return 1 ;; esac } detect_lansafe() { case $OS_NAME in HP-UX) LS_INITSCRIPT_FN="/sbin/init.d/ls.init" ;; AIX) LS_INITSCRIPT_FN="`grep LanSafe /etc/inittab 2>/dev/null | cut -d':' -f4 | sed 's/&//'`" ;; SunOS) LS_INITSCRIPT_FN="/etc/init.d/ls.init" ;; *) #echo "$OS_NAME is not managed!" return 1 ;; esac if [ -n "$LS_INITSCRIPT_FN" -a -f "$LS_INITSCRIPT_FN" ] ; then LS_INSTPATH="`grep instpath $LS_INITSCRIPT_FN | head -n1 | cut -d'=' -f2`" if [ -z "$LS_INSTPATH" ] ; then return 1 #else #echo "LanSafe installation detected." fi else return 1 fi # Lansafe is installed return 0 } uninstall_lansafe() { #echo "LanSafe installation detected. Proceeding to uninstallation." #echo "Calling $LS_INSTPATH/uninstall.sh" # Actual Lansafe uninstallation echo "y" | $LS_INSTPATH/uninstall.sh 2>&1 1> install.log } detect_netwatch() { case $OS_NAME in HP-UX) NW_INITSCRIPT_FN="/sbin/init.d/netwatch.init" ;; AIX) NW_INITSCRIPT_FN="`grep netwatch /etc/inittab 2>/dev/null | cut -d':' -f4 | cut -d' ' -f1`" ;; SunOS) NW_INITSCRIPT_FN="/etc/init.d/netwatch.init" ;; *) #echo "$OS_NAME is not managed!" return 1 ;; esac if [ -n "$NW_INITSCRIPT_FN" -a -f "$NW_INITSCRIPT_FN" ] ; then NW_INSTPATH="`grep INSTALL_PATH $NW_INITSCRIPT_FN | head -n1 | cut -d'=' -f2 | sed 's/\"//g'`" if [ -z "$NW_INSTPATH" ] ; then return 1 #else #echo "Netwatch installation detected." fi else return 1 fi # Netwatch is installed return 0 } uninstall_netwatch() { #echo "Netwatch installation detected. Proceeding to uninstallation." #echo "Calling $NW_INSTPATH/uninstall.sh" # Actual Netwatch uninstallation $NW_INSTPATH/uninstall.sh silent 2>&1 1> install.log # Workaround for buggy uninstall of Netwatch case $OS_NAME in HP-UX) rm -f /sbin/*.d/*netwatch* ;; AIX) cat /etc/inittab | grep -v netwatch > /etc/inittab.upp mv /etc/inittab.upp /etc/inittab ;; SunOS) rm -f /etc/*.d/*netwatch* ;; esac } # Main entry point # Check if Lansafe is installed detect_lansafe if [ $? -eq 0 ]; then # Proceed to uninstallation uninstall_lansafe fi # Check if Netwatch is installed detect_netwatch if [ $? -eq 0 ]; then # Proceed to uninstallation uninstall_netwatch fi #exit $RETVAL nut-2.8.3/scripts/installer/common/0000755000200500020050000000000015001555411014270 500000000000000nut-2.8.3/scripts/installer/common/string.sh0000644000200500020050000001222314602463167016066 00000000000000initDefines() { i=1 ERR_ROOT="$i";i="`expr $i + 1`" ERR_UNKNOWN_SYS_STR1="$i";i="`expr $i + 1`" ERR_UNKNOWN_SYS_STR2="$i";i="`expr $i + 1`" ERR_UNKNOWN_SYS_STR3="$i";i="`expr $i + 1`" CS_ERR_NO_SERIAL="$i";i="`expr $i + 1`" CS_ERR_NO_NUM="$i";i="`expr $i + 1`" WELCOME_STR1="$i";i="`expr $i + 1`" WELCOME_STR2="$i";i="`expr $i + 1`" WELCOME_STR3="$i";i="`expr $i + 1`" INSTALL_INTRO_STR1="$i";i="`expr $i + 1`" INSTALL_INTRO_STR2="$i";i="`expr $i + 1`" INSTALL_INTRO_STR3="$i";i="`expr $i + 1`" INSTALL_INTRO_STR4="$i";i="`expr $i + 1`" STR_VERSION="$i";i="`expr $i + 1`" DEFAULT_PATH_STR="$i";i="`expr $i + 1`" LICENSE_AGREEMENT_1="$i";i="`expr $i + 1`" LICENSE_AGREEMENT_2="$i";i="`expr $i + 1`" LICENSE_AGREEMENT_3="$i";i="`expr $i + 1`" LICENSE_AGREEMENT_4="$i";i="`expr $i + 1`" LICENSE_AGREEMENT_5="$i";i="`expr $i + 1`" ERR_LIC_AGREE="$i";i="`expr $i + 1`" SUCCESS_INSTALL="$i";i="`expr $i + 1`" UNSUCCESS_INSTALL="$i";i="`expr $i + 1`" INSTALL_PACKAGE="$i";i="`expr $i + 1`" REMOVE_PACKAGE="$i";i="`expr $i + 1`" INSTALL_ERROR="$i";i="`expr $i + 1`" CS_SEPARATOR_1="$i";i="`expr $i + 1`" CS_WELCOME_1="$i";i="`expr $i + 1`" # UPS server Configuration CS_SERVER_1="$i";i="`expr $i + 1`" CS_SERVER_2="$i";i="`expr $i + 1`" CS_SERVER_3="$i";i="`expr $i + 1`" CS_SERVER_4="$i";i="`expr $i + 1`" CS_SERVER_5="$i";i="`expr $i + 1`" CS_SERVER_6="$i";i="`expr $i + 1`" CS_SERVER_7="$i";i="`expr $i + 1`" CS_SERVER_8="$i";i="`expr $i + 1`" # Select UPS Password CS_PASSWORD_1="$i";i="`expr $i + 1`" CS_PASSWORD_2="$i";i="`expr $i + 1`" CS_PASSWORD_3="$i";i="`expr $i + 1`" CS_PASSWORD_4="$i";i="`expr $i + 1`" #Please review your configuration CS_REVIEW_1="$i";i="`expr $i + 1`" CS_REVIEW_2="$i";i="`expr $i + 1`" CS_REVIEW_3="$i";i="`expr $i + 1`" CS_REVIEW_4="$i";i="`expr $i + 1`" CS_REVIEW_5="$i";i="`expr $i + 1`" CS_REVIEW_6="$i";i="`expr $i + 1`" CS_REVIEW_7="$i";i="`expr $i + 1`" CS_REVIEW_8="$i";i="`expr $i + 1`" CS_REVIEW_9="$i";i="`expr $i + 1`" CS_REVIEW_10="$i";i="`expr $i + 1`" CS_CONNECTIVITY_1="$i";i="`expr $i + 1`" CS_CONNECTIVITY_2="$i";i="`expr $i + 1`" CS_CONNECTIVITY_3="$i";i="`expr $i + 1`" CS_CONNECTIVITY_4="$i";i="`expr $i + 1`" CS_CONNECTIVITY_5="$i";i="`expr $i + 1`" # Verify Detection CS_ASK_SERIAL_1="$i";i="`expr $i + 1`" CS_ASK_SERIAL_2="$i";i="`expr $i + 1`" CS_ASK_SERIAL_3="$i";i="`expr $i + 1`" CS_ASK_SERIAL_4="$i";i="`expr $i + 1`" CS_ASK_SERIAL_5="$i";i="`expr $i + 1`" CS_ASK_SERIAL_6="$i";i="`expr $i + 1`" # Choose serial device CS_SERIAL_1="$i";i="`expr $i + 1`" CS_SERIAL_3="$i";i="`expr $i + 1`" CS_SERIAL_4="$i";i="`expr $i + 1`" # Manually choose serial device CS_MANUAL_SERIAL_1="$i";i="`expr $i + 1`" CS_MANUAL_SERIAL_2="$i";i="`expr $i + 1`" CS_MANUAL_SERIAL_3="$i";i="`expr $i + 1`" CS_MANUAL_SERIAL_ERR="$i";i="`expr $i + 1`" # SNMP Configuration CS_SNMP_1="$i";i="`expr $i + 1`" CS_SNMP_2="$i";i="`expr $i + 1`" CS_SNMP_3="$i";i="`expr $i + 1`" CS_SNMP_4="$i";i="`expr $i + 1`" CS_SNMP_5="$i";i="`expr $i + 1`" CS_SNMP_6="$i";i="`expr $i + 1`" CS_SNMP_7="$i";i="`expr $i + 1`" CS_SNMP_8="$i";i="`expr $i + 1`" #0. Go back CS_SNMP_9="$i";i="`expr $i + 1`" #Scan for more UPS CS_SNMP_10="$i";i="`expr $i + 1`" #Starting UPP service CS_START_SERVICE="$i";i="`expr $i + 1`" #LanSafe installation detected. Proceeding to uninstallation. CS_REMOVE_LS="$i";i="`expr $i + 1`" CS_REMOVE_NS="$i";i="`expr $i + 1`" CS_REMOVE_OLDIPP="$i";i="`expr $i + 1`" CS_SHUTOFF_ENABLE_1="$i";i="`expr $i + 1`" CS_SHUTOFF_ENABLE_2="$i";i="`expr $i + 1`" CS_SHUTOFF_DELAY_1="$i";i="`expr $i + 1`" CS_SHUTOFF_DELAY_2="$i";i="`expr $i + 1`" CS_SHUTOFF_DELAY_3="$i";i="`expr $i + 1`" CS_MANAGE_1="$i";i="`expr $i + 1`" CS_MANAGE_2="$i";i="`expr $i + 1`" CS_MANAGE_3="$i";i="`expr $i + 1`" CS_MANAGE_4="$i";i="`expr $i + 1`" CS_NETWORK_1="$i";i="`expr $i + 1`" CS_NETWORK_2="$i";i="`expr $i + 1`" CS_NETWORK_3="$i";i="`expr $i + 1`" CS_NETWORK_4="$i";i="`expr $i + 1`" CS_NETWORK_5="$i";i="`expr $i + 1`" CS_ANOTHER_UPS_1="$i";i="`expr $i + 1`" CS_ANOTHER_UPS_2="$i";i="`expr $i + 1`" CS_ANOTHER_UPS_3="$i";i="`expr $i + 1`" CS_ANOTHER_UPS_4="$i";i="`expr $i + 1`" CS_ANOTHER_UPS_5="$i";i="`expr $i + 1`" CS_ANOTHER_UPS_6="$i";i="`expr $i + 1`" CS_MINSUP_1="$i";i="`expr $i + 1`" CS_MINSUP_2="$i";i="`expr $i + 1`" CS_REMOVE_UPS_1="$i";i="`expr $i + 1`" CS_REMOVE_UPS_2="$i";i="`expr $i + 1`" CS_NMC_LOGIN_1="$i";i="`expr $i + 1`" CS_NMC_LOGIN_2="$i";i="`expr $i + 1`" CS_NMC_LOGIN_3="$i";i="`expr $i + 1`" CS_NMC_LOGIN_4="$i";i="`expr $i + 1`" CS_ERR_PASSWORDS_DIFFER="$i";i="`expr $i + 1`" CS_CLIENT_SD_DURATION_1="$i";i="`expr $i + 1`" CS_CLIENT_SD_DURATION_2="$i";i="`expr $i + 1`" CS_XML_MANU_AUTO_1="$i";i="`expr $i + 1`" CS_XML_MANU_AUTO_2="$i";i="`expr $i + 1`" CS_XML_MANU_AUTO_3="$i";i="`expr $i + 1`" CS_XML_MANU_AUTO_4="$i";i="`expr $i + 1`" CS_XML_MANU_AUTO_5="$i";i="`expr $i + 1`" CS_XML_MANU_AUTO_6="$i";i="`expr $i + 1`" CS_XML_MANU_1="$i";i="`expr $i + 1`" CS_XML_MANU_2="$i";i="`expr $i + 1`" CS_STATIC_POWERCYCLE_1="$i";i="`expr $i + 1`" CS_STATIC_POWERCYCLE_2="$i";i="`expr $i + 1`" CS_ERR_BADSTRING="$i";i="`expr $i + 1`" CS_ESDTIMER_1="$i";i="`expr $i + 1`" CS_ESDTIMER_2="$i";i="`expr $i + 1`" } necho() { lineStr="`head -$1 $installres |tail -1`" echo "$lineStr""$2""$3""$4""$5""$6""$7""$8""$9" } nut-2.8.3/scripts/installer/common/solaris_init0000755000200500020050000000227314602463167016655 00000000000000#!/sbin/sh #init.d script to start nut services for IPP - Unix on Solaris # Customizations copyright (c) 2015, by Eaton (R) Corporation. All rights reserved. NUT_DIR="/usr/local/ups" LD_LIBRARY_PATH="$NUT_DIR/lib" export LD_LIBRARY_PATH SHUTDOWN_TIMER=-1 if [ -f ${NUT_DIR}/etc/ipp.conf ]; then . ${NUT_DIR}/etc/ipp.conf fi ups_stop () { pkill -n upsmon pkill -n upsd "$NUT_DIR"/bin/upsdrvctl stop > /dev/null 2>&1 } ups_start () { echo "in ups start function" "$NUT_DIR"/bin/upsdrvctl start #> /dev/null 2>&1 "$NUT_DIR"/sbin/upsd #> /dev/null 2>&1 if [ "$SHUTDOWN_TIMER" -gt -1 ]; then # This host wants early shutdown support, must be root ${NUT_DIR}/sbin/upsmon -p #> /dev/null 2>&1 else ${NUT_DIR}/sbin/upsmon #> /dev/null 2>&1 fi "$NUT_DIR"/init #> /dev/null 2>&1 } case $1 in 'start') ups_start ;; 'stop') ups_stop ;; 'restart') ups_stop while pgrep upsd > /dev/null do sleep 1 done while pgrep upsmon > /dev/null do sleep 1 done while pgrep netxml-ups > /dev/null do sleep 1 done while pgrep snmp-ups > /dev/null do sleep 1 done ups_start ;; *) echo "" echo "Usage: '$0' {start | stop | restart }" echo "" exit 64 ;; esac exit $? nut-2.8.3/scripts/installer/common/ipp-wrapper0000755000200500020050000000223314602463167016420 00000000000000#!/bin/sh # ipp-wrapper # # Copyright (c) 2017, by Eaton (R) Corporation. All rights reserved. # # A shell script to manipulate the environment variables needed for # IPP-Unix programs to dynamically link with their bundled libraries. # # Global variables # NUT_DIR="/usr/local/ups" NUT_BIN_DIR="$NUT_DIR/bin" NUT_SBIN_DIR="$NUT_DIR/sbin" NUT_LIB_DIR="$NUT_DIR/lib" PROGNAME="`basename $0`" if [ "$PROGNAME" = "ipp-wrapper" ]; then echo "This is a wrapper to call other programs; do not call it directly!" >&2 exit 0 fi # Use potentially external /bin/test (/bin/[) for the last time... PROGTYPE="" if [ -x "$NUT_BIN_DIR/$PROGNAME" ]; then PROGTYPE="bin" else if [ -x "$NUT_SBIN_DIR/$PROGNAME" ]; then PROGTYPE="sbin" fi fi # Do not run any other external program after this point, as it may # fail expecting different shared libraries. LD_LIBRARY_PATH="$NUT_LIB_DIR:/usr/lib:/lib:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH case "$PROGTYPE" in bin) exec "$NUT_BIN_DIR/$PROGNAME" "$@" ;; sbin) exec "$NUT_SBIN_DIR/$PROGNAME" "$@" ;; esac echo "FATAL: Program named '$PROGNAME' not found among IPP-Unix binaries" >&2 exit 1 nut-2.8.3/scripts/installer/common/ipp-notifier.sh0000644000200500020050000001316314602463167017171 00000000000000#!/bin/sh # ipp-notifier # # Copyright (c) 2013-2017, by Eaton (R) Corporation. All rights reserved. # # A shell script to send e-mail from IPP - Unix (NUT) # Sends an email messages to one user to notify of a power event. # # Requires configuration from ipp.conf, or otherwise default to the values below # # MC2 Sync: # mc2/scripts/lang/eng.lbl (msg) # mc2/scripts/libs/labels.js (ldate, nodeName, Default{Subject,Message} # # TODO per IPSSUNIX-36: # * There is no error-checking, e.g. a `mailx` command can break due to # unknown parameters (say, `smtp-use-starttls` is not known in Solaris) # * The two codepaths for email are a) local delivery with no "@" in # recipient, or b) Full delivery using a remote relay, with account # and password, etc. - assuming all variables for this are configured. # There is no codepath for delivery to remote account via local relay. NUT_DIR="/usr/local/ups" NUT_CFG_DIR="" for D in "$NUT_DIR/etc" "/etc/nut" "/etc/ups" ; do if [ -d "$D" ] && [ -f "$D/ups.conf" ] && [ -f "$D/ipp.conf" ] ; then NUT_CFG_DIR="$D" break fi done unset D CONFIG_IPP="$NUT_CFG_DIR/ipp.conf" PATH="$PATH:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/usr/ucb:/usr/ccs/bin:/usr/xpg4/bin:/usr/xpg6/bin" # Note: $NUT_DIR/xbin holds the wrappers to run NUT binaries with co-bundled # third party libs and hopefully without conflicts induced for the OS binaries # Use them first! PATH="$NUT_DIR/xbin:$NUT_DIR/sbin:$NUT_DIR/bin:$PATH" export PATH # Search for binaries under current PATH normally, no hardcoding. Scripts: NUT_IPP_OS_SHUTDOWN="ipp-os-shutdown" NUT_IPPSTATUS="ipp-status" #NUT_IPP_OS_SHUTDOWN="$NUT_DIR/sbin/ipp-os-shutdown" #NUT_IPPSTATUS="$NUT_DIR/bin/ipp-status" # Set default values # Notification configuration MAIL_NOTIF=1 CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 # Mail configuration (simple (Lansafe) version) To_User="root" # NOTE: for systems with role-based access and equivalents, or # group-suid for /sbin/shutdown, etc. it may also be possible # to allow "ipp" directly to use the command - in this case # set SHUTDOWN_NEEDS_ROOT=0 in the $CONFIG_IPP file. SHUTDOWN_NEEDS_ROOT=1 SHUTDOWN_TIMER=-1 # Commands CMD_WALL="wall" CMD_MAIL="mailx -n" CMD_SYSLOG="logger" # Create the message parts ldate="`date +\"%y-%m-%d - %H:%M:%S\"`" nodeName="$UPSNAME@`hostname`" DefaultSubject="Intelligent Power Protector (IPP) Alarms" DefaultMessage="Alarm from ${nodeName}:\n\n\t${ldate} - $*" NeedRootMessage="WARNING: ipp-notifier.sh must run as root to request/cancel OS shutdown\nConsider changing the NUT init script to start 'upsmon -p' so you can use SHUTDOWN_TIMER>=0" #...or change upsmon.conf to contain "RUN_AS_USER root" # Include IPP ipp.conf (may overwrite the above default values!) if [ -f "$CONFIG_IPP" ] ; then . "$CONFIG_IPP" fi if [ "$SHUTDOWN_NEEDS_ROOT" = 1 ] && [ "$SHUTDOWN_TIMER" -gt -1 ] 2>/dev/null ; then who="`whoami 2>/dev/null`" if [ "$who" != 'root' ]; then #work around in case no whoami is present who="`id -u 2>/dev/null`" if [ "$who" != '0' ]; then who="`id 2>/dev/null | grep -w '0' | grep -w root`" if [ -z "$who" ]; then DefaultMessage="$DefaultMessage\n$NeedRootMessage" fi fi fi fi if [ "$IPP_DEBUG" = yes ] ; then exec >> /var/tmp/ipp-notifier.log 2>&1 echo "`date`: Started: $0 $*" >&2 set >&2 set -x fi # Console notification if [ "$CONSOLE_NOTIF" -eq 1 ]; then echo "$DefaultSubject\n\n$DefaultMessage" | $CMD_WALL fi # Mail notification OTHER_OPT="" if [ "$MAIL_NOTIF" -eq 1 ]; then echo "$To_User" | grep "@" if [ $? -eq 1 ] then # Simple (Lansafe / local) version env MAILRC=/dev/null echo "$DefaultMessage" | $CMD_MAIL -s "$DefaultSubject" $To_User else # GMail need starttls echo "$SMTP_Server" | grep "gmail.com" if [ $? -eq 0 ]; then OTHER_OPT="-S smtp-use-starttls" fi env MAILRC=/dev/null echo -e "$DefaultMessage" | $CMD_MAIL -s "$DefaultSubject" \ -S from="$SMTP_User" \ -S smtp="smtp://$SMTP_Server" \ -S smtp-auth-user="$SMTP_User" \ -S smtp-auth-password="$SMTP_Password" \ -S smtp-auth=login \ -S ssl-verify=ignore $OTHER_OPT \ $To_User fi fi # System log notification if [ "$SYSLOG_NOTIF" -eq 1 ]; then $CMD_SYSLOG -t eaton-ipp "$*" fi # Scheduled shutdown - request or cancel based on this variable and on # the UPS state (amount of ONLINE sources under the MINSUPPLIES or not?) if [ "$SHUTDOWN_TIMER" -gt -1 ] 2>/dev/null; then # Note this status check clears any invalid PIDfiles SD_STATUS="`${NUT_IPP_OS_SHUTDOWN} status`" SD_STATE=$? ${NUT_IPPSTATUS} -q if [ $? -eq 1 ] ; then if [ "$SD_STATE" = 0 ]; then ${NUT_IPP_OS_SHUTDOWN} & sleep 5 # Let the script begin its work and PIDfiles ${NUT_IPP_OS_SHUTDOWN} status SD_STATE=$? if [ "$SD_STATE" -gt 0 ]; then echo "Shutdown delayed by ${SHUTDOWN_TIMER}m was requested at ${ldate}" echo "${DefaultSubject}\nPowerfail-shutdown delayed by ${SHUTDOWN_TIMER}m was requested at ${ldate}" | $CMD_WALL 2>/dev/null else # Nothing pending nor irreversible echo "FAILED TO REQUEST a Shutdown delayed by ${SHUTDOWN_TIMER}m at ${ldate}" echo "${DefaultSubject}\nFAILED TO REQUEST a Powerfail-shutdown delayed by ${SHUTDOWN_TIMER}m at ${ldate}" | $CMD_WALL 2>/dev/null fi else echo "Shutdown request already running" fi else if [ "$SD_STATE" = 1 ]; then # Cancel any pending not-irreversible shutdown if ${NUT_IPP_OS_SHUTDOWN} -c ; then echo "Shutdown request canceled" echo "${DefaultSubject}\nPowerfail-shutdown request canceled at ${ldate}" | $CMD_WALL 2>/dev/null else echo "Could not cancel Shutdown request" echo "${DefaultSubject}\nPowerfail-shutdown request NOT CANCELED at ${ldate}" | $CMD_WALL 2>/dev/null fi fi fi fi nut-2.8.3/scripts/installer/common/ipp-host-shutdown.sample0000644000200500020050000000544614602463167021054 00000000000000#!/bin/sh # # Script for custom emergency powerfail shutdown of a host to do actions that # were not implemented as part of normal OS shutdown routine for some reason. # Must run as root or with sufficient privileges to execute the actions. # Can print to >&3 some shell lines that would be sourced by the main script. # Copyright (c) 2013-2015, by Eaton (R) Corporation. All rights reserved. # # Note: This file (ipp-host-shutdown.sample) is delivered by the package and # will be overwritten in case of upgrades. It is an example implementation of # a host-specific shutdown routine; make a copy, preferably with a name unique # to a host-role in your deployment, and reference it from `ipp.conf` with the # `SHUTDOWNSCRIPT_CUSTOM` variable. # Notification configuration is normally exported by `ipp-os-shutdown` #CONSOLE_NOTIF=1 #SYSLOG_NOTIF=1 #CMD_WALL="wall" #CMD_SYSLOG="logger" [ -z "${DefaultSubject-}" ] && \ DefaultSubject="Intelligent Power Protector (IPP) Emergency Shutdown" [ -z "${MessageCustomShutdownStarting_s-}" ] && \ MessageCustomShutdownStarting_s="Initiating custom shutdown for %s..." [ -z "${MessageCustomShutdownCompleted_s-}" ] && \ MessageCustomShutdownCompleted_s="Custom shutdown for %s is completed" [ -z "${MessageIrreversibleTrap-}" ] && \ MessageIrreversibleTrap="Sorry, the powerfail shutdown is now irreversible, you should not abort it!" # String with current timestamp (for logging) ldate="" get_ldate() { ldate="`date +\"%y-%m-%d - %H:%M:%S\"`" && return 0 # Optional first argument can contain the default value if [ -n "$1" ] ; then ldate="$1" ; else ldate="`date`"; fi } logmsg() { # The argument string is wrapped with formalities and # logged into echo > stdout, syslog and wall echo "${ldate}: $*" if [ "$CONSOLE_NOTIF" -eq 1 -a -n "$CMD_WALL" ]; then echo "${DefaultSubject}\n$* at ${ldate}" | $CMD_WALL 2>/dev/null fi if [ "$SYSLOG_NOTIF" -eq 1 -a -n "$CMD_SYSLOG" ]; then $CMD_SYSLOG -t eaton-ipp "$*" 2>/dev/null fi } # The custom shutdown routine if clusterware is present if [ -x /etc/init.d/NONEXISTENT/clusterware ]; then get_ldate logmsg $(printf "$MessageCustomShutdownStarting_s" "clusterware") trap 'echo "$MessageIrreversibleTrap">&2' 1 2 3 15 # Launch the cluster shutdown command /etc/init.d/NONEXISTENT/clusterware stop # Sleep after/during(?) cluster shutdown # This cycle allows to keep ignoring CTRL+C and equivalents # (a single sleep is indeed broken out of despite our traps) N=300 while [ $N -gt 0 ]; do N="`expr $N - 1`" sleep 1 done # By default, after clusterware stop there's nothing fragile left # so we can ask for fast shutdown [ -z "${SDFLAG_COMMONOPTIONS-}" ] && \ echo 'SDFLAG_COMMONOPTIONS="$SDFLAG_UNGRACEFUL"' >&3 get_ldate logmsg $(printf "$MessageCustomShutdownCompleted_s" "clusterware") trap '-' 1 2 3 15 fi exit 0 nut-2.8.3/scripts/installer/common/shutdown0000755000200500020050000000664514777767434016061 00000000000000#!/bin/sh # shutdown # # Copyright (c) 2013-2017, by Eaton (R) Corporation. All rights reserved. # # A shell script to command UPSes to power off and back on as part of # the emergency shutdown driven by IPP - Unix (NUT); called from upsmon # # Requires configuration from ipp.conf, or otherwise default to the values below # Also requires matching features to be available in the UPSes and their drivers # # TODO remaining per IPSSUNIX-25: # * The script acts on ALL UPSes configured on this system (`upsc -l`), # rather than those MONITORed as feeding a non-zero amount # power-sources in `upsmon.conf` # * Consider the KILLPOWER flag-file (maybe this host should not power # off any UPS at all?) # * The username is hardcoded as `admin` rather than taken from config # * Maybe we do not try every possible instcmd for UPS poweroff/reboot - # revise against upsrw and upscmd for NETXML and SNMP drivers at least # NUT_DIR="/usr/local/ups" NUT_CFG_DIR="" for D in "$NUT_DIR/etc" "/etc/nut" "/etc/ups" ; do if [ -d "$D" ] && [ -f "$D/ups.conf" ] && [ -f "$D/ipp.conf" ] ; then NUT_CFG_DIR="$D" break fi done unset D CONFIG_IPP="$NUT_CFG_DIR/ipp.conf" # Note: $NUT_DIR/xbin holds the wrappers to run NUT binaries with co-bundled # third party libs and hopefully without conflicts induced for the OS binaries PATH="$NUT_DIR/xbin:$NUT_DIR/sbin:$NUT_DIR/bin:$PATH" export PATH # Search for binaries under current PATH normally, no hardcoding NUT_UPSC="upsc" NUT_UPSCMD="upscmd" NUT_UPSRW="upsrw" #NUT_UPSC="$NUT_DIR/xbin/upsc" #NUT_UPSCMD="$NUT_DIR/xbin/upscmd" #NUT_UPSRW="$NUT_DIR/xbin/upsrw" # Do not normally mangle the LD_LIBRARY_PATH - it can impact system tools too #LD_LIBRARY_PATH="$NUT_DIR/lib:/usr/lib:/lib:$LD_LIBRARY_PATH" #export LD_LIBRARY_PATH # This can be set by `ipp-os-shutdown` script, including via '-k' flag CALLER_POWERDOWNFLAG_USER="${POWERDOWNFLAG_USER-}" # Include IPP ipp.conf (may overwrite the above default values!) to # get shutdown delay and admin password if [ -f "$CONFIG_IPP" ] ; then . "$CONFIG_IPP" fi if [ "$IPP_DEBUG" = yes ] ; then exec >> /var/tmp/ipp-shutdown.log 2>&1 echo "`date`: Started shutting down: $0 $*" >&2 set >&2 set -x fi # If config forbids powercycling, and the caller does not require it, # then do not do it [ "$CALLER_POWERDOWNFLAG_USER" != "enforce" ] && \ [ "$POWERDOWNFLAG_USER" = "forbid" ] && exit 0 # We need a number here, otherwise the UPS stays off # TODO: Consider "shutdown_duration" if netxml_ups is set up? # TODO: Do this per ups (move into the loop below then)? if test -n "$DELAY" && test "$DELAY" -ge 0 ; then true; else DELAY=120; fi DELAYON="`expr $DELAY + 10`" # TODO: Here we want to refine the list to only MONITORed UPSes that power us # and/or take into account the killpower flag-file (upsmon master vs. slave # and/or `upsmon -k` status) # Convert to parsing of "ipp-status -p" which reports all needed details upslist="`"$NUT_UPSC" -l`" echo "$upslist" # NOTE: not all UPSes and not all drivers support all possible instcmd's # so we try as many as possible for u in $upslist; do echo "Configuring poweroff-poweron for UPS '$u' ..." "$NUT_UPSCMD" -u admin -p "$PASSWORD" "$u" load.on.delay "$DELAYON" "$NUT_UPSCMD" -u admin -p "$PASSWORD" "$u" load.off.delay "$DELAY" for o in 3 2 1 ; do "$NUT_UPSRW" -s "outlet.$o.delay.start"="$DELAYON" \ -u admin -p "$PASSWORD" "$u" "$NUT_UPSRW" -s "outlet.$o.delay.shutdown"="$DELAY" \ -u admin -p "$PASSWORD" "$u" done done nut-2.8.3/scripts/installer/common/ipp-status0000755000200500020050000002777014602463167016300 00000000000000#!/bin/sh # ipp-status # # Copyright (c) 2013-2017, by Eaton (R) Corporation. All rights reserved. # # A shell script to request UPS status (power state, runtime remaining) # with upsc and aggregate the results as a table and an exit-status that # can be inspected to see if the system is reliably protected or should # better go into shut-down. Uses configuration variables of upsmon.conf. # # Global variables # NUT_DIR="/usr/local/ups" NUT_CFG_DIR="" for D in "$NUT_DIR/etc" "/etc/nut" "/etc/ups" ; do if [ -d "$D" ] && [ -f "$D/ups.conf" ] && [ -f "$D/ipp.conf" ] ; then NUT_CFG_DIR="$D" break fi done unset D CONFIG_UPSMON="$NUT_CFG_DIR/upsmon.conf" CONFIG_IPP="$NUT_CFG_DIR/ipp.conf" # Do not normally mangle the LD_LIBRARY_PATH - it can impact system tools too #LD_LIBRARY_PATH="$NUT_DIR/lib:/usr/lib:/lib:$LD_LIBRARY_PATH" #export LD_LIBRARY_PATH # Note: $NUT_DIR/xbin holds the wrappers to run NUT binaries with co-bundled # third party libs and hopefully without conflicts induced for the OS binaries PATH="$NUT_DIR/xbin:$NUT_DIR/sbin:$NUT_DIR/bin:$PATH" export PATH # Search for binaries under current PATH normally, no hardcoding NUT_UPSC="upsc" #NUT_UPSC="$NUT_DIR/xbin/upsc" # Flag for support (or not) of early-shutdown on this host SHUTDOWN_TIMER=-1 # Include IPP ipp.conf (may overwrite the above default values!) if [ -f "$CONFIG_IPP" ] ; then . "$CONFIG_IPP" fi # # We need capable awk # awk="awk" # On Solaris, the default awk is a simple implementation # lacking certain functions (most notably the match builtin function). # Luckily, nawk is present to save the day... test "`uname -s`" = "SunOS" && awk="nawk" # # Default settings # overall_status_enabled="yes" overall_status_mode="verbose" devices_status_enabled="yes" devices_formatted="yes" # # Get devices info, mixing config and runtime info # Note that some other scripts may be parsing this via "ipp-status -d", # so only append fields in the end as this evolves # get_devices_info() { for dev in `$awk '/^MONITOR / { print $2 }' "$CONFIG_UPSMON"`; do status="`$NUT_UPSC "$dev" ups.status 2>/dev/null`" runtime="`$NUT_UPSC "$dev" battery.runtime 2>/dev/null`" batterypct="`$NUT_UPSC "$dev" battery.charge 2>/dev/null`" supplies="`get_pwr_value "$dev" | egrep '^[0-9]*$'`" upsmon_ms="`get_ms_value "$dev" | egrep 'master|slave'`" echo "$dev:$status:$runtime:$batterypct:$supplies:$upsmon_ms" done } # # Get minimum of required power supplies # get_min_supplies() { $awk '/^[ \t]*MINSUPPLIES/ { print $2 }' \ "$CONFIG_UPSMON" 2>/dev/null } # # Get a UPS power value (count of this host's power sources fed by UPS=="$1") # get_pwr_value() { $awk '/^[ \t]*MONITOR/ { if (match($2, /'"$1"'(@.*)?/)) print $3; }' "$CONFIG_UPSMON" 2>/dev/null } # # Get a UPS master/slave value (influences shutdown sequence and poweroffs) # get_ms_value() { $awk '/^[ \t]*MONITOR/ { if (match($2, /'"$1"'(@.*)?/)) print $NF; }' "$CONFIG_UPSMON" 2>/dev/null # NF: This is last field in MONITOR line. Or 6th. Currently... } # # Overall status resolution - parsing helpers # parse_protectors_knowngood() { # Lists the UPSes which are known to this host and have stable power # (no regard to how many sources of this host they actually feed) onbattery_sdtimer="$1" # set to yes to trigger a shutdown timer # when UPS are on battery $awk -v ob_sdtimer="${onbattery_sdtimer}" -F: ' { status = $2; # UPS on bypass does not protect anything if (match(status, /^OL BYPASS/)) ; # Other online states are OK else if (match(status, /^OL/)) print $1; # UPS on exhausted battery does not protect anything else if (match(status, /^OB LB/)) ; # - NOK when onbattery_sdtimer = yes # - OK otherwise else if (match(status, /^OB/)) if (match(ob_sdtimer, /^yes/)) ; else print $1; } ' | sort | uniq } parse_protectors_unknown() { # Lists the UPSes which are known to this host but have unknown power # state (e.g. communications not established, driver died, initially # WAITing for data after driver startup, etc.) - without regard as to # how many sources of this host they actually feed $awk -F: ' { status = $2; # Do not cause immediate shutdown if UPS is not accessible # (driver or connection failure) if (status == "") print $1; # Do not cause immediate shutdown when waiting for UPS data else if (match(status, /WAIT/)) print $1; } ' | sort | uniq } # # Overall status resolution - primary logic # overall_status() { devices_info="$1" onbattery_sdtimer="$2" # set to yes to trigger a shutdown timer # when UPS are on battery # Get non-low battery UPSes (still protecting the system) protectors="`echo "$devices_info" | parse_protectors_knowngood "${onbattery_sdtimer}"`" protectors_unknown="`echo "$devices_info" | parse_protectors_unknown`" # Get total powervalue of protecting UPSes protectors_pwr_value=0 protectors_unknown_pwr_value=0 not_protectors=0 for ups in $protectors; do pwr_value="`get_pwr_value "$ups"`" test -n "$pwr_value" || pwr_value=1 if test "$pwr_value" -eq 0 ; then not_protectors="`expr $not_protectors + 1`" else protectors_pwr_value="`expr $protectors_pwr_value + $pwr_value`" fi done for ups in $protectors_unknown; do pwr_value="`get_pwr_value "$ups"`" test -n "$pwr_value" || pwr_value=1 if test "$pwr_value" -eq 0 ; then not_protectors="`expr $not_protectors + 1`" else protectors_unknown_pwr_value="`expr $protectors_unknown_pwr_value + $pwr_value`" fi done # Resolve system protection status overall_status_str="protected" min_supplies="`get_min_supplies`" \ && test -n "$min_supplies" \ && test "$min_supplies" -ge 0 \ || min_supplies=1 # Zero is a resonable value - monitoring station that doesn't shut down min_supplies_eff="$min_supplies" if test "$protectors_unknown_pwr_value" -gt 0; then min_supplies_eff="`expr $min_supplies - $protectors_unknown_pwr_value`" test "$min_supplies_eff" -ge 0 || min_supplies_eff=0 fi if test "$protectors_pwr_value" -lt "$min_supplies_eff"; then overall_status_str="unprotected" fi # Overall status indication by exit code if test "$overall_status_mode" = "silent"; then test "$overall_status_str" = "unprotected" && exit 1 exit 0 # Short form of overall status elif test "$overall_status_mode" = "short"; then echo "$overall_status_str" # Verbose form of overall status elif test "$overall_status_str" = "unprotected"; then cat </dev/null ; then echo "Also, $not_protectors device(s) that do not feed this host are known and monitored" fi case "$onbattery_sdtimer" in [Yy][Ee][Ss]) if test "$min_supplies_eff" != "$min_supplies" ; then echo "WARNING: Some UPSes are not available, but we ignored them since onbattery_sdtimer=yes" >&2 fi ;; esac test "$overall_status_str" = "unprotected" && return 1 return 0 } # # Devices status resolution # devices_status() { devices_info="$1" # No UPS devices found if test -z "$devices_info"; then cat < t) { sig = "-"; t = -t; } ss = t % 60; t = int(t / 60); mm = t % 60; h = int(t / 60); if (length(ss) < 2 && (0 != mm || 0 != h)) ss = "0" ss; t = ss; if (0 != mm || 0 != h) { if (length(mm) < 2 && 0 != h) mm = "0" mm; t = mm ":" t; if (0 != h) t = h ":" t; } return sig t; } BEGIN { external_settings(); id_width = 20; status_width = 15; runt_width = 10; chrg_width = 8; sources_width = 8; upsmonms_width= 7; format_str = "%-" id_width "s%-" status_width "s%" runt_width "s%" chrg_width "s%" sources_width "s %-" upsmonms_width "s\n"; if (devices_formatted) { printf("\nDevices status:\n\n"); printf(format_str, "Identifier", "Status", " Runtime", "Charge%", "Sources", "UPSMon"); printf(format_str, "----------", "------", "--------", "-------", "-------", "------"); } } { id = $1; status = $2 runtime = $3; charge = $4; sources = $5; upsmon_ms = $6; # Resolve basic status if (status == "") status_str = "unknown"; else if (match(status, /WAIT/)) status_str = "unknown"; else if (match(status, /^OL BYPASS/)) status_str = "on bypass"; else if (match(status, /^OL/)) status_str = "online"; else if (match(status, /^OB LB/)) status_str = "low battery"; else if (match(status, /^OB/)) status_str = "on battery"; else if (match(status, /OFF/)) status_str = "off"; else if (match(status, /FSD/)) status_str = "forced shutdown"; else status_str = "\"" status "\""; # Resolve status modifications if (match(status, /OVER/)) status_str = status_str " (OVERLOADED)"; else if (match(status, /TRIM/) || match(status, /BOOST/)) status_str = status_str " (improving mains)"; if (devices_formatted) { if (runtime != "") runtime = t2h_mm_ss(runtime); else runtime = "unknown"; printf(format_str, id, status_str, runtime, charge, sources, upsmon_ms); } else { if (runtime != "") runtime = int(runtime); else runtime = "unknown"; print id ":" status_str ":" runtime ":" charge ":" sources ":" upsmon_ms; } } ' } # # Usage # usage() { this="`basename $0`" cat <&2 # Process options set -- $options while test "$1" != "--"; do case "$1" in -h) # Print usage usage_and_exit 0 ;; -S) # Don't show overall status overall_status_enabled="no" ;; -s) # Short overall status indication overall_status_mode="short" ;; -q) # Silent overall status indication overall_status_mode="silent" devices_status_enabled="no" ;; -D) # Don't show devices status devices_status_enabled="no" ;; -d) # Devices status shall not be formatted devices_formatted="no" ;; -p) # Devices status shall not be formatted devices_formatted="no" # Don't show overall status overall_status_enabled="no" ;; esac # Next option shift done # Shift the final "--" shift # # Main # onbattery_sdtimer="no" if test "$SHUTDOWN_TIMER" -gt -1 2>/dev/null ; then onbattery_sdtimer="yes" fi # Get devices info devices_info="`get_devices_info`" # Overall status if test "$overall_status_enabled" = "yes"; then overall_status "$devices_info" "$onbattery_sdtimer" fi # Devices status if test "$devices_status_enabled" = "yes"; then devices_status "$devices_info" fi nut-2.8.3/scripts/installer/common/ipp-os-shutdown0000755000200500020050000003735714602463167017251 00000000000000#!/bin/sh # # ipp-os-shutdown # # Copyright (c) 2015-2017, by Eaton (R) Corporation. All rights reserved. # # A shell script to manage the emergency shutdown driven by IPP - Unix # (NUT) in a way that can be customized more easily; called from upsmon # # Requires configuration from ipp.conf and upsmon.conf, or otherwise defaults # to the values below # usage() { echo "Usage: $0 [-t timespec | +mins] [-h|-p|-r] [-k|-K]" echo "Usage: $0 -c | cancel" echo "Usage: $0 -s | status" echo "Usage: $0 --help" echo " -t timespec 0+ minutes to delay before proceeding or 'now'==0" echo " +minutes 0+ minutes to delay before proceeding" echo " -h | -p | -r Passed to the OS shutdown command (halt/poweroff/reboot)" echo " -k | -K Enforce or forbid calls to request UPS powercycling" echo " Otherwise rely on KILLPOWER file as managed by upsmon" echo " -c = cancel Cancel a pending shutdown, if any" echo " -s = status Return simple status (string and code) of pending shutdown" } # # Global variables # NUT_DIR="/usr/local/ups" NUT_RUN_DIR="/var/run/nut" NUT_CFG_DIR="" for D in "$NUT_DIR/etc" "/etc/nut" "/etc/ups" ; do if [ -d "$D" ] && [ -f "$D/ups.conf" ] && [ -f "$D/ipp.conf" ] ; then NUT_CFG_DIR="$D" break fi done unset D CONFIG_IPP="$NUT_CFG_DIR/ipp.conf" CONFIG_UPSMON="$NUT_CFG_DIR/upsmon.conf" POWERDOWNFLAG="$NUT_CFG_DIR/killpower" if [ ! -w "$NUT_CFG_DIR" ] ; then echo "WARNING: Configuration directory $NUT_CFG_DIR is not writable by this user," echo " it may be a problem to save the 'killpower' flag file when needed." fi >&2 # Note: $NUT_DIR/xbin holds the wrappers to run NUT binaries with co-bundled # third party libs and hopefully without conflicts induced for the OS binaries PATH="$NUT_DIR/xbin:$NUT_DIR/sbin:$NUT_DIR/bin:$PATH" export PATH # Search for binaries under current PATH normally, no hardcoding NUT_UPSC="upsc" NUT_UPSCMD="upscmd" NUT_UPSRW="upsrw" NUT_UPSMON="upsmon" #NUT_UPSC="$NUT_DIR/xbin/upsc" #NUT_UPSCMD="$NUT_DIR/xbin/upscmd" #NUT_UPSRW="$NUT_DIR/xbin/upsrw" #NUT_UPSMON="$NUT_DIR/xbin/upsmon" # Scripts: NUT_IPPSTATUS="ipp-status" NUT_UPS_SHUTDOWN="shutdown" #NUT_IPPSTATUS="$NUT_DIR/bin/ipp-status" #NUT_UPS_SHUTDOWN="$NUT_DIR/shutdown" # If present and executable, it is called for individual host's additional # shutdown routines. SHUTDOWNSCRIPT_CUSTOM="" # Store the optional -k/-K request to "enforce" or "forbid" powercycling # May be overridden by the ipp.conf, though intended for CLI usage. POWERDOWNFLAG_USER="" SHUTDOWN_PIDFILE="${NUT_RUN_DIR}/shutdown.pid" SHUTDOWN_TIMER=-1 # Set default values # Notification configuration CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 CMD_WALL="wall" CMD_SYSLOG="logger" #################### THE OS SHUTDOWN PROGRAM SETTINGS ################## # The following flags may be OS-dependent and so overridden in the # config file below. Depending on OS and hardware support, "poweroff" # may tell the powersources to cut the power, and "halt" may sit # forever at the "OS is stopped" prompt or equivalent. SDFLAG_POWEROFF="-h" SDFLAG_REBOOT="-r" SDFLAG_HALT="-p" # The flag for quick stop (shorter service stop timeouts and fewer/no # logs, or outright go to kill remaining processes) SDFLAG_UNGRACEFUL="-F" # Trigger a shutdown without delay (zero delay) SDFLAG_INSTANT="+0" # The program which executes an OS shutdown, maybe including flags that # disable its interactive mode CMD_SHUTDOWN="/usr/sbin/shutdown" # Customize the shutdown command by setting the SDFLAG variables above here: CONFIG_SHUTDOWN="$NUT_DIR/etc/ipp-os-shutdown.conf" ######################################################################## # Potentially localizable message strings; those with s in the name contain # an argument processed as a string via printf; otherwise echo'ed directly DefaultSubject="Intelligent Power Protector (IPP) Emergency Shutdown" MessageIrreversible="Beginning irreversible stage of the powerfail shutdown" MessageIrreversibleTrap="Sorry, the powerfail shutdown is now irreversible, you should not abort it!" MessageTimerAbortedTrap="Delayed powerfail shutdown timer was successfully aborted before it expired" MessageShutdownIsDelayed_s="Powerfail shutdown was scheduled as delayed: sleeping for %s seconds" MessageShutdownNotDelayed="Powerfail: shutting down without delay" MessageCancelingPIDS_s="Canceling delayed powerfail shutdown PID: %s" MessageCannotCancelNone="Nothing scheduled, nothing to cancel" MessageCannotCancelIrrev="Scheduled shutdown is already irreversible, can not cancel it" MessageCannotQueueAnother="Shutdown already pending, cancel it first to queue another one" MessageCustomShutdownStarting_s="Initiating custom shutdown for %s..." MessageCustomShutdownCompleted_s="Custom shutdown for %s is completed" MessageKillpowerFileExists_s="the POWERDOWNFLAG file '%s' exists" MessageKillpowerFileAbsent_s="the POWERDOWNFLAG file '%s' does not exist" MessageKillpowerArgumentExists_s="the POWERDOWNFLAG_USER setting is '%s'" MessageKillpowerArgumentAbsent="the POWERDOWNFLAG_USER setting is empty, relying on POWERDOWNFLAG file (if any)" MessageUPSpowercycleCommandingPoweroff_s="Commanding the UPSes to power off and back on after a delay (%s), and powering this host off unconditionally" MessageUPSpowercycleCommanding_s="Commanding the UPSes to power off and back on after a delay (%s), but still proceeding to OS shutdown to the explicit host power-state requested originally" MessageUPSpowercycleNotCommanding="NOT commanding the UPSes to power-cycle; inspecting external power status at this moment" MessageExtPowerIsBackRebooting="External power is back, rebooting host rather than halting it" MessageExtPowerIsBack="External power is back, but we are still proceeding to OS shutdown to the explicit host power-state requested originally" MessageExtPowerNotBack="External power is not back, proceeding to OS shutdown to the host power-state requested originally" MessageRunningCmd_s="Proceeding to execute: '%s'" ORIG_PARAM_STR="$*" # Include definitions for shutdown flags before ipp.conf, so the latter # can e.g. predefine the $SDFLAG_POWERSTATE_DEFAULT value by name. if [ -f "$CONFIG_SHUTDOWN" ]; then . "$CONFIG_SHUTDOWN" fi # Include IPP ipp.conf (may overwrite the above default values!) if [ -f "$CONFIG_IPP" ]; then . "$CONFIG_IPP" fi # If nothing was set/guessed - use this value: [ -z "${SDFLAG_POWERSTATE_DEFAULT-}" ] && \ SDFLAG_POWERSTATE_DEFAULT="$SDFLAG_POWEROFF" # Default is to do whatever shutdown strategy the OS prefers and maybe # customize below (e.g. do fast shutdown if clusterware is present and # was stopped); override in config file to e.g. " " (space) to disable # this behavior and use the one configured value. [ -z "${SDFLAG_COMMONOPTIONS-}" ] && \ SDFLAG_COMMONOPTIONS="" # When we go into irreversible state, rename the existing PIDfile into this # (or create a new one if existing file disappeared) SHUTDOWN_PIDFILE_IRREVERSIBLE="${SHUTDOWN_PIDFILE}.irreversible" # String with current timestamp (for logging) ldate="" get_ldate() { ldate="`date +\"%y-%m-%d - %H:%M:%S\"`" && return 0 # Optional first argument can contain the default value if [ -n "$1" ] ; then ldate="$1" ; else ldate="`date`"; fi } logmsg() { # The argument string is wrapped with formalities and # logged into echo > stdout, syslog and wall echo "${ldate}: $*" if [ "$CONSOLE_NOTIF" -eq 1 -a -n "$CMD_WALL" ]; then echo "${DefaultSubject}\n$* at ${ldate}" | $CMD_WALL 2>/dev/null fi if [ "$SYSLOG_NOTIF" -eq 1 -a -n "$CMD_SYSLOG" ]; then $CMD_SYSLOG -t eaton-ipp "$*" 2>/dev/null fi } check_pid() { # Returns: PID in $1 is running = 0; not running = 1; syntax errors = 2 [ -n "$1" ] && [ "$1" -gt 0 ] || return 2 [ -d "/proc/$1" ] && return 0 ( (ps -ef || ps -xawwu ) | grep -v grep | egrep "`basename $0`|shutdown" | \ awk '{print $2}' | grep -w "$1" ) 2>/dev/null && return 0 return 1 } check_pids_atleastone() { # Checks all args as PID numbers; if any one is running return 0 for P in "$@"; do check_pid "$P" && return 0 done return 1 } check_pidfile() { # First line of PIDFILE ($1) should contain one or more PIDs # Check if file exists, and any pointed PID is running - then return 0 # No PID is running - return 1 # No file / bad filename / other errors - then return 2 if [ -n "$1" ] && [ -s "$1" ] && [ -r "$1" ]; then PIDS="`head -1 "$1"`" && [ -n "$PIDS" ] || return 2 check_pids_atleastone $PIDS || return 1 return 0 fi return 2 } check_shutting_down() { # IF THE PIDFILE DID NOT PASS A TEST, IT IS REMOVED TO REDUCE CONFUSION # If the SHUTDOWN_PIDFILE_IRREVERSIBLE exists and points to a running # process return 2 # If the SHUTDOWN_PIDFILE exists and the PID pointed by it is running # return 1 - this means we can cancel it (can not queue new one) # If neither file exists nor points to a running process return 0 - # this means we can schedule a shutdown / have nothing to cancel check_pidfile "$SHUTDOWN_PIDFILE_IRREVERSIBLE" && return 2 rm -f "$SHUTDOWN_PIDFILE_IRREVERSIBLE" check_pidfile "$SHUTDOWN_PIDFILE" && return 1 rm -f "$SHUTDOWN_PIDFILE" return 0 } cancel_shutdown() { # If the SHUTDOWN_PIDFILE exists and the PID pointed by it is running # then kill that PID and remove the SHUTDOWN_PIDFILE check_shutting_down case "$?" in 0) echo "$MessageCannotCancelNone"; return 0 ;; 1) PIDS="`head -1 "$SHUTDOWN_PIDFILE"`" && [ -n "$PIDS" ] || return 1 get_ldate logmsg $(printf "${MessageCancelingPIDS_s}\n" "$PIDS") kill -9 $PIDS rm -f "$SHUTDOWN_PIDFILE" "$SHUTDOWN_PIDFILE_IRREVERSIBLE" return 0 ;; 2) echo "$MessageCannotCancelIrrev"; return 2 ;; esac } # Start with an empty value, so in the end if it remains empty # we can apply the default; otherwise - it is user's request. SDFLAG_POWERSTATE="" while [ "$#" -gt 0 ]; do case "$1" in -t) case "$2" in now) SHUTDOWN_TIMER=0 ;; [0-9]) [ "$2" -gt -1 ] && SHUTDOWN_TIMER="$2" || \ echo "Bad time parameter '$1 $2', ignoring" >&2 ;; *) echo "Bad time parameter '$1 $2', ignoring" >&2 ;; esac shift ;; +0) SHUTDOWN_TIMER="0" ;; +[1-9]*) N="`echo "$1" | sed 's,^\+,,'`" && N="`expr 0 + "$N"`" && \ [ "$N" -gt -1 ] && SHUTDOWN_TIMER="$N" || \ echo "Bad time parameter '$1', ignoring" >&2 ;; --help|help) usage; exit 0 ;; -h|--halt) SDFLAG_POWERSTATE="$SDFLAG_HALT" ;; -r|--reboot) SDFLAG_POWERSTATE="$SDFLAG_REBOOT" ;; -p|--poweroff) SDFLAG_POWERSTATE="$SDFLAG_POWEROFF" ;; -s|status) check_shutting_down RES=$? case "$RES" in 0) echo "not-pending" ;; 1) echo "pending" ;; 2) echo "irreversible" ;; esac exit $RES ;; -c|cancel) cancel_shutdown ; exit $? ;; -k) POWERDOWNFLAG_USER="enforce" ;; -K) POWERDOWNFLAG_USER="forbid" ;; -l|block) # Undocumented - for dev. purposes touch "${SHUTDOWN_PIDFILE}.disable" ; exit $? ;; -L|unblock) # Undocumented - for dev. purposes rm -f "${SHUTDOWN_PIDFILE}.disable" ; exit $? ;; *) echo "Bad parameter '$1', ignoring" >&2 ;; esac shift done check_shutting_down RES=$? case "$RES" in 1) echo "$MessageCannotQueueAnother"; exit $RES ;; 2) echo "$MessageCannotCancelIrrev"; exit $RES ;; esac if [ -f "$CONFIG_UPSMON" ]; then _VAR="`egrep '^[ \t]*POWERDOWNFLAG ' "$CONFIG_UPSMON" | sed 's,^[ \t]*POWERDOWNFLAG ,,'`" _VAR="$(echo "$_VAR" | sed -e 's,^"\(.*\)"$,\1,g' -e "s,^\'\(.*\)\'$,\1,g")" if [ $? = 0 ] && [ -n "$_VAR" ]; then POWERDOWNFLAG="$_VAR" echo "Detected setting of POWERDOWNFLAG file as '$POWERDOWNFLAG'" fi fi DATE_START_DELAY="`date`" get_ldate "$DATE_START_DELAY" ( echo "$$"; echo "$DATE_START_DELAY" ) > "$SHUTDOWN_PIDFILE" CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 logmsg \ "$0 $ORIG_PARAM_STR was called to commit a powerfail shutdown. Current UPS state:" \ "`$NUT_IPPSTATUS`" # Clean up when this script is exited in any manner trap '_R=$?; rm -f "$SHUTDOWN_PIDFILE" "$SHUTDOWN_PIDFILE_IRREVERSIBLE" "$SHUTDOWN_PIDFILE.custom"; exit ${_R}' 0 # schedule the shutdown delayed for $SHUTDOWN_TIMER minutes if [ "$SHUTDOWN_TIMER" -gt -1 ] 2>/dev/null; then if [ "$SHUTDOWN_TIMER" -eq 0 ]; then echo "$MessageShutdownNotDelayed" else SHUTDOWN_TIMER_SEC="`expr $SHUTDOWN_TIMER \* 60`" \ || SHUTDOWN_TIMER_SEC="120" logmsg $(printf "${MessageShutdownIsDelayed_s}\n" "${SHUTDOWN_TIMER_SEC}") echo "+ ${SHUTDOWN_TIMER_SEC}" >> "$SHUTDOWN_PIDFILE" trap 'get_ldate; logmsg "$MessageTimerAbortedTrap">&2 ; exit 0' 1 2 3 15 /usr/bin/sleep ${SHUTDOWN_TIMER_SEC} fi fi if [ -f "${SHUTDOWN_PIDFILE}.disable" ]; then logmsg "Development hook: '${SHUTDOWN_PIDFILE}.disable' exists, so not doing the actual shutdown" exit 0 fi cd / DATE_START_IRREV="`date`" get_ldate "$DATE_START_IRREV" CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 logmsg "${MessageIrreversible}" trap 'echo "$MessageIrreversibleTrap">&2' 1 2 3 15 (echo "$$"; echo "$DATE_START_DELAY"; echo "+ $SHUTDOWN_TIMER_SEC"; echo "$DATE_START_IRREV" ) \ > "${SHUTDOWN_PIDFILE_IRREVERSIBLE}" \ && rm -f "${SHUTDOWN_PIDFILE}" # The custom shutdown routine if clusterware is present if [ -n "${SHUTDOWNSCRIPT_CUSTOM-}" ] && \ [ -x "${SHUTDOWNSCRIPT_CUSTOM}" ] && \ [ -s "${SHUTDOWNSCRIPT_CUSTOM}" ] \ ; then export MessageCustomShutdownStarting_s MessageCustomShutdownCompleted_s export MessageIrreversibleTrap DefaultSubject export CONSOLE_NOTIF CMD_WALL SYSLOG_NOTIF CMD_SYSLOG export SDFLAG_COMMONOPTIONS SDFLAG_UNGRACEFUL get_ldate logmsg $(printf "$MessageCustomShutdownStarting_s" "$SHUTDOWNSCRIPT_CUSTOM") rm -f "$SHUTDOWN_PIDFILE.custom" touch "$SHUTDOWN_PIDFILE.custom" chmod 600 "$SHUTDOWN_PIDFILE.custom" "$SHUTDOWNSCRIPT_CUSTOM" 3>"$SHUTDOWN_PIDFILE.custom" get_ldate logmsg $(printf "$MessageCustomShutdownCompleted_s" "$SHUTDOWNSCRIPT_CUSTOM") # Some variables for this script could be modified in the custom one [ -s "$SHUTDOWN_PIDFILE.custom" ] && . "$SHUTDOWN_PIDFILE.custom" rm -f "$SHUTDOWN_PIDFILE.custom" fi # Did the power return to sufficient amount of UPSes while we were stopping? # NOTE: If we are the host which commands UPSes to power-cycle, we should # still request the powercycle and halt/poweroff ourselves. # This file is wiped during UPSMON startup so should not interfere needlessly. # We expect the /usr/local/ups tree to be still available POWERDOWNFLAG_UPSMON=no if [ -s "$POWERDOWNFLAG" ] || "$NUT_UPSMON" -K ; then POWERDOWNFLAG_UPSMON=yes fi get_ldate if [ x"$POWERDOWNFLAG_UPSMON" = xyes ] ; then logmsg $(printf "$MessageKillpowerFileExists_s" "$POWERDOWNFLAG") else logmsg $(printf "$MessageKillpowerFileAbsent_s" "$POWERDOWNFLAG") fi if [ -n "$POWERDOWNFLAG_USER" ] ; then logmsg $(printf "$MessageKillpowerArgumentExists_s" "$POWERDOWNFLAG_USER") else logmsg "$MessageKillpowerArgumentAbsent" fi if [ x"$POWERDOWNFLAG_UPSMON" = xyes -o "$POWERDOWNFLAG_USER" = "enforce" ] && \ [ "$POWERDOWNFLAG_USER" != "forbid" ] \ ; then # We will cut our (dev-assumed) power, so should poweroff to be safe... if [ -z "${SDFLAG_POWERSTATE-}" ] ; then CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 logmsg $(printf "$MessageUPSpowercycleCommandingPoweroff_s" "$DELAY") SDFLAG_POWERSTATE="$SDFLAG_POWEROFF" else CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 logmsg $(printf "$MessageUPSpowercycleCommanding_s" "$DELAY") fi POWERDOWNFLAG_USER=enforce "$NUT_UPS_SHUTDOWN" else logmsg "$MessageUPSpowercycleNotCommanding" "$NUT_IPPSTATUS" -q if [ $? -eq 0 ] ; then if [ -z "${SDFLAG_POWERSTATE-}" ] ; then CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 logmsg "$MessageExtPowerIsBackRebooting" SDFLAG_POWERSTATE="$SDFLAG_REBOOT" else CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 logmsg "$MessageExtPowerIsBack" fi else logmsg "$MessageExtPowerNotBack" fi fi # By default, we continue with instant shutdown without waiting any more [ -z "${SDFLAG_COMMONOPTIONS-}" ] && \ SDFLAG_COMMONOPTIONS="$SDFLAG_INSTANT" [ -z "${SDFLAG_POWERSTATE-}" ] && \ SDFLAG_POWERSTATE="$SDFLAG_POWERSTATE_DEFAULT" get_ldate CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 logmsg $(printf "$MessageRunningCmd_s" "$CMD_SHUTDOWN $SDFLAG_POWERSTATE $SDFLAG_COMMONOPTIONS") # Launch the operating system shutdown command $CMD_SHUTDOWN $SDFLAG_POWERSTATE $SDFLAG_COMMONOPTIONS nut-2.8.3/scripts/installer/common/aix_init0000755000200500020050000000753414602463167015767 00000000000000#! /bin/sh # # ups: Starts the Network UPS Tools for IPP - Unix # Customizations copyright (c) 2015, by Eaton (R) Corporation. All rights reserved. # # chkconfig: - 26 74 # description: Network UPS Tools is a collection of programs which provide a common \ # interface for monitoring and administering UPS hardware. # processname: upsd # config: /usr/local/ups/etc # config: /etc/rc.ups # ### BEGIN INIT INFO # Provides: ups # Required-Start: $syslog $network $named # Required-Stop: $local_fs # Default-Stop: 0 1 6 # Short-Description: Starts the Network UPS tools # Description: Network UPS Tools is a collection of programs which provide a common \ # interface for monitoring and administering UPS hardware. ### END INIT INFO NUT_DIR="/usr/local/ups" # Source /etc/profile to get proper env. settings . /etc/profile LD_LIBRARY_PATH="${NUT_DIR}/lib:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH success() { echo OK } failure() { echo FAILED return 1 } # Resolve what processes should run SERVER="no" CLIENT="no" if [ -f ${NUT_DIR}/etc/nut.conf ]; then . ${NUT_DIR}/etc/nut.conf case $MODE in standalone|netserver) SERVER="yes" ;; esac rpm -q nut-client >/dev/null 2>&1 && CLIENT="yes" fi SHUTDOWN_TIMER=-1 if [ -f ${NUT_DIR}/etc/ipp.conf ]; then . ${NUT_DIR}/etc/ipp.conf fi do_start() { if [ "$SERVER" = "yes" ]; then echo "Starting UPS driver controller: \c" ( ${NUT_DIR}/sbin/upsdrvctl start >/dev/null 2>&1 && success || failure ) || \ RETVAL=$? echo "Starting upsd: \c" ( ${NUT_DIR}/sbin/upsd $UPSD_OPTIONS >/dev/null 2>&1 && success || failure ) || \ RETVAL=$? if [ -x ${NUT_DIR}/init ]; then ( ${NUT_DIR}/init > /dev/null 2>&1 && success || failure ) || \ RETVAL=$? fi fi if [ "$CLIENT" = "yes" ]; then echo "Starting UPS monitor: \c" if [ "$SHUTDOWN_TIMER" -gt -1 ]; then # This host wants early shutdown support, must be root ( ${NUT_DIR}/sbin/upsmon -p >/dev/null 2>&1 && success || failure ) || \ RETVAL=$? else ( ${NUT_DIR}/sbin/upsmon >/dev/null 2>&1 && success || failure ) || \ RETVAL=$? fi fi [ "$RETVAL" = 0 ] && touch /var/locks/ups } do_stop() { if test -e /var/run/nut/upsmon.pid; then echo "Stopping UPS monitor: \c" PID=`cat /var/run/nut/upsmon.pid` ( kill $PID && success || failure ) || \ RETVAL=$? rm /var/run/nut/upsmon.pid fi if [ "$SERVER" = "yes" ]; then if test -e /var/run/nut/upsd.pid; then echo "Stopping upsd: \c" PID=`cat /var/run/nut/upsd.pid` ( kill -9 $PID && success || failure ) || \ RETVAL=$? rm /var/run/nut/upsd.pid fi echo "Shutting down UPS driver controller: \c" ( ${NUT_DIR}/sbin/upsdrvctl stop > /dev/null 2>&1 && success || failure ) || \ RETVAL=$? fi [ "$RETVAL" = 0 ] && rm -f /var/locks/ups } do_restart() { do_stop waitmore=5 while [ -n "$(ls /var/run/nut/)" -a $waitmore -ge 1 ] do sleep 1 waitmore=$((waitmore-1)) done do_start } do_reload() { # FIXME: upsd and upsmon always return 0 # => can't tell if reload was successful if [ "$SERVER" = "yes" ]; then echo "Reloading upsd" ${NUT_DIR}/sbin/upsd -c reload || \ RETVAL=$? fi echo "Reloading upsmon" ${NUT_DIR}/sbin/upsmon -c reload || \ RETVAL=$? } RETVAL=0 # See how we are called. case "$1" in start) do_start ;; stop) do_stop ;; restart) do_restart ;; try-restart) [ -f /var/locks/ups ] && do_restart || true ;; reload) do_reload ;; force-reload) do_restart ;; status) if [ "$SERVER" = "yes" ]; then if test -f /var/locks/ups; then echo "upsd is running with PID" `cat /var/run/nut/upsd.pid` fi fi if test -e /var/run/nut/upsmon.pid; then echo "upsmon is running with PID" `cat /var/run/nut/upsmon.pid` elif rpm -q nut-client >/dev/null 2>&1; then echo "upsmon isn't running" fi ;; *) echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}" RETVAL=3 esac exit $RETVAL nut-2.8.3/scripts/installer/common/ipp.conf0000644000200500020050000000430414602463167015664 00000000000000# Eaton - Intelligent Power Protector - Unix ## Note that some OS-specific options needed for `ipp-os-shutdown` ## are provided in their own `ipp-os-shutdown.conf` file. ## Notification configuration ## Set to 1 to enable, 0 to disable MAIL_NOTIF=1 CONSOLE_NOTIF=1 SYSLOG_NOTIF=1 ## Mail notification configuration ## Simple local version (default) To_User="root" ## Advanced (actual emailing) version: #SMTP_Server="domain.something" ## or better, the secured version #SMTP_Server="domain.something:port" #SMTP_User="user@domain" #SMTP_Password="******" #To_User="recipient@domain" ## You may also adapt the following variables to point at your preferred command: #CMD_WALL="wall -n" #CMD_MAIL="mailx -n" #CMD_SYSLOG="logger" ## Set to non-negative minutes to enable early shutdowns via ipp-notify.sh ## Needs upsmon running as 'root', or 'ipp' privileged to call /sbin/shutdown SHUTDOWN_TIMER=-1 ## If you manage to let ipp manage shutdowns directly and not run upsmon as ## root all the time, you don't want notifications about non-root usage. ## In that case, set SHUTDOWN_NEEDS_ROOT=0 by uncommenting the next line: #SHUTDOWN_NEEDS_ROOT=0 ## This is used in early shutdown script to "enforce" or "forbid" powercycling ## the UPS as part of emergency powerfail processing. The value is to be set ## with command-line options (-k|-K) but a default can be set in `ipp.conf`. # POWERDOWNFLAG_USER="forbid" ## This is used in the `ipp-os-shutdown` script, and the OS-dependent values ## for symbols SDFLAG_POWEROFF, SDFLAG_REBOOT and SDFLAG_HALT are defined in ## its `ipp-os-shutdown.conf` which is included before this `ipp.conf` file. ## There are a few ways we end up with some final SDFLAG_POWERSTATE for the ## OS shutdown invocation (the final step in `ipp-os-shutdown` script): ## * a state requested by user via CLI (-h, -p, -r) ## * guessed along with UPS powercycling or external-power-returned decisions ## * using SDFLAG_POWERSTATE_DEFAULT ## The default fall-back action is to power-off, unless another value is ## defined here in `ipp.conf` explicitly: #SDFLAG_POWERSTATE_DEFAULT="$SDFLAG_POWEROFF" # Custom shutdown script for the AIX clusterware SHUTDOWNSCRIPT_CUSTOM="/usr/local/ups/sbin/AIX_Clusterware_shutdown" nut-2.8.3/scripts/installer/common/README_ipp-os-shutdown.adoc0000644000200500020050000002646014777767434021202 00000000000000= README for the ipp-os-shutdown and early shutdown features in IPP - UNIX == General information This version of IPP - Unix includes enhanced scripts and configuration which enable to configure "early shutdown" functionality on chosen hosts. This allows selected systems to power themselves off after a certain time that less than `$MINSUPPLIES` power sources are protected by UPSes that are fully "ONLINE". In order for this to happen, a new configuration variable was introduced in `ipp.conf` file, the `SHUTDOWN_TIMER` which allows to specify the number of minutes that the power protection is insufficient, after which the irreversible shutdown of this host begins. Default value for this variable is `-1` which retains the standard behavior of staying up as long as possible, and shutting down only when the UPS sends an alert that too little battery runtime remains (as configured by default or customized by `shutdown_duration` option for the `netxml-ups` driver). [NOTE] NOTE: If this feature is used, it is recommended to specify the timeout for an early-shutdown feature of at least 5 minutes (`SHUTDOWN_TIMER=5`). Reason: When an NMC in the UPS is rebooted, it can announce dummy values about the UPS and battery status for some time, while it is collecting real data from the UPS hardware, and this data can cause a protected host to begin an early shutdown needlessly. A sufficiently long `SHUTDOWN_TIMER` value allows the host to receive real data from the UPS and so to cancel the pending shutdown (if the battery is indeed well charged and the UPS is really online). Another added option is `POWERDOWNFLAG_USER` which may be pre-set to `enforce` or `forbid` to enable or disable UPS power-cycling at the end of the shutdown procedure. Generally it does not need to be pre-set in the `ipp.conf` file as the script relies on the `POWERDOWNFLAG` file managed by `upsmon` (this in turn depends on whether `upsmon` triggered the shutdown due to an alarm, such as low-battery condition, or just the delayed early shutdown was used as scheduled by "notification"). However it is possible to configure a specific behavior on this host, e.g. to be sure to avoid power-cycling when early shutdown hosts are shutting down due to whatever powerfail-driven reason. These options should be configured by an administrator of the particular host in the `/usr/local/ups/etc/ipp.conf` file. When UPS events are processed by `upsmon` with its configured `NOTIFYCMD` (the packaged `ipp-notifier.sh` script, enhanced for this delivery) it has an ability to detect how many UPSes are `ONLINE` and how many are required by the `MINSUPPLIES` setting. UPSes whose state is currently `unknown` are not considered, in order to avoid erroneous shutdowns while the communications are just starting up. If the protection is deemed insufficient, the new `ipp-os-shutdown` script is launched, which can invoke a customized copy of `ipp-host-shutdown.sample` script for host-specific procedures (such as clusterware shutdown). The `ipp-os-shutdown` script has several roles: * it manages the delayed shutdown (which can be canceled before the timer expires, and can not be aborted after the timer expires - so it proceeds to the end) * it wraps the call to a customized shutdown script, if one is configured and detected * it detects whether the UPSes should be told to power-cycle or not, based on the `killpower` flag-file from `upsmon`, a setting in `ipp.conf` file, or an explicit request from the caller of this shutdown script * in the end it detects whether the UPSes came back online, so the host should try to `reboot` rather than `poweroff` (unless a specific action was requested by the caller of this shutdown script) and calls the OS shutdown program to complete this activity * the same script (with an option of zero delay) is configured as the `SHUTDOWNCMD` in `upsmon.conf` so the same logic is executed in all the different supported shutdown scenarios. It is recommended to configure certain `SHUTDOWN_TIMER` values for the hosts which should shut down early and leave more battery runtime power remaining for the more important hosts. Note that if the external power returns after the early-shutdown hosts have powered off, they will stay down until an administrator boots them. However, if the external power becomes sufficient again during the shutdown procedure (checked between cluster-ware shutdown and the OS shutdown steps) then a reboot of the host is requested instead of a power-off. It is recommended to configure `SHUTDOWN_TIMER=-1` (default) on those more important hosts which should stay up as long as possible and only shut down if all required UPSes have posted a low-battery status or forced-shutdown command. These hosts would by default schedule delayed UPS power-cycling. To be on the safe side, sufficient `shutdown_duration` seconds should be configured in their `netxml-ups` driver blocks in the `/usr/local/ups/etc/ups.conf` file on the host. If the customer elects to use the early shutdown strategy for all hosts, the `POWERDOWNFLAG_USER=enforce` should be configured in the hosts with the highest `SHUTDOWN_TIMER` value so they would cause UPS power-cycling. Do not forget to define sufficient `DELAY` value for the OS shutdown to complete before the UPS turns itself off. The UPS would turn on the load automatically after some time, when external power is back and it has charged the battery sufficiently (configurable in the Network Management web-interface for the UPS). == Installation * Install the package as usual - Un-compress the `ipp-*.tar.gz` archive for your OS - Change into the resulting `ipp-*` subdirectory - (optional) If a complete re-installation is desired (including removal of old configuration files so they do not conflict with the new delivery), please also execute `IPP_WIPE_OLD_CONFIG=yes; export IPP_WIPE_OLD_CONFIG` in the shell before running the installation script - Launch the `install.sh` script and follow the installer instructions * Configure the early shutdown timer You can later change the early shutdown timer, for the cluster nodes, by editing `/usr/local/ups/etc/ipp.conf`, and set `SHUTDOWN_TIMER` to a suitable value (in minutes). * Configure clusterware shutdown command You can configure the variable `SHUTDOWNSCRIPT_CUSTOM` in `ipp.conf` to point at a custom complementary shutdown script with a shutdown routine required by this particular host, which will be called by the master powerfail shutdown script (`/usr/local/ups/sbin/ipp-os-shutdown`). This variable is not set by default. * Configure operating system shutdown command and options Optionally, modify the operating system shutdown command and type. To modify the shutdown command or specific option for the various types of shutdown), edit the file `/usr/local/ups/etc/ipp-os-shutdown.conf` and set or adapt the variables: - `CMD_SHUTDOWN` to point at the shutdown command. This may include the basic mandatory option options, such as the non-interactive flag (`-y`) on some OS such as HP-UX or Solaris, - `SDFLAG_*` to point at the right option for poweroff, reboot or halt. Note that depending on the OS and hardware features, there may be no difference between "halt" (stop the OS and keep the hardware running) and a "poweroff" (halt and instruct the server's PSU to cut the power going to the motherboard -- if that is supported; might be unavailable in e.g. virtualized environments or older hardware). To modify the default shutdown option to halt or reboot, edit the file `/usr/local/ups/etc/ipp.conf` and set `SDFLAG_POWERSTATE_DEFAULT` to either `$SDFLAG_HALT` (halt) or `$SDFLAG_REBOOT` (reboot). * (optionally) Configure UPS power-cycling If the customer elects to use the early shutdown strategy for all hosts, the `POWERDOWNFLAG_USER=enforce` should be configured in the `ipp.conf` file on hosts with the highest `SHUTDOWN_TIMER` value so they would cause UPS power-cycling explicitly. By default, it may be enabled or forbidden depending on the cause of shutdown. Make sure to define a sufficient `DELAY` value (in seconds) as well, for the OS shutdown to complete safely before the UPS(es) power is cut. == Testing The following points about this delivery were verified on AIX 7.1 and Solaris 11. It was tested: - to be installable (and runnable via init-script) - to work as a `SHUTDOWNCMD` handler, including interaction with the killpower flag-file maintained by `upsmon` (with the default setting of `SHUTDOWN_TIMER=-1` in the `ipp.conf` file) - to report progress of the powerfail shutdown onto the system consoles (with `wall`) and into the `syslog` (note: default syslog priority from IPP - Unix is `user.notice` which may be ignored by default `syslog` configuration, check with `/etc/syslog.conf` or equivalent in your OS). - to execute early shutdown when `SHUTDOWN_TIMER=5` (after 5 minutes ONBATT) is defined manually in the `ipp.conf` file - to cancel shutdown if power returns back before timeout expires - to not cancel shutdown if power returns back after timeout expires and shutdown routine has started (and reported to be irreversible) - to report that the shutdown is in irreversible stage, as reaction to CTRL+C during console-run invocations like `ipp-os-shutdown -t now` - to execute custom shutdown script if it is found, and to skip it if not available - to power-off the protected host if power remains lost at the moment when we are about to proceed to `/sbin/shutdown` - to reboot the host if power is already back when we are about to proceed to `/sbin/shutdown` - to set the `netxml-ups` driver argument `shutdown_timer` during installation to a value which matches the chosen `SHUTDOWN_TIMER` (if it is non-negative) so the selected ONBATT timeout is shown in the Eaton NMC Web-GUI - to implement numerous fixes and improvements in the `install.sh` script, including integration of new settings for early shutdown and UPS power-cycling strategy === A few important notes helpful during testing * currently running IPP - Unix processes, UPS states and the pending shutdown status can be queried with the following command: ---- :; ps -ef | grep -v grep | egrep 'ipp|ups|nut|shut|sleep' ; \ ls -la /usr/local/ups/etc/killpower ; \ /usr/local/ups/bin/ipp-status; \ /usr/local/ups/sbin/ipp-os-shutdown -s; date ---- * a pending shutdown that is not yet irreversible can be aborted manually with: ---- :; /usr/local/ups/sbin/ipp-os-shutdown -c ---- * the administrator can create a special file to abort the script just before proceeding to irreversible shutdown; this is automated in the `ipp-os-shutdown` script (undocumented option): ---- :; /usr/local/ups/sbin/ipp-os-shutdown block ---- Do not forget to remove this file when testing is completed to allow actual shutdowns to happen: ---- :; /usr/local/ups/sbin/ipp-os-shutdown unblock ---- * also note that if the host is booted with an administrative action while the remaining UPS battery runtime is under the threshold set with `shutdown_duration`, an emergency powerfail can be triggered by the `netxml-ups` driver as soon as IPP - Unix services are initialized, even if the battery state is "CHARGING". To avoid such shutdowns, an administrator can log in and quickly create the special file described above (temporarily). The recommended procedure is to wait for the hosts to boot up in due time, when the batteries are charged enough to survive another power failure (if one occurs) at least for as long as it takes to shut down the server gracefully. nut-2.8.3/scripts/installer/common/ipp-shutdown-daemon.sh0000644000200500020050000000223214602463167020461 00000000000000#THIS IS WORK IN PROGRESS, THIS IS NOT FUNCTIONAL. exit #!/bin/sh # ipp-shutdown-daemon # # Copyright (c) 2013-2017, by Eaton (R) Corporation. All rights reserved. # # A shell script to detect shutdown from NMC cards IPP - Unix (NUT) # It needs ipp.conf file. # NUT_DIR="/usr/local/ups" NUT_CFG_DIR="" for D in "$NUT_DIR/etc" "/etc/nut" "/etc/ups" ; do if [ -d "$D" ] && [ -f "$D/ups.conf" ] && [ -f "$D/ipp.conf" ] ; then NUT_CFG_DIR="$D" break fi done unset D CONFIG_IPP="$NUT_CFG_DIR/ipp.conf" # Note: $NUT_DIR/xbin holds the wrappers to run NUT binaries with co-bundled # third party libs and hopefully without conflicts induced for the OS binaries PATH="$NUT_DIR/xbin:$NUT_DIR/sbin:$NUT_DIR/bin:$PATH" export PATH # Search for binaries under current PATH normally, no hardcoding NUT_UPSC="upsc" #NUT_UPSC="$NUT_DIR/xbin/upsc" if [ -f "$CONFIG_IPP" ] ; then . "$CONFIG_IPP" fi # Convert to parsing of "ipp-status -p" which reports all needed details for dev in `$NUT_UPSC -l 2>/dev/null`; do shutdown="`$NUT_UPSC "$dev"@localhost ups.timer.shutdown 2>/dev/null`" reboot="`$NUT_UPSC "$dev"@localhost ups.timer.reboot 2>/dev/null`" done nut-2.8.3/scripts/installer/common/init0000755000200500020050000000542214602463167015120 00000000000000#!/bin/sh # init # # Copyright (c) 2013-2017, by Eaton (R) Corporation. All rights reserved. # # A shell script to command UPSes to disable delayed power off of outlet # groups, which could have ben requested as part of the emergency shutdown # driven by IPP - Unix (NUT); called from nut init-script # # Requires configuration from ipp.conf, or otherwise default to the values below # Also requires matching features to be available in the UPSes and their drivers # # TODO remaining per IPSSUNIX-29: # * Mismatch against the `shutdown` script: during shutdown we set # `load.on.delay` and `load.off.delay` via `upscmd` for the UPS itself, # as well as `upsrw` the similar settings for outlet groups, but during # the `init` we reset to `-1` only the outlet group settings and not # those of the UPS itself # * The script acts on ALL UPSes configured on this system (`upsc -l`), # rather than those MONITORed as feeding a non-zero amount # power-sources in `upsmon.conf` # * The username is hardcoded as `admin` rather than taken from config # * Maybe we do not try every possible instcmd for UPS poweroff/reboot - # revise against upsrw and upscmd for NETXML and SNMP drivers at least NUT_DIR="/usr/local/ups" NUT_CFG_DIR="" for D in "$NUT_DIR/etc" "/etc/nut" "/etc/ups" ; do if [ -d "$D" ] && [ -f "$D/ups.conf" ] && [ -f "$D/ipp.conf" ] ; then NUT_CFG_DIR="$D" break fi done unset D CONFIG_IPP="$NUT_CFG_DIR/ipp.conf" # Note: $NUT_DIR/xbin holds the wrappers to run NUT binaries with co-bundled # third party libs and hopefully without conflicts induced for the OS binaries PATH="$NUT_DIR/xbin:$NUT_DIR/sbin:$NUT_DIR/bin:$PATH" export PATH # Search for binaries under current PATH normally, no hardcoding NUT_UPSC="upsc" NUT_UPSCMD="upscmd" NUT_UPSRW="upsrw" #NUT_UPSC="$NUT_DIR/xbin/upsc" #NUT_UPSCMD="$NUT_DIR/xbin/upscmd" #NUT_UPSRW="$NUT_DIR/xbin/upsrw" # Do not normally mangle the LD_LIBRARY_PATH - it can impact system tools too #LD_LIBRARY_PATH="$NUT_DIR/lib:/usr/lib:/lib:$LD_LIBRARY_PATH" #export LD_LIBRARY_PATH # Include IPP ipp.conf (may overwrite the above default values!) to # get shutdown delay and admin password if [ -f "$CONFIG_IPP" ] ; then . "$CONFIG_IPP" fi if [ "$IPP_DEBUG" = yes ] ; then # Keep entries with the same log as shutdown exec >> /var/tmp/ipp-shutdown.log 2>&1 echo "`date`: Started booting: $0 $*" >&2 set >&2 set -x fi [ "$POWERDOWNFLAG_USER" = "forbid" ] && exit 0 # TODO: Here we want to refine the list to only MONITORed UPSes that power us? # Convert to parsing of "ipp-status -p" which reports all needed details upslist="`"$NUT_UPSC" -l`" echo "$upslist" for u in $upslist; do echo "Disabling poweroff for UPS outlet-groups on '$u' ..." for o in 3 2 1 ; do "$NUT_UPSRW" -s "outlet.$o.delay.shutdown=-1" \ -u admin -p "$PASSWORD" "$u" done done nut-2.8.3/scripts/installer/common/ipp-event.sh0000644000200500020050000000225314602463167016471 00000000000000#THIS IS WORK IN PROGRESS, THIS IS NOT FUNCTIONAL exit #!/bin/sh # ipp-event # # Copyright (c) 2013-2017, by Eaton (R) Corporation. All rights reserved. # # A shell script to manage event from IPP - Unix (NUT) # It needs ipp.conf file. # NUT_DIR="/usr/local/ups" NUT_CFG_DIR="" for D in "$NUT_DIR/etc" "/etc/nut" "/etc/ups" ; do if [ -d "$D" ] && [ -f "$D/ups.conf" ] && [ -f "$D/ipp.conf" ] ; then NUT_CFG_DIR="$D" break fi done unset D CONFIG_IPP="$NUT_CFG_DIR/ipp.conf" # Note: $NUT_DIR/xbin holds the wrappers to run NUT binaries with co-bundled # third party libs and hopefully without conflicts induced for the OS binaries PATH="$NUT_DIR/xbin:$NUT_DIR/sbin:$NUT_DIR/bin:$PATH" export PATH # Search for binaries under current PATH normally, no hardcoding. Scripts: CMD_NOTIFIER="ipp-notifier.sh" DAEMON="ipp-shutdown-daemon.sh" #CMD_NOTIFIER="$NUT_DIR/bin/ipp-notifier.sh" #DAEMON="$NUT_DIR/bin/ipp-shutdown-daemon.sh" if [ -f "$CONFIG_IPP" ] ; then . "$CONFIG_IPP" fi #call notifier script $CMD_NOTIFIER "$*" & PROC="`ps -ef | grep "$DAEMON" | awk -F" " '{print $2}'`" case "$1" in ONBATT) if [ $PROC = "" ];then $DAEMON & fi ;; ONLINE) kill -9 $PROC ;; esac nut-2.8.3/scripts/installer/README.adoc0000644000200500020050000000640214777767434014544 00000000000000NUT Installer (command-line) ============================ This directory contains scripts and data used for NUT packaging marketed earlier as Eaton IPSS Unix (or IPP for Unix, or UPP), a freely available download. Most of the work was done on behalf of Eaton by Frederic Bohe, Vaclav Krpec, Arnaud Quette and Jim Klimov. This includes the package (tarball) creation script which relies on presence of third-party library binaries in a `$ARCH/libs` directory, pre-built package files (courtesy of NUT `make package` recipes), and init-scripts from NUT source tree (originally expected as a `nut` subdirectory, can be a symlink to `../..`; currently copies stored in the `$ARCH` subdirectories; eventually should be taken from NUT sources during build, or from packages), as well as an interactive text-mode installer script to set up the package on a target deployment covering package (re-)installation, initial device discovery, password setup, etc., and helper scripts for status overview and shutdown handling. Example `$ARCH` related directory layout in original posting (binary files mentioned below are not provided into NUT Git source code base); these are the contents `make_package.sh` script expects to work with (you can see the names mentioned in `find ... | grep -v ...` filters): * `aix/` example for AIX 6 and 7 based IPSS Unix releases: * `libs/`: `libcrypto.a`, `libcrypto.so`, etc... * `nut-2.6.5-1.aix6.1.ppc.rpm` and `nut-client-2.6.5-1.aix6.1.ppc.rpm` package files * `nutconf` binary for the platform * `aix_init` script * `ipp-os-shutdown.conf.sample` * `hpux/` for PA-RISC: * `libs/`: `libcrypto.sl`, `libexpat.sl`, `libiconv.sl`, `libintl.sl`, `libltdl.sl`, `libneon.sl`, `libnetsnmp.sl.30`, `libssl.sl`, `libz.sl` * Notably, `libnutscan.sl.1` (other platforms did not carry a copy) * `nut.depot.tar.gz` package file * `nutconf` binary for the platform * `ipp-os-shutdown.conf.sample` * Solaris (SPARC and X86) spread across 3 directories: * `solcmn/` with common platform-independent files: * `ipp-os-shutdown.conf.sample` * `solaris_init` script * `solari` with SPARC binaries: * `libs/`: `libcrypto.so.0.9.8`, `libz.so`, etc. * `NUT_solaris_sparc_package2.6.5.local` package file * `nutconf` binary for the platform * `solint` with X86 binaries: * `libs/`: `libcrypto.so.1.0.0`, `libgcc_s.so.1`, `libltdl.so.7`, `libneon.so.27`, `libnetsnmp.so.15`, `libproxy.so.0`, `libssl.so.1.0.0`, `libstdc++.so.6`, `libwrap.so.1` * `NUT_solaris_i386_package2.6.5.local` package file * `nutconf` binary for the platform The installer relies on `nutconf` tool (emulating dummy script for tests provided here), which is part of NUT sources. Note that heavy use of `LD_LIBRARY_PATH` in these scripts may become counterproductive when the package is installed on a system that is too many versions away from the intended target (e.g. mixing up the symbols during dynamic linking), so while this contribution here is published "as is", more work would be needed to make it useful in modern environments. Helper scripts should be quickly useful though. Developed (pre-?)2013-2018 by Eaton; contributed to NUT and re-licensed under same terms as NUT in 2022 by Eaton. Maintained since 2024 by Jim Klimov nut-2.8.3/scripts/installer/hpux/0000755000200500020050000000000015001555411013764 500000000000000nut-2.8.3/scripts/installer/hpux/ipp-os-shutdown.conf.sample0000644000200500020050000000315014602463167021126 00000000000000# # ipp-os-shutdown.conf # # Settings that specify typical shutdown commands for various supported OSes # Version for HP-UX # # See http://docstore.mik.ua/manuals/hp-ux/en/5991-1247B/ch05s09.html # and http://docstore.mik.ua/manuals/hp-ux/en/5991-1247B/ch05s01.html#bgbjeidh # # By default HPUX shutdown leaves the box halted and running, so requesting # delayed UPS powercycling may be critical for proper shutdowns. # # To enable actual powerdown on chosen server models, you may need to # run `acpiconfig enable softpowerdown` from the UEFI shell and reboot # the HPUX partition. See more details in HP docs about your server model. # # The program which executes an OS shutdown, maybe including flags that # disable its interactive mode CMD_SHUTDOWN="/usr/sbin/shutdown -y" #CMD_SHUTDOWN="/sbin/shutdown -y" # Depending on OS and hardware support, "poweroff" option may tell the # host's power source units to cut off their power to the motherboard, # and "halt" may sit forever at the "OS is stopped" prompt or equivalent. SDFLAG_POWEROFF="-h" SDFLAG_REBOOT="-r" SDFLAG_HALT="-R -H" # Reconfigure+Hold # The flag for quick stop (shorter service stop timeouts and fewer/no # logs, or outright go to kill remaining processes) SDFLAG_UNGRACEFUL="now" # Trigger a shutdown without delay SDFLAG_INSTANT="now" ## Filename to store the PID of a pending shutdown ## If this file is absent, the shutdown can not be canceled (killed) ## If the "${SHUTDOWN_PIDFILE}.irreversible" exists and points to running PID ## then the new shutdown can not be queued (caller must cancel old one first) SHUTDOWN_PIDFILE="/var/run/nut/shutdown.pid" nut-2.8.3/scripts/installer/install.sh0000755000200500020050000012360714602463167014752 00000000000000#!/bin/sh # install.sh # Copyright (c) 2013-2016, by Eaton (R) Corporation. All rights reserved. # A shell script which installs IPP - Unix # It installs the native package then runs NUT configuration tools # to create an initial configuration and finally run the service. . ./version.sh PATH="$PATH:/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb:/usr/ccs/bin:/usr/xpg4/bin:/usr/xpg6/bin" export PATH NUT_PACKAGE_SOLARI="NUT_solaris_sparc_package2.6.5.local" NUT_PACKAGE_SOLINT="NUT_solaris_i386_package2.6.5.local" COMMON_DIR="common" LOG_FILE=install.log [ x"${IPP_DEBUG-}" = xyes ] || IPP_DEBUG=no [ x"${IPP_WIPE_OLD_CONFIG-}" = xyes ] || IPP_WIPE_OLD_CONFIG=no #configuration data C_MODE="standalone" C_HOSTNAME="localhost" C_DEVICE="" C_OPTION="" C_NUM_DEV=0 C_PASSWORD="" # Number of seconds for late emergency shutdown, goes into netxml-ups # to get alerts from the UPS when battery runs low, *and* becomes the # DELAY setting in ipp.conf used to power-cycle the UPSes in the end. C_SHUTDOWN_DURATION="120" # Number of minutes spent ONBATT for early-shutdown, goes into ipp.conf # This logically matches the netxml-ups "shutdown_timer" parameter # which is exclusive to this one driver and does not always work. C_SHUTDOWN_TIMER="-1" C_MINSUPPLIES=1 C_COMMUNITY="public" C_NUM_NETWORK_DEVICE=0 # empty for automatic, "forbid" or "enforce" for once-and-for-all C_POWERDOWNFLAG_USER="" FIRST_IP="" LAST_IP="" NUT_PORT="3493" ADMIN_FILE="/tmp/ipp_admin_file" cd "`dirname $0`" . "$COMMON_DIR/string.sh" get_parameters() { case $1 in English) lang=EN ;; # Japanese) # lang=JP # ;; SOLARI) SYSTEM=$1 ;; SOLINT) SYSTEM=$1 ;; HPUX) SYSTEM=$1 ;; AIX) SYSTEM=$1 ;; esac } check_locale_language() { set `locale` >/dev/null 2>&1 case $1 in LANG=en_US) lang=EN ;; LANG=C) lang=EN ;; esac } compute_SYSTEM () { set `uname -a` case "$1" in SunOS) case "$3" in 5.*) case "$5" in i86pc) SYSTEM=SOLINT ;; *) SYSTEM=SOLARI ;; esac ;; *) SYSTEM="Unknown System" ;; esac ;; HP-UX) SYSTEM=HPUX ;; AIX) case "$4" in 6) SYSTEM=AIX ;; 7) SYSTEM=AIX ;; *) SYSTEM="This AIX version is not supported" ;; esac ;; *) SYSTEM="Unknown System" ;; esac compute_system } compute_system () { case "$SYSTEM" in SOLINT) system=solint COMMON_DIR_SYS=solcmn ;; SOLARI) system=solari COMMON_DIR_SYS=solcmn ;; HPUX) system=hpux COMMON_DIR_SYS="$system" ;; AIX) system=aix COMMON_DIR_SYS="$system" ;; *) echo necho $ERR_UNKNOWN_SYS_STR1 necho $ERR_UNKNOWN_SYS_STR2 # echo "Valid systems are tagged SOLINT SOLARI HPUX AIX" necho $ERR_UNKNOWN_SYS_STR3 echo necho $INSTALL_ERROR exit 1 ;; esac } read_def () { default="$2" if [ "$2" = "" ]; then necho "$1" else necho "$1" "[" "$2" "]" fi read answer if [ -z "$answer" ]; then answer="$default" fi } read_def_silent () { default="$2" necho $1 stty -echo read answer stty echo if [ -z "$answer" ]; then answer="$default" fi } create_admin_file () { echo basedir=default > "$ADMIN_FILE" echo runlevel=quit >> "$ADMIN_FILE" echo conflict=nocheck >> "$ADMIN_FILE" echo setuid=nocheck >> "$ADMIN_FILE" echo action=nocheck >> "$ADMIN_FILE" echo partial=nocheck >> "$ADMIN_FILE" echo instance=overwrite >> "$ADMIN_FILE" echo idepend=quit >> "$ADMIN_FILE" echo rdepend=quit >> "$ADMIN_FILE" echo space=quit >> "$ADMIN_FILE" } install_files () { echo case "$LOG_FILE" in /*) ;; *) LOG_FILE="`pwd`/$LOG_FILE" ;; esac rm -f "$LOG_FILE" > /dev/null 2>&1 touch "$LOG_FILE" echo "NOTE: progress of this script's interpretation (and errors) will be logged into" echo " $LOG_FILE" echo " You should attach it to support calls should any problems arise" exec 2>"$LOG_FILE" echo "Started at `date` as: $0 $*" >&2 set >&2 set -x . ./uninstall-lsnw.sh # Check if Lansafe is installed detect_lansafe if [ $? -eq 0 ]; then necho $CS_REMOVE_LS # Proceed to uninstallation uninstall_lansafe fi # Check if Netwatch is installed detect_netwatch if [ $? -eq 0 ]; then necho $CS_REMOVE_NW # Proceed to uninstallation uninstall_netwatch fi # Clean-up previous installation remove_profile_settings if [ -d "/var/state/ups" ]; then rm -rf "/var/state/ups" fi if [ -d "/var/run/nut" ]; then rm -rf "/var/run/nut" fi if [ -d "$instpath/etc" ]; then cp -prf "$instpath/etc" "$instpath/etc.bak-$$" if [ x"${IPP_WIPE_OLD_CONFIG}" = xyes ]; then echo "Removing old configs because IPP_WIPE_OLD_CONFIG=yes" rm -rf "$instpath/etc" fi fi if [ -d "$instpath/xbin" ]; then rm -rf "$instpath/xbin" fi if [ -x "$instpath/bin/uninstall-ipp" ]; then necho $CS_REMOVE_OLDIPP "$instpath/bin/uninstall-ipp" || true fi if [ -e "$instpath/bin/ipp-wrapper" ]; then rm -f "$instpath/bin/ipp-wrapper" || true fi case "$system" in solari) necho $REMOVE_PACKAGE | tee -a "$LOG_FILE" create_admin_file pkgrm -n -a "$ADMIN_FILE" NUT >> "$LOG_FILE" 2>&1 necho $INSTALL_PACKAGE | tee -a "$LOG_FILE" pkgadd -a "$ADMIN_FILE" -n \ -d "$systemdir/$NUT_PACKAGE_SOLARI" NUT \ >> "$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi rm -f "$ADMIN_FILE" # Modified initscript, to run upsmon as full root, # for optional early-shutdown support if [ -s "$COMMON_DIR_SYS/solaris_init" ]; then cp -f "$COMMON_DIR_SYS/solaris_init" "$instpath/nut" res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi fi chown root:ipp "$instpath/nut" >> "$LOG_FILE" 2>&1 && \ chmod 755 "$instpath/nut" >> "$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi rm -f /etc/init.d/nut /etc/rc3.d/K100nut /etc/rc3.d/S100nut /etc/rc3.d/S99nut /etc/rc0.d/K60nut ln -s "../../$instpath/nut" /etc/init.d/nut && \ ln -s "../init.d/nut" /etc/rc3.d/S99nut && \ ln -s "../init.d/nut" /etc/rc0.d/K60nut res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi ;; solint) necho $REMOVE_PACKAGE | tee -a "$LOG_FILE" create_admin_file pkgrm -n -a "$ADMIN_FILE" NUT >> "$LOG_FILE" 2>&1 necho $INSTALL_PACKAGE | tee -a "$LOG_FILE" pkgadd -a "$ADMIN_FILE" -n \ -d "$systemdir/$NUT_PACKAGE_SOLINT" NUT \ >> "$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi rm -f "$ADMIN_FILE" # Modified initscript, to run upsmon as full root, # for optional early-shutdown support if [ -s "$COMMON_DIR_SYS/solaris_init" ]; then cp -f "$COMMON_DIR_SYS/solaris_init" "$instpath/nut" res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi fi chown root:ipp "$instpath/nut" >> "$LOG_FILE" 2>&1 && \ chmod 755 "$instpath/nut" >> "$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi rm -f /etc/init.d/nut /etc/rc3.d/K100nut /etc/rc3.d/S100nut /etc/rc3.d/S99nut /etc/rc0.d/K60nut ln -s "../../$instpath/nut" /etc/init.d/nut && \ ln -s "../init.d/nut" /etc/rc3.d/S99nut && \ ln -s "../init.d/nut" /etc/rc0.d/K60nut res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi ;; hpux) cd "$systemdir" rm -f nut.depot.tar > /dev/null 2>&1 rm -Rf nut.depot > /dev/null 2>&1 gunzip nut.depot.tar.gz >> "../$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then cd .. necho $INSTALL_ERROR exit 1 fi tar xvf nut.depot.tar >> "../$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then cd .. necho $INSTALL_ERROR exit 1 fi cd .. necho $REMOVE_PACKAGE | tee -a "$LOG_FILE" remove_hpux_upsmon_esd_support swremove NUT >> "$LOG_FILE" 2>&1 necho $INSTALL_PACKAGE | tee -a "$LOG_FILE" swinstall -s "`pwd`/$systemdir/nut.depot/" NUT \ >> "$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi add_hpux_upsmon_esd_support ;; aix) necho $REMOVE_PACKAGE | tee -a "$LOG_FILE" rm -rf "$instpath/share/man" >> "$LOG_FILE" 2>&1 rpm -e nut >> "$LOG_FILE" 2>&1 rpm -e nut-client >> "$LOG_FILE" 2>&1 necho $INSTALL_PACKAGE | tee -a "$LOG_FILE" rpm -i --nodeps `ls "$systemdir"/nut-*.aix6.1.ppc.rpm | grep -v 'nut-client'` \ >> "$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi rpm -i --nodeps "$systemdir/"nut-client-*.aix6.1.ppc.rpm \ >> "$LOG_FILE" 2>&1 res=$? if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi # Modified initscript, to run upsmon as full root, # for optional early-shutdown support if [ -s "$COMMON_DIR_SYS/aix_init" ]; then cp -f "$COMMON_DIR_SYS/aix_init" /etc/rc.d/init.d/ups res=$? chown root:ipp "/etc/rc.d/init.d/ups" >> "$LOG_FILE" 2>&1 chmod 755 "/etc/rc.d/init.d/ups" >> "$LOG_FILE" 2>&1 if [ ! $res = 0 ]; then necho $INSTALL_ERROR exit 1 fi fi if [ ! -d "$instpath/share/man" ]; then for N in 1 3 5 8 ; do mkdir -p "$instpath/share/man/man$N" && \ ( cd "$instpath/share/man/man$N" && { \ ln -s ../../../man/man$N/*.$N . ln -s ../../doc/nut-*/docs/man/*.$N . 2>/dev/null } ; ) done >> "$LOG_FILE" 2>&1 fi ;; *) necho $INSTALL_ERROR exit 1 ;; esac #ipp-wrapper goes first of custom files, to symlink against just # the packaged binaries - an action which we do first of all mkdir "$instpath/xbin" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/xbin" >> "$LOG_FILE" 2>&1 chmod 755 "$instpath/xbin" >> "$LOG_FILE" 2>&1 ( cd "$instpath/bin" && for F in * ; do if [ -f "$F" ] && [ ! -d "$F" ] && [ -x "$F" ] ; then ln -s "../bin/ipp-wrapper" "../xbin/$F" fi done ) ( cd "$instpath/sbin" && for F in * ; do if [ -f "$F" ] && [ ! -d "$F" ] && [ -x "$F" ] && [ ! -x "../xbin/$F" ] ; then ln -s "../bin/ipp-wrapper" "../xbin/$F" fi done ) cp "$COMMON_DIR/ipp-wrapper" "$instpath/bin" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/bin/ipp-wrapper" >> "$LOG_FILE" 2>&1 chmod 755 "$instpath/bin/ipp-wrapper" >> "$LOG_FILE" 2>&1 #install additional libraries cp "$systemdir/libs/"* "$instpath/lib" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/lib/*" >> "$LOG_FILE" 2>&1 #powercycle-setting scripts cp "$COMMON_DIR/init" "$instpath" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/init" >> "$LOG_FILE" 2>&1 chmod 744 "$instpath/init" >> "$LOG_FILE" 2>&1 cp "$COMMON_DIR/shutdown" "$instpath" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/shutdown" >> "$LOG_FILE" 2>&1 chmod 744 "$instpath/shutdown" >> "$LOG_FILE" 2>&1 #OS shutdown script cp "$COMMON_DIR/ipp-os-shutdown" "$instpath/sbin" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/sbin/ipp-os-shutdown" >> "$LOG_FILE" 2>&1 chmod 744 "$instpath/sbin/ipp-os-shutdown" >> "$LOG_FILE" 2>&1 # Config file with parameters for the shutdown program cp -f "$COMMON_DIR_SYS/ipp-os-shutdown.conf.sample" "$instpath/etc" if [ ! -s "$instpath/etc/ipp-os-shutdown.conf" ]; then cp -f "$instpath/etc/ipp-os-shutdown.conf.sample" \ "$instpath/etc/ipp-os-shutdown.conf" >> "$LOG_FILE" 2>&1 fi chown root:ipp "$instpath/etc/ipp-os-shutdown.conf" >> "$LOG_FILE" 2>&1 chmod 640 "$instpath/etc/ipp-os-shutdown.conf" >> "$LOG_FILE" 2>&1 #custom shutdown procedure script cp "$COMMON_DIR/ipp-host-shutdown.sample" "$instpath/sbin" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/sbin/ipp-host-shutdown.sample" >> "$LOG_FILE" 2>&1 chmod 644 "$instpath/sbin/ipp-host-shutdown.sample" >> "$LOG_FILE" 2>&1 #notifier script cp "$COMMON_DIR/ipp-notifier.sh" "$instpath/bin" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/bin/ipp-notifier.sh" >> "$LOG_FILE" 2>&1 chmod 754 "$instpath/bin/ipp-notifier.sh" >> "$LOG_FILE" 2>&1 #sensitive config file, including passwords cp -f "$COMMON_DIR/ipp.conf" "$instpath/etc/ipp.conf.sample" >> "$LOG_FILE" 2>&1 if [ ! -s "$instpath/etc/ipp.conf" ]; then cp -f "$instpath/etc/ipp.conf.sample" "$instpath/etc/ipp.conf" >> "$LOG_FILE" 2>&1 fi chown root:ipp "$instpath/etc/ipp.conf" >> "$LOG_FILE" 2>&1 chmod 640 "$instpath/etc/ipp.conf" >> "$LOG_FILE" 2>&1 #uninstall-ipp cp uninstall-ipp "$instpath/bin" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/bin/uninstall-ipp" >> "$LOG_FILE" 2>&1 chmod 744 "$instpath/bin/uninstall-ipp" >> "$LOG_FILE" 2>&1 cp "$COMMON_DIR/string.sh" "$instpath/share" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/share/string.sh" >> "$LOG_FILE" 2>&1 chmod 644 "$instpath/share/string.sh" >> "$LOG_FILE" 2>&1 cp "$COMMON_DIR"_$lang/install.res "$instpath/share" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/share/install.res" >> "$LOG_FILE" 2>&1 chmod 644 "$instpath/share/install.res" >> "$LOG_FILE" 2>&1 #ipp-status cp "$COMMON_DIR/ipp-status" "$instpath/bin" >> "$LOG_FILE" 2>&1 chown root:ipp "$instpath/bin/ipp-status" >> "$LOG_FILE" 2>&1 chmod 755 "$instpath/bin/ipp-status" >> "$LOG_FILE" 2>&1 } ####################### # Configuration screens initial_configure () { conf_ok="" while [ -z "$conf_ok" ]; do C_NUM_DEV=0 choose_mode if [ $? = 1 ]; then review_conf fi done # Make sure configuration files are not world readable chown ipp:ipp "$instpath/etc/ups.conf" >> "$LOG_FILE" 2>&1 chmod 640 "$instpath/etc/ups.conf" >> "$LOG_FILE" 2>&1 chown ipp:ipp "$instpath/etc/upsd.conf" >> "$LOG_FILE" 2>&1 chmod 640 "$instpath/etc/upsd.conf" >> "$LOG_FILE" 2>&1 chown ipp:ipp "$instpath/etc/nut.conf" >> "$LOG_FILE" 2>&1 chmod 640 "$instpath/etc/nut.conf" >> "$LOG_FILE" 2>&1 chown ipp:ipp "$instpath/etc/upsmon.conf" >> "$LOG_FILE" 2>&1 chmod 640 "$instpath/etc/upsmon.conf" >> "$LOG_FILE" 2>&1 chown ipp:ipp "$instpath/etc/upsd.users" >> "$LOG_FILE" 2>&1 chmod 640 "$instpath/etc/upsd.users" >> "$LOG_FILE" 2>&1 # Report the SHUTDOWNSCRIPT_CUSTOM value or that it is missing _VAR="`egrep '^[ \t]*SHUTDOWNSCRIPT_CUSTOM=' "$instpath/etc/ipp.conf" 2>/dev/null`" || CC_SHUTDOWNSCRIPT_CUSTOM="" if [ -n "${_VAR}" ] ; then _VAR="`echo "${_VAR}" | sed 's,^[ \t]*SHUTDOWNSCRIPT_CUSTOM=,,'`" _VAR="`echo "${_VAR}" | sed -e 's,^"\(.*\)"$,\1,g' -e "s,^\'\(.*\)\'$,\1,g"`" case "${_VAR}" in *NUT_DIR*) _VAR1="`egrep '^[^\#]*NUT_DIR=' "$instpath/etc/ipp.conf" 2>/dev/null`" \ && [ -n "${_VAR1}" ] && _VAR1="`eval $_VAR1 && echo "$NUT_DIR"`" && [ -n "${_VAR1}" ] \ && _VAR2="`NUT_DIR="${_VAR1}" ; eval echo "${_VAR}"`" \ && [ -n "${_VAR2}" ] && _VAR="${_VAR2}" ;; esac if [ -n "${_VAR}" ] && [ -s "${_VAR}" ] && [ -x "${_VAR}" ]; then echo "INFO: Your ipp.conf contains SHUTDOWNSCRIPT_CUSTOM='${_VAR}' which points to an executable file" else echo "WARNING: Your ipp.conf contains SHUTDOWNSCRIPT_CUSTOM='${_VAR}' which points to a missing or not executable file" fi else echo "WARNING: Your ipp.conf does not have a SHUTDOWNSCRIPT_CUSTOM set, you might want one" fi unset _VAR _VAR1 _VAR2 } choose_network() { necho $CS_SEPARATOR_1 necho $CS_NETWORK_1 necho $CS_SEPARATOR_1 echo necho $CS_NETWORK_2 echo necho $CS_NETWORK_3 necho $CS_NETWORK_4 read_def $CS_NETWORK_5 "1" case "$answer" in [2]) C_MODE="netserver" ;; *) C_MODE="standalone" ;; esac } display_device () { DISP_COUNTER=1 while [ "$DISP_COUNTER" -le "$C_NUM_DEV" ]; do eval TMP=\$C_DEVICE"$DISP_COUNTER" # DEV_TYPE="`printf "${DISP_COUNTER}- $TMP" | awk -F' ' '{print \$2}'`" DEV_CONF="`echo "$TMP" | awk -F' ' '{print \$3}'`" echo " " "$DISP_COUNTER". "$DEV_TYPE" "$DEV_CONF" DISP_COUNTER="`expr $DISP_COUNTER + 1`" done } remove_ups () { if [ "$answer" -lt 1 ]; then necho $CS_REMOVE_UPS_2 return fi if [ "$answer" -gt "$C_NUM_DEV" ]; then necho $CS_REMOVE_UPS_2 return fi OLD_NUM_DEV="$C_NUM_DEV" C_NUM_DEV="`expr $C_NUM_DEV - 1`" if [ "$C_NUM_DEV" -ne 0 ]; then eval C_DEVICE$answer=\${C_DEVICE$OLD_NUM_DEV} eval C_OPTION$answer=\${C_OPTION$OLD_NUM_DEV} fi } #return 0 to go back #return 1 to continue the configuration #retuen 2 to add another UPS manage_ups () { if [ "$C_NUM_DEV" = 0 ]; then return 0 fi necho $CS_SEPARATOR_1 necho $CS_ANOTHER_UPS_1 necho $CS_SEPARATOR_1 echo display_device echo necho $CS_ANOTHER_UPS_2 necho $CS_ANOTHER_UPS_3 necho $CS_ANOTHER_UPS_4 necho $CS_ANOTHER_UPS_5 read_def $CS_ANOTHER_UPS_6 "1" case "$answer" in [2]) return 2 ;; [3]) read_def $CS_REMOVE_UPS_1 "" remove_ups ret="" manage_ups ret=$? return $ret ;; [0]) return 0 ;; *) return 1 ;; esac } choose_mode() { necho $CS_SEPARATOR_1 necho $CS_WELCOME_1 necho $CS_SEPARATOR_1 echo necho $CS_MANAGE_1 echo necho $CS_MANAGE_2 necho $CS_MANAGE_3 read_def $CS_MANAGE_4 "1" case "$answer" in [2]) necho $CS_SEPARATOR_1 necho $CS_CLIENT_SD_DURATION_1 necho $CS_SEPARATOR_1 echo necho $CS_CLIENT_SD_DURATION_2 read TMP choose_esd_timer C_MODE="netclient" ret=2 while [ $ret = 2 ]; do choose_server manage_ups ret=$? done ;; *) choose_shutdown_duration choose_esd_timer choose_network ret=2 while [ $ret = 2 ]; do choose_connectivity manage_ups ret=$? done if [ $ret = 1 ]; then ret="" choose_password ret=$? fi if [ $C_NUM_DEV -gt 0 ]; then ret="" choose_static_powercycle ret=$? fi ;; esac if [ $ret = 1 ]; then if [ $C_NUM_DEV -gt 1 ]; then ret="" choose_minsupplies ret=$? fi fi return $ret } choose_static_powercycle() { necho $CS_SEPARATOR_1 necho $CS_STATIC_POWERCYCLE_1 necho $CS_SEPARATOR_1 answer="x" while [ "$answer" != "" ] && [ "$answer" != "forbid" ] && [ "$answer" != "enforce" ]; do read_def $CS_STATIC_POWERCYCLE_2 "$C_POWERDOWNFLAG_USER" #Check if this is a valid answer case "$answer" in [Ff]|[Ff][Oo][Rr][Bb][Ii][Dd]|[Nn]|[Nn][Oo]) answer="forbid" ;; [Ee]|[Ee][Nn][Ff][Oo][Rr][Cc][Ee]|[Yy]|[Yy][Ee][Ss]) answer="enforce" ;; ""|[Aa][Uu][Tt][Oo]) answer="" ;; *) necho $CS_ERR_BADSTRING answer="x" ;; esac done C_POWERDOWNFLAG_USER="$answer" return 1 } choose_esd_timer() { necho $CS_SEPARATOR_1 necho $CS_ESDTIMER_1 necho $CS_SEPARATOR_1 answer="" while [ "$answer" = "" ]; do read_def $CS_ESDTIMER_2 "$C_SHUTDOWN_TIMER" #Check if this is a valid number if [ "$answer" = "" ]; then answer="-1"; fi if echo "$answer" | egrep '^\-*[0-9]+$' > /dev/null 2>&1 ; then #this is a number if [ $answer -lt 0 ]; then answer="-1" fi else necho $CS_ERR_NO_NUM answer="" fi done C_SHUTDOWN_TIMER="$answer" return 1 } choose_minsupplies() { necho $CS_SEPARATOR_1 necho $CS_MINSUP_1 necho $CS_SEPARATOR_1 answer="" while [ "$answer" = "" ]; do read_def $CS_MINSUP_2 $C_NUM_DEV #Check if this is a valid number if echo "$answer" | egrep '^[0-9]+$' > /dev/null 2>&1 ; then #this is a number if [ $answer -lt 1 ]; then answer="" fi else necho $CS_ERR_NO_NUM answer="" fi done; C_MINSUPPLIES="$answer" if [ "$answer" -gt "$C_NUM_DEV" ]; then C_MINSUPPLIES="$C_NUM_DEV" fi return 1 } choose_connectivity() { ret="0" while [ $ret = "0" ]; do necho $CS_SEPARATOR_1 necho $CS_CONNECTIVITY_1 necho $CS_SEPARATOR_1 echo necho $CS_CONNECTIVITY_2 necho $CS_CONNECTIVITY_3 necho $CS_CONNECTIVITY_4 read_def $CS_CONNECTIVITY_5 "1" case "$answer" in [0]) return 0 ;; [2]) #TODO choose_xml_manual_or_auto ret=$? ;; *) choose_ask_scan_serial ret=$? ;; esac done return $ret } choose_ask_scan_serial() { ret="0" while [ $ret = "0" ]; do necho $CS_SEPARATOR_1 necho $CS_ASK_SERIAL_1 necho $CS_SEPARATOR_1 echo necho $CS_ASK_SERIAL_2 echo necho $CS_ASK_SERIAL_3 necho $CS_ASK_SERIAL_4 necho $CS_ASK_SERIAL_5 read_def $CS_ASK_SERIAL_6 "1" case "$answer" in [0]) return 0 ;; [2]) choose_manual_serial ret=$? ;; *) choose_serial ret=$? ;; esac done return $ret } choose_serial() { serial_list="`$NUTCONF --scan-serial auto 2>> "$LOG_FILE"`" if [ x"$serial_list" = x"" ]; then echo read_def $CS_ERR_NO_SERIAL "" echo return 0 fi necho $CS_SEPARATOR_1 necho $CS_SERIAL_1 necho $CS_SEPARATOR_1 echo OLD1_IFS="$IFS" IFS=" " i="1" for s in $serial_list; do DEV_NAME="`echo "$s" | awk -F' ' '{print \$3}'`" echo " $i. $DEV_NAME" i="`expr $i + 1`" done IFS="$OLD1_IFS" necho $CS_SERIAL_3 read_def $CS_SERIAL_4 "1" case "$answer" in [0]) return 0 ;; *) OLD1_IFS="$IFS" IFS=" " C_NUM_DEV="`expr $C_NUM_DEV + 1`" i="1" for s in $serial_list; do if [ "$i" = "$answer" ]; then eval C_DEVICE$C_NUM_DEV=\"$s\" eval C_OPTION$C_NUM_DEV=\"\" break; fi i="`expr $i + 1`" done IFS="$OLD1_IFS" ;; esac return 1 } choose_manual_serial () { necho $CS_SEPARATOR_1 necho $CS_MANUAL_SERIAL_1 necho $CS_SEPARATOR_1 echo necho $CS_MANUAL_SERIAL_2 read_def $CS_MANUAL_SERIAL_3 "" DEV="`$NUTCONF --scan-serial $answer 2>> "$LOG_FILE"`" if [ "$DEV" = "" ]; then read_def $CS_MANUAL_SERIAL_ERR "" return 0; fi C_NUM_DEV="`expr $C_NUM_DEV + 1`" eval C_DEVICE$C_NUM_DEV=$DEV return 1 } choose_xml_manual_or_auto() { necho $CS_SEPARATOR_1 necho $CS_XML_MANU_AUTO_1 necho $CS_SEPARATOR_1 echo necho $CS_XML_MANU_AUTO_2 echo necho $CS_XML_MANU_AUTO_3 necho $CS_XML_MANU_AUTO_4 necho $CS_XML_MANU_AUTO_5 read_def $CS_XML_MANU_AUTO_6 "1" case "$answer" in [2]) choose_xml_manual return $? ;; [0]) return 0 ;; *) choose_xml return $? esac } choose_xml_manual() { necho $CS_SEPARATOR_1 necho $CS_XML_MANU_1 necho $CS_SEPARATOR_1 echo read_def $CS_XML_MANU_2 "" if [ x"$answer" = x"" ]; then return 0 fi C_NUM_DEV="`expr $C_NUM_DEV + 1`" eval C_DEVICE$C_NUM_DEV=\"XML netxml-ups http://$answer\" nmc_login return 1 } choose_xml() { necho $CS_SEPARATOR_1 necho $CS_SNMP_1 necho $CS_SEPARATOR_1 echo necho $CS_SNMP_2 echo necho $CS_SNMP_6 echo LIST_XML="`$NUTCONF --scan-xml-http 2>> "$LOG_FILE"`" if [ "$LIST_XML" = "" ]; then read_def $CS_SNMP_7 "" choose_snmp return $? fi LIST_XML="`echo "$LIST_XML" | sort`" echo OLD1_IFS="$IFS" IFS=" " i="1" for s in $LIST_XML; do #FIXME: If there is a comma in the description, the description #will be shown up to this comma only. IP_ADDR="`echo "$s" | awk -F' ' '{print \$3}' | sed 's/http:\/\///g'`" #DESC="`echo "$s" | awk -F\" '{print $6}' | sed -e "s/^.*\"\(.*\)\".*$/\1/"`" echo " $i. $IP_ADDR" i="`expr $i + 1`" done IFS="$OLD1_IFS" # Ask to scan for more UPS printf " $i. " necho $CS_SNMP_10 necho $CS_SNMP_9 read_def $CS_SNMP_8 "1" case "$answer" in "$i") choose_snmp return $? ;; [0]) return 0 ;; *) OLD1_IFS="$IFS" IFS=" " C_NUM_DEV="`expr $C_NUM_DEV + 1`" i="1" for s in $LIST_XML; do if [ "$i" = "$answer" ]; then eval C_DEVICE$C_NUM_DEV=\"$s\" nmc_login IFS=$OLD1_IFS return 1; fi i="`expr $i + 1`" done IFS="$OLD1_IFS" C_NUM_DEV="`expr $C_NUM_DEV - 1`" ;; esac return 0 } choose_snmp() { necho $CS_SEPARATOR_1 necho $CS_SNMP_1 necho $CS_SEPARATOR_1 echo necho $CS_SNMP_2 echo read_def $CS_SNMP_3 $FIRST_IP FIRST_IP="$answer" if [ "$answer" = "" ]; then return 0 fi read_def $CS_SNMP_4 $LAST_IP LAST_IP="$answer" if [ "$answer" = "" ]; then LAST_IP="$FIRST_IP" fi echo read_def $CS_SNMP_5 $C_COMMUNITY C_COMMUNITY="$answer" echo necho $CS_SNMP_6 echo list="`$NUTCONF --scan-snmp "$FIRST_IP" "$LAST_IP" community="$C_COMMUNITY" 2>> "$LOG_FILE"`" list="`echo "$list" | sort`" echo filter_snmp_list if [ "$LIST_SNMP" = "" ]; then read_def $CS_SNMP_7 "" return 0 fi OLD1_IFS="$IFS" IFS=" " i="1" for s in $LIST_SNMP; do #FIXME: If there is a comma in the description, the description #will be shown up to this comma only. IP_ADDR="`echo "$s" | awk -F' ' '{print \$3}'`" #DESC="`echo "$s" | awk -F\" '{print $6}' | sed -e "s/^.*\"\(.*\)\".*$/\1/"`" echo " $i. $IP_ADDR" i="`expr $i + 1`" done IFS="$OLD1_IFS" necho $CS_SNMP_9 read_def $CS_SNMP_8 "1" case "$answer" in [0]) return 0 ;; *) OLD1_IFS="$IFS" IFS=" " C_NUM_DEV="`expr $C_NUM_DEV + 1`" i="1" for s in $LIST_SNMP; do if [ "$i" = "$answer" ]; then eval C_DEVICE$C_NUM_DEV=\"$s\" eval C_OPTION$C_NUM_DEV=\"community=$C_COMMUNITY\" IFS="$OLD1_IFS" return 1 fi i="`expr $i + 1`" done IFS="$OLD1_IFS" C_NUM_DEV="`expr $C_NUM_DEV - 1`" ;; esac return 0 } #Remove XML devices from the SNMP list filter_snmp_list() { LIST_SNMP="" OLD1_IFS="$IFS" IFS=" " for s in $list; do IP_SNMP="`echo "$s" | awk -F' ' '{print \$3}'`" TO_ADD="$s" for x in $LIST_XML; do IP_XML="`echo "$x" | awk -F' ' '{print \$3}' | sed 's/http:\/\///g'`" if [ "$IP_SNMP" = "$IP_XML" ]; then TO_ADD="" break fi done if [ ! "$TO_ADD" = "" ]; then LIST_SNMP="`echo "$LIST_SNMP";echo "$TO_ADD"`" fi done IFS="$OLD1_IFS" } #only used in netclient mode choose_server() { necho $CS_SEPARATOR_1 necho $CS_SERVER_1 necho $CS_SEPARATOR_1 echo necho $CS_SERVER_2 echo read_def $CS_SERVER_3 "" FIRST_IP="$answer" if [ x"$answer" = x"" ]; then return 0 fi read_def $CS_SERVER_4 "" LAST_IP="$answer" if [ x"$answer" = x"" ]; then LAST_IP=$FIRST_IP fi echo necho $CS_SERVER_5 echo list="`$NUTCONF --scan-nut "$FIRST_IP" "$LAST_IP" "$NUT_PORT" 2>> "$LOG_FILE"`" #TODO parse scan results if [ "$list" = "" ]; then read_def $CS_SERVER_6 "" return 0 fi echo OLD1_IFS="$IFS" IFS=" " i="1" for s in $list; do UPS="`echo "$s" | awk -F' ' '{print \$3}'`" echo " $i. $UPS" i="`expr $i + 1`" done IFS="$OLD1_IFS" necho $CS_SERVER_8 read_def $CS_SERVER_7 "1" case "$answer" in [0]) return 0 ;; *) echo "$C_NUM_DEV" C_NUM_DEV="`expr $C_NUM_DEV + 1`" echo "$C_NUM_DEV" i="1" OLD1_IFS="$IFS" IFS=" " for s in $list; do if [ "$i" = "$answer" ]; then eval C_DEVICE$C_NUM_DEV=\"$s\" eval C_OPTION$C_NUM_DEV=\"\" break fi i="`expr $i + 1`" done IFS="$OLD1_IFS" ;; esac return 1 } choose_password() { necho $CS_SEPARATOR_1 necho $CS_PASSWORD_1 necho $CS_SEPARATOR_1 answer="" PASS1="1" while [ ! "$answer" = "$PASS1" ] || [ -z "$answer" ]; do read_def_silent $CS_PASSWORD_3 "" PASS1="$answer" read_def_silent $CS_PASSWORD_4 "" if [ ! "$answer" = "$PASS1" ]; then echo necho $CS_ERR_PASSWORDS_DIFFER echo fi done C_PASSWORD="$answer" return 1 } get_networked_device() { NDEV=0 C_NUM_NETWORK_DEVICE=0 while [ "$NDEV" -lt "$C_NUM_DEV" ]; do NDEV="`expr $NDEV + 1`" eval TMP=\$C_DEVICE"$NDEV" DRIVER="`echo "$TMP" | awk -F' ' '{print \$2}'`" if [ "$DRIVER" = "netxml-ups" ]; then C_NUM_NETWORK_DEVICE="`expr $C_NUM_NETWORK_DEVICE + 1`" fi done } nmc_login() { necho $CS_SEPARATOR_1 necho $CS_NMC_LOGIN_1 necho $CS_SEPARATOR_1 echo read_def $CS_NMC_LOGIN_2 "admin" NMC_LOGIN="$answer" answer="" PASS1="1" while [ ! "$answer" = "$PASS1" ]; do read_def_silent $CS_NMC_LOGIN_3 "" PASS1="$answer" read_def_silent $CS_NMC_LOGIN_4 "" if [ ! "$answer" = "$PASS1" ]; then echo necho $CS_ERR_PASSWORDS_DIFFER echo fi done ESD_NETXML_OPTION="" if [ "$C_SHUTDOWN_TIMER" -gt 0 ] 2>/dev/null; then # Note the leading space is included if value is set # Also note this is a cosmetic setting for NMC web-gui # to display the value, discrepancies that creep in # during later system administration are not sync'ed. ESD_NETXML_OPTION=" shutdown_timer=`expr $C_SHUTDOWN_TIMER \* 60`" || \ ESD_NETXML_OPTION="" fi if [ "$C_SHUTDOWN_TIMER" -eq 0 ] 2>/dev/null; then # Some value >0 must be set to be picked up; for this # choice of "1 sec" the NMC Web-GUI shows "0 min" anyway ESD_NETXML_OPTION=" shutdown_timer=1" fi eval C_OPTION$C_NUM_DEV=\"login=$NMC_LOGIN password=$answer subscribe=yes$ESD_NETXML_OPTION shutdown_duration=$C_SHUTDOWN_DURATION\" } choose_shutdown_duration() { necho $CS_SEPARATOR_1 necho $CS_SHUTOFF_DELAY_1 necho $CS_SEPARATOR_1 echo answer="" while [ "$answer" = "" ]; do read_def $CS_SHUTOFF_DELAY_3 "$C_SHUTDOWN_DURATION" #Check if this is a valid number if echo "$answer" | egrep '^[0-9]+$' > /dev/null 2>&1; then #this is a number, do nothing sleep 0 else necho $CS_ERR_NO_NUM answer="" fi done; C_SHUTDOWN_DURATION="$answer" return 1 } set_shutdown_command_legacy() { SHUTDOWN_CMD="$instpath/shutdown;/usr/sbin/shutdown" case "$system" in solari) $NUTCONF --set-shutdowncmd "$SHUTDOWN_CMD -y -g 0 -i 5" 2>> "$LOG_FILE" ;; solint) $NUTCONF --set-shutdowncmd "$SHUTDOWN_CMD -y -g 0 -i 5" 2>> "$LOG_FILE" ;; hpux) $NUTCONF --set-shutdowncmd "cd /;$SHUTDOWN_CMD -y -h now" 2>> "$LOG_FILE" ;; aix) $NUTCONF --set-shutdowncmd "$SHUTDOWN_CMD -h +0" 2>> "$LOG_FILE" ;; *) ;; esac } set_shutdown_command() { if [ -x "$instpath/sbin/ipp-os-shutdown" ]; then # The new common logic is available, use it $NUTCONF --set-shutdowncmd "$instpath/sbin/ipp-os-shutdown -t now" 2>> "$LOG_FILE" else # Use old OS-specific snippets set_shutdown_command_legacy fi $NUTCONF --set-powerdownflag "$instpath/etc/killpower" 2>> "$LOG_FILE" } set_notify() { # Events messages (mc2/scripts/lang/eng.lbl) # '/Event/UPS.PowerSummary.PresentStatus.ACPresent/1' $NUTCONF --set-notifymsg ONLINE "The system is powered by the utility" 2>> "$LOG_FILE" # "UPS %s on line power" # '/Event/UPS.PowerSummary.PresentStatus.ACPresent/0' $NUTCONF --set-notifymsg ONBATT "The system is powered by the UPS battery" 2>> "$LOG_FILE" #"UPS %s on battery" # '/Event/UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit/1' $NUTCONF --set-notifymsg LOWBATT "Low battery alarm" 2>> "$LOG_FILE" # "UPS %s battery is low" # ? $NUTCONF --set-notifymsg FSD "UPS %s: forced shutdown in progress" 2>> "$LOG_FILE" # '/Event/System.CommunicationLost/0' $NUTCONF --set-notifymsg COMMOK "Communication with device is restored" 2>> "$LOG_FILE" # "Communications with UPS %s established" # '/Event/System.CommunicationLost/1' $NUTCONF --set-notifymsg COMMBAD "Communication with device has failed" 2>> "$LOG_FILE" # "Communications with UPS %s lost" # ? $NUTCONF --set-notifymsg SHUTDOWN "Auto logout and shutdown proceeding" 2>> "$LOG_FILE" # '/Event/UPS.PowerSummary.PresentStatus.NeedReplacement/1' $NUTCONF --set-notifymsg REPLBATT "Battery fault" 2>> "$LOG_FILE" # "UPS %s battery needs to be replaced" $NUTCONF --set-notifymsg NOCOMM "UPS %s is unavailable" 2>> "$LOG_FILE" $NUTCONF --set-notifymsg NOPARENT "Shutdown failure" 2>> "$LOG_FILE" # "upsmon parent process died - shutdown impossible" # Enable mail notification $NUTCONF --set-notifycmd "$instpath/bin/ipp-notifier.sh" 2>> "$LOG_FILE" $NUTCONF --set-notifyflags ONLINE EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags ONBATT EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags LOWBATT EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags FSD EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags COMMOK EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags COMMBAD EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags SHUTDOWN EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags REPLBATT EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags NOCOMM EXEC 2>> "$LOG_FILE" $NUTCONF --set-notifyflags NOPARENT EXEC 2>> "$LOG_FILE" } set_ippconf_value() { # Replaces a value in the installed ipp.conf which is an assignment # of "$1='$2'" and which is not a comment (optional whitespace may # be prepended in the present line, but will be removed in the end) egrep -v '^[ \t]*('"$1"')=' "$instpath/etc/ipp.conf" \ > "$instpath/etc/ipp.conf.tmp" && \ echo "$1='$2'" >> "$instpath/etc/ipp.conf.tmp" && \ cat "$instpath/etc/ipp.conf.tmp" > "$instpath/etc/ipp.conf" res=$? rm -f "$instpath/etc/ipp.conf.tmp" return $res } set_shutdown_duration() { set_ippconf_value DELAY "$C_SHUTDOWN_DURATION" set_ippconf_value PASSWORD "$C_PASSWORD" } set_minsupplies() { $NUTCONF --set-minsupplies "$C_MINSUPPLIES" 2>> "$LOG_FILE" } set_debug_flag() { # Keep an old value if it was set egrep '^[ \t]*IPP_DEBUG=' "$instpath/etc/ipp.conf" >/dev/null || \ echo "IPP_DEBUG='$IPP_DEBUG'" >> "$instpath/etc/ipp.conf" } set_esd_timer() { set_ippconf_value SHUTDOWN_TIMER "$C_SHUTDOWN_TIMER" } set_host_os_flavour() { set_ippconf_value HOST_OS_FLAVOUR "$system" } set_static_powercycle() { # Generally this variable should be left empty and the powercycling # would be enabled or diabled based on killpower flag. However in some # cases a user may want to enforce the setting (e.g. last ESD host). set_ippconf_value POWERDOWNFLAG_USER "$C_POWERDOWNFLAG_USER" } review_conf() { display_conf read_def $CS_REVIEW_10 "n" case "$answer" in [yY]) conf_ok="ok" $NUTCONF --set-mode "$C_MODE" 2>> "$LOG_FILE" case "$C_MODE" in netclient) apply_conf_client ;; netserver) apply_conf_server ;; standalone) apply_conf_standalone ;; esac set_minsupplies set_shutdown_command set_notify set_shutdown_duration set_esd_timer set_static_powercycle set_debug_flag ;; *) ;; esac } display_conf() { necho $CS_SEPARATOR_1 necho $CS_REVIEW_1 necho $CS_SEPARATOR_1 echo if [ "$C_MODE" = "standalone" ]; then necho $CS_REVIEW_2 fi if [ "$C_MODE" = "netserver" ]; then necho $CS_REVIEW_3 fi if [ "$C_MODE" = "netclient" ]; then necho $CS_REVIEW_4 fi echo necho $CS_REVIEW_5 display_device echo if [ "$C_NUM_DEV" -gt 1 ]; then necho $CS_REVIEW_6 " " $C_MINSUPPLIES fi necho $CS_REVIEW_7 " " $C_SHUTDOWN_TIMER echo necho $CS_REVIEW_8 " " $C_SHUTDOWN_DURATION echo necho $CS_REVIEW_9 " " $C_POWERDOWNFLAG_USER echo } apply_conf_client() { NDEV=1 $NUTCONF --set-user upsmon=slave password=upsmon 2>> "$LOG_FILE" eval TMP=\$C_DEVICE$NDEV DEV="`echo "$TMP" | awk -F' ' '{print \$3}'`" UPS="`echo "$DEV" | awk -F'@' '{print \$1}'`" HOST="`echo "$DEV"| awk -F'@' '{print \$2}'`" # TODO: Here we assume that one UPS powers one input of the server # Logically this can mismatch our setting of MINSUPPLIES if the user # (later) specifies real powersource counts, and topology is not 1:1 $NUTCONF --set-monitor "${UPS}" "$HOST" 1 upsmon upsmon slave 2>> "$LOG_FILE" while [ "$NDEV" -lt "$C_NUM_DEV" ]; do NDEV="`expr $NDEV + 1`" eval TMP=\$C_DEVICE$NDEV DEV="`echo "$TMP" | awk -F' ' '{print \$3}'`" UPS="`echo "$DEV" | awk -F'@' '{print \$1}'`" HOST="`echo "$DEV"| awk -F'@' '{print \$2}'`" $NUTCONF --add-monitor "${UPS}" "$HOST" 1 upsmon upsmon slave 2>> "$LOG_FILE" done } split_device () { eval TMP=\$C_DEVICE$NDEV ID="`echo "$TMP" | awk -F' ' '{print \$1}'`" DRIVER="`echo "$TMP" | awk -F' ' '{print \$2}'`" PORT="`echo "$TMP" | awk -F' ' '{print \$3}'`" } setup_tty () { local TTY="$1" > "$LOG_FILE" 2>&1 chmod 666 "$TTY" > "$LOG_FILE" 2>&1 chown ipp:ipp "$TTY" > "$LOG_FILE" 2>&1 } set_device_monitor_user () { NDEV=1 split_device eval TMP=\$C_OPTION$NDEV $NUTCONF --set-device "${ID}$NDEV" "$DRIVER" "$PORT" $TMP 2>> "$LOG_FILE" $NUTCONF --set-monitor "${ID}$NDEV" localhost 1 upsmon upsmon master 2>> "$LOG_FILE" echo "$PORT" | grep '^/dev/tty' >/dev/null && setup_tty "$PORT" while [ "$NDEV" -lt "$C_NUM_DEV" ]; do NDEV="`expr $NDEV + 1`" split_device eval TMP=\$C_OPTION$NDEV $NUTCONF --add-device "${ID}$NDEV" "$DRIVER" "$PORT" $TMP 2>> "$LOG_FILE" $NUTCONF --add-monitor "${ID}$NDEV" localhost 1 upsmon upsmon master 2>> "$LOG_FILE" echo "$PORT" | grep '^/dev/tty' >/dev/null && setup_tty "$PORT" done $NUTCONF --set-user admin password="$C_PASSWORD" actions=SET instcmds=all 2>> "$LOG_FILE" $NUTCONF --add-user upsmon=master password=upsmon 2>> "$LOG_FILE" } apply_conf_server() { $NUTCONF --set-listen 0.0.0.0 2>> "$LOG_FILE" set_device_monitor_user } apply_conf_standalone () { $NUTCONF --set-listen 127.0.0.1 2>> "$LOG_FILE" set_device_monitor_user } start_service () { necho $CS_START_SERVICE stop_service case "$system" in solari) /etc/init.d/nut start >> "$LOG_FILE" 2>&1 ;; solint) /etc/init.d/nut start >> "$LOG_FILE" 2>&1 ;; hpux) /sbin/init.d/nut-drvctl start >> "$LOG_FILE" 2>&1 /sbin/init.d/nut-upsd start >> "$LOG_FILE" 2>&1 /sbin/init.d/nut-upsmon start >> "$LOG_FILE" 2>&1 ;; aix) /etc/rc.d/init.d/ups start >> "$LOG_FILE" 2>&1 ;; *) ;; esac } stop_service () { case $system in solari) /etc/init.d/nut stop >> "$LOG_FILE" 2>&1 ;; solint) /etc/init.d/nut stop >> "$LOG_FILE" 2>&1 ;; hpux) /sbin/init.d/nut-drvctl stop >> "$LOG_FILE" 2>&1 /sbin/init.d/nut-upsd stop >> "$LOG_FILE" 2>&1 /sbin/init.d/nut-upsmon stop >> "$LOG_FILE" 2>&1 ;; aix) /etc/rc.d/init.d/ups stop >> "$LOG_FILE" 2>&1 ;; *) ;; esac } add_hpux_upsmon_esd_support () { if [ -f /etc/rc.config.d/nut-upsmon ]; then cat >>/etc/rc.config.d/nut-upsmon < /tmp/nut-upsmon.tmp.$$ mv /tmp/nut-upsmon.tmp.$$ /etc/rc.config.d/nut-upsmon fi } add_profile_settings () { if [ -f /etc/profile ]; then cat >>/etc/profile < /tmp/profile.tmp.$$ mv /tmp/profile.tmp.$$ /etc/profile fi } main () { # Setup some globals instpath=/usr/local/ups #skip_install=true #skip_license=true #skip_service=true #skip_config=true ret=TRUE # Must check parameters lang="" SYSTEM="" if [ "$1" != "" ] ; then get_parameters $1 fi if [ "$2" != "" ] ; then get_parameters $2 fi if [ "$3" != "" ] ; then get_parameters $3 fi # Get language locale if [ "$lang" = "" ]; then check_locale_language if [ -z "$lang" ]; then lang=EN fi fi # Initialize resource strings. installres="$COMMON_DIR"_$lang/install.res licenseres="$COMMON_DIR"_$lang/license.txt initDefines compute_SYSTEM systemdir="$system" NUTCONF="$systemdir/nutconf" who="`whoami 2>/dev/null`" if [ "$who" != 'root' ]; then #work around in case no whoami is present who="`id -u 2>/dev/null`" if [ "$who" != '0' ]; then who="`id 2>/dev/null | grep -w '0' | grep -w root`" if [ -z "$who" ]; then necho $ERR_ROOT exit 1 fi fi fi # Say hello # we'll install vanilla IPP unix. clear echo echo echo "-----------------------------------------------------------------" echo echo " EATON" echo # echo "Welcome to IPP Unix!" necho $WELCOME_STR1 # echo " `pwd`/$0 Version 5.0.0" lineStr="`head "-$STR_VERSION" $installres |tail -1`" #echo " `pwd`/$0 $lineStr $lineStr1" echo " $lineStr $IPP_VERSION" echo # echo " To install IPP - Unix, select (y)" # echo "and fill in the configuration items as they are presented to you." necho $WELCOME_STR2 necho $WELCOME_STR3 echo # echo "The default install path name for this software is: $instpath" lineStr="`head -$DEFAULT_PATH_STR $installres |tail -1`" echo " $lineStr" echo " $instpath" echo echo "-----------------------------------------------------------------" echo # echo "NOTE: If you already have LanSafe for Unix installed and you" # echo " do not wish to re-install it, select (N)o to stop" # echo " LanSafe for Unix installation." necho $INSTALL_INTRO_STR1 necho $INSTALL_INTRO_STR2 necho $INSTALL_INTRO_STR3 echo echo # read_def " Continue IPP - Unix installation? (y/n) [y] " "y" read_def $INSTALL_INTRO_STR4 "y" case "$answer" in [yY]|[yY][eE][sS]) ;; *) exit 0 ;; esac if [ x"$system" = x"Unknown System" ] then echo # echo " Unable to determine your system." lineStr="`head -$ERR_UNKNOWN_SYS_STR1 $installres |tail -1`" echo " $lineStr" exit 0 fi # end-of "if system = Unknown system" echo echo # License Agreement if [ -z "$skip_license" ]; then echo " " more $licenseres echo " " necho $LICENSE_AGREEMENT_1 echo necho $LICENSE_AGREEMENT_2 necho $LICENSE_AGREEMENT_3 necho $LICENSE_AGREEMENT_4 echo read_def $LICENSE_AGREEMENT_5 "n" case "$answer" in [yY]|[yY][eE][sS]) ;; *) necho $ERR_LIC_AGREE exit 1 ;; esac fi stop_service # Install files if [ -z "$skip_install" ]; then install_files set_host_os_flavour fi echo echo # Build initial configuration if [ -z "$skip_config" ]; then PATH="$PATH:/usr/local/ups/xbin:/usr/local/ups/bin" export PATH # LD_LIBRARY_PATH="$instpath/lib:/usr/local/lib:$LD_LIBRARY_PATH" # export LD_LIBRARY_PATH initial_configure fi # Add IPP - Unix specific env. settings add_profile_settings # Start service if [ -z "$skip_service" ]; then start_service fi # Say goodbye if [ "$conf_ok" = "ok" ]; then echo "---------------------------------------------------------------" # echo " IPP - Unix was successfully installed on your system. " lineStr="`head -$SUCCESS_INSTALL $installres |tail -1`" echo " $lineStr" echo "---------------------------------------------------------------" else echo "-----------------------------------------------------------------------------" # echo " WARNING: IPP - Unix was NOT successfully installed on your system. " lineStr="`head -$UNSUCCESS_INSTALL $installres |tail -1`" echo " $lineStr" echo "-----------------------------------------------------------------------------" echo # necho $INSTALL_ERROR exit 1 fi } main $1 $2 $3 nut-2.8.3/scripts/installer/Makefile.am0000644000200500020050000000606514777767434015020 00000000000000# Network UPS Tools: scripts/installer EXTRA_DIST = \ README.adoc \ make_package.sh \ version.sh \ install.sh \ uninstall-lsnw.sh \ uninstall-ipp \ nutconf-dummy \ common_EN/license.txt \ common_EN/install.res \ common/solaris_init \ common/ipp-shutdown-daemon.sh \ common/README_ipp-os-shutdown.adoc \ common/ipp-status \ common/ipp.conf \ common/ipp-wrapper \ common/ipp-event.sh \ common/string.sh \ common/ipp-host-shutdown.sample \ common/shutdown \ common/ipp-notifier.sh \ common/ipp-os-shutdown \ common/init \ common/aix_init \ aix/ipp-os-shutdown.conf.sample \ aix/aix_init \ hpux/ipp-os-shutdown.conf.sample \ solcmn/solaris_init \ solcmn/ipp-os-shutdown.conf.sample # Originally an Eaton license was used, changed along with donation of sources # to NUT project. Having the file name populated helps keep the scripts as is. common_EN/license.txt: $(top_srcdir)/LICENSE-GPL2 $(MKDIR_P) '$(@D)' cp -pf '$?' '$@' SPELLCHECK_SRC = README.adoc common/README_ipp-os-shutdown.adoc nut: rm -f "$@" $(LN_S) $(top_srcdir) "$@" # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked */*-spellchecked common_EN/license.txt # Remove "nut" if it is a symlink to the source tree clean-local: if test -L nut || test -h nut ; then rm -f nut ; fi MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.3/scripts/README.adoc0000644000200500020050000000214714777733634012544 00000000000000NUT contributed and integration scripts ======================================= These directories hold various scripts and resources needed for systems integration, and other non-core functionality, which were contributed over time by the NUT Team, side projects and/or general community members (users of the software), including: - example startup and shutdown scripts for various operating systems and distributions, - `hotplug` and `udev` integration for on the fly privileges settings (Linux only), - `UPower` (previously `DeviceKit-power`) rules file, - Python Client module and application, - Perl client module, - Augeas support lenses and modules for NUT, - support to run NUT components as service unit instances: * shared `nut-driver-enumerator` and `upsdrvsvcctl` logic, * `systemd` support files, * SMF (Solaris/illumos Service Management Framework) support files, - init-scripts and/or packaging elements for several Unix operating systems, - Windows build helpers and information, - software-driven USB reset suggestions and helpers (for stuck devices), - `logrotate` integration, - and many others. nut-2.8.3/scripts/external_apis/0000755000200500020050000000000015001555412013642 500000000000000nut-2.8.3/scripts/external_apis/README.adoc0000644000200500020050000000126014777767434015402 00000000000000NUT external API integration scripts ==================================== These directories hold scripts that help integrate NUT with external APIs not yet natively supported. These may include REST API, Web-based JSON, or any other protocol that doesn't have a supported NUT driver but a prototype to interact with the device can be easily scripted. They are useful both for adding the integration to an existing install, or as a starting point for creating new integrations. - `enphase`: web-API based integration with Enphase's locally hosted IQ Gateway. + Supports web-based login and token management, and maps JSON data to files consumed by the linkman:dummy-ups[8] driver. nut-2.8.3/scripts/external_apis/enphase/0000755000200500020050000000000015001555412015265 500000000000000nut-2.8.3/scripts/external_apis/enphase/README.adoc0000644000200500020050000001634714777767434017041 00000000000000Enphase Monitor for dummy-ups ============================= The Enphase Monitor is a `bash` script that queries the local IQ Gateway's API, and makes "Grid On/Off" and Battery State-Of-Charge status available to NUT's `dummy-ups` driver by updating its "port" file (see the linkman:dummy-ups[8] man page). NOTE: Location where we write the data file for `dummy-ups` to process and publish should not be in a temporary file system, as we may inherit some manually added data points in the file that we want to retain across reboots. On systems with wear-prone storage (flash/SSD), you can fiddle with a "manually-made" file that would be copied into a tmpfs mount point, and have the script (and `dummy-ups` driver) pick up *that* tmpfs location with initially inherited data points. The `enphase-monitor` script supports the following: - auto-login to 'enlighten.enphaseenergy.com' to generate and auto-renew tokens for local Gateway API access (tokens are cached until expiration) - retains any (non-generated) values in the "port" file - gracefully handles split-phase or 3-phase input/output values - calculates derived values such as battery voltage, runtime and `ups.load` - handles no-comms with temporary rename of the port file (indicates "stale data") - dedicated configuration file (for login, API query timing, etc.) - enforces access permissions on files containing secrets - is fully self-documented (leading comment in the script included below) - GPLv2 licensed - minimal requirements: `bash`, `jq`, `base64` and `curl` - includes a sample instantiated systemd service for use with `dummy-ups` - includes a "TEST" mode that loops through various states and randomly expires the token Developed by Scott Shambarger Documentation ------------- The script is self-documented, but the following is the script's leading comments block with installation instructions and configuration reference: ---- Usage: enphase-monitor [ ] -c | -c - use named config-file (or set $CONFIG_FILE) - use config-file /etc/ups/enphase-.conf (or set $UPS) may include: -d - increase debug to stderr (2+ exposes secrets!) -h - show help and exit -s - perform one network check and exit -v - verbose output -x - set 'nocomms' and exit" must contain: USERNAME= PASSWORD= SERIAL= PORT_FILE= and optionally (defaults shown): DISABLE_METERS= any value to disable power reporting ENVOY_HOST="envoy.local" ip/hostname of IQ Gateway on local network STATE_DIR="$NUT_STATEPATH" (e.g. "/var/lib/ups") writable directory for portfile/tokens POLLFREQ=60 seconds between API queries, min 5 POLLFREQALERT=20 seconds between API queries when on battery, min 5 TOKEN_FILE="enphase-.token" path defaults to STATE_DIR LOADKWH=768 max load/1kWh capacity, used for ups.load calculation 0 disables calc (default based on IQ 5P rate 3.84kVA/5kWh) LOGIN_TIMEOUT=10 timeout (secs) for login/token gen, min 5 API_TIMEOUT=5 timeout (secs) for local ENVOY_HOST api access, min 2 Add section to /etc/ups/ups.conf for your name (replace ) [] driver = dummy-ups port = / this should be an absolute path! mode = dummy-once or name with `.dev` extension desc = "Enphase IQ Gateway" MUST EXIST before running the monitor (to ensure it's running on the correct machine). The following entries are optional but used if specified (defaults shown); other non-generated entries are retained. battery.charge.low: 20 battery.voltage.high: 86.4 battery.voltage.nominal: 76.8 battery.voltage.low: 68.5 device.mfr: Enphase Energy device.model: IQ Gateway The monitor uses the enphase + to retrieve a long-term token and saves it in STATE_DIR (token renewal is handled automatically) The monitor then queries the ENVOY_HOST (local IQ Gateway) API at POLLFREQ intervals to retrieve the envoy state, and updates . Using values retrieved from the API and settings above, the monitor calculates the values ups.load, battery.voltage and battery.runtime enphase-monitor needs to have write access to , so usually upsd hosting should be on local host, but shared filesystems may allow upsd to be remote. NOTE: if connections to ENVOY_HOST fail, is renamed -nocomms to trigger dummy-ups to show stale data. Either filename may exist on startup. Environment (optional): CONFIG_FILE - override default UPS - set a default NUT_SYSCONFIG - default directory (NUT_CONFPATH, e.g. /etc/ups) NUT_LOCALSTATE - default for STATE_DIR (NUT_STATEPATH, e.g. /var/lib/ups) === INSTALL === Install required support programs: bash, base64, jq, and curl Create an entry in /etc/ups/ups.conf (as above) Copy enphase-monitor to some (e.g. /usr/local/libexec) Create a file with required variables. If only used to start the monitor, is looks for `/etc/ups/enphase-.conf` Ensure can be read by monitor and is not world readable! Choose a NUT writable directory for STATE_DIR (default /var/lib/ups), and create an empty there: $ touch / $ chown : / If using SELinux, ensure NUT's dummy-ups has access to the (even in /var/lib/ups!) by adding a label, e.g. $ semanage fcontext -a -t nut_conf_t / $ restoreconf -F / Create a systemd template file (replace items) --- /etc/systemd/system/enphase-monitor@.service --- [Unit] Description=Enphase API monitor for NUT dummy-ups %I PartOf=nut-driver.target Before=nut-driver@%i.service [Service] SyslogIdentifier=%N User= ExecStartPre=/enphase-monitor -s %I ExecStart=/enphase-monitor %I Type=exec Restart=always RestartSec=30 [Install] WantedBy=nut-driver@%i.service --- end of file --- Enable the instance for $ systemctl daemon-reload $ systemctl enable nut-driver@ $ systemctl enable enphase-monitor@ Restart NUT :) === TEST MODE === If using the distributed `test.conf`, copy `test-ref.dev` to `test.dev` and then run: $ ./enphase-monitor -c test.conf `test.conf` sets "UPS=test" and "STATE_DIR=." and PORT_FILE="test.dev" (so token/portfiles are located in the current directory) It also sets "DEBUG=1" to show debug output (optional), and POLLFREQ to a few secs. "TEST" mode will loop (and randomly expire the token): online -> nocomms -> online -> onbatt -> lowbatt <- A "TEST" mode should set: TEST=1 <- required for "TEST" mode TEST_SESS= use {"session_id":"some-value"} TEST_TOKEN= JWT token, should have valid expires! TEST_RELAY= ivp/ensemble/relay {"mains_oper_state":"@RELAY_STATE@"} TEST_LIVE= ivp/livedata/status, {"soc":"@BATT_SOC@"} TEST_REPORTS= ivp/meters/reports TEST_SECCTRL= ivp/ensemble/secctrl, {"soc_recovery_exit":10} TEST_INFO= info.xml Output from real HTTP requests can be used (use "-d -d" to see output) for each of those APIs. Any empty TEST_XXXX value simulates a failed API query. ---- nut-2.8.3/scripts/external_apis/enphase/enphase-monitor@.service.in0000644000200500020050000000274314777767434022446 00000000000000# Network UPS Tools (NUT) systemd integration # Copyright (C) 2025 by Scott Shambarger # Copyright (C) 2025 by NUT contributors # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ [Unit] Description=Enphase API monitor for NUT dummy-ups %I PartOf=nut-driver.target # NOTE: Works with individual service instances prepared by nut-driver-enumerator Before=nut-driver@%i.service [Service] SyslogIdentifier=%N # NOTE: Does not have to be same run-time account as NUT daemons, just the # files created by it should be readable by the dummy-ups daemon. For more # secured installations, customize this via a drop-in systemd file with a # different dedicated account: User=@RUN_AS_USER@ # NOTE: On systems with wear-prone storage (flash/SSD), you can fiddle with # a "manually-made" file that would be copied into a tmpfs, and have the # script (and dummy-ups driver) pick up that tmpfs location with initially # inherited data points, e.g.: ### ExecStartPre=/bin/cp @CONFPATH@/enphase-%I.default /dev/shm/nut/enphase-%I.seq # First run once to scrap obsolete data from the existing file # Replace -s with -x to start in nocomms (no network APIs) below: ExecStartPre=@NUT_LIBEXECDIR@/enphase-monitor -s %I # Start as the continuously running service ExecStart=@NUT_LIBEXECDIR@/enphase-monitor %I Type=exec # Restart really always, do not stop trying: StartLimitInterval=0 Restart=always RestartSec=30 [Install] WantedBy=nut-driver@%i.service nut-2.8.3/scripts/external_apis/enphase/enphase-monitor.in0000755000200500020050000007274514777767434020723 00000000000000#!/usr/bin/env bash # -*- mode: sh; sh-basic-offset: 2; indent-tabs-mode: nil; -*- # vim:set ft=sh et sw=2 ts=2: # SPDX-License-Identifier: GPL-2.0-or-later # # Copyright (C) 2025 Scott Shambarger # # Enphase Monitor for NUT dummy-ups v0.9.3 # Author: Scott Shambarger # # Enphase Monitor is designed to work with Network UPS Tools # , accessing Enphase IQ Gateway's # local API and supplying "Grid On/Off" and Battery State-Of-Charge # to the dummy-ups driver (v2.8+ recommended) # # Usage: enphase-monitor [ ] -c | # # -c - use named config-file (or set $CONFIG_FILE) # - use config-file /etc/ups/enphase-.conf (or set $UPS) # # may include: # -d - increase debug to stderr (2+ exposes secrets!) # -h - show help and exit # -s - perform one network check and exit # -v - verbose output # -x - set 'nocomms' and exit" # # must contain: # # USERNAME= # PASSWORD= # SERIAL= # PORT_FILE= # # and optionally (defaults shown): # # DISABLE_METERS= # any value to disable power reporting # ENVOY_HOST="envoy.local" # ip/hostname of IQ Gateway on local network # STATE_DIR="$NUT_STATEPATH" # writable directory for portfile/tokens # (e.g. "/var/lib/ups") # POLLFREQ=60 # seconds between API queries, min 5 # POLLFREQALERT=20 # seconds between API queries when on battery, min 5 # TOKEN_FILE="enphase-.token" # path defaults to STATE_DIR # LOADKWH=768 # max load/1kWh capacity, used for ups.load calculation # 0 disables calc (default based on IQ 5P rate 3.84kVA/5kWh) # LOGIN_TIMEOUT=10 # timeout (secs) for login/token gen, min 5 # API_TIMEOUT=10 # timeout (secs) for local ENVOY_HOST api access, min 2 # # Add section to /etc/ups/ups.conf for your name (replace ) # # [] # driver = dummy-ups # port = / # this should be an absolute path! # mode = dummy-once # or name with `.dev` extension # desc = "Enphase IQ Gateway" # # MUST EXIST before running the monitor (to ensure it's running # on the correct machine). The following entries are optional but # used if specified (defaults shown); other non-generated entries are retained. # # battery.charge.low: 20 # battery.voltage.high: 86.4 # battery.voltage.nominal: 76.8 # battery.voltage.low: 68.5 # device.mfr: Enphase Energy # device.model: IQ Gateway # # The monitor uses the enphase + to retrieve a long-term # token and saves it in STATE_DIR (token renewal is handled automatically) # # The monitor then queries the ENVOY_HOST (local IQ Gateway) API at POLLFREQ # intervals to retrieve the envoy state, and updates . # Using values retrieved from the API and settings above, the monitor # calculates the values ups.load, battery.voltage and battery.runtime # # enphase-monitor needs to have write access to , so usually # upsd hosting should be on local host, but shared filesystems may # allow upsd to be remote. # # NOTE: if connections to ENVOY_HOST fail, is renamed # -nocomms to trigger dummy-ups to show stale data. # Either filename may exist on startup. # # Environment (optional): # CONFIG_FILE - override default # UPS - set a default # NUT_SYSCONFIG - default directory (NUT_CONFPATH, e.g. /etc/ups) # NUT_LOCALSTATE - default for STATE_DIR (NUT_STATEPATH, e.g. /var/lib/ups) # # === INSTALL === # # Install required support programs: bash, base64, jq, and curl # # Create an entry in /etc/ups/ups.conf (as above) # # Copy enphase-monitor to some (e.g. /usr/local/libexec) # # Create a file with required variables. If only # used to start the monitor, is looks for `/etc/ups/enphase-.conf` # Ensure can be read by monitor and is not world readable! # # Choose a NUT writable directory for STATE_DIR (default /var/lib/ups), # and create an empty there: # # $ touch / # $ chown : / # # If using SELinux, ensure NUT's dummy-ups has access to the # (even in /var/lib/ups!) by adding a label, e.g. # # $ semanage fcontext -a -t nut_conf_t / # $ restoreconf -F / # # Create a systemd template file (replace items) # # --- /etc/systemd/system/enphase-monitor@.service --- # [Unit] # Description=Enphase API monitor for NUT dummy-ups %I # PartOf=nut-driver.target # Before=nut-driver@%i.service # # [Service] # SyslogIdentifier=%N # User= # ExecStartPre=/enphase-monitor -s %I # ExecStart=/enphase-monitor %I # Type=exec # Restart=always # RestartSec=30 # # [Install] # WantedBy=nut-driver@%i.service # --- end of file --- # # Enable the instance for # # $ systemctl daemon-reload # $ systemctl enable nut-driver@ # $ systemctl enable enphase-monitor@ # # Restart NUT :) # # === TEST MODE === # # If using the distributed `test.conf`, copy `test-ref.dev` to `test.dev` # and then run: # # $ ./enphase-monitor -c test.conf # # `test.conf` sets "UPS=test" and "STATE_DIR=." and PORT_FILE="test.dev" # (so token/portfiles are located in the current directory) # It also sets "DEBUG=1" to show debug output (optional), and POLLFREQ # to a few secs. # # "TEST" mode will loop (and randomly expire the token): # # online -> nocomms -> online -> onbatt -> lowbatt <- # # A "TEST" mode should set: # # TEST=1 # <- required for "TEST" mode # TEST_SESS= # use {"session_id":"some-value"} # TEST_TOKEN= # JWT token, should have valid expires! # TEST_RELAY= # ivp/ensemble/relay {"mains_oper_state":"@RELAY_STATE@"} # TEST_LIVE= # ivp/livedata/status, {"soc":"@BATT_SOC@"} # TEST_REPORTS= # ivp/meters/reports # TEST_SECCTRL= # ivp/ensemble/secctrl, {"soc_recovery_exit":10} # TEST_INFO= # info.xml # # Output from real HTTP requests can be used (use "-d -d" to see output) # for each of those APIs. Any empty TEST_XXXX value simulates a # failed API query. # # shellcheck disable=SC2076 # install defaults # Script configuration file location, defaults to NUT configuration location: NUT_CONFPATH=${NUT_CONFPATH:-@CONFPATH@} NUT_SYSCONFIG=${NUT_SYSCONFIG:-$NUT_CONFPATH} # Location where we write the data file for dummy-ups to process and publish. # Should not be in a tmpfs, as we may inherit some manually added data points # that we want to retain across reboots. On systems with wear-prone storage # (flash/SSD), you can fiddle with a "manually-made" file that would be copied # into a tmpfs, and have the script pick up that tmpfs location with initially # inherited data points. # Does not have to be among NUT common directories (/var/lib/ups is another # reasonable option), but should be writeable to this script (see service # definition for run-time user involved) and readable for NUT driver run-time # user account. # The corresponding dummy-ups section in ups.conf should refer to file name # under this location in its "port" definition (path may be skipped if this # is NUT_CONFPATH). NUT_STATEPATH=${NUT_STATEPATH:-@STATEPATH@} NUT_LOCALSTATE=${NUT_LOCALSTATE:-$NUT_STATEPATH} # these can be changed ENPHASE_LOGIN="https://enlighten.enphaseenergy.com/login/login.json?" ENPHASE_TOKENS="https://entrez.enphaseenergy.com/tokens" msg() { printf '%s\n' "$*"; } warn() { msg >&2 "$*"; } debug() { # [ ] [[ $DEBUG ]] || return 0 local p=': ' [[ $1 =~ ^[1-9]$ ]] && { (( $1 > DEBUG )) && return p="$1:" shift } warn "DEBUG$p $*" } verbose() { if [[ $DEBUG ]]; then warn "$*" elif [[ $VERBOSE ]]; then msg "$*" fi } die() { warn "enphase-monitor $UPS: $*"; exit 1; } int100() { # = * 100 local _i _s='' LC_NUMERIC=C printf -v _i "%.2f" "${2/,/.}" _i=${_i/./} [[ ${_i:0:1} == - ]] && { _s=-; _i=${_i#-}; } _i=${_i#0} printf -v "$1" "%s" "${_s}${_i#0}" } fmtfloat() { # LC_NUMERIC=C printf -v "$2" "%.${1}f" "${3/,/.}" } idiv2float() { # (dest = inta / intb) local -i _x=${3-} _y=${4-}; local _i _j _s='' (( _y == 0 )) && { LC_NUMERIC=C printf -v "$2" "%.${1}f" "0"; return; } (( _x<0 || _y<0 )) && { ((_x<0 && _y<0)) || _s=-; } _x=${_x/-/}; _y=${_y/-/} (( _i = _x / _y, _j = (_x % _y) * (10 ** $1) / _y )) || : printf -v _j "%0${1}d" "$_j" LC_NUMERIC=C printf -v "$2" "%.${1}f" "$_s$_i.$_j" } get_perms() { # stat -L "${STAT_ARGS[@]}" "$1" } check_dir_perms() { # local type=$1 dir=$2 perm debug 2 "checking directory perms for $dir" perm=$(get_perms "$dir") || die "Unable to stat $type directory '$dir'" perm=${perm: -1} (( ( perm >> 1 ) % 2 == 0 )) || die "World write permissions on $type directory $dir" debug 2 " perms $perm ok" } # check permissions (contains secrets) check_file_perms() { # local type=$1 file=$2 perm dir debug 2 "checking file perms for $file" perm=$(get_perms "$file") || die "Unable to stat $type '$file'" perm=${perm: -1} (( ( perm >> 2 ) % 2 == 0 )) || die "World read permissions exist on $type $file" debug 2 " perms ok" dir=${file%/*} [[ $dir == "$file" ]] && dir=. check_dir_perms "$type" "$dir" } TEST_CYCLE=init test_cycle() { case $TEST_CYCLE in init) TEST_CYCLE=online ;; online) TEST_CYCLE=nocomms ;; nocomms) TEST_CYCLE=online2 ;; online2) TEST_CYCLE=onbatt ;; onbatt) TEST_CYCLE=lowbatt ;; *) TEST_CYCLE=online ;; esac debug "TEST_CYCLE now $TEST_CYCLE" } # echos output based on and TEST_CYCLE gen_test_out() { # local out relay batt mode case $TEST_CYCLE in onbatt*) relay=open batt=90 ;; lowbatt*) relay=open batt=${REF[batt_low]} if [[ $batt ]]; then int100 batt "$batt" (( batt = (batt - 100) / 100 )) || : else batt=10 fi ;; *) relay=closed batt=100 ;; esac if [[ $* =~ "$ENPHASE_LOGIN" ]]; then out=$TEST_SESS; mode=login elif [[ $* =~ "$ENPHASE_TOKENS" ]]; then out=$TEST_TOKEN; mode=tokens else # only apply nocomms to envoy queries [[ $TEST_CYCLE == nocomms ]] && die "Testing nocomms" if [[ $* =~ ensemble/relay$ ]]; then out=${TEST_RELAY/@RELAY_STATE@/$relay}; mode=relay elif [[ $* =~ livedata/status$ ]]; then out=${TEST_LIVE/@BATT_SOC@/$batt}; mode=live elif [[ $* =~ meters/reports$ ]]; then out=$TEST_REPORTS; mode=reports elif [[ $* =~ ensemble/secctrl$ ]]; then out=$TEST_SECCTRL; mode=secctrl elif [[ $* =~ info\.xml$ ]]; then out=$TEST_INFO; mode=info else die "Unknown test url: $*" fi fi [[ $out ]] || die "Testing $mode failure" printf %s "$out" } debug_curl() { # [[ $DEBUG ]] || return 0 if (( DEBUG > 1 )); then debug 2 "curl $*" else local p=$* debug "curl to http${p##*http}" fi } curl_get() { # debug_curl -ksSf -X GET "$@" if [[ $TEST ]]; then gen_test_out "$*" else curl -ksSf -X GET "$@" fi } envoy_get() { # [[ $1 ]] || die "envoy_get() requires a token" local token=$1 url=$2 [[ $url ]] || die "envoy_get() requires a URL" curl_get --retry 1 -m "$API_TIMEOUT" -H "Authorization: Bearer $token" \ -H 'Accept: application/json' "https://$ENVOY_HOST/${url#/}" } curl_post() { # [[ $1 ]] || die "curl_post() requires a URL" debug_curl -sSf -X POST "$@" if [[ $TEST ]]; then gen_test_out "$*" else curl -sSf -X POST "$@" fi } json() { # jq 2>/dev/null -r "$2" <<< "$1" } # echo if valid echo_token_expires() { # local token=$1 data payload expires now debug 2 "parsing token for expires: $token" data=${token%.*} data=${data#*.} [[ $data ]] || die "Failed to parse token" payload=$(base64 2>/dev/null -d <<< "${data}==") [[ $payload ]] || die "Failed to base64 decode token payload" debug 2 "token payload: $payload" expires=$(json "$payload" '.exp') [[ $expires ]] || die "Token payload missing expires" now=$(date +%s) [[ $now ]] || die "Unable to get current time" [[ $TEST ]] && { # randomly expire token (force re-query) unless initial query (( RANDOM % 5 == 0 )) && [[ -z ${web_token-} ]] && { debug "randomly expiring token" expires=$now } } [[ $DEBUG ]] && { local full if [[ $(uname -s) == Darwin ]]; then full=$(date 2>/dev/null -r "$expires") else full=$(date 2>/dev/null -d "@$expires") fi debug "token expires: $expires ($full)" } # token needs at least an hour of life... (( expires < ( now + 3600 ) )) && { if (( expires <= now )); then verbose "Token expired" else verbose "Token lifetime less than 1 hour" fi return 1 } debug 2 "token expires ok" printf %s "$expires" } # echo echo_sid() { local session sid # login session=$(curl_post \ -m "$LOGIN_TIMEOUT" \ -H "Accept: application/json" \ --data-urlencode "user%5Bemail%5D=$USERNAME" \ --data-urlencode "user%5Bpassword%5d=$PASSWORD" \ "$ENPHASE_LOGIN") [[ $session ]] || die "Enphase login failed for user $USERNAME" debug 2 "session created: $session" sid=$(json "$session" ".session_id") [[ $sid ]] || die "Unable to retrieve session_id for user $USERNAME" debug "session_id found: $sid" printf %s "$sid" } # echo token or return false echo_saved_token() { local token='' if [[ $TOKEN_CACHE ]]; then token=$TOKEN_CACHE else [[ -r $TOKEN_FILE ]] || return check_file_perms "token" "$TOKEN_FILE" debug "loading token from $TOKEN_FILE" read -d '' -r token < "$TOKEN_FILE" || : [[ $token ]] || return fi [[ $(echo_token_expires "$token") ]] || return printf %s "$token" } save_token() { # local val=$1 dir dir=${TOKEN_FILE%/*} [[ $dir ]] || dir=/ [[ -d $dir && -w $dir ]] || die "Token directory '$dir' not writable" check_dir_perms "token" "$dir" debug 2 "Saving token $val to $TOKEN_FILE" rm -f "$TOKEN_FILE" printf '' > "$TOKEN_FILE" || die "Unable to create token file '$TOKEN_FILE'" chmod o-rwx "$TOKEN_FILE" || die "Unable to remove world permissions from token file $TOKEN_FILE" printf %s "$val" > "$TOKEN_FILE" debug "Saved new token to $TOKEN_FILE" return 0 } echo_token() { local sid web_token echo_saved_token && return [[ -f $TOKEN_FILE ]] && rm -f "$TOKEN_FILE" # if login failure, fail sid=$(echo_sid) || return # acquire long-term token web_token=$(curl_post \ -m "$LOGIN_TIMEOUT" \ --json "{\"session_id\": \"$sid\", \"serial_num\": \"$SERIAL\", \"username\": \"$USERNAME\"}" \ "$ENPHASE_TOKENS") # token query failure means serial# invalid, fail [[ $web_token ]] || die "Failed to acquire web_token for user $USERNAME, serial# $SERIAL" debug "web_token retrieved" # if new token not valid, fail [[ $(echo_token_expires "$web_token") ]] || die "New token invalid, verify serial# $SERIAL" save_token "$web_token" printf %s "$web_token" } # CONSTANTS # nut fields to DS key mapping declare -rA FM=([ups.status]=status [battery.charge]=batt_soc) # nut group to DS key mapping declare -rA FGM=([input]=input [output]=output [battery]=battery) # nut fields to REF key mapping declare -rA RM=([battery.charge.low]=batt_low [battery.capacity]=capacity [battery.charge.restart]=batt_restart [battery.type]=batt_type [battery.voltage.high]=batt_high [battery.voltage.low]=batt_min [battery.voltage.nominal]=batt_nom [device.serial]=serial [device.mfr]=mfr [device.model]=model [device.type]=dev_type [ups.serial]=userial [ups.mfr]=umfr [ups.model]=umodel [ups.firmware]=software [input.phases]=phases [output.phases]=phases [output.current.high.critical]=max_current) # used for power meter fields; METER_KEYS indexes used in update_portfile declare -r METER_KEYS=(realpower power voltage powerfactor frequency) # METER_FIELDS must map to METER_KEYS declare -r METER_FIELDS="currW, apprntPwr, rmsVoltage, pwrFactor, freqHz" # LiFePO4 SOC to voltage map (in 10% increments, >100% charging) declare -ra LFP=(250 290 310 320 325 330 335 340 345 350 360 365) # sets STATE, NDS query_envoy() { local token data item live alive=() token=$(echo_token) || exit TOKEN_CACHE=$token [[ $token ]] || return 0 STATE=nocomms [[ $NOCOMMS ]] && return # relay appears to be the only reliable way to see if grid is hot # ("live" query doesn't show a change in main_relay_state) data=$(envoy_get "$token" "ivp/ensemble/relay") && [[ $data ]] && { item=$(json "$data" ".mains_oper_state") debug "mains operational state: $item" case $item in '') warn "envoy relay API missing mains_oper_state" ;; closed) STATE=online ;; open) STATE=onbatt ;; *) warn "envoy relay API unknown mains_oper_state '$item'" ;; esac } [[ $STATE == nocomms ]] && return # livedata if fast data=$(envoy_get "$token" "ivp/livedata/status") && [[ $data ]] && { live=$(json "$data" ".meters | { soc, phase_count, enc_agg_energy } | [.[]] | @csv") # some values used in INIT [[ $live ]] && IFS=, read -r -a alive <<< "$live" [[ ${alive[0]} != null ]] && NDS[batt_soc]=${alive[0]} } [[ $INIT ]] || { # just try this once... INIT=1 REF[serial]=$SERIAL REF[userial]=$SERIAL data=$(envoy_get "$token" "info.xml") && [[ $data ]] && { while read -r item; do case $item in ""*"") item=${item#*} REF[software]=${item%*} ;; esac done <<< "$data" } # get batt_restart for runtime calc data=$(envoy_get "$token" "ivp/ensemble/secctrl") && [[ $data ]] && { item=$(json "$data" ".soc_recovery_exit") [[ $item != null ]] && REF[batt_restart]=$item } REF[phases]='' [[ ${#alive[*]} ]] && { [[ ${alive[1]} == 3 ]] && REF[phases]=3 [[ ${alive[2]} != null ]] && REF[capacity]=${alive[2]} } } # TODO with meters off, we could still get power from livedata [[ $DISABLE_METERS ]] || { # meters is slow, so can be disabled if values aren't wanted data=$(envoy_get "$token" "ivp/meters/reports") && [[ $data ]] && { local phase key=input vals for meter in net total; do vals=$(json "$data" ".[] | select(.reportType == \"${meter}-consumption\") | .cumulative, .lines[] | { $METER_FIELDS } | [.[]] | @csv") [[ $vals ]] && { for (( phase=0; phase <= ${REF[phases]:-0}; phase++ )); do read -r item && NDS[$key.L$phase]=$item done <<< "$vals" } key=output done NDS[battery]=$(json "$data" ".[] | select(.reportType == \"storage\") | .cumulative | { $METER_FIELDS } | [.[]] | @csv") } } return 0 } parse_portline() { # local k=${1%%:*} v=${1#*:}; v=${v## } [[ ${FM[$k]} ]] && DS[${FM[$k]}]=$v [[ ${RM[$k]} ]] && REF[${RM[$k]}]=$v } # uses STATE, sets NDS[status] check_status() { case $STATE in online*) NDS[status]=OL ;; onbatt*) NDS[status]=OB ;; nocomms*) NDS[status]='' ;; esac [[ ${NDS[batt_soc]} && ${REF[batt_low]} && ${NDS[status]} ]] && { local soc low int100 soc "${NDS[batt_soc]}"; int100 low "${REF[batt_low]}" (( soc < low )) && NDS[status]+=" LB" } } update_portfile() { local change line key lines=() # check for changes check_status debug "checking if portfile needs updating" [[ $DEBUG ]] && debug 3 "$(declare -p NDS)" [[ ${NDS[status]} != "${DS[status]}" ]] && { if [[ ${DS[status]} && -z ${NDS[status]} ]]; then verbose "Communication lost, hiding portfile" [[ -f $PORT_FILE ]] && { mv "$PORT_FILE" "${PORT_FILE}-nocomms" || die "Unable to disable port file $PORT_FILE" } elif [[ ${NDS[status]} && -z ${DS[status]} ]]; then verbose "Communication restored, restoring portfile" [[ -f ${PORT_FILE}-nocomms ]] && { mv "${PORT_FILE}-nocomms" "$PORT_FILE" || die "Unable to enable port file $PORT_FILE" } fi [[ ${NDS[status]} ]] && verbose "ups.status now ${NDS[status]}" DS[status]=${NDS[status]} change=1 } # if port file disabled, we're done [[ ${DS[status]} ]] || return 0 debug 2 "checking for changed values" for key in "${!NDS[@]}"; do [[ ${NDS[$key]} == "${DS[$key]}" ]] && continue debug 2 " new $key ${NDS[$key]}" DS[$key]=${NDS[$key]} change=1 done [[ $change ]] || return 0 verbose "Updating $PORT_FILE" [[ -w $PORT_FILE ]] || die "Port file '$PORT_FILE' missing/write-protected!" local nk while read -r line; do nk=${line%%:*} [[ ${FM[$nk]} ]] && continue # keep any REF user may configure case $nk in battery.charge.low|*.mfr|*.model) : ;; battery.voltage.high|battery.voltage.nominal|battery.voltage.low) : ;; ups.load) continue ;; # calculated *) [[ ${RM[$nk]} ]] && continue ;; # don't parse other REFs esac parse_portline "$line" [[ ${RM[$nk]} ]] && continue for key in "${!FGM[@]}"; do case $nk in "$key"*) continue 2 ;; esac done lines+=("$line") done < "$PORT_FILE" [[ $DEBUG ]] && debug 3 "$(declare -p DS REF)" for nk in "${!FM[@]}"; do key=${FM[$nk]}; [[ ${DS[$key]} ]] && lines+=("$nk: ${DS[$key]}") done for nk in "${!RM[@]}"; do key=${RM[$nk]}; [[ ${REF[$key]} ]] && lines+=("$nk: ${REF[$key]}") done local i v p phase pfx val outp soc vals=() for nk in "${!FGM[@]}"; do key=${FGM[$nk]} case $key in input|output) for (( phase=0; phase <= ${REF[phases]:-0}; phase++ )); do p='' v='' pfx=$nk (( phase > 0 )) && pfx+=".L$phase" IFS=, read -r -a vals <<< "${DS[$key.L${phase}]}" # loop over meter keys for (( i=0; i<${#METER_KEYS[*]}; i++ )); do val=${vals[i]} # treat nulls as 0 [[ $val == null ]] && val=0 if (( i == 3 )); then # pwrFactor fmtfloat 2 val "$val" else fmtfloat 1 val "$val" fi [[ ${METER_KEYS[i]} ]] && { if (( phase > 0 && i == 2 )); then # phase voltage is special lines+=("${pfx}-N.${METER_KEYS[i]}: $val") else lines+=("${pfx}.${METER_KEYS[i]}: $val") fi } # enphase cumulative current is 2x, calc real (( i == 0 )) && { int100 p "$val" # save for load calc [[ $phase == 0 && $key == output ]] && outp=$p } (( i == 2 )) && int100 v "$val" done [[ $p && $v ]] && { idiv2float 2 val "$p" "$v" lines+=("${pfx}.current: $val") } done ;; battery) IFS=, read -r -a vals <<< "${DS[$key]}" int100 p "${vals[0]}" int100 v "${vals[2]}" idiv2float 2 val "$p" "$v" lines+=("$nk.current: $val") ;; esac done # batt voltage based on SOC and voltage.high [[ ${NDS[batt_soc]} && ${REF[batt_high]} ]] && { # cell voltage not in the API, so calc from known LiFePO4 charts int100 soc "${NDS[batt_soc]}" # range limit (( (soc>11000) ? (soc=11000) : ( (soc<0) ? (soc=0) : 0 ) )) || : # calc LFP index (( i = (soc > 10000) ? 10 : (soc / 1000) )) || : # voltage = base + % to next base val=${LFP[i]} (( val += (LFP[i+1] - val) * (soc - (i * 1000)) / 1000 )) || : # adjust based on high voltage == 100% SOC int100 v "${REF[batt_high]}"; (( val = (val * v) / LFP[10] )) || : idiv2float 1 val "$val" 100 lines+=("battery.voltage: $val") } # load calc if output.power and capacity available [[ ${REF[capacity]} && $outp ]] && { v=${REF[capacity]} # runtime based on (100 - batt_restart) * (seconds at power) [[ ${NDS[batt_soc]} ]] && { int100 p "${REF[batt_restart]}" int100 soc "${NDS[batt_soc]}" if (( outp <= 0 )); then val=172800 elif (( soc < p )); then val=0 else # runtime = (% capacity) / power (in secs) (( val = ((soc - p) * v * 36) / outp )) || : # 2 day max (( val > 172800 ? (val = 172800) : 0 )) || : fi lines+=("battery.runtime: $val") } (( ${LOADKWH:-0} > 0 )) && { (( v = LOADKWH * (v / 10), outp *= 100 )) idiv2float 1 val "$outp" "$v" lines+=("ups.load: $val") } } [[ $DEBUG ]] && debug 3 "new file: ${lines[*]}" local IFS=$'\n' printf '%s\n' "${lines[*]}" > "$PORT_FILE" || die "Unable to update PORT_FILE $PORT_FILE" } # sets NDS read_portfile() { local file=$PORT_FILE [[ -r $file ]] || { # check for disabled file="${PORT_FILE}-nocomms" [[ -r $file ]] || die "Port file '$PORT_FILE' unreadable" } debug "Reading portfile '$file'" local line while read -r line; do parse_portline "$line" done < "$file" [[ $DEBUG ]] && debug 3 "$(declare -p DS REF)" # if nocomms, set [status] [[ -r $PORT_FILE ]] || DS[status]='' } main_loop() { local -A DS NDS REF=([batt_low]="20" [batt_type]=LFP [batt_nom]="76.8" [batt_high]="86.4" [batt_min]="68.5" [dev_type]="ups" [batt_restart]=10 [mfr]="Enphase Energy" [model]="IQ Gateway" [umfr]="Enphase Energy" [umodel]="IQ Gateway") local STATE INIT local -i delay read_portfile debug "initial status: ${DS[status]}" while :; do [[ $TEST ]] && test_cycle query_envoy debug "current state: $STATE" update_portfile [[ $NOCOMMS || $SINGLE ]] && break # adaptive delay delay=$POLLFREQ case $STATE in onbatt|nocomms) delay=$POLLFREQALERT ;; esac debug "delay: $delay" sleep $delay done } gen_token_file() { if [[ $TOKEN_FILE ]]; then [[ ${TOKEN_FILE#/} == "$TOKEN_FILE" ]] && TOKEN_FILE="$STATE_DIR/$TOKEN_FILE" else TOKEN_FILE="$STATE_DIR/enphase-${UPS}.token" fi debug "token file is '$TOKEN_FILE'" } read_config() { [[ $CONFIG_FILE ]] || { [[ $UPS ]] || usage CONFIG_FILE=${CONFIG_FILE:-${DEF_CONFIG//"@UPS@"/$UPS}} } [[ -r $CONFIG_FILE ]] || die "Unable to read config '$CONFIG_FILE'" check_file_perms config "$CONFIG_FILE" # read config verbose "Reading config file $CONFIG_FILE" bash -n "$CONFIG_FILE" || die "Config $CONFIG_FILE cannot be parsed" # shellcheck disable=SC1090 . "$CONFIG_FILE" # validate config local var fail val (( POLLFREQ < 5 )) && POLLFREQ=5 (( POLLFREQALERT < 5 )) && POLLFREQALERT=5 (( LOGIN_TIMEOUT < 5 )) && LOGIN_TIMEOUT=5 (( API_TIMEOUT < 2 )) && API_TIMEOUT=2 debug "config values:" for var in USERNAME PASSWORD SERIAL ENVOY_HOST STATE_DIR PORT_FILE \ POLLFREQ POLLFREQALERT LOGIN_TIMEOUT API_TIMEOUT; do val=${!var-} [[ $val ]] || fail+="$var " [[ $DEBUG ]] || continue if [[ $var == PASSWORD ]]; then (( DEBUG > 1 )) && { debug 2 " $var=$val"; continue; } val="" fi debug " $var=$val" done [[ $fail ]] && die "Config $CONFIG_FILE requires values for $fail" [[ -d $STATE_DIR && -w $STATE_DIR ]] || die "STATE_DIR '$STATE_DIR' not writable!" check_dir_perms "state" "$STATE_DIR" gen_token_file } check_portfile() { [[ ${PORT_FILE#/} == "$PORT_FILE" ]] && PORT_FILE="$STATE_DIR/$PORT_FILE" debug "portfile is '$PORT_FILE'" local dir=${PORT_FILE%/*} [[ $dir ]] || dir=/ [[ -d $dir && -w $dir ]] || die "Port file directory '$dir' not writable" } check_requires() { local exe fail (( BASH_VERSINFO[0] < 4 )) && die "Bash v4+ required (for assoc arrays)" for exe in head stat base64 curl jq date chmod uname; do command >/dev/null -v "$exe" || fail+="$exe " done [[ $fail ]] && die "Unable to find required programs in PATH: $fail" } usage() { local rc=2 out=warn case ${1-} in '') ;; 0) rc=0; out=msg ;; *) warn "Unknown option: '$1'" ;; esac $out "Usage: ${0##*/} [ ] -c | " $out " -c - use named config-file (or set \$CONFIG_FILE)" $out " - use config-file ${DEF_CONFIG//@UPS@/} (or set \$UPS)" $out $out " may include:" $out " -d - increase debug to stderr (2+ exposes secrets!)" $out " -h - show help and exit" $out " -s - perform one network check and exit" $out " -v - verbose output" $out " -x - set 'nocomms' and exit" exit $rc } main() { # global state local VERBOSE DEBUG TOKEN_CACHE STAT_ARGS=(-c %a) NOCOMMS SINGLE local DEF_CONFIG="$NUT_SYSCONFIG/enphase-@UPS@.conf" # config local USERNAME PASSWORD SERIAL PORT_FILE TOKEN_FILE DISABLE_METERS local ENVOY_HOST="envoy.local" STATE_DIR="$NUT_LOCALSTATE" local -i POLLFREQ=60 POLLFREQALERT=20 LOADKWH=768 local -i LOGIN_TIMEOUT=10 API_TIMEOUT=10 check_requires [[ $(uname -s) == Darwin ]] && STAT_ARGS=(-f %p) while [[ $1 ]]; do case $1 in -c) shift [[ $1 ]] || usage CONFIG_FILE=$1 ;; -d) [[ $DEBUG ]] && { (( DEBUG++ )) || :; } || DEBUG=1 ;; -h|--help) usage 0 ;; -s) SINGLE=1 ;; -v) VERBOSE=1 ;; -x) NOCOMMS=1 ;; -*) usage "$1" ;; *) UPS=$1; break ;; esac shift done read_config [[ $UPS ]] || { warn "UPS must be set (env, or as argument)" usage } check_portfile main_loop } main "$@" nut-2.8.3/scripts/external_apis/Makefile.am0000644000200500020050000000517014777767434015655 00000000000000# Network UPS Tools: scripts/external_apis EXTRA_DIST = \ README.adoc \ enphase/README.adoc \ enphase/enphase-monitor.in \ enphase/enphase-monitor@.service.in SPELLCHECK_SRC = README.adoc enphase/README.adoc # Handle optional installation: if ENABLE_EXTAPI_ENPHASE extapi_enphase_datadir = @datadir@/external_apis/enphase extapi_enphase_data_DATA = enphase/README.adoc extapi_enphase_execdir = @libexecdir@ extapi_enphase_exec_SCRIPTS = enphase/enphase-monitor if HAVE_SYSTEMD systemdsystemunit_DATA = \ enphase/enphase-monitor@.service endif HAVE_SYSTEMD endif ENABLE_EXTAPI_ENPHASE # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked enphase/*-spellchecked # Do not remove files generated from .in templates during mere "make check": DISTCLEANFILES = \ enphase/enphase-monitor \ enphase/enphase-monitor@.service MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.3/scripts/external_apis/Makefile.in0000644000200500020050000007200615001555011015627 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/external_apis VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = scripts/external_apis ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(extapi_enphase_execdir)" \ "$(DESTDIR)$(extapi_enphase_datadir)" \ "$(DESTDIR)$(systemdsystemunitdir)" SCRIPTS = $(extapi_enphase_exec_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(extapi_enphase_data_DATA) $(systemdsystemunit_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = \ README.adoc \ enphase/README.adoc \ enphase/enphase-monitor.in \ enphase/enphase-monitor@.service.in SPELLCHECK_SRC = README.adoc enphase/README.adoc # Handle optional installation: @ENABLE_EXTAPI_ENPHASE_TRUE@extapi_enphase_datadir = @datadir@/external_apis/enphase @ENABLE_EXTAPI_ENPHASE_TRUE@extapi_enphase_data_DATA = enphase/README.adoc @ENABLE_EXTAPI_ENPHASE_TRUE@extapi_enphase_execdir = @libexecdir@ @ENABLE_EXTAPI_ENPHASE_TRUE@extapi_enphase_exec_SCRIPTS = enphase/enphase-monitor @ENABLE_EXTAPI_ENPHASE_TRUE@@HAVE_SYSTEMD_TRUE@systemdsystemunit_DATA = \ @ENABLE_EXTAPI_ENPHASE_TRUE@@HAVE_SYSTEMD_TRUE@ enphase/enphase-monitor@.service CLEANFILES = *-spellchecked enphase/*-spellchecked # Do not remove files generated from .in templates during mere "make check": DISTCLEANFILES = \ enphase/enphase-monitor \ enphase/enphase-monitor@.service MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/external_apis/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/external_apis/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-extapi_enphase_execSCRIPTS: $(extapi_enphase_exec_SCRIPTS) @$(NORMAL_INSTALL) @list='$(extapi_enphase_exec_SCRIPTS)'; test -n "$(extapi_enphase_execdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(extapi_enphase_execdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(extapi_enphase_execdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(extapi_enphase_execdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(extapi_enphase_execdir)$$dir" || exit $$?; \ } \ ; done uninstall-extapi_enphase_execSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(extapi_enphase_exec_SCRIPTS)'; test -n "$(extapi_enphase_execdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(extapi_enphase_execdir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-extapi_enphase_dataDATA: $(extapi_enphase_data_DATA) @$(NORMAL_INSTALL) @list='$(extapi_enphase_data_DATA)'; test -n "$(extapi_enphase_datadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(extapi_enphase_datadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(extapi_enphase_datadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(extapi_enphase_datadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(extapi_enphase_datadir)" || exit $$?; \ done uninstall-extapi_enphase_dataDATA: @$(NORMAL_UNINSTALL) @list='$(extapi_enphase_data_DATA)'; test -n "$(extapi_enphase_datadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(extapi_enphase_datadir)'; $(am__uninstall_files_from_dir) install-systemdsystemunitDATA: $(systemdsystemunit_DATA) @$(NORMAL_INSTALL) @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemunitdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(systemdsystemunitdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystemunitdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystemunitdir)" || exit $$?; \ done uninstall-systemdsystemunitDATA: @$(NORMAL_UNINSTALL) @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(systemdsystemunitdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(extapi_enphase_execdir)" "$(DESTDIR)$(extapi_enphase_datadir)" "$(DESTDIR)$(systemdsystemunitdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-extapi_enphase_dataDATA \ install-systemdsystemunitDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-extapi_enphase_execSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-extapi_enphase_dataDATA \ uninstall-extapi_enphase_execSCRIPTS \ uninstall-systemdsystemunitDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am \ install-extapi_enphase_dataDATA \ install-extapi_enphase_execSCRIPTS install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip install-systemdsystemunitDATA installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-extapi_enphase_dataDATA \ uninstall-extapi_enphase_execSCRIPTS \ uninstall-systemdsystemunitDATA .PRECIOUS: Makefile # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/avahi/0000755000200500020050000000000015001555410012072 500000000000000nut-2.8.3/scripts/avahi/nut.service.in0000644000200500020050000000207514553676503014635 00000000000000 %h _nut._tcp @PORT@ nut-2.8.3/scripts/misc/0000755000200500020050000000000015001555411011736 500000000000000nut-2.8.3/scripts/misc/osd-notify0000644000200500020050000000202714553676503013716 00000000000000#!/bin/sh # **********************************************************# # osd-notify: script to make On Screen Display notification # # **********************************************************# # Copyright 2003 - Arnaud Quette # # Distributed under the GNU GPL v2 # # See attached file (osd-notify.txt) for usage information # # **********************************************************# # select your font with xfontsel # ****************************** FONT="-adobe-courier-bold-*-*-*-34-*-100-*-*-*-*-*" # Position # ******** POSITION="-p middle -A center" # Delay in seconds # **************** DELAY="10" # Color # ***** COLOR="red" # You can use a combination of valid message values: # $* => for full text # $UPSNAME => for ups name # $NOTIFYTYPE => depending on event (ONLINE, ONBATT, ...) # ********************************************************************* MESSAGE="$*" # Processing part # *************** echo $MESSAGE | osd_cat - -c $COLOR -f $FONT -d $DELAY $POSITION nut-2.8.3/scripts/misc/nut.bash_completion0000644000200500020050000001223214553676503015575 00000000000000# Bash completion function for Network UPS Tools 'upsc' command. # # Install in /etc/bash_completion.d (and run '. /etc/bash_completion if this # has not been done in your startup files already). # # Charles Lepple _nut_local_upses() { upsc -l 2>/dev/null } _nut_upses() { upsc -l 2>/dev/null # Example syntax: echo UPS@host:port # ... could add others from upsmon.conf, etc. } ### _nut_upsc_completion() { local upses cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} # The 'list' options can take a hostname and a port, but we don't complete # the port number: case "$prev" in -l|-L) COMPREPLY=( $(compgen -A hostname ${cur}) ) ; return 0 ;; esac # If the user starts to type an option, then only offer options for that word: if [[ "$cur" == -* ]]; then COMPREPLY=( $(compgen -W "-l -L" -- ${cur}) ) ; return 0 fi upses="$(_nut_upses)" COMPREPLY=( $(compgen -W "-l -L $upses" -- ${cur}) ) return 0 } complete -F _nut_upsc_completion upsc ### _nut_upscmd_completion() { local cur options prev pprev upses COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} (( COMP_CWORD >= 3 )) && pprev=${COMP_WORDS[COMP_CWORD-3]} options="-h -l -u -p" case "$prev" in -u|-p) # TODO: match against upsd.users, if readable. COMPREPLY=( ) ; return 0 ;; -l) upses="$(_nut_upses)" COMPREPLY=( $(compgen -W "$upses" -- ${cur}) ) ; return 0 ;; upscmd) upses="$(_nut_upses)" COMPREPLY=( $(compgen -W "$options $upses" -- ${cur}) ) ; return 0 ;; esac # If the user starts to type an option, then only offer options for that word: if [[ "$cur" == -* ]]; then COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 fi # If we have hit the end of the command line, then don't try and match the command as a host: [[ "$pprev" == -* || "$pprev" == "upscmd" ]] && return 0 # Get the list of commands from the UPS named in the previous word: local cmds cmds=$(upscmd -l $prev 2>/dev/null | tail -n +3 | sed 's/ - .*//' ) COMPREPLY=( $(compgen -W "$cmds" -- ${cur}) ) return 0 } complete -F _nut_upscmd_completion upscmd ### _nut_upsd_completion() { local cur options prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} options="-c -D -f -h -r -u -V -4 -6" case "$prev" in -c) # commands: COMPREPLY=( $(compgen -W "reload stop" -- ${cur}) ) ; return 0 ;; -r) # chroot: COMPREPLY=( $(compgen -A directory -- ${cur}) ) ; return 0 ;; -u) # system user, not in upsd.users COMPREPLY=( $(compgen -u -- ${cur}) ) ; return 0 ;; esac # Only options, no other words: COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 return 0 } complete -F _nut_upsd_completion upsd ### _nut_upsdrvctl_completion() { local cur options prev upses COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} options="-h -r -t -u -D" case "$prev" in -r) # chroot: COMPREPLY=( $(compgen -A directory -- ${cur}) ) ; return 0 ;; -u) # system user, not in upsd.users COMPREPLY=( $(compgen -u -- ${cur}) ) ; return 0 ;; start|stop|shutdown) upses="$(_nut_local_upses)" COMPREPLY=( $(compgen -W "$upses" -- ${cur}) ) ; return 0 ;; esac # If the user starts to type an option, then only offer options for that word: if [[ "$cur" == -* ]]; then COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 fi # Don't auto-complete shutdown because it doesn't usually do what you want (upsmon -c fsd): COMPREPLY=( $(compgen -W "$options start stop" -- ${cur}) ) return 0 } complete -F _nut_upsdrvctl_completion upsdrvctl ### _nut_upsmon_completion() { local cur options prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} options="-c -D -h -K -u -4 -6" case "$prev" in -c) # commands: COMPREPLY=( $(compgen -W "fsd reload stop" -- ${cur}) ) ; return 0 ;; -u) # system user, not in upsd.users COMPREPLY=( $(compgen -u -- ${cur}) ) ; return 0 ;; esac # Only options, no other words: COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 return 0 } complete -F _nut_upsmon_completion upsmon ### _nut_upsrw_completion() { local cur options prev upses COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} options="-s -u -p -h" upses="$(_nut_upses)" case "$prev" in -u|-p) # TODO: match against upsd.users, if readable. COMPREPLY=( ) ; return 0 ;; -l) COMPREPLY=( $(compgen -W "$upses" -- ${cur}) ) ; return 0 ;; esac # If the user starts to type an option, then only offer options for that word: if [[ "$cur" == -* ]]; then COMPREPLY=( $(compgen -W "$options" -- ${cur}) ) ; return 0 fi COMPREPLY=( $(compgen -W "$options $upses" -- ${cur}) ) return 0 } complete -F _nut_upsrw_completion upsrw nut-2.8.3/scripts/HP-UX/0000755000200500020050000000000015001555411011644 500000000000000nut-2.8.3/scripts/HP-UX/nut-drvctl.sh0000755000200500020050000000524114777534446014257 00000000000000#!/sbin/sh # # nut-drvctl: NUT ups model-specific drivers start-up and shutdown script # # Allowed exit values: # 0 = success; causes "OK" to show up in checklist. # 1 = failure; causes "FAIL" to show up in checklist. # 2 = skip; causes "N/A" to show up in the checklist. # Use this value if execution of this script is overridden # by the use of a control variable, or if this script is not # appropriate to execute for some other reason. # 3 = reboot; causes the system to be rebooted after execution. # Input and output: # stdin is redirected from /dev/null # # stdout and stderr are redirected to the /etc/rc.log file # during checklist mode, or to the console in raw mode. umask 022 PATH=/usr/sbin:/usr/bin:/sbin export PATH NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY WHAT='NUT UPS driver (Network UPS Tools -- http://www.exploits.org/nut)' WHAT_PATH=/opt/nut/bin/upsdrvctl WHAT_CONFIG=/etc/rc.config.d/nut-drvctl # NOTE: If your script executes in run state 0 or state 1, then /usr might # not be available. Do not attempt to access commands or files in # /usr unless your script executes in run state 2 or greater. Other # file systems typically not mounted until run state 2 include /var # and /opt. rval=0 # Check the exit value of a command run by this script. If non-zero, the # exit code is echoed to the log file and the return value of this script # is set to indicate failure. set_return() { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" rval=1 # script FAILed fi } case $1 in 'start_msg') echo "Starting $WHAT" ;; 'stop_msg') echo "Stopping $WHAT" ;; 'start') if [ -f $WHAT_CONFIG ] ; then . $WHAT_CONFIG else echo "ERROR: $WHAT_CONFIG defaults file MISSING" fi if [ "X$RUNAS" = "X" ] ; then # no user set if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then $WHAT_PATH start $UPSNAME && echo $WHAT started $UPSNAME set_return else rval=2 fi else # start upsd as a specified user if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then su $RUNAS -c $WHAT_PATH start $UPSNAME && echo $WHAT started $UPSNAME as user $RUNAS set_return else rval=2 fi fi ;; 'stop') if [ "X$RUNAS" = "X" ] ; then $WHAT_PATH stop $UPSNAME if [ $? -eq 0 ]; then echo "$WHAT stopped $UPSNAME" else rval=1 echo "Unable to stop $WHAT $UPSNAME" fi else su $RUNAS -c $WHAT_PATH stop $UPSNAME if [ $? -eq 0 ]; then echo "$WHAT stopped $UPSNAME by user $RUNAS" else rval=1 echo "User $RUNAS unable to stop $WHAT $UPSNAME" fi fi ;; *) echo "usage: $0 {start|stop|start_msg|stop_msg}" rval=1 ;; esac exit $rval nut-2.8.3/scripts/HP-UX/nut.psf.in0000644000200500020050000001422314553676503013534 00000000000000B/ # PSF file for Network UPS Tools 11/2/2011 # # Useful commands: # # swpackage -p -vv -s /depot/psf_files/xxx.psf -d /depot/s700_opt # swmodify -p -d -vv -s /depot/psf_files/xxx.psf xxx @ /depot/s700_opt # swremove -p -v -d xxx,r=yyy @ /depot/s700_opt # swinstall -p -v -s /depot/s700_opt xxx # # References: # - Creating a Product Specification File (PSF) # http://docs.hp.com/en/B2355-90127/ch09s05.html # - swpackage(8) manual page # http://nixdoc.net/man-pages/hp-ux/man4/swpackage.4.html # # http://www.massconfusion.com/tim/notes/hpux_depot_create_howto.txt # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # This section is optional # This section is optional -- delete it if you don't want it. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # vendor tag NUT-Team title "NUT - Network UPS Tools - Team" description "UPS monitoring tool" end # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # product # ---------------------------------------- tag NUT title "Network UPS Tools" description "Network UPS Tools (NUT) is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes." revision @PACKAGE_VERSION@ # ---------------------------------------- architecture S700/S800_HPUX_10/HP-UX_B.11.23_IA/PA machine_type * os_name HP-UX #os_release ?.11.2* os_release ?.10.*|?.11.* os_version * # ---------------------------------------- #Including "NUT - Server" files. fileset tag Server title "nut-server" revision @PACKAGE_VERSION@ postinstall ./postinstall #Including "conf" files under "/usr/local/ups/etc/". file -u 644 -g bin -o bin ./nut_install@prefix@/etc/ups.conf.sample @prefix@/etc/ups.conf.sample file -u 644 -g bin -o bin ./nut_install@prefix@/etc/upsd.conf.sample @prefix@/etc/upsd.conf.sample file -u 644 -g bin -o bin ./nut_install@prefix@/etc/upsd.users.sample @prefix@/etc/upsd.users.sample #Including "server" files under "/usr/local/ups/sbin". file -u 755 -g bin -o bin ./nut_install@prefix@/sbin/upsd @prefix@/sbin/upsd #Including "share" files under "/usr/local/ups/share". file -u 644 -g bin -o bin ./nut_install@prefix@/share/cmdvartab @prefix@/share/cmdvartab file -u 644 -g bin -o bin ./nut_install@prefix@/share/driver.list @prefix@/share/driver.list #Including required "libupsclient1" under "/usr/local/ups/lib" file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl.3 @prefix@/lib/libupsclient.sl.3 file -u 555 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl.3.1 @prefix@/lib/libupsclient.sl.3.1 #Including nut service script to "usr/local/ups/script" file -u 744 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-upsd.sh @prefix@/script/nut-upsd.sh file -u 744 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-drvctl.sh @prefix@/script/nut-drvctl.sh file -u 744 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-upsmon.sh @prefix@/script/nut-upsmon.sh file -u 444 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-upsd @prefix@/script/nut-upsd file -u 444 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-drvctl @prefix@/script/nut-drvctl file -u 444 -g bin -o bin @top_srcdir@/scripts/HP-UX/nut-upsmon @prefix@/script/nut-upsmon #Including required UPS drivers files under "/usr/local/ups/bin/". #such as "nut-snmp", "nut-xml or netxml-ups" directory ./nut_install@prefix@/bin=@prefix@/bin/ #file_permissions -u 755 -g bin -o bin file * #TBD files to be added under "/usr/share/doc/nut-server/*.gz" #TBD files to be added under "/usr/share/man/man5/*.gz" #TBD files to be added under "/usr/share/man/man8/*.gz" end # ---------------------------------------- #Including "NUT - Client" files. fileset tag Client title "nut-client" revision @PACKAGE_VERSION@ file -u 755 -g bin -o bin ./nut_install@prefix@/bin/upsc @prefix@/bin/upsc file -u 755 -g bin -o bin ./nut_install@prefix@/bin/upscmd @prefix@/bin/upscmd file -u 755 -g bin -o bin ./nut_install@prefix@/bin/upslog @prefix@/bin/upslog file -u 755 -g bin -o bin ./nut_install@prefix@/bin/upsrw @prefix@/bin/upsrw file -u 755 -g bin -o bin ./nut_install@prefix@/sbin/upsmon @prefix@/sbin/upsmon file -u 755 -g bin -o bin ./nut_install@prefix@/sbin/upssched @prefix@/sbin/upssched #Including "conf" files under "/usr/local/ups/etc". file -u 644 -g bin -o bin ./nut_install@prefix@/etc/nut.conf.sample @prefix@/etc/nut.conf.sample file -u 644 -g bin -o bin ./nut_install@prefix@/etc/upsmon.conf.sample @prefix@/etc/upsmon.conf.sample file -u 644 -g bin -o bin ./nut_install@prefix@/etc/upssched.conf.sample @prefix@/etc/upssched.conf.sample #Need to check if "libupsclient1" required for Client again. #file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl.3 @prefix@/lib/libupsclient.sl.3 #file -u 555 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl.3.1 @prefix@/lib/libupsclient.sl.3.1 end # ---------------------------------------- #Including "libupsclient1-dev" files. fileset tag Development title "libupsclient1-dev" revision @PACKAGE_VERSION@ file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.a @prefix@/lib/libupsclient.a file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.la @prefix@/lib/libupsclient.la file -u 755 -g bin -o bin ./nut_install@prefix@/lib/libupsclient.sl @prefix@/lib/libupsclient.sl file -u 644 -g bin -o bin @top_srcdir@/include/parseconf.h @prefix@/include/parseconf.h file -u 644 -g bin -o bin @top_srcdir@/clients/upsclient.h @prefix@/include/upsclient.h file -u 755 -g bin -o bin ./nut_install@prefix@/lib/pkgconfig/libupsclient.pc @prefix@/lib/pkgconfig/libupsclient.pc end # ---------------------------------------- #Including "libups-nut-perl" files. fileset tag libups-nut-perl title "libups-nut-perl" revision @PACKAGE_VERSION@ file -u 644 -g bin -o bin @top_srcdir@/scripts/perl/Nut.pm @prefix@/share/perl5/UPS/Nut.pm end # ---------------------------------------- end #End product nut-2.8.3/scripts/HP-UX/nut-upsmon.sh0000755000200500020050000000420014777534446014274 00000000000000#!/sbin/sh # # nut-upsmon: NUT ups monitor start-up and shutdown script # # Allowed exit values: # 0 = success; causes "OK" to show up in checklist. # 1 = failure; causes "FAIL" to show up in checklist. # 2 = skip; causes "N/A" to show up in the checklist. # Use this value if execution of this script is overridden # by the use of a control variable, or if this script is not # appropriate to execute for some other reason. # 3 = reboot; causes the system to be rebooted after execution. # Input and output: # stdin is redirected from /dev/null # # stdout and stderr are redirected to the /etc/rc.log file # during checklist mode, or to the console in raw mode. umask 022 PATH=/usr/sbin:/usr/bin:/sbin export PATH NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY WHAT='NUT UPS monitor (Network UPS Tools -- http://www.exploits.org/nut)' WHAT_PATH=/opt/nut/sbin/upsmon WHAT_CONFIG=/etc/rc.config.d/nut-upsmon # NOTE: If your script executes in run state 0 or state 1, then /usr might # not be available. Do not attempt to access commands or files in # /usr unless your script executes in run state 2 or greater. Other # file systems typically not mounted until run state 2 include /var # and /opt. rval=0 # Check the exit value of a command run by this script. If non-zero, the # exit code is echoed to the log file and the return value of this script # is set to indicate failure. set_return() { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" rval=1 # script FAILed fi } case $1 in 'start_msg') echo "Starting $WHAT" ;; 'stop_msg') echo "Stopping $WHAT" ;; 'start') if [ -f $WHAT_CONFIG ] ; then . $WHAT_CONFIG else echo "ERROR: $WHAT_CONFIG defaults file MISSING" fi if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then $WHAT_PATH $UPSMON_ARGS && echo $WHAT $UPSMON_ARGS started set_return else rval=2 fi ;; 'stop') $WHAT_PATH -c stop if [ $? -eq 0 ]; then echo "$WHAT stopped" else rval=1 echo "Unable to stop $WHAT" fi ;; *) echo "usage: $0 {start|stop|start_msg|stop_msg}" rval=1 ;; esac exit $rval nut-2.8.3/scripts/HP-UX/nut-upsd0000644000200500020050000000032114553676503013303 00000000000000# NUT_START: Set to 1 to start NUT # NUT_ARGS: Command line arguments to pass to NUT # # To configure the NUT environment: NUT_START=1 UPSNAME= # Blank == all configured UPSs RUNAS= # Blank == run as root nut-2.8.3/scripts/HP-UX/nut-upsd.sh0000755000200500020050000000504514777534446013736 00000000000000#!/sbin/sh # # nut-upsd: NUT upsd start-up and shutdown script # # Allowed exit values: # 0 = success; causes "OK" to show up in checklist. # 1 = failure; causes "FAIL" to show up in checklist. # 2 = skip; causes "N/A" to show up in the checklist. # Use this value if execution of this script is overridden # by the use of a control variable, or if this script is not # appropriate to execute for some other reason. # 3 = reboot; causes the system to be rebooted after execution. # Input and output: # stdin is redirected from /dev/null # # stdout and stderr are redirected to the /etc/rc.log file # during checklist mode, or to the console in raw mode. umask 022 PATH=/usr/sbin:/usr/bin:/sbin export PATH NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY WHAT='NUT UPS daemon (Network UPS Tools -- http://www.exploits.org/nut)' WHAT_PATH=/opt/nut/sbin/upsd WHAT_CONFIG=/etc/rc.config.d/nut-upsd # NOTE: If your script executes in run state 0 or state 1, then /usr might # not be available. Do not attempt to access commands or files in # /usr unless your script executes in run state 2 or greater. Other # file systems typically not mounted until run state 2 include /var # and /opt. rval=0 # Check the exit value of a command run by this script. If non-zero, the # exit code is echoed to the log file and the return value of this script # is set to indicate failure. set_return() { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" rval=1 # script FAILed fi } case $1 in 'start_msg') echo "Starting $WHAT" ;; 'stop_msg') echo "Stopping $WHAT" ;; 'start') if [ -f $WHAT_CONFIG ] ; then . $WHAT_CONFIG else echo "ERROR: $WHAT_CONFIG defaults file MISSING" fi if [ "X$RUNAS" = "X" ] ; then # no user set if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then $WHAT_PATH && echo $WHAT started set_return else rval=2 fi else # start upsd as a specified user if [ "$NUT_START" -eq 1 -a -x $WHAT_PATH ]; then su $RUNAS -c $WHAT_PATH && echo $WHAT started as user $RUNAS set_return else rval=2 fi fi ;; 'stop') if [ "X$RUNAS" = "X" ] ; then $WHAT_PATH -c stop if [ $? -eq 0 ]; then echo "$WHAT stopped" else rval=1 echo "Unable to stop $WHAT" fi else su $RUNAS -c "$WHAT_PATH -c stop" if [ $? -eq 0 ]; then echo "$WHAT stopped by user $RUNAS" else rval=1 echo "User $RUNAS unable to stop $WHAT" fi fi ;; *) echo "usage: $0 {start|stop|start_msg|stop_msg}" rval=1 ;; esac exit $rval nut-2.8.3/scripts/HP-UX/nut-drvctl0000644000200500020050000000032114553676503013626 00000000000000# NUT_START: Set to 1 to start NUT # NUT_ARGS: Command line arguments to pass to NUT # # To configure the NUT environment: NUT_START=1 UPSNAME= # Blank == all configured UPSs RUNAS= # Blank == run as root nut-2.8.3/scripts/HP-UX/nut-upsmon0000644000200500020050000000022714553676503013656 00000000000000# NUT_START: Set to 1 to start NUT # NUT_ARGS: Command line arguments to pass to NUT # # To configure the NUT environment: NUT_START=1 UPSMON_ARGS= nut-2.8.3/scripts/HP-UX/postinstall.in0000644000200500020050000000413314777534446014521 00000000000000#!/bin/sh # directory definitions NUT_DIR="@prefix@" INSTALLPATH="$NUT_DIR/script" CONFIGPATH=/etc/rc.config.d SCRIPTPATH=/sbin/init.d LINKPATH=/sbin/rc3.d LINKPREFIX=991 OWNER=root GROUP=root SCRIPTS="nut-upsd.sh nut-drvctl.sh nut-upsmon.sh" CONFIGS="nut-drvctl nut-upsd nut-upsmon" SCRIPTPERMS=0744 CONFIGPERMS=0444 # make sure the nut user exists and has correct memberships res=`grget -n nut` if [ -z "$res" ]; then groupadd nut fi res=`pwget -n nut` if [ -z "$res" ]; then useradd -g nut -G root -d ${NUT_DIR}/bin nut fi # make sure that conffiles are secured and have the correct ownerships if [ -d @CONFPATH@ ] ; then chown root:nut @CONFPATH@ fi for file in nut.conf ups.conf upsd.conf upsmon.conf upsd.users upssched.conf; do if [ -f @CONFPATH@/$file ] ; then chown root:nut @CONFPATH@/$file chmod 640 @CONFPATH@/$file fi done # make sure that /var/run exists (for privileged processes) if [ ! -d @PIDPATH@ ] ; then mkdir -p @PIDPATH@ fi # make sure that /var/run/nut exists and has the correct ownerships if [ ! -d @ALTPIDPATH@ ] ; then mkdir -p @ALTPIDPATH@ fi if [ -d @ALTPIDPATH@ ] ; then chown root:nut @ALTPIDPATH@ chmod 770 @ALTPIDPATH@ fi # make sure that /var/state/ups exists and has the correct ownerships if [ ! -d @STATEPATH@ ] ; then mkdir -p @STATEPATH@ fi if [ -d /var/state/ups ] ; then chown root:nut @STATEPATH@ chmod 770 @STATEPATH@ fi #Set-up automatic start-up if [ ! -d $CONFIGPATH ]; then echo "NO $CONFIGPATH"; exit 1; fi if [ ! -d $SCRIPTPATH ]; then echo "NO $SCRIPTPATH"; exit 1; fi if [ ! -d $LINKPATH ]; then echo "NO $LINKPATH"; exit 1; fi for script in $SCRIPTS; do name=`basename ${script} .sh` ; cp $INSTALLPATH/$script $SCRIPTPATH/$name chown $OWNER:$GROUP $SCRIPTPATH/$name chmod $SCRIPTPERMS $SCRIPTPATH/$name ln -f -s $SCRIPTPATH/$name $LINKPATH/K$LINKPREFIX$name ln -f -s $SCRIPTPATH/$name $LINKPATH/S$LINKPREFIX$name done for config in $CONFIGS; do cp $INSTALLPATH/$config $CONFIGPATH chown $OWNER:$GROUP $CONFIGPATH chmod $CONFIGPERMS $CONFIGPATH done nut-2.8.3/scripts/Windows/0000755000200500020050000000000015001555412012436 500000000000000nut-2.8.3/scripts/Windows/build-mingw-nut.sh0000755000200500020050000002037414777767434016001 00000000000000#!/usr/bin/env bash # NOTE: bash syntax (non-POSIX script) is used below! # # script to cross compile NUT for Windows from Linux using MinGW-w64 # http://mingw-w64.sourceforge.net/ #set -x SCRIPTDIR="`dirname "$0"`" SCRIPTDIR="`cd "$SCRIPTDIR" && pwd`" DLLLDD_SOURCED=true . "${SCRIPTDIR}/dllldd.sh" # This should match the tarball and directory name, # if a stable version is used: [ -n "$VER_OPT" ] || VER_OPT=2.8.3 DEBUG=true # default to 32bits build # Note: README specifies dependencies to pre-build and install; # those DLLs should correspond to same architecture selection cmd=all32 if [ -n "$1" ] ; then cmd="$1" fi if [ "$cmd" == "all64" ] || [ "$cmd" == "b64" ] || [ "$cmd" == "all32" ] || [ "$cmd" == "b32" ] ; then ARCH="x86_64-w64-mingw32" if [ "$cmd" == "all32" ] || [ "$cmd" == "b32" ] ; then ARCH="i686-w64-mingw32" fi else echo "Usage:" echo " $0 [all64 | b64 | all32 | b32]" echo " Default: 'all32'" echo "Optionally export SOURCEMODE=[stable|dist|out-of-tree]" case "${cmd}" in -h|--help|help) exit 0 ;; *) exit 1 ;; esac fi # These paths are somewhat related: [ -n "${WINDIR-}" ] || WINDIR="$(pwd)" [ -n "${TOP_DIR-}" ] || TOP_DIR="$WINDIR/../.." # These may be located elsewhere: [ -n "${BUILD_DIR-}" ] || BUILD_DIR="$WINDIR/nut_build_${ARCH}" [ -n "${INSTALL_DIR-}" ] || INSTALL_DIR="$WINDIR/nut_install_${ARCH}" # Convenience symlink to find the latest completed build workspace and # installed results; not used by the script other than updating the symlink: [ -n "${BUILD_DIR_SYMLINK-}" ] || BUILD_DIR_SYMLINK="$WINDIR/nut_build" [ -n "${INSTALL_DIR_SYMLINK-}" ] || INSTALL_DIR_SYMLINK="$WINDIR/nut_install" rm -rf "$BUILD_DIR" "$INSTALL_DIR" "$BUILD_DIR_SYMLINK" "$INSTALL_DIR_SYMLINK" if [ x"$BUILD_DIR" != x"$BUILD_DIR_SYMLINK" ] ; then ln -fsr "$BUILD_DIR" "$BUILD_DIR_SYMLINK" fi if [ x"$INSTALL_DIR" != x"$INSTALL_DIR_SYMLINK" ] ; then ln -fsr "$INSTALL_DIR" "$INSTALL_DIR_SYMLINK" fi CONFIGURE_SCRIPT="./configure" [ -n "$SOURCEMODE" ] || SOURCEMODE="out-of-tree" case "$SOURCEMODE" in stable) # FIXME # Stable version (download the latest stable archive) VER_OPT_SHORT="`echo "$VER_OPT" | awk -F. '{print $1"."$2}'`" if [ ! -s "nut-$VER_OPT.tar.gz" ] ; then wget "https://www.networkupstools.org/source/$VER_OPT_SHORT/nut-$VER_OPT.tar.gz" fi rm -rf "nut-$VER_OPT" tar -xzf "nut-$VER_OPT.tar.gz" mv "nut-$VER_OPT" "$BUILD_DIR" ;; dist) # In-place version (no download) cd ../.. rm -f nut-?.?.?*.tar.gz [ -s Makefile ] || { ./autogen.sh && ./configure; } make dist SRC_ARCHIVE="$(ls -1 nut-?.?.?*.tar.gz | sort -n | tail -1)" cd scripts/Windows tar -xzf "../../$SRC_ARCHIVE" mv nut-?.?.?* "$BUILD_DIR" ;; out-of-tree) CONFIGURE_SCRIPT="../../../configure" cd ../.. if [ ! -x ./configure ]; then ./autogen.sh fi if [ -s Makefile ]; then make distclean fi cd scripts/Windows mkdir -p "$BUILD_DIR" ;; esac if [ -z "$INSTALL_WIN_BUNDLE" ]; then echo "NOTE: You might want to export INSTALL_WIN_BUNDLE=true to use main NUT Makefile" echo "recipe for DLL co-bundling (default: false to use logic maintained in $0" fi >&2 do_build_mingw_nut() { cd "$BUILD_DIR" || exit HOST_FLAG="--host=$ARCH" # --build needs to be specified, beside of --host, to avoid Warning # but this version is very Debian specific!!! # FIXME: find something more generic BUILD_FLAG="--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE`" export CC="$ARCH-gcc" export CXX="$ARCH-g++" # TODO: Detect/parameterize? # This prefix is currently valid for mingw packaging in Debian/Ubuntu. ARCH_PREFIX="/usr/$ARCH" export PATH="${ARCH_PREFIX}/bin:$PATH" # Note: _WIN32_WINNT>=0x0600 is needed for inet_ntop in mingw headers # and the value 0xffff is anyway forced into some components at least # by netsnmp cflags. # _POSIX_THREAD_SAFE_FUNCTIONS whould help with localtime_r() gmtime_r() # on recent mingw releases (as of 2019), per # https://stackoverflow.com/questions/18551409/localtime-r-support-on-mingw export CFLAGS+=" -D_POSIX=1 -D_POSIX_C_SOURCE=200112L -D_POSIX_THREAD_SAFE_FUNCTIONS=200112L -I${ARCH_PREFIX}/include/ -D_WIN32_WINNT=0xffff" export CXXFLAGS+=" -D_POSIX=1 -D_POSIX_C_SOURCE=200112L -D_POSIX_THREAD_SAFE_FUNCTIONS=200112L -I${ARCH_PREFIX}/include/ -D_WIN32_WINNT=0xffff" export LDFLAGS+=" -L${ARCH_PREFIX}/lib/" KEEP_NUT_REPORT_FEATURE_FLAG="" if [ x"${KEEP_NUT_REPORT_FEATURE-}" = xtrue ]; then KEEP_NUT_REPORT_FEATURE_FLAG="--enable-keep_nut_report_feature" fi # Note: installation prefix here is "/" and desired INSTALL_DIR # location is passed to `make install` as DESTDIR below. # FIXME: Implement support for --without-pkg-config in m4 and use it RES_CFG=0 $CONFIGURE_SCRIPT $HOST_FLAG $BUILD_FLAG --prefix=/ \ $KEEP_NUT_REPORT_FEATURE_FLAG \ PKG_CONFIG_PATH="${ARCH_PREFIX}/lib/pkgconfig" \ --with-all=auto \ --with-doc="man=auto html-single=auto html-chunked=skip pdf=skip" \ --without-systemdsystemunitdir \ --with-pynut=app \ --with-augeas-lenses-dir=/augeas-lenses \ --enable-Werror \ || RES_CFG=$? echo "$0: configure phase complete ($RES_CFG)" >&2 [ x"$RES_CFG" = x0 ] || exit $RES_CFG echo "Configuration finished, starting make" >&2 if [ -n "$PARMAKE_FLAGS" ]; then echo "For parallel builds, '$PARMAKE_FLAGS' options would be used" >&2 fi if [ -n "$MAKEFLAGS" ]; then echo "Generally, MAKEFLAGS='$MAKEFLAGS' options would be passed" >&2 fi # FIXME: parameterize ${MAKE} ? make 1>/dev/null || exit make doc 1>/dev/null || exit make -k man-man html-man 1>/dev/null || true (cd docs && make check) 1>/dev/null || exit echo "$0: build phase complete ($?)" >&2 if [ "x$INSTALL_WIN_BUNDLE" = xtrue ] ; then # Going forward, this should be the main mode - "legacy code" # below picked up and transplanted into main build scenarios: echo "NOTE: INSTALL_WIN_BUNDLE==true so using main NUT Makefile logic for DLL co-bundling" >&2 make install-win-bundle DESTDIR="${INSTALL_DIR}" || exit else # Legacy code from when NUT for Windows effort started; # there is no plan to maintain it much (this script is PoC): echo "NOTE: INSTALL_WIN_BUNDLE!=true so using built-in logic for DLL co-bundling" >&2 make install DESTDIR="${INSTALL_DIR}" || exit # Per docs, Windows loads DLLs from EXE file's dir or some # system locations or finally PATH, so unless the caller set # the latter, we can not load the pre-linked DLLs from ../lib: # http://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx#standard_search_order_for_desktop_applications # Be sure upsmon can run even if at cost of some duplication # (maybe even do "cp -pf" if some system dislikes "ln"); also # on a modern Windows one could go to their installed "sbin" to # mklink .\libupsclient-3.dll ..\bin\libupsclient-3.dll (cd "$INSTALL_DIR/bin" && ln libupsclient*.dll ../sbin/) (cd "$INSTALL_DIR/cgi-bin" 2>/dev/null && ln ../bin/libupsclient*.dll ./) \ || echo "NOTE: FAILED to process OPTIONAL cgi-bin directory; was NUT CGI enabled?" >&2 echo "NOTE: Adding third-party dependency libraries for each installed program" >&2 echo " Do not worry about lack of libnut* and libups* in system locations" >&2 # Cover dependencies for nut-scanner (not pre-linked) # Note: lib*snmp*.dll not listed below, it is # statically linked into binaries that use it (cd "$INSTALL_DIR/bin" && cp -pf "${ARCH_PREFIX}/bin"/{libgnurx,libusb,libltdl}*.dll .) || true (cd "$INSTALL_DIR/bin" && cp -pf "${ARCH_PREFIX}/lib"/libwinpthread*.dll .) || true # Steam-roll over all executables/libs we have here and copy # over resolved dependencies from the cross-build environment: (cd "$INSTALL_DIR" && { dllldddir . | while read D ; do cp -pf "$D" ./bin/ ; done ; } ) || true # Hardlink libraries for sbin (alternative: all bins in one dir): (cd "$INSTALL_DIR/sbin" && { DESTDIR="$INSTALL_DIR" dllldddir . | while read D ; do ln -f ../bin/"`basename "$D"`" ./ ; done ; } ) || true # Hardlink libraries for cgi-bin if present: (cd "$INSTALL_DIR/cgi-bin" 2>/dev/null && { DESTDIR="$INSTALL_DIR" dllldddir . | while read D ; do ln -f ../bin/"`basename "$D"`" ./ ; done ; } ) \ || echo "NOTE: FAILED to process OPTIONAL cgi-bin directory; was NUT CGI enabled?" >&2 fi # If we had fatal errors above, we exited there - so here we are SUCCESSful echo "$0: SUCCESS: install phase complete ($?)" >&2 cd .. } do_build_mingw_nut nut-2.8.3/scripts/Windows/dllldd.sh0000755000200500020050000001723114777534446014207 00000000000000#!/bin/sh # This is a helper script to find Windows DLL library files used by another # Portable Executable (DLL or EXE) file, restricted to paths in the MinGW # environment. It can do so recursively, to facilitate installation of NUT # for Windows, bundled with open-source dependencies. # # Copyright (C) # 2022 Jim Klimov REGEX_WS="`printf '[\t ]'`" REGEX_NOT_WS="`printf '[^\t ]'`" dllldd() ( # Traverse an EXE or DLL file for DLLs it needs directly, # which are provided in the cross-build env (not system ones). # Assume no whitespaces in paths and filenames of interest. # grep for standard-language strings where needed: LANG=C LC_ALL=C export LANG LC_ALL # Otherwise try objdump, if ARCH is known (linux+mingw builds) or not (MSYS2 builds) SEEN=0 if [ -n "${ARCH-}${MINGW_PREFIX-}${MSYSTEM_PREFIX-}" ] ; then for OD in objdump "$ARCH-objdump" ; do (command -v "$OD" >/dev/null 2>/dev/null) || continue ODOUT="`$OD -x "$@" 2>/dev/null | grep -Ei "DLL Name:" | awk '{print $NF}' | sort | uniq | grep -vEi '^(|/.*/)(msvcrt|userenv|bcrypt|rpcrt4|usp10|(advapi|kernel|user|wsock|ws2_|gdi|ole||shell)(32|64))\.dll$'`" \ && [ -n "$ODOUT" ] || continue for F in $ODOUT ; do if [ -n "$DESTDIR" -a -d "${DESTDIR}" ] ; then OUT="`find "$DESTDIR" -type f -name "$F" \! -size 0 2>/dev/null | head -1`" \ && [ -n "$OUT" ] && { echo "$OUT" ; SEEN="`expr $SEEN + 1`" ; continue ; } fi if [ -n "$ARCH" -a -d "/usr/${ARCH}" ] ; then OUT="`ls -1 "/usr/${ARCH}/bin/$F" "/usr/${ARCH}/lib/$F" 2>/dev/null || true`" \ && [ -n "$OUT" ] && { echo "$OUT" ; SEEN="`expr $SEEN + 1`" ; continue ; } fi if [ -n "$MSYSTEM_PREFIX" -a -d "$MSYSTEM_PREFIX" ] ; then OUT="`ls -1 "${MSYSTEM_PREFIX}/bin/$F" "${MSYSTEM_PREFIX}/lib/$F" 2>/dev/null || true`" \ && [ -n "$OUT" ] && { echo "$OUT" ; SEEN="`expr $SEEN + 1`" ; continue ; } fi if [ -n "$MINGW_PREFIX" -a "$MINGW_PREFIX" != "$MSYSTEM_PREFIX" -a -d "$MINGW_PREFIX" ] ; then OUT="`ls -1 "${MINGW_PREFIX}/bin/$F" "${MINGW_PREFIX}/lib/$F" 2>/dev/null || true`" \ && [ -n "$OUT" ] && { echo "$OUT" ; SEEN="`expr $SEEN + 1`" ; continue ; } fi # Look for compiler-provided libraries, e.g. in cross-builds on linux+mingw # we have a selection of such C++ required artifacts as: # /usr/lib/gcc/x86_64-w64-mingw32/9.3-win32/libgcc_s_seh-1.dll # /usr/lib/gcc/x86_64-w64-mingw32/9.3-win32/libstdc++-6.dll # /usr/lib/gcc/x86_64-w64-mingw32/9.3-posix/libgcc_s_seh-1.dll # /usr/lib/gcc/x86_64-w64-mingw32/9.3-posix/libstdc++-6.dll # /usr/lib/gcc/i686-w64-mingw32/9.3-win32/libstdc++-6.dll # /usr/lib/gcc/i686-w64-mingw32/9.3-posix/libstdc++-6.dll # while on MSYS2 there is one in standard path matched above: # /mingw64/bin/libstdc++-6.dll # A clumsy alternative would be to link deliverable C++ libs/bins # statically with "-static-libgcc -static-libstdc++" options. COMPILER_PATHS="" if [ -n "$CC" ] ; then # gcc and clang support this option: COMPILER_PATHS="`$CC --print-search-dirs | grep libraries: | sed 's,^libraries: *=/,/,'`" else # FIXME: Try to look up in config.log first? if [ -n "$ARCH" ] && (command -v "${ARCH}-gcc") 2>/dev/null >/dev/null ; then COMPILER_PATHS="`"${ARCH}-gcc" --print-search-dirs | grep libraries: | sed 's,^libraries: *=/,/,'`" fi fi if [ -n "$CXX" ] ; then # g++ and clang support this option: COMPILER_PATHS="`$CXX --print-search-dirs | grep libraries: | sed 's,^libraries: *=/,/,'`:${COMPILER_PATHS}" else # FIXME: Try to look up in config.log first? if [ -n "$ARCH" ] && (command -v "${ARCH}-g++") 2>/dev/null >/dev/null ; then COMPILER_PATHS="`"${ARCH}-g++" --print-search-dirs | grep libraries: | sed 's,^libraries: *=/,/,'`" fi fi if [ -n "$COMPILER_PATHS" ] ; then COMPILER_PATHS="`echo "$COMPILER_PATHS" | tr ':' '\n'`" for P in $COMPILER_PATHS ; do OUT="`ls -1 "${P}/$F" 2>/dev/null || true`" \ && [ -n "$OUT" ] && { echo "$OUT" ; SEEN="`expr $SEEN + 1`" ; continue 2 ; } done fi echo "WARNING: '$F' was not found in searched locations (system paths)!" >&2 done done if [ "$SEEN" != 0 ] ; then return 0 fi fi # if `ldd` handles Windows PE (e.g. on MSYS2), we are lucky: # libiconv-2.dll => /mingw64/bin/libiconv-2.dll (0x7ffd26c90000) # but it tends to say "not a dynamic executable" # or that file type is not supported OUT="`ldd "$@" 2>/dev/null | grep -Ei '\.dll' | grep -E '/(bin|lib)/' | sed "s,^${REGEX_WS}*\(${REGEX_NOT_WS}${REGEX_NOT_WS}*\)${REGEX_WS}${REGEX_WS}*=>${REGEX_WS}${REGEX_WS}*\(${REGEX_NOT_WS}${REGEX_NOT_WS}*\)${REGEX_WS}.*\$,\2," | sort | uniq | grep -Ei '\.dll$'`" \ && [ -n "$OUT" ] && { echo "$OUT" ; return 0 ; } return 1 ) dlllddrec() ( # Recurse to find the (mingw-provided) tree of dependencies dllldd "$1" | while read D ; do echo "$D" dlllddrec "$D" done | sort | uniq ) # Alas, can't rely on having BASH, and dash fails to parse its syntax # even if hidden by conditionals or separate method like this (might # optionally source it from another file though?) #diffvars_bash() { # diff -bu <(echo "$1") <(echo "$2") | grep -E '^\+[^+]' | sed 's,^\+,,' #} dllldddir() ( # Recurse the current (or specified) directory, find all EXE/DLL here, # and locate their dependency DLLs, and produce a unique-item list if [ $# = 0 ]; then dllldddir . return fi # Assume no whitespace in built/MSYS/MinGW paths... ORIGFILES="`find "$@" -type f | grep -Ei '\.(exe|dll)$'`" || return # Quick OK, nothing here? [ -n "$ORIGFILES" ] || return 0 # Loop until we see nothing new: SEENDLLS="`dllldd $ORIGFILES | sort | uniq`" [ -n "$SEENDLLS" ] || return 0 #if [ -z "$BASH_VERSION" ] ; then TMP1="`mktemp`" TMP2="`mktemp`" trap "rm -f '$TMP1' '$TMP2'" 0 1 2 3 15 #fi NEXTDLLS="$SEENDLLS" while [ -n "$NEXTDLLS" ] ; do MOREDLLS="`dllldd $NEXTDLLS | sort | uniq`" # Next iteration we drill into those we have not seen yet #if [ -n "$BASH_VERSION" ] ; then # NEXTDLLS="`diffvars_bash "$SEENDLLS" "$MOREDLLS"`" #else echo "$SEENDLLS" > "$TMP1" echo "$MOREDLLS" > "$TMP2" NEXTDLLS="`diff -bu "$TMP1" "$TMP2" | grep -E '^\+[^+]' | sed 's,^\+,,'`" #fi if [ -n "$NEXTDLLS" ] ; then SEENDLLS="`( echo "$SEENDLLS" ; echo "$NEXTDLLS" ) | sort | uniq`" fi done if [ -z "$BASH_VERSION" ] ; then rm -f "$TMP1" "$TMP2" trap - 0 1 2 3 15 fi echo "$SEENDLLS" ) dllldddir_pedantic() ( # For `ldd` or `objdump` versions that do not act on many files # Recurse the current (or specified) directory, find all EXE/DLL here, # and locate their dependency DLLs, and produce a unique-item list if [ $# = 0 ]; then dllldddir_pedantic . return fi # Two passes: one finds direct dependencies of all EXE/DLL under the # specified location(s); then trims this list to be unique, and then # the second pass recurses those libraries for their dependencies: find "$@" -type f | grep -Ei '\.(exe|dll)$' \ | while read E ; do dllldd "$E" ; done | sort | uniq \ | while read D ; do echo "$D"; dlllddrec "$D" ; done | sort | uniq ) if [ x"${DLLLDD_SOURCED-}" != xtrue ] ; then # Work like a command-line tool: case "$1" in ""|-h|-help|--help) cat << EOF Tool to find DLLs needed by an EXE or another DLL Directly used libraries: $0 dllldd ONEFILE.EXE Recursively used libraries: $0 dlllddrec ONEFILE.EXE Find all EXE/DLL files under specified (or current) dir, and list their set of required DLLs $0 dllldddir [DIRNAME...] $0 dllldddir_pedantic [DIRNAME...] EOF ;; dlllddrec|dllldd|dllldddir|dllldddir_pedantic) "$@" ;; *) dlllddrec "$1" ;; esac exit 0 fi # Caller said DLLLDD_SOURCED=true echo "SOURCED dllldd methods" nut-2.8.3/scripts/Windows/Makefile.in0000644000200500020050000010311115001555011014413 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/Windows VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = $(am__EXEEXT_1) # Some binutils packages (e.g. on Slackware 15) include windres and windmc # tools, even though they do not deliver the rest of files such as windows.h # that would be needed for actual builds targeting Windows. @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@am__append_1 = nut halt @HAVE_MINGW_RESGEN_TRUE@am__append_2 = winevent.rc winevent.o winevent.h subdir = scripts/Windows ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@am__EXEEXT_1 = \ @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@ nut$(EXEEXT) \ @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@ halt$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am__halt_SOURCES_DIST = halt.c @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@am_halt_OBJECTS = \ @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@ halt.$(OBJEXT) halt_OBJECTS = $(am_halt_OBJECTS) halt_LDADD = $(LDADD) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am__nut_SOURCES_DIST = wininit.c @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@am_nut_OBJECTS = \ @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@ wininit.$(OBJEXT) nut_OBJECTS = $(am_nut_OBJECTS) @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@nut_DEPENDENCIES = $(top_builddir)/common/libcommon.la \ @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@ winevent.o AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/halt.Po ./$(DEPDIR)/wininit.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(halt_SOURCES) $(nut_SOURCES) DIST_SOURCES = $(am__halt_SOURCES_DIST) $(am__nut_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ AM_CFLAGS = -I$(top_srcdir)/include EXTRA_DIST = \ winevent.mc \ build-mingw-nut.sh \ build-mingw-prereqs.sh \ dllldd.sh \ README.adoc \ DriverInstaller/wdi-simple.c \ DriverInstaller/README.adoc \ Installer/README.adoc \ Installer/BuildInstaller.bat \ Installer/NUT-Installer.xml.in \ Installer/ImageFiles/icons/completi.ico \ Installer/ImageFiles/icons/info.ico \ Installer/ImageFiles/icons/custicon.ico \ Installer/ImageFiles/icons/Up.ico \ Installer/ImageFiles/icons/exclamic.ico \ Installer/ImageFiles/icons/powernut_Stop.ico \ Installer/ImageFiles/icons/repairic.ico \ Installer/ImageFiles/icons/New.ico \ Installer/ImageFiles/icons/removico.ico \ Installer/ImageFiles/icons/powernut_logo.ico \ Installer/ImageFiles/icons/insticon.ico \ Installer/ImageFiles/Images/NUT_wix_vertical.bmp \ Installer/ImageFiles/Images/NUT_wix_horizontal.bmp \ Installer/ImageFiles/Others/StopService.bat \ Installer/ImageFiles/Others/StartService.bat \ Installer/ImageFiles/emptyDir/man1/temp.txt \ Installer/ImageFiles/emptyDir/cgi-bin/temp.txt \ Installer/ImageFiles/emptyDir/pkgconfig/temp.txt \ Installer/ImageFiles/emptyDir/include/temp.txt \ Installer/ImageFiles/emptyDir/html/temp.txt \ Installer/ImageFiles/emptyDir/man3/temp.txt \ Installer/ImageFiles/emptyDir/run/temp.txt CLEANFILES = *-spellchecked */*-spellchecked $(am__append_2) @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@nut_SOURCES = wininit.c @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@nut_LDADD = $(top_builddir)/common/libcommon.la winevent.o @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@halt_SOURCES = halt.c SPELLCHECK_SRC = README.adoc DriverInstaller/README.adoc Installer/README.adoc MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .c .in .in-spellchecked .lo .o .obj .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Windows/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Windows/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list halt$(EXEEXT): $(halt_OBJECTS) $(halt_DEPENDENCIES) $(EXTRA_halt_DEPENDENCIES) @rm -f halt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(halt_OBJECTS) $(halt_LDADD) $(LIBS) nut$(EXEEXT): $(nut_OBJECTS) $(nut_DEPENDENCIES) $(EXTRA_nut_DEPENDENCIES) @rm -f nut$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nut_OBJECTS) $(nut_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/halt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wininit.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/halt.Po -rm -f ./$(DEPDIR)/wininit.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/halt.Po -rm -f ./$(DEPDIR)/wininit.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS .PRECIOUS: Makefile $(top_builddir)/common/libcommon.la: FORCE +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) FORCE: # Avoid "Using $< in a non-suffix rule context is a GNUmake idiom" by $? @HAVE_MINGW_RESGEN_TRUE@winevent.rc winevent.h: winevent.mc @HAVE_MINGW_RESGEN_TRUE@ $(WINDMC) $? @HAVE_MINGW_RESGEN_TRUE@winevent.o: winevent.rc winevent.h @HAVE_MINGW_RESGEN_TRUE@ $(WINDRES) winevent.rc winevent.o @HAVE_MINGW_RESGEN_TRUE@wininit.$(OBJEXT): winevent.h # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/Windows/build-mingw-prereqs.sh0000755000200500020050000002531314777767434016652 00000000000000#!/bin/sh # Copyright (C) 2022-2025 by Jim Klimov # Licensed GPLv2+, same as NUT # # Helper automating the nuances from NUT::scripts/Windows/README.adoc # to provide prerequisites needed in semi-native or cross-builds. # # NOTE: Currently constrained to providing net-snmp under MSYS2 # (where not packaged/installed) and custom libmodbus from NUT Git. # # We can not rely on certain common shell facilities like `true` # and `false` programs being available (in PATH or at all) so we # `echo ""` instead. # TODO: Support `make uninstall` attempts for older versions?.. # # NOTE: Experimentally can use for prerequisites on other platforms, e.g. # SUDO=" " PREFIX_ROOT="${HOME}/nut-deps-inst" PREFIX="" \ # ARCH="`uname -s`-`uname -p`" ./scripts/Windows/build-mingw-prereqs.sh prepareEnv() { [ -n "${MAKE-}" ] || { (command -v gmake) 2>/dev/null >/dev/null \ && MAKE="gmake" \ || MAKE="make" } export MAKE [ -n "${MAKEFLAGS-}" ] || { MAKEFLAGS="-j 8" export MAKEFLAGS } if [ -z "${SUDO-}" ] ; then SUDO=" " # avoid reeval if (command -v sudo) ; then SUDO="sudo" ; fi fi export SUDO [ -n "${DLDIR-}" ] || DLDIR=~/nut-win-deps if [ -n "${ARCH-}" ] && [ -n "${PREFIX-}" ] ; then [ -n "${WSDIR-}" ] || WSDIR="$DLDIR"/"$ARCH" mkdir -p "$WSDIR" "$DLDIR" else BUILD_FLAG="" HOST_FLAG="" export HOST_FLAG if [ -n "${MSYS2_PATH-}" ]; then # Assume semi-native build for same env [ -n "${ARCH-}" ] || ARCH="$MINGW_CHOST" [ -n "${PREFIX_ROOT-}" ] || PREFIX_ROOT="/" [ -n "${PREFIX-}" ] || PREFIX="${PREFIX_ROOT}/$MINGW_PREFIX" # Normalize away extra slashes, they confuse at least MSYS2 tools PREFIX="`echo "${PREFIX}" | sed 's,//*,/,g'`" case "${PATH}" in "${PREFIX}/bin"|"${PREFIX}/bin:"*|*":${PREFIX}/bin:"*|*":${PREFIX}/bin") ;; *) PATH="${PREFIX}/bin:${PATH}" ;; esac case "${PATH}" in */ccache/*) ;; *) if [ -d "${PREFIX}/lib/ccache/bin" ] ; then # Potentionally customized by builder echo "Injecting MSYS2 ccache symlink collection (under PREFIX) into PATH" >&2 PATH="${PREFIX}/lib/ccache/bin:${PATH}" else if [ -d "${MINGW_PREFIX}/lib/ccache/bin" ] ; then echo "Injecting MSYS2 ccache symlink collection (under MINGW_PREFIX) into PATH" >&2 PATH="${MINGW_PREFIX}/lib/ccache/bin:${PATH}" fi fi ;; esac export ARCH PATH PREFIX if ! (command -v sudo) ; then sudo() ( "$@" ) ; fi else if [ -z "${ARCH-}" ] ; then # TODO: Select by args, envvars, directory presence... ARCH="x86_64-w64-mingw32" #ARCH="i686-w64-mingw32" fi # Assumes Ubuntu/Debian with mingw prepared, per README HOST_FLAG="--host=$ARCH" [ -n "${PREFIX_ROOT-}" ] || PREFIX_ROOT="/usr" [ -n "${PREFIX-}" ] || PREFIX="${PREFIX_ROOT}/${ARCH}" PREFIX="`echo "${PREFIX}" | sed 's,//*,/,g'`" export ARCH PREFIX if (command -v dpkg-architecture) ; then BUILD_FLAG="--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE`" fi fi fi if [ -z "${ARCH-}" ] || [ -z "${PREFIX-}" ] ; then echo "FAILED to determine ARCH and/or PREFIX!" >&2 exit 1 fi case "$CFLAGS" in *"${PREFIX}/include"*) ;; *) CFLAGS="$CFLAGS -D_POSIX=1 -I${PREFIX}/include/" ;; esac case "$CXXFLAGS" in *"${PREFIX}/include"*) ;; *) CXXFLAGS="$CXXFLAGS -D_POSIX=1 -I${PREFIX}/include/" ;; esac case "$LDFLAGS" in *"${PREFIX}/lib"*) ;; *) LDFLAGS="$LDFLAGS -L${PREFIX}/lib/" ;; esac case "$PKG_CONFIG_PATH" in *"${PREFIX}/lib"*) ;; *) PKG_CONFIG_PATH="${PREFIX}"/lib/pkgconfig ;; esac export CFLAGS CXXFLAGS LDFLAGS PKG_CONFIG_PATH [ -n "${WSDIR-}" ] || WSDIR="$DLDIR"/"$ARCH" mkdir -p "$WSDIR" "$DLDIR" } # Provide prerequisites; reentrant (quick skip if installed; quick install if built) provide_netsnmp() ( PKGCFG_NAME="netsnmp" DEP_PRJNAME="net-snmp" DEP_VERSION="5.9.1" DEP_DIRNAME="${DEP_PRJNAME}-${DEP_VERSION}" DEP_ARCHIVE="${DEP_DIRNAME}.tar.gz" FORCE=false if [ x"${1-}" = x"-f" ] ; then FORCE=true ; fi set +e if [ x"$FORCE" = x"false" ] ; then # TODO: Check version if pkg-config --exists "$PKGCFG_NAME" ; then echo "SKIP: pkg-config says '$PKGCFG_NAME' exists" >&2 return 0 fi # Quickly install if prebuilt if [ -d "${WSDIR}/${DEP_DIRNAME}/.inst" ]; then ( cd "${WSDIR}/${DEP_DIRNAME}/.inst" || exit (command -v rsync) && $SUDO rsync -cavPHK ./ / && exit $SUDO cp -pr ./ / && exit exit 1 ) && { echo "INST: (re-)applied '${WSDIR}/${DEP_DIRNAME}/.inst'" >&2 return 0 } fi # no stashed .inst; any Makefile at least? if [ -s "${WSDIR}/${DEP_DIRNAME}/Makefile" ]; then ( cd "${WSDIR}/${DEP_DIRNAME}" && $SUDO $MAKE install ) && { echo "INST: ran 'make install' from '${WSDIR}/${DEP_DIRNAME}'" >&2 return } fi # Not pre-built, fall through fi # (Re-)make and install from scratch set -e # Funny ways to fetch from Sourceforge help get the archive, # not the download page... For some reason, this bites CI # builds on Appveyor but not local runs: echo "FETCH: ${DEP_ARCHIVE}..." >&2 ( cd "$DLDIR" && curl -L "https://sourceforge.net/projects/${DEP_PRJNAME}/files/${DEP_PRJNAME}/${DEP_VERSION}/${DEP_ARCHIVE}" > "${DEP_ARCHIVE}" ) || \ ( cd "$DLDIR" && wget -c "https://sourceforge.net/projects/${DEP_PRJNAME}/files/${DEP_PRJNAME}/${DEP_VERSION}/${DEP_ARCHIVE}" -O "${DEP_ARCHIVE}" ) echo "BUILD: '${WSDIR}/${DEP_DIRNAME}'..." >&2 cd "${WSDIR}" || exit rm -rf ${DEP_DIRNAME} || echo "" tar xzf "$DLDIR/${DEP_ARCHIVE}" || exit cd "./${DEP_DIRNAME}" || exit yes "" | ./configure --prefix="${PREFIX}" --with-default-snmp-version=3 \ --disable-agent --disable-daemon --with-sys-contact="" --with-sys-location="" \ --with-logfile=none --with-persistent-directory="${PREFIX}/var/net-snmp" \ --disable-embedded-perl --without-perl-modules --disable-perl-cc-checks \ --enable-shared || { cat config.log ; exit 1; } $MAKE LDFLAGS="-no-undefined -lws2_32 -lregex -Xlinker --ignore-unresolved-symbol=_app_name_long -Xlinker --ignore-unresolved-symbol=app_name_long" || exit # Beside leaving a pre-install location for future runs, # this may build some more artifacts: rm -rf "`pwd`/.inst" || echo "" $MAKE DESTDIR="`pwd`/.inst" install || exit # Summarize what we have got find ./ -type f -name "*.dll" -o -name "*.dll.a"; $SUDO $MAKE install echo "INST: ran 'make install' from '${WSDIR}/${DEP_DIRNAME}'" >&2 ) provide_libmodbus_git() ( # Provide the libmodbus version with RTU USB support PKGCFG_NAME="libmodbus" DEP_PRJNAME="libmodbus-git" DEP_GITREPO="https://github.com/networkupstools/libmodbus" DEP_VERSION="rtu_usb" # Git branch/tag/commit point # Use PR #3 temporarily: #DEP_GITREPO="https://github.com/jimklimov/libmodbus" # TEMP #DEP_VERSION="fix-mingw-build" # TEMP DEP_DIRNAME="${DEP_PRJNAME}-${DEP_VERSION}" FORCE=false if [ x"${1-}" = x"-f" ] ; then FORCE=true ; fi # Make sure we have current repo code checked out cd "${DLDIR}" if [ -d "${DEP_DIRNAME}" ] ; then { # NOTE: Use `git ls-remote {URL|.}` to not modify the local FS if # there's nothing to change (avoid re-packaging of CI artifact cache) cd "${DEP_DIRNAME}" && \ LOCAL_HASH="`git log -1 --format='%H'`" && \ OTHER_HASH="`git ls-remote "${DEP_GITREPO}" | grep -E '(refs/(heads|tags)/'"${DEP_VERSION}"'$|^'"${DEP_VERSION}"')' | awk '{print $1}'`" && \ if [ x"${LOCAL_HASH}" = x"${OTHER_HASH}" ] ; then echo "FETCH: Current git commit in '`pwd`' matches current '${DEP_VERSION}' in '${DEP_GITREPO}'" >&2 else echo "FETCH: Update git workspace in `pwd`..." >&2 git fetch --tags && \ git fetch --all && \ git checkout "${DEP_VERSION}" && \ _GITDIFF="`git diff "origin/${DEP_VERSION}"`" && \ if [ -n "${_GITDIFF}" ] ; then # Ensure rebase etc. or fail git pull && \ ./autogen.sh && \ FORCE=true else echo "Current content in '`pwd`' matches current '${DEP_VERSION}' in '${DEP_GITREPO}'" >&2 fi fi } || { cd "${DLDIR}" ; chmod -R +w "${DEP_DIRNAME}" || echo "" ; rm -rf "${DEP_DIRNAME}" ; } fi cd "${DLDIR}" if [ ! -d "${DEP_DIRNAME}/.git" ] ; then echo "FETCH: Clone git workspace in '${DLDIR}/${DEP_DIRNAME}' from '${DEP_VERSION}' in '${DEP_GITREPO}'..." >&2 FORCE=true chmod -R +w "${DEP_DIRNAME}" || echo "" rm -rf "${DEP_DIRNAME}" git clone "${DEP_GITREPO}" -b "${DEP_VERSION}" "${DEP_DIRNAME}" || exit fi if [ ! -s "${DEP_DIRNAME}/configure" ] || [ x"$FORCE" = x"true" ] ; then echo "FETCH: (Re-)bootstrap git workspace in '${DLDIR}/${DEP_DIRNAME}'..." >&2 (cd "${DEP_DIRNAME}" && ./autogen.sh) || exit FORCE=true fi set +e if [ x"$FORCE" = x"false" ] ; then # TODO: Check version - harder with git rolling, so no-op for now if false && pkg-config --exists "$PKGCFG_NAME" ; then echo "SKIP: pkg-config says '$PKGCFG_NAME' exists" >&2 return 0 fi # Quickly install if prebuilt if [ -d "${WSDIR}/${DEP_DIRNAME}/.inst" ]; then ( cd "${WSDIR}/${DEP_DIRNAME}/.inst" || exit (command -v rsync) && $SUDO rsync -cavPHK ./ / && exit $SUDO cp -pr ./ / && exit exit 1 ) && { echo "INST: (re-)applied '${WSDIR}/${DEP_DIRNAME}/.inst'" >&2 return 0 } fi # no stashed .inst; any Makefile at least? if [ -s "${WSDIR}/${DEP_DIRNAME}/Makefile" ]; then ( cd "${WSDIR}/${DEP_DIRNAME}" && $SUDO $MAKE install ) && { echo "INST: ran 'make install' from '${WSDIR}/${DEP_DIRNAME}'" >&2 return } fi # Not pre-built, fall through fi # (Re-)make and install from scratch set -e echo "BUILD: '${WSDIR}/${DEP_DIRNAME}'..." >&2 cd "${WSDIR}" if [ -e "./${DEP_DIRNAME}" ] ; then # Take care of read-only destdir pieces chmod -R +w "./${DEP_DIRNAME}" || echo "" rm -rf "./${DEP_DIRNAME}" || echo "" fi mkdir -p "./${DEP_DIRNAME}" || exit cd "./${DEP_DIRNAME}" || exit "${DLDIR}/${DEP_DIRNAME}/configure" --prefix="${PREFIX}" --with-libusb --enable-static --disable-shared --enable-Werror \ || { cat config.log ; exit 1 ; } $MAKE || exit $MAKE check || echo "WARNING: make check is flaky or failed outright" >&2 # Beside leaving a pre-install location for future runs, # this may build some more artifacts: rm -rf "`pwd`/.inst" || echo "" $MAKE DESTDIR="`pwd`/.inst" install || exit # Summarize what we have got find ./ -type f -name "*.dll" -o -name "*.a" $SUDO $MAKE install echo "INST: ran 'make install' from '${WSDIR}/${DEP_DIRNAME}'" >&2 ) prepareEnv || exit echo "Prepared environment for $0:" >&2 set | grep -E '^(ARCH|PREFIX|PREFIX_ROOT|PATH|MAKE|MAKEFLAGS|SUDO|DLDIR|WSDIR|CFLAGS|CXXFLAGS|LDFLAGS|PKG_CONFIG_PATH|BUILD_FLAG|HOST_FLAG|MINGW_CHOST|MINGW_PREFIX|MSYS2_PATH)=' >&2 # TODO: Loop, params, help, etc... # For now, let it pass "-f" to the builder provide_netsnmp "$@" ls -la "${PREFIX}/lib/pkgconfig/netsnmp.pc" cat "${PREFIX}/lib/pkgconfig/netsnmp.pc" provide_libmodbus_git "$@" ls -la "${PREFIX}/lib/pkgconfig/libmodbus.pc" cat "${PREFIX}/lib/pkgconfig/libmodbus.pc" nut-2.8.3/scripts/Windows/wininit.c0000644000200500020050000005041614777767434014245 00000000000000/* wininit.c - MS Windows service which replaces the init script (compiled as "nut.exe") Copyright (C) 2010 Frederic Bohe 2021-2024 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef WIN32 #include "config.h" /* should be first */ #include "common.h" #include "winevent.h" #include "wincompat.h" #define NUT_START TRUE #define NUT_STOP FALSE typedef struct conn_s { HANDLE handle; OVERLAPPED overlapped; char buf[LARGEBUF]; struct conn_s *prev; struct conn_s *next; } conn_t; static DWORD upsd_pid = 0; static DWORD upsmon_pid = 0; static BOOL service_flag = TRUE; HANDLE svc_stop = NULL; static SERVICE_STATUS SvcStatus; static SERVICE_STATUS_HANDLE SvcStatusHandle; static void print_event(DWORD priority, const char * fmt, ...) { HANDLE EventSource; va_list ap; CHAR * buf; int ret; buf = xmalloc(LARGEBUF); va_start(ap, fmt); ret = vsnprintf(buf, LARGEBUF, fmt, ap); va_end(ap); if (ret < 0) { return; } if (!service_flag) { upslogx(LOG_ERR, "EventLog : %s\n",buf); } EventSource = RegisterEventSource(NULL, SVCNAME); if (NULL != EventSource) { ReportEvent( EventSource, /* event log handle */ priority, /* event type */ 0, /* event category */ SVC_EVENT, /* event identifier */ NULL, /* no security identifier*/ 1, /* size of string array */ 0, /* no binary data */ (const char **)&buf, /* array of string */ NULL); /* no binary data */ DeregisterEventSource(EventSource); } if (buf) free(buf); } /* returns PID of the newly created process or 0 on failure */ static DWORD create_process(char * command) { STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; BOOL res; DWORD LastError; memset(&StartupInfo, 0, sizeof(STARTUPINFO)); StartupInfo.cb = sizeof(StartupInfo); memset(&ProcessInformation, 0, sizeof(ProcessInformation)); res = CreateProcess( NULL, command, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &StartupInfo, &ProcessInformation ); LastError = GetLastError(); if (res == 0) { print_event(LOG_ERR, "Can't create process %s : %d", command, LastError); return 0; } return ProcessInformation.dwProcessId; } /* Return a statically allocated buffer, no need to free() it */ static const char * makearg_debug(void) { static char buf[SMALLBUF]; char *p = buf; size_t i; if (nut_debug_level < 1) return(""); *p = '-'; p++; for (i = 0; (i < (size_t)nut_debug_level && i < (sizeof(buf) - 2)); i++, p++) { *p = 'D'; } *p = '\0'; return (const char *)buf; } /* return PID of created process or 0 on failure */ static DWORD run_drivers(void) { char command[NUT_PATH_MAX]; char *path; path = getfullpath(PATH_BIN); if (nut_debug_level < 1) { snprintf(command, sizeof(command), "%s\\upsdrvctl.exe start", path); } else { snprintf(command, sizeof(command), "%s\\upsdrvctl.exe -d %s start", path, makearg_debug()); } free(path); return create_process(command); } /* return PID of created process or 0 on failure */ static DWORD stop_drivers(void) { char command[NUT_PATH_MAX]; char *path; path = getfullpath(PATH_BIN); if (nut_debug_level < 1) { snprintf(command, sizeof(command), "%s\\upsdrvctl.exe stop", path); } else { snprintf(command, sizeof(command), "%s\\upsdrvctl.exe %s stop", path, makearg_debug()); } free(path); return create_process(command); } /* return PID of created process or 0 on failure */ static void run_upsd(void) { char command[NUT_PATH_MAX]; char *path; path = getfullpath(PATH_SBIN); snprintf(command, sizeof(command), "%s\\upsd.exe", path); if (nut_debug_level > 0) { snprintfcat(command, sizeof(command), " %s", makearg_debug()); } free(path); upsd_pid = create_process(command); } static void stop_upsd(void) { if (sendsignal(UPSD_PIPE_NAME, COMMAND_STOP, 0)) { print_event(LOG_ERR, "Error stopping upsd (%d)", GetLastError()); } } /* return PID of created process or 0 on failure */ static void run_upsmon(void) { char command[NUT_PATH_MAX]; char *path; path = getfullpath(PATH_SBIN); snprintf(command, sizeof(command), "%s\\upsmon.exe", path); if (nut_debug_level > 0) { snprintfcat(command, sizeof(command), " %s", makearg_debug()); } free(path); upsmon_pid = create_process(command); } static void stop_upsmon(void) { if (sendsignal(UPSMON_PIPE_NAME, COMMAND_STOP, 0)) { print_event(LOG_ERR, "Error stopping upsmon (%d)", GetLastError()); } } /* Return 0 if powerdown flag is set */ static DWORD test_powerdownflag(void) { char command[NUT_PATH_MAX]; char *path; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; BOOL res; DWORD LastError; DWORD status; int i = 10; int timeout = 500; path = getfullpath(PATH_SBIN); snprintf(command, sizeof(command), "%s\\upsmon.exe -K", path); if (nut_debug_level > 0) { snprintfcat(command, sizeof(command), " %s", makearg_debug()); } free(path); memset(&StartupInfo, 0, sizeof(STARTUPINFO)); StartupInfo.cb = sizeof(StartupInfo); memset(&ProcessInformation, 0, sizeof(ProcessInformation)); res = CreateProcess( NULL, command, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &StartupInfo, &ProcessInformation ); LastError = GetLastError(); if (res == 0) { print_event(LOG_ERR, "Can't create process %s : %d", command, LastError); return 1; } while (i > 0) { res = GetExitCodeProcess(ProcessInformation.hProcess, &status); if (res != 0) { if (status != STILL_ACTIVE) { return status; } } Sleep(timeout); i--; } return 1; } static DWORD shutdown_ups(void) { char command[NUT_PATH_MAX]; char *path; path = getfullpath(PATH_BIN); if (nut_debug_level < 1) { snprintf(command, sizeof(command), "%s\\upsdrvctl.exe shutdown", path); } else { snprintf(command, sizeof(command), "%s\\upsdrvctl.exe -d %s shutdown", path, makearg_debug()); } free(path); return create_process(command); } /* return 0 on failure */ static int parse_nutconf(BOOL start_flag) { char fn[NUT_PATH_MAX]; FILE *nutf; char buf[SMALLBUF]; char fullname[NUT_PATH_MAX]; snprintf(fn, sizeof(fn), "%s/nut.conf", confpath()); nutf = fopen(fn, "r"); if (nutf == NULL) { snprintf(buf, sizeof(buf), "Error opening %s", fn); print_event(LOG_ERR, buf); return 0; } while (fgets(buf, sizeof(buf), nutf) != NULL) { if (buf[0] != '#') { if (strstr(buf, "standalone") != NULL || strstr(buf, "netserver") != NULL ) { if (start_flag == NUT_START) { print_event(LOG_INFO, "Starting drivers"); run_drivers(); print_event(LOG_INFO, "Starting upsd"); run_upsd(); /* Wait a moment for the drivers to start */ Sleep(5000); print_event(LOG_INFO, "Starting upsmon"); run_upsmon(); return 1; } else { print_event(LOG_INFO, "Stopping upsd"); stop_upsd(); print_event(LOG_INFO, "Stopping drivers"); stop_drivers(); print_event(LOG_INFO, "Stopping upsmon"); stop_upsmon(); /* Give upsmon a chance to write the POWERDOWNFLAG file */ Sleep(1000); if (test_powerdownflag() == 0) { print_event(LOG_INFO, "Shutting down the UPS"); shutdown_ups(); } print_event(LOG_INFO, "End of NUT stop"); return 1; } } if (strstr(buf, "netclient") != NULL) { if (start_flag == NUT_START) { print_event(LOG_INFO, "Starting upsmon (client only)"); run_upsmon(); return 1; } else { print_event(LOG_INFO, "Stopping upsmon (client only)"); stop_upsmon(); return 1; } } } } GetFullPathName(fn, sizeof(fullname), fullname, NULL); snprintf(buf, sizeof(buf), "NUT disabled, please adjust the configuration to your needs. " "Then set MODE to a suitable value in %s to enable it.", fullname); print_event(LOG_ERR, buf); return 0; } static int SvcInstall(const char * SvcName, const char * args) { SC_HANDLE SCManager; SC_HANDLE Service; TCHAR Path[NUT_PATH_MAX]; if (!GetModuleFileName(NULL, Path, NUT_PATH_MAX)) { printf("Cannot install service (%d)\n", (int)GetLastError()); return EXIT_FAILURE; } if (args != NULL) { snprintfcat(Path, sizeof(Path), " %s", args); } SCManager = OpenSCManager( NULL, /* local computer */ NULL, /* ServiceActive database */ SC_MANAGER_ALL_ACCESS); /* full access rights */ if (NULL == SCManager) { upslogx(LOG_ERR, "OpenSCManager failed (%d)\n", (int)GetLastError()); return EXIT_FAILURE; } Service = CreateService( SCManager, /* SCM database */ SvcName, /* name of service */ SvcName, /* service name to display */ SERVICE_ALL_ACCESS, /* desired access */ SERVICE_WIN32_OWN_PROCESS, /* service type */ SERVICE_AUTO_START, /* start type */ SERVICE_ERROR_NORMAL, /* error control type */ Path, /* path to service binary */ NULL, /* no load ordering group */ NULL, /* no tag identifier */ NULL, /* no dependencies */ NULL, /* LocalSystem account */ NULL); /* no password */ if (Service == NULL) { upslogx(LOG_ERR, "CreateService failed (%d)\n", (int)GetLastError()); CloseServiceHandle(SCManager); return EXIT_FAILURE; } else { upslogx(LOG_INFO, "Service installed successfully\n"); } CloseServiceHandle(Service); CloseServiceHandle(SCManager); return EXIT_SUCCESS; } /* Returns a positive value if the service name exists * -2 if we can not open the service manager * -1 if we can not open the service itself * +1 SvcName exists */ static int SvcExists(const char * SvcName) { SC_HANDLE SCManager; SC_HANDLE Service; SCManager = OpenSCManager( NULL, /* local computer */ NULL, /* ServicesActive database */ SC_MANAGER_ALL_ACCESS); /* full access rights */ if (NULL == SCManager) { upsdebugx(1, "OpenSCManager failed (%d)\n", (int)GetLastError()); return -2; } Service = OpenService( SCManager, /* SCM database */ SvcName, /* name of service */ DELETE); /* need delete access */ if (Service == NULL) { upsdebugx(1, "OpenService failed (%d) for \"%s\"\n", (int)GetLastError(), SvcName); CloseServiceHandle(SCManager); return -1; } CloseServiceHandle(Service); CloseServiceHandle(SCManager); upsdebugx(1, "Service \"%s\" seems to exist", SvcName); return 1; } static int SvcUninstall(const char * SvcName) { SC_HANDLE SCManager; SC_HANDLE Service; SCManager = OpenSCManager( NULL, /* local computer */ NULL, /* ServicesActive database */ SC_MANAGER_ALL_ACCESS); /* full access rights */ if (NULL == SCManager) { upslogx(LOG_ERR, "OpenSCManager failed (%d)\n", (int)GetLastError()); return EXIT_FAILURE; } Service = OpenService( SCManager, /* SCM database */ SvcName, /* name of service */ DELETE); /* need delete access */ if (Service == NULL) { upslogx(LOG_ERR, "OpenService failed (%d)\n", (int)GetLastError()); CloseServiceHandle(SCManager); return EXIT_FAILURE; } if (!DeleteService(Service)) { upslogx(LOG_ERR, "DeleteService failed (%d)\n", (int)GetLastError()); } else { upslogx(LOG_ERR, "Service deleted successfully\n"); } CloseServiceHandle(Service); CloseServiceHandle(SCManager); return EXIT_SUCCESS; } static void ReportSvcStatus( DWORD CurrentState, DWORD Win32ExitCode, DWORD WaitHint) { static DWORD CheckPoint = 1; SvcStatus.dwCurrentState = CurrentState; SvcStatus.dwWin32ExitCode = Win32ExitCode; SvcStatus.dwWaitHint = WaitHint; if (CurrentState == SERVICE_START_PENDING) SvcStatus.dwControlsAccepted = 0; else SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; if ( (CurrentState == SERVICE_RUNNING) || (CurrentState == SERVICE_STOPPED) ) { SvcStatus.dwCheckPoint = 0; } else { SvcStatus.dwCheckPoint = CheckPoint++; } /* report the status of the service to the SCM */ SetServiceStatus(SvcStatusHandle, &SvcStatus); } static void WINAPI SvcCtrlHandler(DWORD Ctrl) { switch(Ctrl) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); /* Signal the service to stop */ SetEvent(svc_stop); ReportSvcStatus(SvcStatus.dwCurrentState, NO_ERROR, 0); return; case SERVICE_CONTROL_INTERROGATE: break; default: break; } } static void SvcStart(char * SvcName) { /* Register the handler function for the service */ SvcStatusHandle = RegisterServiceCtrlHandler( SvcName, SvcCtrlHandler); if (!SvcStatusHandle) { upslogx(LOG_ERR, "RegisterServiceCtrlHandler\n"); return; } SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; SvcStatus.dwServiceSpecificExitCode = 0; /* Report initial status to the SCM */ ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000); } static void SvcReady(void) { svc_stop = CreateEvent( NULL, /* default security attributes */ TRUE, /* manual reset event */ FALSE, /* not signaled */ NULL); /* no name */ if (svc_stop == NULL) { ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0); return; } ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); } static void close_all(void) { pipe_conn_t *conn; for (conn = pipe_connhead; conn; conn = conn->next) { pipe_disconnect(conn); } } static void WINAPI SvcMain(DWORD argc, LPTSTR *argv) { DWORD ret; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; int maxhandle = 0; pipe_conn_t *conn; DWORD priority; char *buf; NUT_UNUSED_VARIABLE(argc); NUT_UNUSED_VARIABLE(argv); if (service_flag) { SvcStart(SVCNAME); } /* A service has no console, so do has its children. */ /* So if we want to be able to send CTRL+BREAK signal we must */ /* create a console which will be inherited by children */ AllocConsole(); print_event(LOG_INFO, "Starting"); /* pipe for event log proxy */ pipe_create(EVENTLOG_PIPE_NAME); /* parse nut.conf and start relevant processes */ if (parse_nutconf(NUT_START) == 0) { print_event(LOG_INFO, "exiting"); if (service_flag) { ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0); } return; } if (service_flag) { SvcReady(); } while (1) { maxhandle = 0; memset(&handles, 0, sizeof(handles)); /* Wait on the read IO of each connections */ for (conn = pipe_connhead; conn; conn = conn->next) { handles[maxhandle] = conn->overlapped.hEvent; maxhandle++; } /* Add the new pipe connected event */ handles[maxhandle] = pipe_connection_overlapped.hEvent; maxhandle++; /* Add SCM event handler in service mode*/ if (service_flag) { handles[maxhandle] = svc_stop; maxhandle++; } ret = WaitForMultipleObjects(maxhandle, handles, FALSE, INFINITE); if (ret == WAIT_FAILED) { print_event(LOG_ERR, "Wait failed"); return; } if (handles[ret] == svc_stop && service_flag) { parse_nutconf(NUT_STOP); if (service_flag) { print_event(LOG_INFO, "Exiting"); close_all(); ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0); } return; } /* Retrieve the signaled connection */ for (conn = pipe_connhead; conn != NULL; conn = conn->next) { if (conn->overlapped.hEvent == handles[ret - WAIT_OBJECT_0]) { break; } } if (handles[ret] == pipe_connection_overlapped.hEvent) { /* a new pipe connection has been signaled */ pipe_connect(); } else { /* one of the read event handles has been signaled */ if (conn != NULL) { if (pipe_ready(conn)) { buf = conn->buf; /* a frame is a DWORD indicating priority followed by an array of char (not necessarily followed by a terminal 0) */ priority = *((DWORD *)buf); buf = buf + sizeof(DWORD); print_event(priority, buf); pipe_disconnect(conn); } } } } } static void help(const char *arg_progname) { print_banner_once(arg_progname, 2); printf("NUT for Windows all-in-one wrapper for driver(s), data server and monitoring client\n"); printf("including shutdown and power-off handling (where supported). All together they rely\n"); printf("on nut.conf and other files in %s\n", confpath()); printf("\nUsage: %s {start | stop}\n\n", arg_progname); printf(" start Install as a service (%s) if not yet done, then `net start` it\n", SVCNAME); printf(" stop If the service (%s) is installed, command it to `net stop`\n", SVCNAME); printf("Note you may have to run this in an elevated privilege command shell, or use `runas`\n"); printf("\nUsage: %s [OPTION]\n\n", arg_progname); printf("Options (note minus not slash as the control character), one of:\n"); printf(" -I Install as a service (%s)\n", SVCNAME); printf(" -U Uninstall the service\n"); printf(" -N Run once in non-service mode\n"); printf(" -D Raise debug verbosity (passed to launched NUT programs)\n"); printf(" -V Display NUT version and exit\n"); printf(" -h Display this help and exit\n"); /* also /? but be hush about the one slash */ printf("\n%s", suggest_doc_links( "nut.exe" /*arg_progname*/, "nut.conf, ups.conf, upsmon.conf, upsd.conf and upsd.users" )); } int main(int argc, char **argv) { int i, default_opterr = opterr; const char *progname = xbasename(argc > 0 ? argv[0] : "nut.exe"); if (argc > 1) { if (!strcmp(argv[1], "/?")) { help(progname); return EXIT_SUCCESS; } if (!strcmp(argv[1], "stop")) { int ret; if (SvcExists(SVCNAME) < 0) fprintf(stderr, "WARNING: Can not access service \"%s\"", SVCNAME); ret = system("net stop \"" SVCNAME "\""); if (ret == 0) return EXIT_SUCCESS; fatalx(EXIT_FAILURE, "FAILED stopping %s: %i", SVCNAME, ret); } if (!strcmp(argv[1], "start")) { int ret; if (SvcExists(SVCNAME) < 0) { fprintf(stderr, "WARNING: Can not access service \"%s\", registering first", SVCNAME); SvcInstall(SVCNAME, NULL); } ret = system("net start \"" SVCNAME "\""); if (ret == 0) return EXIT_SUCCESS; fatalx(EXIT_FAILURE, "FAILED starting %s: %i", SVCNAME, ret); } } /* TODO: Do not warn about unknown args - pass them to SvcMain() * Currently neutered because that method ignores argc/argv de-facto. * opterr = 0; */ while ((i = getopt(argc, argv, "+IUNDVh")) != -1) { switch (i) { case 'I': return SvcInstall(SVCNAME, NULL); case 'U': return SvcUninstall(SVCNAME); case 'N': service_flag = FALSE; upslogx(LOG_ERR, "Running in non-service mode\n"); break; case 'D': nut_debug_level++; break; case 'V': /* just show the version and optional * CONFIG_FLAGS banner if available */ print_banner_once(progname, 1); nut_report_config_flags(); return EXIT_SUCCESS; case 'h': help(progname); return EXIT_SUCCESS; default: /* Assume console-app start would come up - and pass args * there, quietly; note that getopt() converts unknown * chars to '?' so we can not log what exactly was wrong. */ upsdebugx(1, "%s: unknown option ignored " "(maybe SvcMain would use it later)", progname); break; } } optind = 0; opterr = default_opterr; SERVICE_TABLE_ENTRY DispatchTable[] = { { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain }, { NULL, NULL } }; /* This call returns when the service has stopped */ if (service_flag) { if (!StartServiceCtrlDispatcher(DispatchTable)) { DWORD LastError = GetLastError(); if (LastError == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { const char *msg = "StartServiceCtrlDispatcher failed: " "exiting. This is a Windows service which can't " "be run as a regular application by default. " "Try -N to start it as a regular application."; print_event(LOG_ERR, "%s", msg); fprintf(stderr, "ERROR: %s\n\n", msg); if (argc < 2) { help(progname); } } else { print_event(LOG_ERR, "StartServiceCtrlDispatcher failed (%ld): " "exiting", LastError); } return EXIT_FAILURE; } } else { SvcMain(argc, argv); } return EXIT_SUCCESS; } #else /* !WIN32 */ /* Just avoid: ISO C forbids an empty translation unit [-Werror=pedantic] */ int main (int argc, char ** argv); #endif /* !WIN32 */ nut-2.8.3/scripts/Windows/Makefile.am0000644000200500020050000001011514777767434014444 00000000000000# Network UPS Tools: scripts/Windows AM_CFLAGS = -I$(top_srcdir)/include $(top_builddir)/common/libcommon.la: FORCE +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) EXTRA_DIST = \ winevent.mc \ build-mingw-nut.sh \ build-mingw-prereqs.sh \ dllldd.sh \ README.adoc \ DriverInstaller/wdi-simple.c \ DriverInstaller/README.adoc \ Installer/README.adoc \ Installer/BuildInstaller.bat \ Installer/NUT-Installer.xml.in \ Installer/ImageFiles/icons/completi.ico \ Installer/ImageFiles/icons/info.ico \ Installer/ImageFiles/icons/custicon.ico \ Installer/ImageFiles/icons/Up.ico \ Installer/ImageFiles/icons/exclamic.ico \ Installer/ImageFiles/icons/powernut_Stop.ico \ Installer/ImageFiles/icons/repairic.ico \ Installer/ImageFiles/icons/New.ico \ Installer/ImageFiles/icons/removico.ico \ Installer/ImageFiles/icons/powernut_logo.ico \ Installer/ImageFiles/icons/insticon.ico \ Installer/ImageFiles/Images/NUT_wix_vertical.bmp \ Installer/ImageFiles/Images/NUT_wix_horizontal.bmp \ Installer/ImageFiles/Others/StopService.bat \ Installer/ImageFiles/Others/StartService.bat \ Installer/ImageFiles/emptyDir/man1/temp.txt \ Installer/ImageFiles/emptyDir/cgi-bin/temp.txt \ Installer/ImageFiles/emptyDir/pkgconfig/temp.txt \ Installer/ImageFiles/emptyDir/include/temp.txt \ Installer/ImageFiles/emptyDir/html/temp.txt \ Installer/ImageFiles/emptyDir/man3/temp.txt \ Installer/ImageFiles/emptyDir/run/temp.txt CLEANFILES = *-spellchecked */*-spellchecked bin_PROGRAMS = FORCE: if HAVE_MINGW_RESGEN # Avoid "Using $< in a non-suffix rule context is a GNUmake idiom" by $? winevent.rc winevent.h: winevent.mc $(WINDMC) $? winevent.o: winevent.rc winevent.h $(WINDRES) winevent.rc winevent.o wininit.$(OBJEXT): winevent.h # Some binutils packages (e.g. on Slackware 15) include windres and windmc # tools, even though they do not deliver the rest of files such as windows.h # that would be needed for actual builds targeting Windows. if HAVE_WINDOWS bin_PROGRAMS += nut halt nut_SOURCES = wininit.c nut_LDADD = $(top_builddir)/common/libcommon.la winevent.o halt_SOURCES = halt.c endif HAVE_WINDOWS CLEANFILES += winevent.rc winevent.o winevent.h endif HAVE_MINGW_RESGEN SPELLCHECK_SRC = README.adoc DriverInstaller/README.adoc Installer/README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.3/scripts/Windows/DriverInstaller/0000755000200500020050000000000015001555412015547 500000000000000nut-2.8.3/scripts/Windows/DriverInstaller/README.adoc0000644000200500020050000000065614777534446017312 00000000000000To easily compile `wdi-simple.exe`, unzip a copy of `libwdi` on your disk. Then set it up to be able to build following http://sourceforge.net/apps/mediawiki/libwdi/index.php?title=Install NOTE: Modern development may be at https://github.com/pbatard/libwdi Then copy `wdi-simple.c` and `nutscan-usb.h` into the "examples" subdirectory of libwdi directory. Finally run `ddk_build.cmd` from the root of the `libwdi` directory. nut-2.8.3/scripts/Windows/DriverInstaller/wdi-simple.c0000644000200500020050000001006314777534446017734 00000000000000/* wdi-simple.c: Console Driver Installer for NUT USB devices Copyright (c) 2010 Pete Batard Copyright (c) 2011 Frederic Bohe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #ifdef _MSC_VER #include "getopt/getopt.h" #else #include #endif #include "libwdi.h" #include "nutscan-usb.h" #define oprintf(...) do {if (!opt_silent) printf(__VA_ARGS__);} while(0) #define DESC "NUT USB driver" #define INF_NAME "usb_device.inf" #define DEFAULT_DIR "usb_driver" int __cdecl main(int argc, char** argv) { char desc[128] = DESC; struct wdi_device_info *ldev, *ldev_start, dev = {NULL, 0, 0, false, 0, DESC, NULL, NULL, NULL}; struct wdi_options_create_list ocl = { 0 }; struct wdi_options_prepare_driver opd = { 0 }; struct wdi_options_install_driver oid = { 0 }; int c, r; int opt_silent = 0, opt_extract = 0, log_level = WDI_LOG_LEVEL_WARNING; /* int opt_silent = 0, opt_extract = 0, log_level = WDI_LOG_LEVEL_DEBUG; */ char *inf_name = INF_NAME; char *ext_dir = DEFAULT_DIR; bool matching_device_found; int index = 0; ocl.list_all = true; ocl.list_hubs = true; ocl.trim_whitespaces = true; opd.driver_type = WDI_LIBUSB0; /* opd.driver_type = WDI_WINUSB; */ wdi_set_log_level(log_level); oprintf("NUT UPS driver installer.\n"); oprintf("-------------------------\n\n"); oprintf("Searching for known UPS...\n"); /* Try to match against a plugged device */ matching_device_found = false; if (wdi_create_list(&ldev, &ocl) == WDI_SUCCESS) { r = WDI_SUCCESS; ldev_start = ldev; while( usb_device_table[index].vendorID != 0xFFFF || usb_device_table[index].productID != 0xFFFF) { dev.next = NULL; dev.vid = usb_device_table[index].vendorID; dev.pid = usb_device_table[index].productID; dev.is_composite = false; dev.mi = 0; dev.desc = desc; dev.driver = NULL; dev.device_id = NULL; dev.hardware_id = NULL; /* oprintf("NUT device : vid : %0X - pid : %0X\n",dev.vid, dev.pid); */ for (ldev = ldev_start; (ldev != NULL) && (r == WDI_SUCCESS); ldev = ldev->next) { /* oprintf("trying vid : %0X - pid : %0X\n",ldev->vid, ldev->pid); */ if ( (ldev->vid == dev.vid) && (ldev->pid == dev.pid) && (ldev->mi == dev.mi) ) { oprintf("Found UPS : vendor ID = %0X - Product ID = %0X\n",ldev->vid, ldev->pid, ldev->mi); dev.hardware_id = ldev->hardware_id; dev.device_id = ldev->device_id; matching_device_found = true; oprintf("Extracting driver files...\n"); r = wdi_prepare_driver(&dev, ext_dir, inf_name, &opd); oprintf(" %s\n", wdi_strerror(r)); if ((r != WDI_SUCCESS) || (opt_extract)) return r; oprintf(" %s: ", dev.hardware_id); fflush(stdout); oprintf("Installing driver\n"); r = wdi_install_driver(&dev, ext_dir, inf_name, &oid); oprintf("%s\n", wdi_strerror(r)); if( r == WDI_SUCCESS ) { oprintf("You should now unplug and re-plug your device to finish driver's installation.\nHit enter when it's done.\n"); } else { oprintf("An error occured while installing driver.\nTry installing libUSB manually.\nHit enter to continue\n"); } getc(stdin); } } index++; } } /* No plugged USB device matches */ if (!matching_device_found) { oprintf("No known UPS device found.\nTry installing libUSB manually.\nHit enter to continue\n"); getc(stdin); } return r; } nut-2.8.3/scripts/Windows/README.adoc0000644000200500020050000006766614777767434014224 00000000000000NUT and MS Windows ================== Introduction ------------ NUT is now also available for the Microsoft Windows platform. This methodology (and Windows support in general) are currently experimental, so pull requests are welcome to tie up some loose ends (add more prerequisites, test and fix programs, re-enable some code just commented away by `ifdef`'s...) [NOTE] ====== It is possible to prepare a Windows machine with tools and prerequisites for building NUT natively, using the MSYS2 environment, as detailed in linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt], and easily handled by NUT common `ci_build.sh` script with default parameters. Most prerequisites are already packaged in that environment, but notably `net-snmp` is missing -- however it can be built from source following this document. Possibly, the instructions below would converge in that document over time to keep it simple. ====== For additional reference about prerequisite preparation and further ideas for the NUT for Windows effort, please see detailed report in the mailing list: * https://alioth-lists.debian.net/pipermail/nut-upsdev/2016-April/007171.html - [Nut-upsdev] How to build NUT Windows Port * https://alioth-lists.debian.net/pipermail/nut-upsdev/2016-April/007172.html - [Nut-upsdev] NUT Windows port sources review Cross compiling from Linux -------------------------- Fortunately, you are not forced to have a real Windows system to compile NUT. The following chapters will guide you through setting up up a link:http://mingw-w64.sourceforge.net[MinGW-w64] build environment and compiling NUT. NOTE: These instructions were re-verified (and codebase slightly amended) with an Ubuntu 21.10 container as the dedicated build environment. Support was added to NUT common `ci_build.sh` script to call the helper `build-mingw-nut.sh` from this directory when cross-building on Linux for Windows in the specially crafted sandbox (conformance is assumed), if you use one of `BUILD_TYPE=cross-windows-mingw(-64|-32|)` as this made NUT CI farm integration easier. NOTE: The Ubuntu (20.04 or newer) environment provided by WSL2 also seems suitable for semi-native builds on a Windows system, following the same instructions. However, note that some builds may be broken or complicated by antivirus software (it really dislikes someone writing into EXE files). Beside MinGW detailed below, you would need the usual dependencies to configure and build NUT (if you would bootstrap it from github sources rather than a tarball -- without a pre-generated `configure` script). Notably, `asciidoc` with its many dependencies may be required for generation of man pages into the intermediate tarball used by script referenced below. MinGW-w64 build environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~ You will first need to setup a MinGW-w64 build environment. NOTE: While adding `ccache` is optional, it is quite recommended especially if you plan to iterate many builds (whether of NUT or the dependencies). At least for Ubuntu 21.10 packaging, it is integrated with `mingw-w64` tool naming out of the box. On Debian/Ubuntu and similar systems, use: # apt-get update # apt-get install mingw-w64 On Redhat and similar systems, use: # ??? You will also need pthread and mingw regex libraries, and other recommended dependencies as detailed below. [NOTE] ====== Be sure to install NUT build prerequisites and toolkits, as detailed in linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt]. If builds complain similarly to ---- syntax error near unexpected token 'LIBUSB_1_0,' 'PKG_CHECK_MODULES(LIBUSB_1_0, libusb-1.0 >= 0.9.1)' ---- make sure you have installed `pkgconf`, e.g.: # apt-get install pkgconf ====== [NOTE] ================================================================================ If you use script `./build-mingw-nut.sh` mentioned below, you may skip setting these environment variables when building NUT itself. You would however need to use them once (per `ARCH`) to provide the prerequisites below if they are built from source. The build routines detailed below expect to be run in a terminal (shell per `ARCH`) with all these environment variables set once and inherited from one component build to another. Should you need to rebuild something, you would have to set these variables again in that session. When using the compilation approach, you would typically use the following `ARCH`, `HOST_FLAG` and `BUILD_FLAG`, as well as `CC`, `CFLAGS`, `LDFLAGS` and `PREFIX` values: - prefer either to + ------ :; export ARCH="x86_64-w64-mingw32" ------ + or + ------ :; export ARCH="i686-w64-mingw32" ------ + (it can help to open two terminals and copy one `ARCH` into each and then the other lines below into both of them; be sure to use separate directory trees for the unpacked build workspaces, while you can use the same source tarball download directory for both -- just do not paste the commands simultaneously to avoid downloading in parallel; the `wget -c` used below would skip downloads that are already completed) - for either-`ARCH` build environment further set: + ------ :; export HOST_FLAG="--host=$ARCH" :; PREFIX="/usr/$ARCH" ------ - NOTE: Technically, these instructions may apply to builds with MinGW on Windows semi-natively (e.g. to add the net-snmp libraries which are not packaged for MSYS2 MinGW currently). Generally you can use environment variables set by different launchers of MinGW terminal sessions depending on the target profile (32/64 bit, gcc/clang, libc implementation...) ** For `sudo make install` in instructions below, you may have to omit the `sudo` part if missing in your MSYS2 MinGW environment; ** For a "native build" directly for consumption in the currently configured environment, you would not use cross-build path in `PREFIX` and not set the `HOST_FLAG` value: + ------ :; export ARCH="$MINGW_CHOST" :; PREFIX="$MINGW_PREFIX" :; export HOST_FLAG="" ------ ** If you wanted a "real cross-build" for a different MinGW environment, you might want to set those (but the NUT build would then need to be told to search for headers, libraries and pkg-config data in extra locations): + ------ :; export ARCH="$MINGW_CHOST" :; PREFIX="$MINGW_PREFIX/$ARCH" :; export HOST_FLAG="--host=$ARCH" ------ ** You might want then to verify that it sets values you expect with a command like this: + ------ :; set | grep -E '^(ARCH|PREFIX|HOST_FLAG)=' #export ARCH="x86_64-w64-mingw32" #PREFIX="/mingw64/x86_64-w64-mingw32" ------ - on Debian/Ubuntu style systems also: + ------ :; BUILD_FLAG="--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE`" ------ * Note that this bit is very Debian specific! Hints for Redhat-style systems are wanted. - also export the following compilation flags: + ------ :; export CFLAGS="$CFLAGS -D_POSIX=1 -I${PREFIX}/include/" :; export CXXFLAGS="$CXXFLAGS -D_POSIX=1 -I${PREFIX}/include/" :; export LDFLAGS="$LDFLAGS -L${PREFIX}/lib/" :; export PKG_CONFIG_PATH="${PREFIX}"/lib/pkgconfig ------ - prepare the download and build area, e.g. to match copy-paste instructions below, it would be like: + ------ :; DLDIR=~/nut-win-deps :; WSDIR="$DLDIR"/"$ARCH" :; mkdir -p "$WSDIR" "$DLDIR" ------ ================================================================================ NOTE: Instructions below use `sudo` to specify operations you may need to run with privilege elevation (assuming installation into a `PREFIX=/usr/$ARCH`); the majority of operations can be done (recommended) as an unprivileged user. pthread library ^^^^^^^^^^^^^^^ NOTE: The MinGW distribution in Ubuntu 21.10 already includes pthread files, so the build instructions below were not relevant for this component. On older Debian systems, you can use the following packages repository: link:https://launchpad.net/~mingw-packages/+archive/ppa[MinGW PPA] However at the moment this PPA seems to be stale and serve very old packages, so it could be better to roll your own as detailed below. On Redhat: FIXME //////////////////////////////////////////////////////////////////////////////// http://fedoraproject.org/wiki/MinGW/CrossCompilerFramework https://fedoraproject.org/wiki/Packaging:MinGW?rd=Packaging:MinGW_Future https://fedoraproject.org/wiki/Packaging:MinGW_Old //////////////////////////////////////////////////////////////////////////////// You can also compile it (where that is still needed) using: :; ( cd "$DLDIR" && wget -c http://mirrors.kernel.org/sources.redhat.com/pthreads-win32/pthreads-w32-2-8-0-release.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/pthreads-w32-2-8-0-release.tar.gz :; cd pthreads-w32-2-8-0-release/ :; make -f GNUmakefile "CROSS=$ARCH-" GC-inlined [NOTE] ====== If it complains about `pthread.h:307:8: error: redefinition of 'struct timespec'` please edit `config.h` to add a `HAVE_STRUCT_TIMESPEC` definition and re-run `make`, e.g.: :; echo '#define HAVE_STRUCT_TIMESPEC 1' >> config.h :; make -f GNUmakefile "CROSS=$ARCH-" GC-inlined There may also be some warnings from newer compilers about `cast to pointer from integer of different size` -- these are presumed inconsequential. You can try a not-"inlined" build instead. ====== Finally, install the resulting files into locations under `PREFIX`: :; sudo mkdir -p "${PREFIX}/pthreads/lib/" :; sudo cp *.dll "${PREFIX}/pthreads/lib/" :; sudo mkdir -p "${PREFIX}/lib/" :; sudo cp *.a "${PREFIX}/lib/" :; sudo mkdir -p "${PREFIX}/pthreads/include/" :; sudo cp pthread.h sched.h semaphore.h "${PREFIX}/pthreads/include/" MinGW regex library ^^^^^^^^^^^^^^^^^^^ You can compile it using: :; ( cd "$DLDIR" && wget -c http://netcologne.dl.sourceforge.net/project/mingw/Other/UserContributed/regex/mingw-regex-2.5.1/mingw-libgnurx-2.5.1-src.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/mingw-libgnurx-2.5.1-src.tar.gz :; cd mingw-libgnurx-2.5.1 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install libtool (libltdl) ^^^^^^^^^^^^^^^^^ :; ( cd "$DLDIR" && wget -c https://ftpmirror.gnu.org/libtool/libtool-2.4.6.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libtool-2.4.6.tar.gz :; cd libtool-2.4.6 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install libusb ^^^^^^ * libusb-1.0 :; ( cd "$DLDIR" && wget -c https://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-1.0.26/libusb-1.0.26.tar.bz2 ) :; cd "$WSDIR" :; tar xjf "$DLDIR"/libusb-1.0.26.tar.bz2 :; cd libusb-1.0.26 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install * libusb-compat-0.1 (API translation layer for older codebase, uses libusb-1.0) :; ( cd "$DLDIR" && wget -c https://github.com/libusb/libusb-compat-0.1/archive/refs/heads/master.zip -O libusb-compat-0.1-master.zip ) :; cd "$WSDIR" :; unzip "$DLDIR"/libusb-compat-0.1-master.zip :; cd libusb-compat-0.1-master :; ./bootstrap.sh :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install zlib ^^^^ Needed for libpng at least, but likely many others too. [NOTE] ====== On recent Debian/Ubuntu systems, you might have luck with: ------ :; sudo apt-get install libz-mingw-w64-dev ------ ====== On any system, you can build from source; however the current version has a nuance to address for mingw builds: :; ( cd "$DLDIR" && wget -c -O zlib-1.2.12.tar.gz https://github.com/madler/zlib/archive/refs/tags/v1.2.12.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/zlib-1.2.12.tar.gz :; cd zlib-1.2.12 # Edit the `configure` script (not autotools generated) to # neuter the MINGW `leave 1` line: MINGW* | mingw*) # temporary bypass rm -f $test.[co] $test $test$shared_ext echo "Please use win32/Makefile.gcc instead." | tee -a configure.log - leave 1 + ###leave 1 LDSHARED=${LDSHARED-"$cc -shared"} LDSHAREDLIBC="" EXE='.exe' ;; :; CHOST="$ARCH" ./configure --prefix="$PREFIX" :; make :; sudo make install openssl ^^^^^^^ OpenSSL is an optional dependency for NUT itself (it or Mozilla NSS can be used to protect the networking communications), and for libneon below (OpenSSL or GnuTLS). Note the non-standard `config` script bundled along, and hoops to jump through... :; ( cd "$DLDIR" && wget -c https://www.openssl.org/source/openssl-1.1.1q.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/openssl-1.1.1q.tar.gz :; cd openssl-1.1.1q # Build options partially lifted from OBS packaging, see: # https://build.opensuse.org/package/view_file/windows:mingw:win32/mingw32-openssl-1_1/mingw32-openssl-1_1.spec?expand=1 :; ( case "$ARCH" in *x86_64*) SYSTEM=MINGW64 ;; *i?86*) SYSTEM=MINGW32 ;; *) SYSTEM=MINGW ;; esac export SYSTEM ./config \ no-idea enable-rfc3779 zlib shared \ -fno-common \ --prefix="$PREFIX" --cross-compile-prefix="/usr/bin/$ARCH-" \ -DPURIFY -D__USE_GNU ) :; make :; sudo make install xz (liblzma) ^^^^^^^^^^^^ Needed for libxml2. :; ( cd "$DLDIR" && wget -c https://tukaani.org/xz/xz-5.2.5.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/xz-5.2.5.tar.gz :; cd xz-5.2.5 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install libxml2 ^^^^^^^ Needed for libneon. ///////////////////////////////////////////////////////////////////////////// // ...and for fontconfig ///////////////////////////////////////////////////////////////////////////// :; ( cd "$DLDIR" && wget -c https://gitlab.gnome.org/GNOME/libxml2/-/archive/v2.9.14/libxml2-v2.9.14.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libxml2-v2.9.14.tar.gz :; cd libxml2-v2.9.14 :; ./autogen.sh --prefix="$PREFIX" $HOST_FLAG --without-python :; make :; sudo make install gd (cgi) ^^^^^^^^ Note that for the general-case build libgd supports a huge dependency tree, so for the NUT purposes we are going for as little as possible. Initially the purpose was to have libgd installed to build/link against for the Windows target. Subsequently more dependencies were documented, but still further refinement may be needed to have it actually usable for CGI web pages rendering. Finally note that end-users would have to install a CGI-capable web server to use this feature in practice. * zlib: see above * iconv: + Seems to be directly used by `libgd` (at least queried in its `configure` script): :; ( cd "$DLDIR" && wget -c https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.17.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libiconv-1.17.tar.gz :; cd libiconv-1.17 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install * freetype: + NOTE: For some reason it won't build in an Ubuntu 20.04 running under WSL2 -- blocks running an `apinames.exe` program that it has just built. May be a problem of the emulation layer (as it calls the EXE via `/tools/init`), and/or of the system antivirus interaction?.. :; ( cd "$DLDIR" && wget -c https://download.savannah.gnu.org/releases/freetype/freetype-2.12.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/freetype-2.12.1.tar.gz :; cd freetype-2.12.1 :; ./configure --prefix="$PREFIX" $HOST_FLAG --without-brotli :; make :; sudo make install ///////////////////////////////////////////////////////////////////////////// WIP - fontconfig not usable yet due to ICU failing to cross-build Maybe an older version of either would fare better?.. * gperf is needed by fontconfig build routine as a tool usable on the build system, so a packaged install should suffice, e.g. `apt-get install gperf`. Otherwise, build one from source (and note that this may be needed e.g. for native builds on Windows, but not "just" for using a cross-binary that the build host can generate but not run natively). :; ( cd "$DLDIR" && wget -c http://ftp.gnu.org/pub/gnu/gperf/gperf-3.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/gperf-3.1.tar.gz :; cd gperf-3.1 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install * ICU: For a cross-build of ICU, you should first build and install a copy for the host system, then use it as a resource for the final build. Set aside a good part of an hour to get this built: :; ( cd "$DLDIR" && wget -c https://github.com/unicode-org/icu/releases/download/release-71-1/icu4c-71_1-src.tgz ) # This one is built for native host architecture and provides # some resources to ARCH builds later on: :; cd "$DLDIR" :; tar xzf icu4c-71_1-src.tgz :; rm -rf icu-native || true :; mv icu icu-native # note, no version in the pathname :; cd icu-native/source :; ./configure CFLAGS= CXXFLAGS= LDFLAGS= ARCH= :; make :; cd "$WSDIR" :; tar xzf "$DLDIR"/icu4c-71_1-src.tgz :; cd icu/source :; ./configure --prefix="$PREFIX" $HOST_FLAG --with-cross-build="$DLDIR"/icu-native/source :; make :; sudo make install * fontconfig: :; ( cd "$DLDIR" && wget -c https://www.freedesktop.org/software/fontconfig/release/fontconfig-2.14.0.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/fontconfig-2.14.0.tar.gz :; cd fontconfig-2.14.0/ :; ./configure --prefix="$PREFIX" $HOST_FLAG --enable-libxml2 :; make :; sudo make install // for fontconfig ///////////////////////////////////////////////////////////////////////////// * libpng: :; ( cd "$DLDIR" && wget -c https://download.sourceforge.net/libpng/libpng-1.6.37.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libpng-1.6.37.tar.gz :; cd libpng-1.6.37 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install * libgd itself: + TODO: This works for 64-bit builds, however 32-bit ones are burdened with `@8` or `@12` suffixes to symbol names, and subsequent link checks in NUT fail to find `libgd` as usable -- so CGI is not built in 32-bit mode. According to such context, this must be something about STDCALL and/or "extern C"... :; ( cd "$DLDIR" && wget -c https://github.com/libgd/libgd/releases/download/gd-2.3.3/libgd-2.3.3.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libgd-2.3.3.tar.gz :; cd libgd-2.3.3 :; ./configure --prefix="$PREFIX" $HOST_FLAG \ --with-png --with-freetype \ --without-tiff --without-jpeg --without-xpm \ --without-fontconfig # Note: currently we configure away almost all capabilities, # to match the dependency binaries (and/or headers) present # on the build system. Review resulting build recipes that # they DO NOT refer to system /usr/include locations! # In practice we would likely need the fontconfig pieces to work. :; make :; sudo make install libmodbus ^^^^^^^^^ :; ( cd "$DLDIR" && wget -c https://libmodbus.org/releases/libmodbus-3.1.7.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/libmodbus-3.1.7.tar.gz :; cd libmodbus-3.1.7 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install net-snmp ^^^^^^^^ :; ( cd "$DLDIR" && wget -c https://sourceforge.net/projects/net-snmp/files/net-snmp/5.9.1/net-snmp-5.9.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/net-snmp-5.9.1.tar.gz :; cd net-snmp-5.9.1 :; yes "" | ./configure --prefix="$PREFIX" $HOST_FLAG \ --with-default-snmp-version=3 --disable-agent --disable-daemon \ --with-sys-contact="" --with-sys-location="" --with-logfile=none \ --with-persistent-directory="${PREFIX}/var/net-snmp" \ --disable-embedded-perl --without-perl-modules --disable-perl-cc-checks \ --enable-shared # NOTE: ./configure script may ask a few questions, or may just print # a banner that it would; hopefully all replies needed for current # version are covered above # The following long `LDFLAGS` ensure that shared `libnetsnmp-40.dll` # gets built and later installed (and siblings which NUT does not use): :; make LDFLAGS="-no-undefined -lws2_32 -lregex -Xlinker --ignore-unresolved-symbol=_app_name_long -Xlinker --ignore-unresolved-symbol=app_name_long" :; find . -type f -name '*.dll' -o -name '*.dll.a' :; sudo make install NOTE: net-snmp tends to only `make` a static-linking library for Windows by default (the shared library only appears with `LDFLAGS` proposed above). In this case consumers must link not only with `-lnetsnmp` but also its dependencies explicitly -- see `Libs.private` line in `netsnmp.pc` of your build (or installation in `${PREFIX}/lib/pkgconfig/netsnmp.pc`). Builds can extract this info with `pkg-config --libs --static netsnmp` as NUT scenarios do (for mingw, if shared-linking attempt fails). libneon ^^^^^^^ As of release 0.32.2 libneon failed to build -- neither in Windows MSYS2 nor in Linux mingw environments. Some tinkering was needed to make it happen, and was posted as https://github.com/notroj/neon/pull/84 (pull request sourced from https://github.com/jimklimov/neon/tree/fix-mingw-cross branch). Due to this, instructions below differ from others by setting up an out-of-tree build instead of a tarball download. Eventually it would hopefully suffice to fetch https://notroj.github.io/neon/neon-0.32.5.tar.gz or newer (PR was merged after libneon 0.32.4 release). NOTE: Ability to `make docs` here relies on presence of `xmlto` program. In NUT CI workers prepared according to linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] this should be among dependencies for `asciidoc`; beware that with prerequisites it has quite a large installation footprint. Alternately check PR #69, or consult the Makefiles for current `install` target definition to run its job without `install-docs` part (example posted below). #:; ( cd "$DLDIR" && git clone -b fix-mingw-cross https://github.com/jimklimov/neon neon-git ) :; ( cd "$DLDIR" && git clone https://github.com/notroj/neon neon-git ) :; ( cd "$DLDIR/neon-git" && ./autogen.sh ) :; cd "$WSDIR" :; rm -rf neon-git ; mkdir neon-git :; cd neon-git :; "$DLDIR"/neon-git/configure --prefix="$PREFIX" $HOST_FLAG \ --enable-shared --with-ssl=openssl :; make all docs :; sudo make install \ || sudo make install-lib install-headers install-config install-nls ###install-docs cppunit ^^^^^^^ Needed for C++ unit tests (optional, and may be pointless in cross-builds where you can not also run the tested binaries built for another platform): :; ( cd "$DLDIR" && wget -c http://dev-www.libreoffice.org/src/cppunit-1.15.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/cppunit-1.15.1.tar.gz :; cd cppunit-1.15.1 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make all :; sudo make install ///////////////////////////////////////////////////////////////////////////// // for avahi libpcre ^^^^^^^ Needed for glib2 (further for avahi). :; ( cd "$DLDIR" && wget -c https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.40/pcre2-10.40.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/pcre2-10.40.tar.gz :; cd pcre2-10.40 :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make all :; sudo make install :; sudo ln -s libpcre2-posix.pc ${PREFIX}/lib/pkgconfig/libpcre.pc gettext/libintl ^^^^^^^^^^^^^^^ WARNING: Currently gettext does not build, at least on WSL2 Ubuntu, fails with `undefined reference to '__imp_formatstring_ruby'`. Needed for glib2 (further for avahi). :; ( cd "$DLDIR" && wget -c https://ftp.gnu.org/pub/gnu/gettext/gettext-0.20.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/gettext-0.20.tar.gz :; cd gettext-0.20 # Flags tweaked due to http://savannah.gnu.org/bugs/?36443 :; ./configure --prefix="$PREFIX" $HOST_FLAG \ CFLAGS="$CFLAGS -O2" CXXFLAGS="$CXXFLAGS -O2" :; make all :; sudo make install glib2 ^^^^^ WARNING: Currently glib2 does not build, at least on WSL2 Ubuntu, fails to find gettext (not built above). Needed for avahi. Requires `meson` build system, e.g. via: ------ :; sudo apt-get install meson ------ NOTE: Latest glib-2.73.3 as of this writing requires `meson >= 0.60.0` but the one provided in WSL2 Ubuntu 20.04 OS packages is older (0.53.2). In this case, try an older glib2 release, e.g. glib-2.72.1 seems compatible. Configuration options below were initially borrowed from https://build.opensuse.org/package/view_file/windows:mingw:win32/mingw32-glib2/mingw32-glib2.spec?expand=1 :; ( cd "$DLDIR" && wget -c https://gitlab.gnome.org/GNOME/glib/-/archive/2.72.1/glib-2.72.1.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/glib-2.72.1.tar.gz :; cd glib-2.72.1 :; case "$ARCH" in *x86_64*) cp -pf .gitlab-ci/cross_file_mingw64.txt .gitlab-ci/cross_file_${ARCH}.txt ;; *i686*) sed 's,x86_64,i686,g' < .gitlab-ci/cross_file_mingw64.txt > .gitlab-ci/cross_file_${ARCH}.txt ;; esac # We do not have an ARCH-dependent pkg-config binary: :; sed "s,^pkgconfig = .*\$,pkgconfig = 'pkg-config'," \ -i .gitlab-ci/cross_file_${ARCH}.txt # With meson, config and build can be done in one shot: :; meson --prefix="$PREFIX" \ --buildtype=plain --wrap-mode=nodownload \ --auto-features=auto \ --cross-file=.gitlab-ci/cross_file_${ARCH}.txt \ . build \ --default-library=shared \ -Dman=false -Dgtk_doc=false \ -Dsystemtap=false -Ddtrace=false \ -Dinstalled_tests=false -Dlibelf=disabled :; sudo meson install avahi ^^^^^ WARNING: Currently avahi does not build, at least on WSL2 Ubuntu, fails to find glib2 (not built above). Release 0.8 (and current git as of this writing) sources use `-Wl,-z...` linking flags which are not supported by mingw `ld` tooling, and so fail to configure. [NOTE] ====== To build from Git sources or regenerate `configure` in tarball sources like shown below, you should also have `gettextize` tool before running `autogen.sh`, e.g. via: ------ :; sudo apt install intltool autopoint :; ( cd "$DLDIR" && git clone https://github.com/lathiat/avahi avahi-git ) :; ( cd "$DLDIR/avahi-git" && ./autogen.sh ) # Stock script would go on to try configuring by default, # and that bit fails in cross-env vars ------ ====== :; ( cd "$DLDIR" && wget -c https://github.com/lathiat/avahi/releases/download/v0.8/avahi-0.8.tar.gz ) :; cd "$WSDIR" :; tar xzf "$DLDIR"/avahi-0.8.tar.gz :; cd avahi-0.8 :; vi common/acx_pthread.m4 # Edit `common/acx_pthread.m4` to remove `-Wl,-z,defs` near # AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) # Alternatively just edit `configure` script from the tarball. :; ./autogen.sh || true :; ./configure --prefix="$PREFIX" $HOST_FLAG :; make :; sudo make install // for avahi ///////////////////////////////////////////////////////////////////////////// Other requirements ^^^^^^^^^^^^^^^^^^ ipmi, ssl with Mozilla NSS... * https://ftp.gnu.org/gnu/freeipmi/freeipmi-1.6.9.tar.gz * https://ftp.mozilla.org/pub/security/nss/releases/NSS_3_79_RTM/src/nss-3.79-with-nspr-4.34.tar.gz Cross-building NUT with MinGW in Linux ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After preparing at least the required dependencies above, use one of the following methods to compile NUT as: * out-of-tree from git source (easier to iterate for development, so default): (cd scripts/Windows/ && ./build-mingw-nut.sh all64) + or, depending on the build environment(s) you have prepared, + (cd scripts/Windows/ && ./build-mingw-nut.sh all32) + [NOTE] ====== This is also automated for common NUT CI build script, calling it like this: ------ # Try to guess bitness based on ARCH or CFLAGS: BUILD_TYPE=cross-windows-mingw ./ci_build.sh # Or specifically: BUILD_TYPE=cross-windows-mingw-32 ./ci_build.sh BUILD_TYPE=cross-windows-mingw-64 ./ci_build.sh ------ ====== * an existing source tarball (can be fetched from NUT website): :; export SOURCEMODE=stable ### Optionally: export VER_OPT=2.8.1 :; cd scripts/Windows/ :; ./build-mingw-nut.sh * To (re-)build from scratch with a dist tarball, e.g. testing how a stable release would fare, starting from a git checkout, use this: :; ./autogen.sh && ./configure && make dist && \ (cd scripts/Windows/ && SOURCEMODE=dist ./build-mingw-nut.sh all64) If everything goes fine, you will find a NUT installation tree in 'nut_install' sub-directory (technically, a symbolic link to `nut_install_${ARCH}` directory). Note the script accepts some parameters e.g. for 32/64 bit build targets. NOTE: For other ways of building and packaging, it might make sense for a packaged delivery to also `make install DESTDIR=.../nut_install_${ARCH}` from the sources of dependency projects built above, or at least to copy the built `*.dll` files from `${PREFIX}/bin` to `nut_install_${ARCH}/bin`. For those dependencies that are listed above, the script does this best-effort activity (does not fail if some are missing, but running the programs can fail later). nut-2.8.3/scripts/Windows/winevent.mc0000644000200500020050000000102114777534446014557 00000000000000MessageIdTypedef=DWORD SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS Informational=0x1:STATUS_SEVERITY_INFORMATIONAL Warning=0x2:STATUS_SEVERITY_WARNING Error=0x3:STATUS_SEVERITY_ERROR ) FacilityNames=(System=0x0:FACILITY_SYSTEM Runtime=0x2:FACILITY_RUNTIME Stubs=0x3:FACILITY_STUBS Io=0x4:FACILITY_IO_ERROR_CODE ) LanguageNames=(English=0x409:MSG00409) ; // The following are message definitions. MessageId=0x1 Severity=Error Facility=Runtime SymbolicName=SVC_EVENT Language=English %1. . nut-2.8.3/scripts/Windows/Installer/0000755000200500020050000000000015001555412014373 500000000000000nut-2.8.3/scripts/Windows/Installer/README.adoc0000644000200500020050000001437414777767434016145 00000000000000NUT for Windows Installer ========================= This component aims to provide an integrated installer for NUT on Windows, including registration as the preferred handler of certain USB vendor and product identifiers. Various waves of the NUT for Windows effort happened over the decades, with the latest one being integration of the platform-specific source code which was previously available in side projects, into the main Network UPS Tools project and its continuous-integration builds, between NUT v2.8.0 and v2.8.1 releases (over 2022-2023 time frame). NOTE: This document aims to revive institutional knowledge about producing a NUT for Windows installer file. Currently builds of NUT for Windows are quite possible, they can result in preparation of a tarball of an installed directory tree which is immediately usable on Windows. However, separate steps may be needed for USB specifically (so that NUT drivers and not the default "HID Battery" handler can attach to the device) and for OS Service integration. It is assumed that the installer would handle these rituals. Prerequisites for building NUT for Windows ------------------------------------------ Please see the documentation provided with the NUT sources about prerequisites needed for semi-native builds (on Windows using MinGW x64 and MSYS2 projects) and cross-builds (on Linux with mingw64 packages): * linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] * linkdoc:scripts/Windows/README.adoc[] With these dependencies in place, the common NUT `ci_build.sh` script can be used to wrap the typical configuration, build and installation procedures. Similar results can be of course achieved by direct use of the `configure` script, which may be the way to go particularly for customized builds. See also `scripts/Windows/build-mingw-nut.sh` for the cross-build wrapper details. Prerequisites for building the installer ---------------------------------------- NUT for Windows uses the WiX Toolset to codify and implement the installer: * https://wixtoolset.org/ * https://wixtoolset.org/docs/intro/ * https://wixtoolset.org/docs/tools/wixexe/ * https://wixtoolset.org/docs/tools/heat/ * link:https://wixtoolset.org/docs/v3/overview/candle/[candle.exe] and link:https://wixtoolset.org/docs/v3/overview/light/[light.exe] tools were used in current scripts (dating from 2013) but were obsoleted after WiX v3 and became part of `wix.exe` according to https://wixtoolset.org/docs/fourthree/ update notes * https://github.com/wixtoolset/ * https://github.com/wixtoolset/wix/ The toolset in turn requires the .NET framework (and the related NuGet tool) which is available on Windows and Linux platforms, at least. In case of the latter (for cross-builds) note that many of the newer distribution releases should include dotnet packages in their repositories; for earlier releases a Microsoft repository can be added -- as detailed in their documentation: * https://learn.microsoft.com/en-us/dotnet/core/install/linux * https://dotnet.microsoft.com/en-us/download * https://www.nuget.org/downloads For example, on Ubuntu the installation can be performed like this: ---- :; sudo apt-get update && \ sudo apt-get install -y dotnet-sdk-7.0 nuget ---- NOTE: For installation on Ubuntu 20.04 and older, where an additional package repository is required, please see instructions at https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu-2004 Subsequent installation of the toolset on either platform would be: ---- :; dotnet tool install --global wix ---- Maintaining the recipes and building the installer artifact ----------------------------------------------------------- NOTE: To be investigated, modernized and completed per https://github.com/networkupstools/nut/issues/1485 Files were not touched considerably since 2013 (or earlier?) and would likely need deeper investigation and update to be useful. Findings so far: - Directory `scripts/Windows/DriverInstaller` contains a helper program (currently named `wdi-simple`) for driver installation - Directory `scripts/Windows/Installer` (with this document) contains the batch file script to call WiX tools (currently geared for WiX v3 or older) and the XML file which describes the installer actions and the file/directory structures it would deliver. * It would be helpful to find how to generate the filesystem structure (names, `GUID`s, what else?) based on the prototype area prepared by `make install DESTDIR=...` during a NUT build. It does not have to be part of *every* build (e.g. we can want this separated by driver types to allow end-users to install just a subset of NUT, similar to how this happens with multi-package approach on Unix/Linux) but an automated process which makes maintenance easier would be great: let a human sort where different filenames are categorized, and let automation discover that some installed files are not mentioned or some listed files are not present. - Directory `scripts/Windows/Installer/ImageFiles` contains various resources used by the installer, including apparently `Others/` for third-party files and `emptyDir` as a target for NUT `make install`? * This may be moderately compatible with what the Makefile driven installation does with current codebase -- especially how it pulls third-party library DLL files into the prototype install area. - The `scripts/Windows/wininit.c` program provides a rough equivalent to POSIX init scripts, to wrap various NUT daemons as a single unit. Its git history saw several re-architecting decisions, so if there are any concerns if the current version does "the right thing", we have some precedent ideas to look at. To a lesser extent, similar code might have appeared and disappeared in the Windows-branch code of daemons like `upsd` and `upsmon` before it condensed in this one. The batch file and the XML manifest currently list a few libraries from msys/mingw (as of back when this was coded). Current Makefile recipes take a more active approach by walking the dynamic dependencies of the built NUT binaries to copy those from the build environment. The batch file takes care to pass sample configuration and documentation files through `unix2dos` -- keep this in mind for new implementations. nut-2.8.3/scripts/Windows/Installer/BuildInstaller.bat0000644000200500020050000000244314777534446017752 00000000000000::This script can be used to Create and Build NUT installer using WiX. @echo off SET BATDIR=%~dp0 cd /d %BATDIR% SET MSYS_BIN_DIR=c:\mingw\msys\1.0\bin\ SET MINGW_BIN_DIR=c:\mingw\bin\ SET NUT-XML-FILE=NUT-Installer.xml SET wixobjName=NUT-Installer.wixobj SET msiPackageName=NUT-Installer.msi %MSYS_BIN_DIR%unix2dos.exe ../../../conf/upssched.conf.sample echo copy DLL files from MSYS copy /Y %MSYS_BIN_DIR%msys-1.0.dll .\ImageFiles\Others copy /Y %MSYS_BIN_DIR%msys-crypto-1.0.0.dll .\ImageFiles\Others copy /Y %MSYS_BIN_DIR%msys-ssl-1.0.0.dll .\ImageFiles\Others copy /Y %MSYS_BIN_DIR%msys-regex-1.dll .\ImageFiles\Others REM use "candle.exe" to create the "object" file candle.exe "%NUT-XML-FILE%" -out "%wixobjName%" >"log.txt" @echo ========================================================= @echo Please wait as MSI package creation in progress... @echo off REM use "light.exe" to create the "MSi" package light.exe "%wixobjName%" -out "%msiPackageName%" >>"log.txt" @echo ========================================================= @echo MSI package "%msiPackageName%" complete @echo ========================================================= @echo Check output file "log.txt" for status of completion... @echo ========================================================= nut-2.8.3/scripts/Windows/Installer/NUT-Installer.xml.in0000644000200500020050000051562114777534446020104 00000000000000 If the automatic USB driver installation fails, you can try to install a driver manually. For this go to : https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/ After installling libusb-win32, run libUSB's Inf Wizard and choose your device. Click Next to continue [Wizard]. If you use a USB UPS, please plug it in now, so that we can try to install the relevant driver. [DlgTitleFont][ProductName] installs the following libraries, location of licenses are - Click Next to continue [Wizard]. 1. msys-1.0.dll - http://sourceforge.net/projects/mingw/files/MSYS/BaseSystem/msys-core/msys-1.0.16-1/ 2. msys-ssl-1.0.0.dll and msys-crypto-1.0.0.dll - http://sourceforge.net/projects/mingw/files/MSYS/openssl/openssl-1.0.0-1/ 3. libregex-1.dll - http://sourceforge.net/projects/mingw/files/MSYS/BaseSystem/regex/regex-1.20090805-2/ Click the Finish button to exit the [Wizard]. {\VerdanaBold13}Completing the [ProductName] [Wizard] {\VerdanaBold13}[ProductName] [Wizard] ended prematurely [ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again. Click the Finish button to exit the [Wizard]. Please wait while the [Wizard] prepares to guide you through the installation. {\VerdanaBold13}Welcome to the [ProductName] [Wizard] Please wait while the [Wizard] [Progress2] [ProductName]. This may take several minutes. [DlgTitleFont][Progress1] [ProductName] {\VerdanaBold13}[ProductName] [Wizard] was interrupted [ProductName] setup was interrupted. Your system has not been modified. To install this program at a later time, please run the installation again. Click the Finish button to exit the [Wizard]. Browse to the destination folder [DlgTitleFont]Change current destination folder Are you sure you want to cancel [ProductName] installation? The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it. Some files that need to be updated are currently in use. [DlgTitleFont]Files in Use "Yes"]]> {\rtf1\ansi\ansicpg1252\deff0\deftab720 {\fonttbl{\f0\froman\fprq2 Times New Roman;}} {\colortbl\red0\green0\blue0;} \deflang1033\horzdoc{\*\fchars }{\*\lchars } \pard\plain\f0\fs18 \par GNU GENERAL PUBLIC LICENSE \par Version 2, June 1991 \par \par 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. \par Preamble \par 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. \par \par 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. \par 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. \par \par 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. \par \par We protect your rights with two steps: \par (1) copyright the software, and \par (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. \par \par 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. \par \par 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. \par \par The precise terms and conditions for copying, distribution and modification follow. \par \par GNU GENERAL PUBLIC LICENSE \par \par TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION \par \par 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". \par \par 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. \par \par 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. \par \par 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. \par \par 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: \par \par a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. \par \par 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. \par \par 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.) \par \par 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. \par \par 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. \par \par 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. \par \par 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: \par \par 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, \par \par 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, \par \par 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.) \par \par 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. \par \par 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. \par \par 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. \par \par 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. \par \par 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. \par \par 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. \par \par 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. \par \par 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. \par \par This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. \par \par 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. \par \par 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. \par \par 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. \par \par 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. \par \par NO WARRANTY \par \par 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. \par \par 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. \par \par END OF TERMS AND CONDITIONS \par \par How to Apply These Terms to Your New Programs \par \par 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. \par \par 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. \par \par <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> \par \par 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. \par \par 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. \par \par 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. \par \par Also add information on how to contact you by electronic and paper mail. \par \par If the program is interactive, make it output a short notice like this when it starts in an interactive mode: \par \par 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. \par 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. \par \par 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: \par \par Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. \par \par <signature of Ty Coon>, 1 April 1989 \par Ty Coon, President of Vice \par \par 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. \par \par } [DlgTitleFont]Re&pair [DlgTitleFont]&Remove Select the operation you wish to perform. [DlgTitleFont]Repair or Remove installation Removes [ProductName] from your computer. Repairs errors in the most recent installation state - fixes missing or corrupt files, shortcuts and registry entries. The [Wizard] will allow you to change the way [ProductName] features are installed on your computer or even to remove [ProductName] from your computer. Click Next to continue or Cancel to exit the [Wizard]. {\VerdanaBold13}Welcome to the [ProductName] [Wizard] 1]]> The [Wizard] will complete the installation of [ProductName] on your computer. Click Install to continue or Cancel to exit the [Wizard]. {\VerdanaBold13}Resuming the [ProductName] [Wizard] 1]]> Click Install to begin the installation. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard. The [Wizard] is ready to begin the [InstallMode] installation [DlgTitleFont]Ready to Install 1]]> 1]]> Click Remove to remove [ProductName] from your computer. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard. You have chosen to remove the program from your computer. [DlgTitleFont]Remove [ProductName] 1]]> 1]]> 1]]> Click Repair to repair the installation of [ProductName]. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard. The [Wizard] is ready to begin the repair of [ProductName]. [DlgTitleFont]Repair [ProductName] The [Wizard] will install [ProductName] on your computer. Click Next to continue or Cancel to exit the [Wizard]. {\VerdanaBold13}Welcome to the [ProductName] [Wizard] bytes GB KB MB Entire feature will be unavailable Feature will be installed when required Entire feature will be installed to run from CD Entire feature will be installed on local hard drive Entire feature will be installed to run from network Will be installed to run from CD Will be installed on local hard drive Will be installed to run from network Gathering required information... This feature will remain uninstalled This feature will be set to be installed when required This feature will be installed to run from CD This feature will be installed on the local hard drive This feature will be installed to run from the network This feature will become unavailable Will be installed when required This feature will be available to run from CD This feature will be installed on your local hard drive This feature will be available to run from the network This feature will be uninstalled completely, you won't be able to run it from CD This feature will change from run from CD state to set to be installed when required This feature will remain to be run from CD This feature will change from run from CD state to be installed on the local hard drive This feature frees up [1] on your hard drive. This feature requires [1] on your hard drive. Compiling cost for this feature... This feature will be completely removed This feature will be removed from your local hard drive, but will be set to be installed when required This feature will be removed from your local hard drive, but will be still available to run from CD This feature will remain on you local hard drive This feature will be removed from your local hard drive, but will be still available to run from the network This feature will be uninstalled completely, you won't be able to run it from the network This feature will change from run from network state to set to be installed when required This feature will change from run from network state to be installed on the local hard drive This feature will remain to be run from the network This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive. This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive. This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive. This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive. Time remaining: {[1] minutes }{[2] seconds} Available Difference Required Disk Size Volume Validating install Copying new files Copying network install files Computing space requirements Computing space requirements Computing space requirements Creating shortcuts Publishing Qualified Components Publishing Product Features Publishing product information Registering Class servers Registering extension servers Registering MIME info Registering program identifiers Allocating registry space Searching for installed applications Binding executables Searching for qualifying products Creating folders Deleting services Creating duplicate files Searching for related applications Installing ODBC components Installing new services Evaluating launch conditions Migrating feature states from related applications Moving files Patching files Updating component registration Registering COM+ Applications and Components Registering fonts Registering product Registering type libraries Registering user Removing duplicated files Updating environment strings Removing applications Removing files Removing folders Removing INI files entries Removing ODBC components Removing system registry values Removing shortcuts Searching for qualifying products Registering modules Unregistering modules Initializing ODBC directories Starting services Stopping services Unpublishing Qualified Components Unpublishing Product Features Unregister Class servers Unregistering COM+ Applications and Components Unregistering extension servers Unregistering fonts Unregistering MIME info Unregistering program identifiers Unregistering type libraries Updating environment strings Writing INI files values Writing system registry values Advertising application Generating script operations for action: Installing system catalog Publishing assembly information Unpublishing assembly information Rolling back action: Removing backup files Removing moved files Unpublishing product information {{Fatal error: }} {{Error [1]. }} Warning [1]. Info [1]. The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is [1]. {{The arguments are: [2], [3], [4]}} {{Disk full: }} Action [Time]: [1]. [2] [ProductName] {[2]}{, [3]}{, [4]} Message type: [1], Argument: [2] === Logging started: [Date] [Time] === === Logging stopped: [Date] [Time] === Action start [Time]: [1]. Action ended [Time]: [1]. Return value [2]. Time remaining: {[1] minutes }{[2] seconds} Out of memory. Shut down other applications before retrying. Installer is no longer responding. Installer stopped prematurely. Please wait while Windows configures [ProductName] Gathering required information... Removing older versions of this application... Preparing to remove older versions of this application... {[ProductName] }Setup completed successfully. {[ProductName] }Setup failed. Error reading from file: [2]. {{ System error [3].}} Verify that the file exists and that you can access it. Cannot create the file '[2]'. A directory with this name already exists. Cancel the install and try installing to a different location. Please insert the disk: [2] The installer has insufficient privileges to access this directory: [2]. The installation cannot continue. Log on as administrator or contact your system administrator. Error writing to file: [2]. Verify that you have access to that directory. Error reading from file [2]. {{ System error [3].}} Verify that the file exists and that you can access it. Another application has exclusive access to the file '[2]'. Please shut down all other applications, then click Retry. There is not enough disk space to install this file: [2]. Free some disk space and click Retry, or click Cancel to exit. Source file not found: [2]. Verify that the file exists and that you can access it. Error reading from file: [3]. {{ System error [2].}} Verify that the file exists and that you can access it. Error writing to file: [3]. {{ System error [2].}} Verify that you have access to that directory. Source file not found{{(cabinet)}}: [2]. Verify that the file exists and that you can access it. Cannot create the directory '[2]'. A file with this name already exists. Please rename or remove the file and click retry, or click Cancel to exit. The volume [2] is currently unavailable. Please select another. The specified path '[2]' is unavailable. Unable to write to the specified folder: [2]. A network error occurred while attempting to read from the file: [2] An error occurred while attempting to create the directory: [2] A network error occurred while attempting to create the directory: [2] A network error occurred while attempting to open the source file cabinet: [2] The specified path is too long: [2] The Installer has insufficient privileges to modify this file: [2]. A portion of the folder path '[2]' is invalid. It is either empty or exceeds the length allowed by the system. The folder path '[2]' contains words that are not valid in folder paths. The folder path '[2]' contains an invalid character. '[2]' is not a valid short file name. Error getting file security: [3] GetLastError: [2] Invalid Drive: [2] Error applying patch to file [2]. It has probably been updated by other means, and can no longer be modified by this patch. For more information contact your patch vendor. {{System Error: [3]}} A file that is required cannot be installed because the cabinet file [2] is not digitally signed. This may indicate that the cabinet file is corrupt. A file that is required cannot be installed because the cabinet file [2] has an invalid digital signature. This may indicate that the cabinet file is corrupt.{{ Error [3] was returned by WinVerifyTrust.}} Failed to correctly copy [2] file: CRC error. Failed to correctly move [2] file: CRC error. Failed to correctly patch [2] file: CRC error. The file '[2]' cannot be installed because the file cannot be found in cabinet file '[3]'. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package. The cabinet file '[2]' required for this installation is corrupt and cannot be used. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package. There was an error creating a temporary file that is needed to complete this installation.{{ Folder: [3]. System error code: [2]}} Could not create key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not open key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not delete value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not delete key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not read value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not write value [2] to key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not get value names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not get sub key names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not read security information for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. Could not increase the available registry space. [2] KB of free registry space is required for the installation of this application. Another installation is in progress. You must complete that installation before continuing this one. Error accessing secured data. Please make sure the Windows Installer is configured properly and try the install again. User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product. Your current install will now continue. User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product. Out of disk space -- Volume: '[2]'; required space: [3] KB; available space: [4] KB. Free some disk space and retry. Are you sure you want to cancel? The file [2][3] is being held in use{ by the following process: Name: [4], Id: [5], Window Title: '[6]'}. Close that application and retry. The product '[2]' is already installed, preventing the installation of this product. The two products are incompatible. There is not enough disk space on the volume '[2]' to continue the install with recovery enabled. [3] KB are required, but only [4] KB are available. Click Ignore to continue the install without saving recovery information, click Retry to check for available space again, or click Cancel to quit the installation. Could not access network location [2]. The following applications should be closed before continuing the install: Could not find any previously installed compliant products on the machine for installing this product. An error occurred while applying security settings. [2] is not a valid user or group. This could be a problem with the package, or a problem connecting to a domain controller on the network. Check your network connection and click Retry, or Cancel to end the install. {{Unable to locate the user's SID, system error [3]}} The key [2] is not valid. Verify that you entered the correct key. The installer must restart your system before configuration of [2] can continue. Click Yes to restart now or No if you plan to manually restart later. You must restart your system for the configuration changes made to [2] to take effect. Click Yes to restart now or No if you plan to manually restart later. An installation for [2] is currently suspended. You must undo the changes made by that installation to continue. Do you want to undo those changes? A previous installation for this product is in progress. You must undo the changes made by that installation to continue. Do you want to undo those changes? An installation package for the product [2] cannot be found. Try the installation again using a valid copy of the installation package '[3]'. Installation completed successfully. Installation failed. Product: [2] -- [3] You may either restore your computer to its previous state or continue the install later. Would you like to restore? An error occurred while writing installation information to disk. Check to make sure enough disk space is available, and click Retry, or Cancel to end the install. One or more of the files required to restore your computer to its previous state could not be found. Restoration will not be possible. [2] cannot install one of its required products. Contact your technical support group. {{System Error: [3].}} The older version of [2] cannot be removed. Contact your technical support group. {{System Error [3].}} Installed [2] Configured [2] Removed [2] File [2] was rejected by digital signature policy. The Windows Installer Service could not be accessed. This can occur if you are running Windows in safe mode, or if the Windows Installer is not correctly installed. Contact your support personnel for assistance. There is a problem with this Windows Installer package. A script required for this install to complete could not be run. Contact your support personnel or package vendor. {{Custom action [2] script error [3], [4]: [5] Line [6], Column [7], [8] }} There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action: [2], location: [3], command: [4] }} There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. {{Action [2], location: [3], command: [4] }} There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action [2], entry: [3], library: [4] }} Removal completed successfully. Removal failed. Advertisement completed successfully. Advertisement failed. Configuration completed successfully. Configuration failed. You must be an Administrator to remove this application. To remove this application, you can log on as an Administrator, or contact your technical support group for assistance. The path [2] is not valid. Please specify a valid path. Out of memory. Shut down other applications before retrying. There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to go back to the previously selected volume. There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to return to the browse dialog and select a different volume. The folder [2] does not exist. Please enter a path to an existing folder. You have insufficient privileges to read this folder. A valid destination folder for the install could not be determined. Error attempting to read from the source install database: [2]. Scheduling reboot operation: Renaming file [2] to [3]. Must reboot to complete operation. Scheduling reboot operation: Deleting file [2]. Must reboot to complete operation. Module [2] failed to register. HRESULT [3]. Contact your support personnel. Module [2] failed to unregister. HRESULT [3]. Contact your support personnel. Failed to cache package [2]. Error: [3]. Contact your support personnel. Could not register font [2]. Verify that you have sufficient permissions to install fonts, and that the system supports this font. Could not unregister font [2]. Verify that you that you have sufficient permissions to remove fonts. Could not create Shortcut [2]. Verify that the destination folder exists and that you can access it. Could not remove Shortcut [2]. Verify that the shortcut file exists and that you can access it. Could not register type library for file [2]. Contact your support personnel. Could not unregister type library for file [2]. Contact your support personnel. Could not update the ini file [2][3]. Verify that the file exists and that you can access it. Could not schedule file [2] to replace file [3] on reboot. Verify that you have write permissions to file [3]. Error removing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel. Error installing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel. Error removing ODBC driver: [4], ODBC error [2]: [3]. Verify that you have sufficient privileges to remove ODBC drivers. Error installing ODBC driver: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it. Error configuring ODBC data source: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it. Service '[2]' ([3]) failed to start. Verify that you have sufficient privileges to start system services. Service '[2]' ([3]) could not be stopped. Verify that you have sufficient privileges to stop system services. Service '[2]' ([3]) could not be deleted. Verify that you have sufficient privileges to remove system services. Service '[2]' ([3]) could not be installed. Verify that you have sufficient privileges to install system services. Could not update environment variable '[2]'. Verify that you have sufficient privileges to modify environment variables. You do not have sufficient privileges to complete this installation for all users of the machine. Log on as administrator and then retry this installation. Could not set file security for file '[3]'. Error: [2]. Verify that you have sufficient privileges to modify the security permissions for this file. Component Services (COM+ 1.0) are not installed on this computer. This installation requires Component Services in order to complete successfully. Component Services are available on Windows 2000. Error registering COM+ Application. Contact your support personnel for more information. Error unregistering COM+ Application. Contact your support personnel for more information. The description for service '[2]' ([3]) could not be changed. The Windows Installer service cannot update the system file [2] because the file is protected by Windows. You may need to update your operating system for this program to work correctly. {{Package version: [3], OS Protected version: [4]}} The Windows Installer service cannot update the protected Windows file [2]. {{Package version: [3], OS Protected version: [4], SFP Error: [5]}} The Windows Installer service cannot update one or more protected Windows files. {{SFP Error: [2]. List of protected files:\r\n[3]}} User installations are disabled via policy on the machine. An error occured during the installation of assembly component [2]. HRESULT: [3]. {{assembly interface: [4], function: [5], assembly name: [6]}} TARGETDIR="" TARGETDIR="" ]]> @@@@@]]> TARGETDIR="" TARGETDIR="" LIBUSBINSTALL=1 nut-2.8.3/scripts/Windows/Installer/ImageFiles/0000755000200500020050000000000015001555412016400 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/Images/0000755000200500020050000000000015001555412017605 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/Images/NUT_wix_vertical.bmp0000644000200500020050000160576614777534446023527 00000000000000BM 6(8   מM֜IԜDՙ;Ԙ6Җ-Ӕђ ёБΏ΍ϏώύЎό΋ό΋͉̈Ί͋Ί͉΋ΊΊ͉͉̈΋όЎύЎύЎЎяЎΌ΋όЏђђҕә+ؠQ֝L֜I՚Dՙ>ԗ8Ӗ.ԔђВЏ͎ΏΎ΍ώΌ͋΋΋͉͉͉͉͉͉͉̈΋͉͉͉̉Ί΋όЎЎύЎЎЎύό΋όϏБВғءVןP֝J֝GלD֚?ԙ7Ӗ0ӕ&єґώώύώЎύΌό΋΋͉͉͉͉͉͊̈̈̈̈̈̈͊̈΋ύЎЎύЎЎЏώό΋΋ώёђءYؠTםM՝I֜I֛D՚>Ә8Ӗ2ҕ%ғёϐЎύ΍΍͌Ό͊Ί͉͉͉͉͉͉͈͊̈̈̈̈̈̈̈ΊόύύύύЏЏЎόΊ΋ύѐנXנUןQמM֜J՜HԛDԚ>Ԙ:Ӗ0ӕ'ғВ АЎ͍͌̋Ό΋͉͉͉͋̈̈̈̈̈̈̈̈̈̈̈̈̈̈΋Ό΋ΌύЎЎяό͉͊όנXנVؠTןP՝L՝J՜H՛B֙>՘8Ӗ1є&ҕѓ Бώ̋͌΋Ί͉͉͊̈̈̈̈ˇ̈ˇ͉ˇ͉̈̈̈̈̈̈̈΋ϋ΋όώяЎ͍͊͊֠\ؠYןUמQ֞N֝K՜I֛FԚ@ԗ<Ԙ9Ӗ1Ӗ+ҔѓёϏ͍΋ΉΉ͉͉͉̈̈̈̈ˇ̈ˇ̈̈̈̈̈̈ˇˇ̈Ί΋΋΋ΌώЎЎΌ͊ؤaס]آXؠV؞Q՝J՜H֜HԛFԙ@Ԙ9Ә5Җ2ҕ)ҔђВϏΎΌ͉Ή͉͉̈̈̈ˇ̈̈ˇˇ͉̈̈̈̈̈ˈ͉̇̈͊͊όόύЎύύ٤d٣aס]סYןRמN֝K՝H՝H՛E՚?ՙ9ԗ6Җ1ҕ(Гђёϐ΍͉͉̋͊̈̈̈̈̈ˇˇʆʅ̈̈̈̈̈̈ˆˈ͉͉̈͊΋΋΋ύЎۧg٤dآa٣[סXؠUןQ֝KԛG֛E՚A՚<՗:ӗ4ӕ/Ҕ$єђ БΏΎΌ͉͉͋̈̈̈̈ˇʆʆʅˇˆ̇̈ˈˇ̇ˇˇ̈̈͊΋͋͊όЍۨjڦgڤb٣^ءZסXؠU֞N՝I՜GԚB՘;ԗ9՘9ԗ5Ӗ,є єГђяЎύΊ̈̈ˇˈˈ̇ʇˆˆˆʄɄ˅̇ˈ̇ʈ̇̆̅ˇ͉Ί͊΋΋ܩkۧiۦfأaע^آYסW؟R֞N՜GԛFԙ@՘:ԗ9җ5җ1ҕ+ғ!ҔӔ ВАϏ͍͋̉ˈʈʈ̆ˇ̆ʆ˅ʆɅʅʅˇ̇̈ˇˇˆ͈̆̈΋ό͉ܩkܩkۥgڤdأ_آ[ءZؠWמS֝M՜I՜GԚBԘ:ӗ4җ2Ӗ/Ҕ'Дϑ ̎ʌƉсĂǃɄɅʅʅɄʃʃ˅̆ˇˇˇˇʆ͉͉͉̇̇ܪlݩlܨiۦf٣_٢^ء\ءXؠTןP՝L֜H՛H֛Cԙ;ӗ6Д1ʎ( $),/*(!z{ȃɄɃɃʄʄʅˆˇˈˆ̅ˆˇ͈̇۩mܩlܨiۦgڤc٣aآ]٢Y٢XؠUמR֜KԜIԜGϗAŌ54>Jƥ^βlռwŃˊϐӕ͎ʉҹrɫ_I1w~ǃȄʄɃʃ˄ʇˇ̇̅ʅ̅̄·ܫo۩lۨjܧiۥg٤bأ^آZءYסWؠSמOҚIƐBDşZѲqÄӕؚٛי֗ҕϒΒѓѓיܜܜԚɋҶrğP#y~ǂʂɃʂȃ˅ˆˇʅ˄˃̅ޭwܫq۩lۧjۦhڥd٤aآ]٣Z٢Y֟SΘNEZӸ}}}~}|}̔ͼИםl^WF_WGʹӚ۠q;2%[F!muȂʃɂʃɄʄʆ˄˃˃ޯ{ޯxܫrܪoܩkڦgڥc٤`٣\՟YɖQOϳ|ΙӞwnY0.-740851840841630ID<ҾɶӚࣇz`82/73.xҝ١u<:60..fGp}ǃʃɃȁɄɅ̄̅̄߰|ޯzޮyܭuݫnۨkۧh٤aԠYœR]ʘץڧԢg`P"""!!))+kwt{hqvMZb]pyv٥ۦ͝ƷnfV{͜Ӹzs zǁȃȂɃɃ˄˄˄~߱|߯{ޮyݭsܫoܪlգe“Vm֨ت٪۫էiaR!""!!"  "%,9Y}Ar>oCP|0|>z4Jr))*}׫ܱܱϞ~!xƀȂȁɂɂʂ߶ആ᳁~ްz۫wɝkƧ}۴߶߶޶޶޶㺈n$&,4PmPt^^xapfi]s\fe^IlDP|IkJJ~Gi-Uz3Uqױ޶޵߹̝~xƁɂȁǀǀඋⵉߵೂް}Ϥså|س߻®KMN (Kdjkxu}sikjj[|Xo]xXSBg+E^'C]+Kgݺy{ɁʂȁȀⶌᶌඉഅթ{ġzѯȿa%5I9ASLV|fwT^V``o{LJkqtaz-/?3:Q_ta^ARy! #" %$'2*\ϰsv }ɁȁȀⷌ᷌ඊܱɢyǷf_;EU%%+utsāPaz-3<,/>R`fbJ];Np5@\3Mn5j5wݼIwƁɁɀ亏⸌ൈѨ~̯̿cxړLUo!" !$",do؂΍R_w?J]ERmN^ifHY?Kp7@]@a@{8zEǛ|ɁɁ㺓㹏۲ʧȮsʄCHZ('.#%)!"'%$)"!%,,5it͖Ύؙ]m%&-:DSUdmmHU~#$+)+:E^Nz>};umWxȁ仕廑ԭˮz˅u{_krp}\dNJÑإsDL^XkeypoavBMq?RsQlWyRuKt>}Ϭ~|ɀ伕ḑϬƯۖ͐먽ꖩ׼҇י{΋}vv]xDVw>LmStW}VzC{8xe⼔Hz~⼕ܵɬtԪ֏ǘᘯJQi^kk}ԂVj)/<-3@Me\{W|QzLrN{Ɓ⹓հʴ䇯ԣߔ˧)(1 "" &m䈧au2:I1;IOZ\sYzYuNr>wݳ~ÀṓЭ˸Րޘ̭Q[m\h~BJ^dt፨_p'+5)*6M]]|XOPs;v^G~߹ʪ͝ߛͫπ|⏯uHVv=EeUn_^~U}Lx9{K̳|޸Ħ}Ԯߙͭ㔱摱䀝rd}czd_y[yN~;|8zͭy۷êm{صfpwalwhszjt{huޝ͵er029gsꑱ䀛vsgd\UJ@|8wZ֯w ٶʴOݶ]fl#akx駿ܙͲ_l" %锶vjyhdy`WMNxJtbw ٶϻP^fn !126ؙηELZň⼙ײɲԁҷ愬ݪXaoU^jS[jR[kS[kPYiU_r֏ˢ\jAIX,0:k烮zP^uGZs^oJ5wHԸˍ⻚޶ɬܗȱޕ䣻ܞڝ۞ܞۚڣ藯׋ɝTav|Tc}[r~}WjNiӼW<|2vmԽ$ϑ ⻘߹ϭѓղ텮ރܩՈǚ喻PaxMXn8?MpypWp#$(39EȮgC6x?ٿZǏ-є⺘Ṙհ̱˒޾삫zפ҆ƚ瘺n,-4/6D`M]^s_jwHN[yF;|6yyͪDϕ4Ӗ.⼗㻘ݶʧĪɡw^qЖ砿뜻뙺}݈a\uUmΐ{bm}]{H>|5xUƥoő>Ӛ:ՙ7㼘㻘㺕կ̰ڻĢoNH{ً畷鉮~[\mmxZvש{)*.+1<5`=z4xEĜPИB՛?՚;㻗优㺖߷˥ԾŸlGoviυZq[WqˇTcy #""&»7EX*@W7h6wJֿضġiǓE՝HםC՜A㸒㹔Ổ⺔۳ƥ̫߼ƽV^k\w{yԂـ~؎䅤q٧r?FNQXf}Aw6g3b5qgۻ߼дNԝOؠM֝IמE㹔⸓⹒⹓⹔ԬǪҭ߸޸޸෿²zGMYFP^]rdxf{pР떱ԕɳp}|{M)Fd"$(}۴߷߷޸߸WҝV١T١PןM؟I井⸓Ḓ⸓⹔ต˦ɮӪ޲ݳܱô3-* #GMX᝷דȤ硽}\~Dv4u4v1`;KVVXTmfWׯݱݲݲĚb͛X٣[ڤXڣUءP٠N㸒⹓⸓⹔⸒⹓߶ʥɭҦݮڮ٭t" ""!!!!&)/ZwcXW7Pk/B"2B"3E;l]rpʻ٭ۭܯėf̚^٦b٤_٤[ڤ[آU١Q߳෎⹓⹔ⷒ⸒⸒޶˦ǪȜݬ̠wn\'%'$"% ",++1/.0./$&,! #+$Ko)d(a,r.Pm>EI((+JE<ɧ߫oGC=IE>֦۫ҹj͝bۧfۧdڦ`٤]أ\٤YڣUܫuްඍ⸑⸑⹒⹓Ṑ޵ϩŦҺҟlHD= e\Njmi-++$$(Ucivx&&*QKC˹עџqGB;EA;|ʛɭ˜gРhڨkܨhۦeۦbڥ_ڥ_ڤ[٣Yڦi۩sޯ~ඉⷎ⸏㸑᷐᷐ൎ֭ǤƫɗΙ^WHy_˘ƒ41/ #fΘܢ}sZf^N30.zҜ՝m31/752gqȞk֦nܩn۪m۩lܧhܧeڦbڦaڤ]٢Z٤eڥi۩oܭx߲ⷌ⸐⷏ᶍᶌߵٲͨ¢ɯ}dvʓҙЗzbyͻǵʔԚw}luΖ՚˸v[dUE~^̢qګtܬtݬtܬqݪoݩjܨhܧeۧb٥^ۦ\ءbסdأfڧmܫtݰᶊ⸐㸏෌ᶌ്޴د˦yxмϒѓВˏËȎ͑ʎ̑ϓˏˎɎŋ͐ӽvmnϤuݮ|ܭxݮxݭuܬrܫqݫoݩmܩiۧcڦaڥ_֞Yנ_آcأdڥhܨnޯzೇ⸍⸎ඌᵊᶌඍ޵ٰΧzxū|иƈ͍͋͌͌̌͌͌ʹ¥xrĝuѧ{ٮ}ް~߰}}{ޯyޯxݭtܬrܫqݫnܩkۧgۧdڦbԚQ՜U֟]סbآcؤh٧nܬw߲᷌᷍ᶌ෌ඊᶌോഊݳ׮Χş|vtvwyuvtxɡ{Ҩخܱ߳ು߱}ޯ{ޯ{ݮyޮvݭsܪoܪnܩlݩhۧeҘIәKӜQ֟Xנ`עcأeڥjܫsޯ~ഈൊᶌᵌᶋᶋᶋൊൊߵߴܲڰح֬׭׮ٯ۲ݲݴߵߵ߳߳߳~}߰|}߰|ޯ{ޯyޯxܭtܫrݫpݫmܩkܩjҗ@ӗDԚJԛO՝U֞[ء`آc٦hڧoݭ|߱൉ᶌᶋᶋᶋᶋൊൊᶋᶋᵉᴈߵߴߵൈඉ൉ߵߴ᳇೅ೃೄಀ~߰|߱|}߰{ޯzݯxݮwݬvݫrܫn۪mݫmѓ9ѕ@ҖCҙHԚN՜U֟Zנ^آbأgۧm۩uݯ}ഈോൊᶋᶋߵߵᶋᶋߵഈഇߴ߳ೄആഇߴߴആೄೃೄೂ᳀~߰|߰|ޯ{߰{߰z߱zްxޯuޭsܫqܪoΏ ѓ5ҕ?ӗCҗFӚL՜S֞W֟[ס`٢bڥh۩oޮ|߳ߵൊോൊൈߴൊߴ൉ߴߴೄೃೄ᳅߲߳ೃഄ߳ುೀ߲ೀ}|߰|ް{ް{߰yްxޯwޭuޭtܫpʊ̍ϑ+ҕ=ѕAїDҙIԛP՝S֞Y֟[ע`٤eۧl۬v߲ഈൊൊೈ޵ߵߵഈߵഈ೅೅ᴄᲄ߱߱ీ߳ೂೀೀ߳~߰|߰|ޯ{߰{߯xޯwޯxޮwݮvܭtɈɈ̊ Ϗ&є9ѕ?іCӘHҙJ՛Q֝W֟Zա]עa٥j۪sݯ}߳ᴉഉ޵ߵ߶ᴈߴߵߴഈഄೃಁް߰~߱߰ుಀ߲߳~߰|}߰|߰{߰yݮvݮvޮwݮvݯvʈɇɇʉ͎ϒ6є=Җ@җDӘI՚N՜T՞XנYס_ؤfڨnܬy߱ߴ൉ൈഈᴈೇഈഈ൉ߴ߳ుްް߯~ޯ|߱߱~}~߰|߰|߰|߰{ݮxܭwޮuޯvޮvȅʈʈɇɈ̍ϑ1є=Ӗ@їBҘFәJԛR֝V֟Z֠^آc٥j۪uݯ~߲޳ߴೆ೅ᴇഇഈᴈ೅޳߲߱~߰|ޯ{߰}߰|߰|}߱߯|ޯ|߰}߱|ްzޯxޮvޯxޭvǃɆʈɈˉˊϐ,Г8Ҕ;і@ӗDӘHԚN՜T՞Uנ[סa٤gڨqޭ|߳ഈߴߵ߲߲߳ೇೇഄߴೃ߰ޯ}ݮzܭzܭ{ޮz߯|ޮz߰|߰|߰|ް{ޯz߯{zްzݯwz~ƂʆɈɇʇ̋Ώ&В5Ҕ:ѕ?ӗCҙFӚM֜Q֝T֞V֟[٤d٧kܬyݯ޲޳ഈ߲޲޲߳ߴ߳ߴ߱}߱~ޯ|ޮzޮ{ݯ{ܭyޭyݮzޯ{߰|ޯ{ް{߰{ݮxެw߮wyz~ƂDžɇʈȇʉ͎ϒ1Г;є>ѕ?іDҘKԚO՜Q՜S֟Zע]ئiܫtޮ|ޱ߲߳߳߱߱߱ಃಀ߱߰ޮ|ޮ{ݮzݮzޮyޮyݭzݮzޯ{ޮ{ޯzݮxܭxܮxxyz|ƁȅɇɈɆʈ̎ϐ*В7Г9ѕ@ҖCӘGԚM՜RԝU՞W֠]ؤdڨoݭyްݱޱޱް߯~ް߰߱ޱް߰}ޯ{ޮzޯ{ݭyݮxݭyݮzݮzݭyݮyݭzݭyܭwvxyz|ŀDŽɇɇɅɉ͋ Ώ$ϑ0Г;ѕ=Ӗ@ӗCԙMԛQ՜S՝Q֟Yآa٦iܫuޯ~ݱ߱ޱްްޯ}ޯ}ް~ްޯް~߰|ݯ{ݮzݭyݮxݮyݭxݭxݮyݭzܮyܭwtuxyy|ƃȆDžʆʈˊΐϒ0ϒ6ѓ9ҕ=җCҘGӚM՛N՜R֞Vס\٤g۩rݮz߯ݱ߱ްޯ|ݭzޮzޯ|ް~߰~߰|ޯ{ޮ{ݮzܮwܬvݬvܭxݭxޭxܭxݭxssuwyz{~ǂȅɆɆȆˊ͍ϐ+ϑ1В3є=Җ@јEәJԚMԛO՝Sؠ[أbڧk۫vް~߰߱ޯ~ޮ{ޮ{ޯ{߯|ݮ{ޯ|ޮzޯ|ޮ{ݮxܭwܬwܭwܭwܬvܬvݬwstttvxyy}łȅɆɆȆˉΌΏ%Α.В4Г9ҕ=җAӘGӚKӛL՜QןWء^٤g۩qܮyޯ߰ް~ޯ{߰{ޯ{ޮzޭ{ޯ{߰|߮zޮzݭyܬwܬvܬvܬwܬwܭxqssssuxxz{ŀDŽȆȅȅʈ̌ Ύ!Α-Α/ђ7є;ѕ@їFӘHӚKӜLԝQءX٢bݩnܭwޯ}ް߰ޯ|ޯzޯ{ݭ{ޯ{ݮzޮzޮzݭyܭxܭwܭw۫tܫuܬwrrssssuxyy{ȃȆɆȄʆˊ΍ϐ&ϒ,В0Ҕ9Ӗ>җAӘFԙJӚK՝P֟S٢Y٤h۪rܭyݯ|ޯ}ޮ{ޮ{ޮzݮzܭyޭzݮyݮxޮyݮyܬwݫtܬvܬvoqrssrsuxyy{~ƂȄȅDŽȅɈ̋Ώ$Ϗ(ϐ/Г4ҕ:Җ@ҘCԙGԘGԛMןSנZ٣bۨpܬwݮ{ݭzݭzݮ{߮{ܮyޭzޮzݭzܭyܭxݬyܬxܭxܭwnpoqssrstvwyz}ƁDŽȅȅȄʈ̋Ύώ(Ϗ)В3є:Җ?ӗBҗEӗFәI՜NןTآ]ڦj۫t۬xݮzݮzܭ{ݫyݯyݮwݮyݭyݭyޮzݮxܭw۬voonorsrsssuxxy|ǁʄʅȄǂȆ̊ΎϏ%Ϗ'Б/В3є8Җ?ӗAҗFӘGӚI՜OנX٥f۩qܬwݭ{ޯzݬyݭyܭxܭwܬvܭwܭxܭxݮxݮxjmnnprrrrssuxxy|ǂƃƂƃɆɉΌЏА%ΐ(В.ѓ5ѕ;Җ@ӗAӘDәI՜NןUأ`ۧj۫sݭyݭyݭyݮzݭxܬvۭv۬vܭwݭwݮxfjlnnoprsrrsuwxx{~ƂƂƂƂȅʈ̋ ͍ΎΏ"Б+ѓ2Ҕ8Җ<ӗCӘCәEԛK֝RנZڥg۩qܫwܭyޮzݭyܭxܭvܬuݬvܭwܮxefimnnnqqsrsttvxxzƂƂƂǃɃɇʊ͎͌ΏΏ&ϒ-ѓ5Җ=ӗAӗAәCәGԛMמW٢_ڦk۪sݭyݭyݭyݭxݬuޫvܬw۬vadehmnnopqsssssvxyz}ƁǂƂƁǂɆˉ̌ ΎΎϏА+Б0є9ӕ=җ>ӗ@ԘCԚI՝QסZ٥e۪pܬuݭyݭxܬuެwܫvܫu[`dehlmnoopsrsrsuvwx|ƀƁƂŁǂʅʉ͎͌̍ Ύϐ%ϑ,є1ҕ:Җ=Җ=Ә?ӚFԝN֞T٢`٧k۪s۬xܬwܬwܫvܫvYZ`dehlmnopqrsrsttvwx|ĀƂƂƂƂDŽˉˋ̌̍Ώΐϐ(В/ѓ5ӕ:ԗ;җ<՗DԙH՝Rء\٤f۩pݫu۬wݬwܬvYXZ_cehlnnooqrssrsuwvw{ǁƀŁŁȂʈʊ̌̌Ό ΎϏ#Б)ѓ2ҕ8Ӗ8ҕ8ԗBԙH՝M՞Tأaڨlܫsݬw۬uZZXZ_dehllnnoqrrssrtvvwzƁƂŁŁǂɆˉˋ͍͌Ώϐΐ"ϒ0Д5ҕ8Ӗ8Ӗ;ӘA՛IמQء[ڦhڪpܬvZZYWY_cdhklmnopqqqrssuuvz}ŀƁƁƁȄʇˊˊ̋͌Ύϐ!Б&Г0Г3є5Ԗ:ԗ?ԙF՜K֞UأaڧjXZZXWY^cdgklmmrą$Ä%„$Ä%Ä$Å$Ƈ%Lj%lj$ȋ$Ɏ%ʐ$̑%˒%ː$̒%͕$Η$Й&ʏƇɊ͍͎ϐ#Б.Г2Г4ѕ7Ӗ=әCԛH՜O١\TXZZYXX^cefkmjƋ4ͱwnɉ̌ ͎͏ϑ'ϒ.ѓ0є4җ8Ә=ԙD՜LPTXYYXWX^bcfkiʼn1uzNnʊ͍͋Ώϐ#ϑ*В.Г/є5ӕ9ӘBNPTXYYXWX]ccfgĈ0۲v}u`9c@dʉʋˋ͎̌ ΐΐ"Б)ϑ.ѓ/Е7LMOSWYXXWX]accÇ3»t_E DQ)W/X1Y2Y1Y2Z3[3\5^8^8]8\7e?~Qiʈʉʊˊˋ͍Ώϐΐ"ђ'ϒ,LK MPTXXXXWX\acoհ}ôs=IQY[\^\_abdefkuɄɇʇʉʉˊ͍̋ΏϏ!В'LKL MOTWXXWVW]bcf o)͵?]fnpqprtxz{|}Ƃȅɇʈʈʉʊ̋͌̍ ώLLKLM ORWXXWVW\a`ZSVӼ@dkqtttx{}ǀȃȆɇʈʉˊˊ͍̋KKLLM MOUVWXWUW]`a^YPzM õDfnrttwz}~}ǂȄɆɇɇʉʉ̋ILKLKL MOSWWWWTV\abc`\N|N̺Pjppsvy|~~}ƁDŽȅȇȆʇʈGIKKKKLNNSVWWVVW\`bdfd[JRԿYsoovy}~~}}ŁǃȅɆȆɇHGIKKKKL LOTVWWVRTZ^`cfecYD~O dʻĠgrjsx|}}|~ŀǃȅɆȆGFGIKKLKLMOSWV\j o(p'u(y(y'}(('~(|(t%cb)pnRhsxz}}}}}ŀłȅȆFGHHJKLLKLL OSTo%ݿ˷ƹpd9[mtwz|}}{{~ƁȃFGGGGIKKKKKM OOx4sK(Rjstwy{||{|}ƀEFFGGHJKJLLLMLi!ѰðƺƾtdKM+Pjsrsuyz|}|z{EFFGHGGJKKLKK MRZRpC]9Y7Y7Y7\:^<]=^=`>`>_=`?bAbBbBbBaB[: i>Vkrrrsuxz{{yzEEEFGHGFIJKKKL M MJCz>z={>y>x>}A~D}@E\i.b#}D}FMPPPVcmqsrrsuyzz{zEEEFEFGFGJKKKKLL NOOPPPPNs.ϵd]cgjmoorsssrswyz{CEFFEEFFFHJKKKKL M NSUVU[ Τy|c1FLDt>yBQ`dfghiklmlmmTYUJFCBBCBDCDEEEFEFHIHHGy< e0nI(kS|h|eOG#j5HOLLQX^cehghijlmllNUXRIECCCBBCDCDDEEEEHY*e9W$FCt: d0[*Y)h4~?LRQQV[]_cffhiijlmlMOUXPHECBBACCDDDEEB=@á᲍rs0=>=;;?CJORQSX[]`degghhilkONOUWPHDCCACCDEDDAhFȽv~~Ü|ÝzƞuǞsYl+LPQSW[]_cffgghjkONMPWWM GDDCCBBDDC~=ǯQEMPRX[[_deggggiNOMMQXVKECCBBBCEC~>lƈZ*@LQRWZZ`beggghFONNMRWSIECBAAADECM'U4uN3=)M7'T;(V<)X<(V='X='\A*~oqWe/GOQRWZ\`dfgghu=IONMNSWRHDBB~A}B~BDFC|>m;)C" W+ ]/ ^0 ]/ ^0 ^/ sH$nN"ANPRQWZ\`cefgo;u>JNMMOTWPGDBAB}ABDDC~CǮ6V,t;~BBAC@T$ƶnEu;LPPPRVZ\`defo:q;{@L NMMOVWM FCBC~B|ABCCDhH}enM7G" a2|@GJHJHR g~mL/O%x<LQROPSXZ\`cem:o:o;DNNMMPXUL FCB~A}B~AADC}a}fqI1e=$q@{BCEHFKHC x:d1f3BNRRRPPTWY\acl9n:o;r<FNNMMRXTIDC~B}A|ABCFͶïlfF[4P#FDFGEBB IOQQRPOPTWX\`m9m9o:n:t=INNMMSWRHDCA}AB~BEǯpsOd:R#CEJKNQPPQPPPTWY[n:m9m9n:o;y?K NNNMTVPGDC~A}A~BBP,nRuºθb8DILMOQQQQPPUXZk8n:l9m:n:n:|AL NNLOTWN FDB~A|B}A{@s9^+ P' [:$oTBj]vh1BIL NPQQPPPQSXj8l9m9l9m:n:o:DM NMNPVTLECB}A|A~A}@y?r;f4\+ P L U0y^NuI o:FKM NPPPPQPPTl9k8k9l9k8m:m9q;GNNNNQVSJDBBA~A~?|<z8 |?aAxŲz6d4CKKL OPPPPPOPm9l9l8l9m9m:o:o9s<JNMNNRVQHCAB}>X7sӾgWK=&C!i5DJLLM NPQPOPOr<m9l8m9m9m9m9n:o9x?L NMMOTVN FDE¦}cJ:B&?!?!B" I& \/u=FHIJLM OPQPOPCq:n:l7m9m:l8l8n9o9~BM NMMPTTK EFȯaJ;<"9; A! F$O(X/`3l7y?DGHIJKLMOPPOOJ|@o:l9j8l8l8m8m9n9q;ENNMMPURJG¦ʦkXqH-uF&yC!{AAEGHGIHIKLMOPPPKHy?o:l9j7l8m9l8l8m9s;INMM MRVQHY5nĭmS1}?EGGHHHJKK NPPPGKGv=n:k9j8m9m8l8m9n9x?K NNL NSUOCp5T$DS6&u_Rþ`, z>CGHIHHJKL NOOIHKCr;m9j9j9m9m9m9m9o:~BM OM M NTUL Dv<k7]-Q"D9X8#hZvDg5AFGHHHHJKL OOKHIJ}Ao;k9j9l8k9k9l8l8q;EN MM L PURG <w7{C`D~h´ƿvn3^0{?EFFHHHHJJL OL LHJHw>n:k9k8k9k9j8l:l:r=HNM M M PWq2oʰĻsdZD0"= b3{@DGGGHHHIJJL M L JHJEs<m:i9j9k:i9j9l:l9z?K M N M O ͥziUHU=/M2 A%< D# U,m:CDEGHHIHHIJKMM MJIKDq<n:j9k9l8k7k9m;n;DN NN PոǿdN@I2 C*?$< B" M(W-_2g6p;{?CEDFGHHIHHILNN M LIKJ{@q;k9l9l9l8l8m:m9p;GMM O xHq?r>T,E% B" D" K&S+\1b3l8v={@|ABBCEDCGHGHIHHKQNN M KIMHu>o:j7k8l8l8m9l:l9u=JN M K Fx<n8l8rF$bHlR`EyG%xAz@}ACCCCCDEEEGHGHIIHTQNN M JILDr<o9i8j8k8j8k8m:m:x@M O M J R`ěw_s@z@DCBCDDDDEFHHHJHUSPN N MIKL~Bq:m8k8k8k8k8m:m;n:DNM `%Įn@"t:CCCDCDDCFGGHHH\TRON N KHMIw?o:l9k7l9l9l9m:k9p;ITѱƥlVvbQnb[0t<BCBCCCDDEGGHIdYSPNN N JILEs=n:k8j8k9l8l8m:n:w?g4V79GO$I!CgI5ɾfL9].z@CBCDCDDCFHGIm`VQON M MIILCr<n:j8j8l9l8k9m9o<tdE*8Q)r:CB t;h4ZB|j_G! o:BCCECDDCEGHGzh\UQOM M LIJK|Ap;l9k8m9l9j8l9n<ȼ<K&l7GQRJ~AQ.Ⱦ{s9a3|@ECCDDDDEFGF̍NrdZSQOM M JHKIx?o:m8l8l8l8l9p<Ĺ:Y-@ K RURGT0Ź~u4Z/w=ECBDDDEEEFFץ{ƅ:maWQNM M L IIKEs=m9j8l8l8j8l:}Q1[,C M NTUN]5~nd5X.s<DEDCDEEDEEFผЗcyh\UQOM L M IJK}Bp;l9k9m9l8n9^ET'~?K L OSW̧gRD8\/u=}AEEDDEEDEEEǵۭˎNs cYSPM N L JIJHx?p:m9l8o8j8uD&Ž\2JNPy@Ȯ9 A" b4w?|ABEEDCDEFFFբwŃ5m`VQON N M KILFs=o:l:m:m9l9\D\C06P)l8}AABDFECEDDEEο޵ϗb{h]TPPN N MIJK}Br=n:l9l:m8i5ZCĹ^@$6J& d3x>~A~BBBDFDDEDDFǴڬʌIs dYRPON N LILHx?r;m9l9k5h1_+ ]2fWĺkU@<E Z.j6 w>BC~ABCCFGDFEDF⾧աwł/n`UQPO N MJILFv=q;o;kS{`I`/V) C>CCDJ"W,m7BHFDEB~ABBDEEEFEE̺޴Е]yh\TRPN N LIKKBs=r=ƲFT$X&V%a*o0o0q1x4;BMNGEC~ACCBCFEEFDű٩ʋFr dYQPO N N KILHx?t>ì¶ɻͼνо°¯î¯į̵JIIFCBDCCCFGEEDຠӜo%k_UQPN O N KKMEwAdztz8FGFCCBCCCFEEEɷܰΒXwf[SPOO N MJLKEW8r؇q[X(AJ GEEBBBCDGGFץ}Ȇ>obYRQOP O LILKU33#,26 8 :!D&K* J) I( I'[.AOKGECCBBCEFF̹߶љi} i]UQQO P N KJOs10 : F&M)O*P*X.k7 m8l7 n7w=IQPJFDDCCCDFGŰ٫̍Qt cYSPP O O MJOӸ~p2@" V-c4h7i7j7j9|@H I I J NSTO HEEDDDCDFн⻢Ԣuƃ8l_VROM O O LLƟ͆qa7N(f6p;q<q<q<s<x@JP O O NQTSLFFEDDDDEȲܱϓ\weZXdd&RN NLBz7]1N*\/m9s<r<p;r<s<r<CNO O O P STQIGFEEEDEϿ俧ק~ȇBp_p$ڼªWCGIEC y;f2 g2m7o7n7m7n6o7o7s9CM P O N P STN IFEEEDDʵ޷ҙi~(g2^lBsDxFvJtLtGoKkNjNjOjNkNjNjMjNjNqR_(M O O O RTSLGFFFFFҽê͎۬Qq ƒ.笆i?K N O P SUQJFFFEF̵ຟ֡tƀ0Ȍ7~W(BL O O PTTM HGFEFŭܰϓZƃ-ÍDXrVkW~kWjY~kW~kX~jZ|i[}kYr_P~qfnaWreZtf[uf\ve\yk`O<.B u< J O O O RTSLIFEE̷㼢إzLJ>l Rp<\1Y/Y.W.V.T. Q) T, cQF1; @# A# C#C" N(r<M P P P P TTP JHGFӾƭ޳Ҙez#`RGCDB B ~AS&нK*W.^1a3a4e6r<MQ P Q O QTSNJHGͷᾡ٨̋IrbXQPNPwEtR:f7l8s<v=v=EO Q P P P TVQKHGӽƮ޵қk*l_WS\ėl鞊xD"J0¹qi=m8v=x?y>KQ P P P RUUP JHֿ϶۫ΏSve[Wƙl~dK>C"V*S'|õqK/f4u=y?CNQ P P P RUSMIѸƬ߷՟pȃ3m`[ۻgG(>M'`1 |? Dh2 _E¹wM$k7w>{@GQ Q P P Q TURK׿Һ̲㿢۬ΐWxg^Цztk<I!V-p:BJOIn8 nC#}:_1t<zABMS Q P Q SUUOڿٿؿؿԼ϶ǬทաtɅ@objGp7j6z? I N MPOGt:h9{fqZI?Z/r;zA|AFQQ Q P Q TVSؾ׽׽׽׽׽׽׽׽׽׽׽׾ռѹ˱ۮД]yh[PFGL P Q OMQNDw=n;`5W- c3s;z@}@~CKR Q Q P Q UUּּּּ׼׼׼׼׼׼׼׼ּջӸβƩ߶أwˇErbXQQR Q R Q ONQI~Cx?q<n:r=y?{@}A~AFPR R R Q TVպպպպպպպպպպպչչԸҷдˮܮҗb|&j_WSTR Q R QMQOG~C|Az?|@|@|@}B}A~CJR R Q R R UӷӷӷӷӶӶӶӶӶӶӶӶӶҵҵг̮Ħ߷ףx̉Gr dZTSR Q R S MOPKEC|A|A}B}A}A}B}BEOS R Q Q RѲѲѲѲгггггггвѳѳѲв̮ȩ依ۭїb{*j^XTTR R Q Q OPNGDB}A~C~CCC}CDJR R R R Q ϱϱϱϱϱϱϱϱϱϱϱϱϱϱϱϱΰʫģ൑أẘIsc[UTS S R S POQLFC~C~CC~C}B}CCENR R R R ѴϰϰϰϰϰϰϰϰϰϰϰϰϰίήͮʪŤ⺘۬ѕ^{)h]UQQPOR S OPPIDDDBD~BCBBIR R S S ϰ̭̭̭̭̭ͮͮͬͬͬͬͬͬϯԸֻҷдʮ⿠ܱӝfȊ8~,v-r0q2r4h)UKN PQMGDDCCBABCENS S R ˫˫˫̫̪̪̪̪˪̫̪˩˩˨ӶѾֺi\"DPQJFDDCCCCCDIR S S ʨʨʨʨʨʨʨʨ˨ʨʧɧɧȥԸǵh==P NIFDDDCDDDENT T ɦɦɦɦɦɦɦɦɦɦɦɦɦȥϱÿ½˿U/@N KGFDEDDEDDHR S ǣǣǣǣǣǣǣƢǣǣǣǣǣǣǤ}jyiXseUrcSrbQp\JmU@hK/cB_;[7Y5Z8jK-Ⱦf5 G MIGDDEEEDDDMS ƢŢšƢššššššššššġϲxvtqj}[nE]OGBz?v<zI÷pP3q8L KHFEDDDDDDHQ ÞÞÞÞÞÞÞÞÞÞÞÞÞÞğÞ޽ںٹڸشկѥ~ɖh@l^WQPKsDjVW*G OJFFEFGGFEEMœœœœœœœœœœÜ›Ü›㻔ോ٧yѓ[}(k`YVRi*ziI"|A PMHFEFFEEFFI㼔᷎ܭ՜jʆBr d\WTi%qEr; N QJHGGGFFFFF㿗㿗㿗俗㿗㿖㼔ṏ߲إuϑX{%j_XTk({hEp: L S NIHGFFFFFF俕俕俕俕㿖㿕㿕㿕㿕㿕㿕㿕㿕㿕㿕㿕㾕侕俕侔㾔侔佔⹐ߴ۫}ԛfʄ?r c[VEjTG!q< KS RKHGGGGFGG㽒㽒㽒㽓体佒佒佒佒佒佒佒佒伒㽒㽒佒佒佒㽑佒佒㽑⻏උݯآpώRx"gZdϸeJ0M%y@M R T OIHHHG H II⼐⼐⼐㼐㼑佑㼑㼐佐㼐㼐㼐㼐㼐㺏᷊ඇേ޵޵޵޵ߵ޳ݰګ{ՠnΎTz2v͓OͱC!W,EP RT RLIHHHGHI㹍㹍㹍㹍㺍㺍㺍⹌㺍㺍㺍㺍㺍⹌ĞX<C g6JS R TU PLIHIHH I ⹌⹌⹌⹌⹍⹍⹍⹌⹌⹌⹌⹌⹌᷉Ƣ[?#@[.AP U S ST S MJIIIH H᷉᷉᷉෉෉෉෉෉ඈ᷉᷉᷉᷉െğƽmTE(E$W-x>MU VU SS V PKJIJJI ߵߵߵߵߵߵߵߵඇߵඇߵߵඈൈԬg{cI]K8YI5XH4YH4YI5YI5YI5XG4WF3VD0U@,S:!P3S/Z0j6BNTU V WT S U R LKJKK Kߴߴߴߴ޴ݳݳ޴޴޴޴߳߳ೄߴد›sawXtVuVuVtVtVtVtUtTqRlLc?Y-QNOSVX W W V X TT V PLKJ J K ޳޳޳޳߳߳߳߳޳߳߳߳޳޳߳ܰժẓtȠrȟrȟrȟrȠrȠrȠrȟrƞpěm×g[Go#c[VVWXW W VV U V T NLK J J ుుుు߱߱߱߱ް߱ް߱ݱޱേƣšĠġġĠġġĠġàᾙ߹ۯԢmΕLʍDƊIj!RVW W VW T T V QNL K J ߰~߰~߰~߰~߰}ް}ް}ް}ް}߰}߰}ݰ}ݰ}ܮ{x@PVV V XV T V S N M L K ݮ{ݮ{ݮ{ݮzޯ{ݮ{ݮzݮzݮzݮ{ݮzܮzܮzܬw㽓ua-FTX W XW U V U P M M M ݭyݭyݭyݭyܭyݭyݭyݭyݭyܭyܬxݭyݭyܫv㼒~tvyyxxqˋy~str}lycyacG)V+BSX X W WU V W S O M L ۬w۬w۬w۬wܬwܬwܬxܭxܬwܬwܭxܬwܬw۪t⻑xgVI6#^H/pU9uZb4e4s;HTXY W WWV W U P M M ۪u۪u۪u۪uܪuܪuܪuܪuܪuܪuܪuܪvܪvۨs⺐m\^I1lJZ```W̹º_K7sYrg`ZYXYX X YW W X U Q ڦlڦlڦlڦlڦl٦lڦlڦlڦlڦlڦlڦlڦlڦlעfҷuR`Ҡjڦpްm[aI.oIĕb٢j֟dӗZ͉Gx&ia\YXYXX YX W W WR ٤k٤kڥlڥlڥl٤kڥl٤k٤k٤k٤k٤k٤k٤kآgܳʴٻ̮cN:gN3yN˚cآh֟dԚ^ϏO7pe^YYYYXYYW W X U ٤iؤiأi٣i٣i٤i٣i٤i٤i٤i٤i٤i٤i٤i٣iԝcݾsbPU?'}^=Vўe٣fנd՜`ѓTʅ@vh`[ZXXYXYX V X V ٢fآfآf٢f٣f٣f٣f٢f٢f٢f٢f٣f٣f٣fآgءe͘_ίัp`OP<%mR3wKŔ^ןfءf֟d֝`ҕW͊Gz+lb][YYYXXYV X X נdؠdؠeסeסdסdסdנdנdנeנdעeסdءdסeסe՟cĐWaqxy|nwgV[G2Y@&sW6sHYҝbؠdؠeןc֝`ԗZώMȀ7pe^[ZYYYYYX Y X נcנcנcנcנcנcנcנcנcנcנcנcנcנcנcנc֠dӞaƒZLm?^7wV2xW3^9lC}MXЛ`՟b֟b֟b֟a֜_ՙ\БQʄ?uja\[YZYZYXX Y ֟b՞a՟b՞a֞a֞a֞bןb֞aןb֞a՞a֟b֟bןaמa֟a՝`ҙ[̓T‹MKKOSŽV˕[ӛ^Ԟ`՞`֞a՞`՛]җVіTђR͉G{.m c^[YZZYYYX W ֝_՝_֝_՝_֝_֝_֝_֝_֝_֝_֝_֝_֝`՝_֝_֝^՛\ףhϲڽWȑWЙ]՜^֝_՝_֝_՝_ןbἒ̱̙cąE~5qf`\[ZZYXYZ W ՜^՜^՜^՜^՜^՜^ԛ]ԛ^ԛ_ԛ^ԛ^՜^՜^ԛ]՛]ԚYۮzʳZQΗZ՛^֜]֜\՜\՜[޳빙vq:y8v"ib\[[ZZYZZX ԛ]ԛ]ԛ]՛]֛]՛]֛]՛]ԛ]՛]ԛ]Ӛ\ԛ\՜]Ԛ[٤jqENΖYԛZԚ\Ԛ\Ӛ[٫uv~V,q8w,m d^[ZYZYY[Y ՚Y՚Y՚Y֛Z՛ZԚY՚YԚXԚY՚Y՚Y՚Y՚Y՚YԖRǢȽeL1J2o[꜆mj:QҘY՚XԙXԙW٧n{fE"j6y2rg`][[[ZZ[Z֘X֘X֘X՘XԙXԙXԙXԙXԙXԙXԙX՘X՘X՗W֛]cJ/R: jL+[2h|\8yEʒU՘X՘X՘Wڤl^?f6z7v#ia]\Z[ZYZ[՘X՘X՗XԗWՙXԙWԘWԘWԘWԙWӘWԗWԗWӖT٦mXB'hK+l=JU͸~hOd7NҖUԘVӗU٥l[>f6{;z,m d_\Z[[ZZ[ԘWԘWӗVԗVԘVԘVԘVӗUӗUԘVӗUӗUӗUҕR۫unY@%]4HϓSГRزyzW1|E̒RӗUӖTܫvp\>g7?~2pga\[ZZZZ[ӖTӖTӖTӖTӖTӖTӖTӖSҖSҖSӖSӖSҖSҔPکszh_D&f8LҕRҕPӡiw]@i7ËMГRҕRΰkV`C!k9Bʂ9t"hb]\[[ZZZҕQҕQҕQҕQҕQҕQҕQҕQҕQҕQҕQҔPӕQғNأhxcH(i:KҕQҔPϒOƽtRo4ʐTƢȿ]D*kK(q<ƆD̅=y(l d^\\[ZZ[єPєPҕQєPєPєPєPєPѕQѕQѕQєPҕQѓOӚZeK-g7IѓPєPГMϜbuaQ8~W0{AˋGΈA~0of`\[[[Z[ѓOѓOғOѓOѓOѓOѓOғOғOғOғOѓOғOѓNЎIȧkP3a3FГOєNғN͏K˞lqM4fG%j8F΍IΉDɁ5shb^\\[[[ҔNҔNєNҔNғNҔNҒMђLГMђMѓMѓMВLѓMғNˎK{A[0rQ*d5FϑMѓLѓMђMɋHO̷黳kYCL4`D$`1}AˍJώIϋEʃ:w%k c_][[\[ђLђLђLђLГLђLґLҒMѓMѓMѓMВLѓMВLѓLϑLHw=n:w>ˆGАMѓLВLҒLБLƉHu<[*gEV:U:^A!pO*c3zANjIАLЏJЍF˅<{+of`]\[[\ВLВLВLђLґLВLВLВLВLВLВLђLђLВLБKАL̏JƉHÇGƊHˎJАKБKБKБKБLϏJNJHBr;h6e4i7s=CȌHΏJёKϏI΍F͈>~1rha^\[[[ѐKѐKёKёKѐKѐKҐKяJяJяJяJяJяJяJяJѐJѐJяJАJѐKБJБJАKАJАKАKЏJяJˍHNJH†ED‡FȊG͎HϏJѐKАJАIύF͊Aʁ5u"ib_\\[[яIяIЏIЏIЏIЏIЏIЏIАIАIАIАIАIАIАIАJАIАIАIАIЏHѐIАIАIАIяIѐIѐIАIѐIАIАIАIяIАIЏIЏIАIЏHύF͊A˃8x'md`]\\\ЏHЏHώGώGЏHЏHϏGЏHЏHЏHЏHЏHЏHЏHЏHϏHϏHϏHώGώGЏHЏHώGώGώGЎGяHяHяGЎHЏHЏHЏHЎHЏHяHЏHϏHϏH΍F΋B̄;{,ofa^]\\юHюHюHЎGюHяHяHЎGЎGЎGЎGюHюHюHЎGЎGЎGЏHяGюHяGюGяHяHяHяHЎGЎHЎGЎGюHюHЎGюGЏGЏFЏGЎHЏH΍EЋB͇=~/rib^\\[яGЏFЏFЏGЏEЏEЏFЎEЎEЎEЎEЏEЏEЏFύD͉>͆;ЍDяFЎGЎFЏEЏEЏEЏEЏEЎEЏEЏEύDЏEЎEύDύEЎEЍEЍEЎEюEЍDϋB̈=2u!j d_]\[ЏDώDώDώDΎDώDΎDώDώDώDώDώDэDόAԛYĝս˔Wƅ@ˊC΍EώDώDώDώDώDώDώDώDϏDϏEϏEώD΍DύDЍDύDώDЎEэDϋB̈>˂7y(mf`^\[ώDΎDΎDύDэDЍDЍDЍDЍDЍDЍDΎDЌD΋@ףg^q5=ʉBώDΎDΎDΎDύDЍDύCύCЌCЌCόCЌCЌCόB΍CύC΍C΍CЌCΊÄ>̃8z,pga_]\όC΍CόCЋCЌCЌCЌCЌCЌCЌCЌCόCЌCω?١fuSU)q6Ɔ@ЍDόBЋCϋBЌCЌCϋBЌCЌCϋBЌCЌCЌCЌCόCЌCόCόCЌCΊẢ>̄:}.rhc_^]ЌCϊAϊAϋAΊAϋBϋBΊA΋A΋AϋAϋAϋAΈ>ءefKgDj2Ą?ЋBΊA΋A΋AΊA΋A΋A΋AΊAόBΊA΋A΋A΋A΋AΊAΊAΊB΋@΋@͉>̆;2u j d_^]όCΌAΌAΌAόAΌAΌAόAόAΌAόAΌAόAΉ>ءf{cIa?h/Â<Њ@΋@΋@΋@΋@΋@΋@΋@΋@΋@΋@΋@΋@ϋ@ϋAϋAϋAϋAϋAϋ@Ί?ˇ;ʁ4w&mea^]΋@ό@ό@ό@ό@ό@ό@Ό@ό@ό@Ό@ό@όA͉=ءet]rU5xFɐQӗUӗTӗTӗTӗTӗTӗTӗTӗTӗTӗTӗTӗTӘVАI͊?΋@΋@΋@΋@͊?̈<˃5z*ofa^\΋@΋@΋@΋@΋@΋@΋@΋@΋@΋@΋@΋@όA͉<סdǾХvz3ă=̉?͊@͊?Ί?̈=̄7|-qha^]͊?͊?͊?Ί?΋@Ί@΋@Ί?͊?͊?͊?͊?͊?̈;נc[$u6Ņ<Ί@΋@Ί?̈=̅8~0tjc`^Ή>Ή>͉>Ί>Ί>Ί>Ί>Ί>Ή>͉>Ή>Ί?͉>̇;נdľſƿȋxchCh/;Ί?͊?Ί?̈=̅81u#k da^͊?͊?͊?͊?͉>͉>͉>͉>͊?Ί?͊?͉>͊?̇;ןbt]YE.cL2mR7oT7oU6oU6pU6oT6oU7pT7oU6pU6pU6pU6pT6oU6oU7eH(qL!j/:͉>͊=͉=͇<̅9ʁ2x&nea^Έ>Έ>Έ>Έ=͈=͉=͉=͉=͉>͉>͉>·=Έ>ͅ:؟bv`FP3pJ Y'^)](^)](](^)^)])^)^)^(^*^)])`+i/w6DŽ;̉>͇=̉=̈;˅7ʁ4z*pgb_͈>Ή?͉>͈>χ?ψ>ψ?͈>Έ>ψ=͉>Ή>͈=̆:֟b{cI_=`*w5~9~78~8|6{4z2z1z2{3}688~8~88Dž<̈=͉>χ?Ή>͈;͇8ʃ5|-rhb^͉<͉<̈;ˇ;̈<̈<ˇ;ˈ=͈=·=ˉ=͇=͈>̆:֞b|cHb@e-9̈<Ή<Έ;͊@أjƢԼ߿˖]}5Ȅ;ˆ<͈=͈;̇:ˈ<ˈ=͈<͈<̇<͆;̃7}0t jdȧ:̇:ˇ:̇:͇:͇:͈:̇:̇:͈:͇:ʇ9̈:˅7՞_zcGb?e-7͈:͈;עgŷMz3ǃ9̇;̈;̇:·<ˈ:ˈ:̇:̆9˄71u#k d`͇:͇:͇:͇:Έ;Έ;Έ;ˇ:ˇ:̇:͇:͈;̇:̆8ѓNܶվxX6lGh.Á8̈:עiݪSo.Á7ˇ:ʆ9͆:͇:͇:͇:̆9˃62x&nfa͇:͇:͇:͇:͇:͇:͇:̇:̆9͆9̆9̇:̆9̇:̆8|1f$X$['q1Ł8ѐH굧sY?N0K+\;jMķ˿_/p/ŀ7˅9̆9̆9͆9̆9˅8̄7ʀ2z)ogb̆9̆9̆9̆9̆9̇9̇9̆9͇:̆9ˆ9̆9͇9̇9̆9Ʉ9|5t2t2~6ʄ8ءgxR1T5mGU$\'Y#U!tXY"x4ʄ9̆9˅8̆9̆9̆9̈́7ˁ3{*qib̆8͆9̆9̆9͇:͇9͈8̆8̆9˅8̆9̆8͈9̇8̆8̇8ʅ7Ȅ7ȃ7ʄ7͆:志fG$W8zP"h,v2|5|5x2GpnEn.ł6̆8̅9̆9̆9̆8˄6ˁ4|-sjd͇8͇8͇8̇9̆9̇9̇8ˆ8̆9˅8̆9̆8̇8̆8̆9̇9͇9͇8̇9̆9Έ;̫Q. mGg,}5Ʉ7ˆ8ˆ8˅7̍Hֿ|_<d+6̆8̆9̆9̆9˅8˄6˂4~.u"k d͇9̆8̆9̇9˅8̇9̇8̆9̆9̆9˅8ˆ8ˇ7ˆ8˅9̆8̆9ˆ8Ά8͇8͇<ƢŻX6{P"s1Ʉ8͆9͇9͇9̆7ёLx[9`)|4ˆ8̆9̆9͇:̆9˅7ʂ40w%lĕ9̆9̆9̆9˅8̆9̇9͇:̆9͇9ˆ8̆9̇9̆9̆9̆:̆9˅8̇8͆9·:ݰ~|cGwKu2ʄ8ˇ9͇8̇9̄6מc{c\:`(}5̆8˅9̆9̆9̆9̆8˃51x'nf̆9̆9̆9̆9˅8̆9̆9̆9̆9̆9̆9̆9̆9̆9̆9̆9̆9˅9̇9̆8͆8ϑNǾ^7a#}1ʃ5̓5˂1ҖSpV9c>d*}6̅9˅9̆9˅9ˆ8̆7̃6ʀ2{(pg˅8̆9˅8˅8̆9˅8ʄ7˅8˅8˅8˅8˅8˅8˅8˅8˅8ʄ7˅8̅8̆8ʄ6ˈ<޽Ǵ˨Ԫ{ܴQ2pJl-Ł6̅7˅9˅8̆9ˆ8ˆ7̃6ʁ2{+ri˅8˅8˅8˅8̆9˅8ʄ7˅8ʆ8̆8̆7ʄ7ʅ8˅8˅7ʄ7˅8˅8ʅ8ʄ8̆7ʃ7ƆAȯS6\<X%u1ȃ6ˆ7ʄ7ʅ8ʄ7ʅ7˅7̃6˂4|-rjʄ7ʄ7ʄ7ʅ7˅7̅7˅8ˆ8̆8ˆ8ˆ7˅7ʆ8ˆ7ˆ8ʆ7ˆ7ʆ7ˆ8̆8ʆ8ʆ8Ɓ5x4}ˍ{gI, Z:}Q"l.4ʅ7ˆ7ʆ7ʆ7ʆ7ˆ8ˆ7ʄ5˂3}/t!k ˅7˅7˅7˅7˅7˅7˄7˅7̆8˅7ˆ7̆7ˆ7˅6̆7ˆ7̆7˅7̅7̅7˅7˅7̄8Ā4m'\$e?z_jmUjP5L. T3gDU#l,|3Ʉ6̄7̄6˅6˅6˅6˅7˅7˄5ˁ3~/v#m̄6̄6̄6̄6̅6̅6̄6̅6̅7̄6̅6̄6̈́6̃5̄6̄6̄6̄6̄6̄6̄6̄6̄6ʄ5Ɓ4v.e#U|JuGvJ~Q Z$e)s/}3Ƀ5̄6̄6˅7̄6̄6̄6̄6̄6̃5ˁ3/x&n˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˄6˄5˃5̄6̄6˃5˃5˃5˄6˅6ʃ3ʀ/͊CϚ`͠oȞqjWv7o&|2ǁ4˃6̈́6˅6ͅ6˄6˃5˃5˃5˃5̄6̄6˂4ɀ0y(p̄6̄6̄6̄6̄6̄6̄6̄6̄6̄6̄6˃5˃5̃6̃6˃5̄6̄6˃5̄6̃6˄6ʃ3Ί@ṍѺЩ}x2|/Ƀ5̄6˄6˄6̃5˄6̄6̄6˃5˃5˃5˂4ʁ1z*q̄6̄6̄6̄6̄6̄6̄6̄6̄6̄6˃5̄6̄6˃5̄6̄6˃5˃5̄6̄6̄6˃4ύE־Լs6w/ǁ4˃5˃6̃5̄6̄6̄6˃5˃5˃5̃5ʁ2{,r̄6̄6̄6̄6̄6̄6̄6̄6̄6̄6˃5̄6̄6̃5̃6˄6̄6̄6˄5̃5˃5͈<ǣ֡|waIoW>}fP^$w1Ȃ5˄5˃5̄6̄6˃5̄6̄6̄6̃5˂2}-t̄6̄6̄6̄6˄6˄6˄6̄6̄6̄6˃5̄6̄6˄6˄6̃6̄6˄5̃6˅6̓6ғPȺiL+S8Z:iDtL{R%a:΍kEb%|2˃5̅7˄6˄6˄6̄6̄6˃5˃5ʁ3~.v"ʃ5ʃ5ʃ5˃5̓5̃5̓5˃5ʃ5ʂ4̄6˃5ʂ4˃5̃5ʃ5˃5ʃ5˃5̃5ʄ6߲}_AQ2hCX$g*n,o-j)Q|dyJp.ǁ3˃5̃5̓5̃5˃5ʃ5˃5˃5ʁ3/w$΃5̓5͂4̃5˃5̃5̃5˂4˃5˃5̄6̃5˃5˂4̃5ʂ4ʂ4˃5ʃ5̂4̅7ǥĸV2 b?\%s/~3ǀ4ǁ42ÇFwe=g(~3˂4ʂ5̓5̃5˃5̃5ʃ5˃5ʂ2.y&̂4̃5̓5̓5̄6̈́6̈́6˃5˂4̃5˃5˂4̂4˃5˃5ʂ4ʂ4˃5̈́5̃4̈́7ɨQ. vKl+3̓5̄5̈́5̃4ЎG{[7`&{1˃4˂5˂5˂5˂5̂5˃5ʂ4˂2ɀ0z&ʂ5˃5ʂ4˃5̃5̄5˃5˃5˃5˂4ʂ4ʃ5ʃ5ʃ5ʃ4˂5˃5ʂ4̓5ʃ5̅7⻑fH'yMr.Ɂ3̄4̓5˃3˂3ӕQn[8]&y1˂4̃5̃5̃5̃5˃5˂5̂4̃4ʀ1z)ʃ4ʃ4˃4ʃ4˃4˄4ʄ4˄5˃5˃5ʃ4˄4˄4˄4˃4˂5˂5ʂ5˃4˃4ʃ4Ӟ`wLg#}.Ɂ0ȁ0ɀ.̇;㾖߁iM];`&{1˃4ʄ4ʄ4ʄ4ʄ4ʃ4˃4ɂ3˂3ʀ1{*˄3˄3˄3˃4ʃ4ʃ4˃4ʃ3˄4˄4ʄ3˃4˃4˃4˃4ʃ4ʃ4˃4ʄ5̃5ʃ4̈<麨bMʏLϕT٩sʧõ]?hBf(}1ʂ4˄3˄3˄3˃4˃4˃4ʂ3˃2ˀ1|+˃4˃4˃4˃4˂5˂5˂5˃4ʃ4ʃ4˃4˂5˂5˂5ʃ4˄4˃3ʃ3ʄ4˄5ʃ4ʃ5͛at[@S3|P p-ŀ3ʃ4˃4˃4˃4˃4˃5ʃ4˃4ʃ3ˁ2~-˂5˂5˂5˂5˃4˃5˃4˂5˂5˂5˂5˃4˃5ʂ4˃5̄4̃4˃4˃4˄5˄5ʃ33’\̺mU;P1kEc&z/ɂ4ʄ4˂5˂5˂5˂5˂4˂5˃5ʂ4ʁ2/˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5ʁ2|){'ʁ1˄4ʃ4˃4˄4ʂ4z0u9}TxqnX>[@$U6lG^%t.ƀ3ʂ4ʄ5˂4˃5˃5˃5˃5˃5ʃ5ʂ3˂20˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˂5˂5˂5ʀ1ӘWHy,~0ɀ1ʁ2ʁ2ǀ0y-l)^&~T%rL$iFeBd@pGTe%v-ŀ2ʃ3˃4˃5ʂ5˃5˃5˃5˃5˃5˃5ʂ5̂30˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃4˄3˃4Ɂ/՚ZnUŒ[ϙ^К^љ_К^К]˗\ÑZXVSSUVYɕ]LjE~0ǀ3ʂ3˃4ʂ5˃5˃5˃5˃5˃5˂5ʂ4̄4ʁ1˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃4˄3˄4Ɂ0՛Z̭i#y0Ɓ3ʃ4˂5˃5˃5˃5˃5˃5˃5ʂ4˄4ʁ1˂5˂4˃4˂5˂5˂5˂5˂5˃4˃5˃4ʄ3˄4ʁ0ԙYyzLj*|2ʂ4˃4˃5˃5˃5˃5˃5˃5ʂ4ʃ3ʁ1˃4ʃ5˂5˃4˃4˃4˃4˃4˂5˃5˃4˃3ʃ3ʂ2ΌBҢmum~h}h~ii}h}i~ihi~iiiiiiimqX;kDd'{1ʂ4˃5˃5˃5˃5˃5˃5˂5ʃ4˃4˂2ʃ3˃5˃4˃4˄3˄3˄3˃4˂5˃5˂4˃3ʃ4ʂ4ʂ3z,h$SrGoEoEpEpEnDnBoCoDpEpEoEoEoEoFpEoDuKY#m+~2ʂ4˃5˃5˃5˃5˃5˃5ʂ5˃4ʃ4̃3ʂ4˃5˄4˄3˃4˄4˄3˃4˂5˃5˂4ʃ3˃4˃5˃4ȁ3|1u.q-p-p,p-o*p+IPs4l'o,p-p,p.o+i"h!n(t.|1ȁ3ʂ5ʃ4˃5˃5˃5˃5˃5˂5˃4ʃ3˂2˃4ʃ5ʃ4˃4˄3˄3˄3˃4˂5˂5˂4˃4˃4ʃ5˃4ʃ4ɂ3ȁ3ǁ4ȁ4ȁ3Ȁ3̍HǦӺĕ`v/}0Ɓ3ǀ2̍GƣáɒWy-2Ɂ3ʃ4˂5˂5˂5˂5˃4˃5˂5˃4ʃ4̃3ʄ3˄4˄4ʃ4˃4˃4˄4˃4˃5˃5˃5˄4˃4˃4ʄ4˃4˃4˃5˃4˃5˄3̈;ѳxHo+|1ʀ2ҖSŸze"w/ŀ2ʃ3˃4˃4˃4˃4˂5˃5˂5ʃ4˃4ʃ4ʃ3˄4˄4ʃ4˃4˃5˃4˃4˄4˄4˄4˃3˄3˄3˃4˄4˃4ʃ5̃4ʃ5˄4֜]ļȹU#n,~2ЏG}vHh)}1˃4ʄ3˄3˄3˃4˂5˃5˂5˃4˃3ʃ4ʃ3ʃ3ʃ3˄3˄4˃5˂5˃4˃4˃4ʃ4˄3˄4˄3˄4˄4˃4˃5ʄ5˃5̄6߸wZ:L0qQ/Z#u-͍E}]9_&z1˂4ʄ3˄4˄3˃4˂5˃5˂5˃4˄4ʃ3˄4˄4ʃ3˃4˂5˃5˄4˃4˃5ʃ5˃4ʄ3˄4˃3˄4˄4˃4ʃ5̄5̃5˄7ʨöQ0 ]:kCpGj)ɋFr[7\%y1ʂ4ʄ3˄3˄3˃4˂5˃5˂5˃5˃4ʃ3ʂ5ʂ5˂5˂5˃4˂4˂5˂5˂4˂5ʃ4˄3˄4˄3˃4˂5˂5ʂ5˂4̃4ʆ6ɨP-tL_ηkL)]$œZy`^9^%{/ʂ4˂5˂5˂5˂5˃4˃5˃5˂4˃5ʂ4˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃4˄3˄4˄3˃4˂5˃5ʂ4ʃ4ʄ4˄6㾕ɾ\<~Qp(Ϟf۷qV8b>b&}1ʃ4ʂ5˃5˃5˃5˃5˃5˃5˃5ʂ4˃5˂5˂5˂5˂5˃4˃5˃4˂5˂5˂5˃4˄3˄3˄3˃4˂5ʂ4˂5˃4˄4ʄ6ڬyķoQ/|Os.x'˯zQ2pHj+~1˃4ʂ5˃5˃5˃5˃5˃5˃4˂5˂5˃4˃4˃4˃4˃4˂5˃5˂5˃4˃4˃4˃4˃4˃4˃4˃4˂5˃5˂5ʃ4ʃ5˃3ˊBYsHtO'W"t-ǁ2|3ؿʟT8];X#t.ƀ3ʃ4˃5ʂ4˃5˃5˃5˃5˂5˃4˃4˂5˄3˄3˄3˃4˂5˃5˂5˃4˄3˄3˄3˂5˂5˂5˂5˃4˃5˃4˂5˂4ʂ5Ȁ1w*f&`&i)y/Ɂ31o&wDwTnQ1R2b>T"l+}1ʂ4˃4ʂ4˃5ʂ4˃5˃5ʂ4˂5˃4ʃ4˃4˄4˄4˄3˃4˂5˃5˂5˃4˄3˄4˃4˂5˃5˃5˃5˃5˃5ʂ4˃5˃5ʂ4Ɂ3Ɓ2|1y0{0ŀ2ʂ4ʂ4Ā1s+a#X Y"`%o,{1Ɂ3ʃ4˂4ʂ4˃5˃5ʂ4ʂ4˃5ʂ4ʂ5˃4˄3˄3˄3˄3˃4˂5˃5˂5ʃ4ʃ3˄3˄3˂5˃5˃5˃5˃5˃5˃5ʂ4ʂ5ʂ5ʁ4˃4ʂ4ɂ4Ƀ3ʃ4ʃ4˃4ʂ4Ɓ3}1x/w.z02ʁ4˂5ʃ3ʂ4˃5ʂ4˃5ʂ4ʂ4ʂ4ʂ4ʃ4˃4˃4˃4˃4˃4˃4˂5˃5ʂ5˄4˄4ʃ4˃4˂5˃5˃5˃5˃5˃5˂5ʃ4ʃ4ʃ4ʃ4˃5˃5˃5˃4˃4˃4ʃ4˃5ʃ4ʂ4ʂ4ʂ4ʂ4ʂ4˃4˃5˂4˃5˃4˃5ʂ4˃5˃5ʂ4ʂ5˃4ʃ4˃4˂5˂5˂5˂5˃4˃5ʂ5˃4˄3ʂ5˂5˃4˃5˃5˃5˃5˃5ʂ5˃4˄3˄3˃4ʂ5˃5˂4˂5˂5˂5˂5ʃ4˃5˃5˃5˃5˃5˃5ʃ5ʂ4ʃ5˃5˃5˃5˃5˃5ʂ4Ɂ3ʂ4˃4˄3˄3˃5˃5˃5˃5˃5˃5˂5ʃ4ʂ5˃4˃4˂5˃5˃5˃5˃5˃5˂5˃4˄3˄3˃4˂5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5ʂ4ʂ4ʂ5˃4˄3˄4nut-2.8.3/scripts/Windows/Installer/ImageFiles/Images/NUT_wix_horizontal.bmp0000644000200500020050000024760614777534446024101 00000000000000BMO6(:PO  Ӛ/ҔђҒЎЍ͉͊ύύύό͉͈͊̈ψ͆˃˃˃ʃȃɃȁȀǁǁɀɁǀɀƁĀ|xrnnjklruz…Ɖ͍ϒғі&ӗ1֙9ԛ;ԛ@֝CמG؟KؠOڢQڣUڣY٢Yۥ\ۥ^٥`ڦbڦeۨiޫmܪnܪo۫qݯuݮvݮvޭuܯv߯wݮwܭwܭwܭwܭxݬvۭvܫxܬvܬw۬vګuܭwܭwݮx۬v۬vݫvܬv۬v۬uݬw۪rۥg١ZԛKԘDҖ9ϒ0В(Б#΍ ͌̌ˉɇɇȆȅǂ|{zz{yyvsrprqonlnlmlkljhggfeecb\ZYWTPPPPPPPPOONL LLJIHGIHIGGFGFEFEEGEDEDFFFHGFEEDFFFFDFFFHHIKP SUWUTR Q R S S R S T ST SNJGFGGHHH II I KJ K K J L M K N N N P Q Q R U V X X Y Y V W W X YZZ[[[[[\\\[[\\\\\[\\]]\\\^]]^^_^`_aaaccdeeghhjk m moqpssu!w#x$y%y(z({*|+~.~/~//0ʁ1ɀ0ʁ1ʁ1˂2̃3˂2̃3ʂ3ʃ3ɂ2ʃ3Ɂ3ʂ4ʂ4ʂ4˃5˃4˄3˃4ʃ4˄4˄4˄4˄3ʂ4ʂ4˃5ʁ3˃2̃3ʂ3̂3ʂ3ʃ3˂2̃3˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3Җ!ѓёё΋͈̉΋Ўύύό͋΋͉ˈ̅˃˃̄ͅʂȃɃȁȀǀǀɀʁƀ~~ztnzA¥lǦĞæg:~{ˆˎ%ϕ2Ә5Ԛ:՚>לA՜G֞KסNנOآTۤYؤZڥ[ڥ\ڥ_ڥbۧdݩiۨkܪn۪oݬqޭuܭuݮvޯw߭xݯy߭vܭwݮyݭyܭwܭx۬uۭvܫx۫uܬxܭw۬vݮxܭwܮxۭw۬vݪuܪuݫwެwګtڨkס[ԜMԘFԘ:ђ.ӓ.ђ$͍ˌ͌ˊˈȆɆȆDŽƁ~zyz|zxusrqrqonmlnlmmlkiggffecb_YZWTQOPPPOOOOPMKKKJHHKHIHHHGFEDEFFEDEEFDFFGGFDEDDFFEFEFHGIKOSUVUVRQ R R R S S R TTS NIEFFFGGHHH II I KJ K J L L L L N O N Q SV X X X X X W X X Y Y[[ZZ[[[[[[\\[[[[\[[\\]\]]]]_``a`abbbcefhijj lmoorsu!v"x%x'y){*|,},~,--1001ʁ1ʁ1ʁ1˂2˂3ʃ3ʃ3ʃ3˃3ʂ3ʂ3ɂ3ʃ4ʃ4˄4ʃ3ʃ4Ɂ3˃5˃5ʂ4˃5˃4˄3˃4ʃ4˄4˄4˄4ʄ3ʂ4˃5˃5ʁ3̃2̃3ʂ3˂3ʂ3ʃ3˂2̃3˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ВБϏύ͊ˊ̌ЎЎΌΊ͊΋͉͊ˇ͆̃̄̄ͅ˃ȂȂǀɁʂȂȁƀ~xqz¤iƺ\60Ɛ7ϙ@՛B՝FןMןM٢R٣W٣\أ\٥_ڧ`٥`ڦ`ڦcۧhܩkݪl۪lܫq߭v߮vݮvޮw߮tܮu߰yݮwܭwܭyܫzޮzݭyݪuۭw۫uܫrݫu۬wݮxܭwܭwܬvݪvݫvެxۭwܭxܫu۩oأd՞QӚHј:ҕ8ϑ1͐(ΐ̍̋ˊˊȅɇȇDŽŁ|{|zyxusrsrrpnmmnllllihgfgheea^ZWWVPOPOOOPPPNO JJKIIGHHIGGHGFEEEEEDCEFEDEEHGEC~CDEEFEFEFHJHMQ TTUSRP R R P Q R R T S S PIEDEFEGFGG G H H IJKKK K L L M O N Q T W W XXWV U W X Y YZ[Z[ZYZYZZ[[\[[[\\]^[]]^]^a`_`abbcefhijk mnprt u!y#y&y(z+{-},},~-0ɀ0ʁ1˂2ʀ2ʀ3ʁ1˂2̃3˂2˂2̃3ʃ3ʂ4ɂ2Ɂ3ʃ4ʃ3ʃ3ɂ3ȁ2ʄ3ʄ3˄4ʄ3ʃ4˄4˄4˄4˃5˃5ʂ4ʂ4ʃ4˃4˂5ʃ4ʃ3˄4˄4ʄ3˄3ʂ4˃5ʂ5ˁ4ʂ3˂3̂2̄4ʃ3ɂ2˃3̃3̂3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ғϐύ΋Ή΋ЎЎύ΋΋͊Ί̈ˇʆʅɄʆʆɅȂʁʂʁɀǁ~ypv ׹ӿDAʔEҜI֟N؟PڢQؤYؤ\أZ٥]ڥaۦcۧd۩h۩jݫoݬpݪqޭsޮuޮvݮwܭwܮx߮v߯|ޯ{ްzݮxޮyܭwݮyۭuݫvܫvۭwܫvݭyޭzܭw۬v۫wܬvݫuݬtګuݪwܪpڦiןUӛJәEә9Д0ϒ-Ғ+͏̌̋ʉɇɈɆɅƃƀ{{}{{ywusqrrponmnllmliifefgdca]ZYXTPPPOPPPPOOL LJJIHGIIHGHGGFEEEDFEDEGEDEGFFDDCDCDDFFEGHHKNSUUWTP P Q R Q Q Q R S T OJEDDDFFGFEGH G II IJJJ LM M O N Q T U VW W W V V W YYXXZYXXZ Z[Z[[[[[[Z\\\\\^]]^`aabbdefgikk npotu v"x'y({*|-|-}.~/1ˁ2˂31ʀ2ʀ2ʀ3̂4̂4˂5˃5ʂ4ʂ4Ɂ3͂4ʀ2ȁ3ȁ1˂4˃5ʂ4˃5ʂ4Ɂ3˃5˃5˃5ʂ5˂5ʂ5˂5˃5ʂ5˂5˂5˃5ʂ4˃5ʂ4ʂ4ʂ4ʂ4˂5˂5ʂ4ʂ4˂5˂5˄3ʄ3ʃ3ʃ2̃2̃2̃3˂2̂2̃3̃3˂2˃2̃2ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ϑЎ͉͊ύЎяяό͊ό͈͈͊̈̃ͅʅʅɄɅ˂ʂǁǂǂ|suٶǢCHΙOסTڣZ٣\٥^ؤ]٦_ۦcۦfݨjݩlݫm۩mܪoܪtܮuޯxްzޯvܭuګsޯyޮz߱{ޯ{ܬxޭzݮxޭzܭwܭw۬uܮxܮwܬxޮzݮxڬvܬtޭu۬w۬vܭw۪uڧjء^֝OԙFӘAє5ϓ.ϑ%ΑΎˋˊˊɇʈȅƂŁ}y|{|yxsrrsrppnnlnllljhhghgfca]XYWTPQOPQQPOPNK KJJJGHJIHGHFFFCCEFDCDDDCDEFFDBBCDDDEFEEGIJNP TVVSRO O Q R Q R S Q S QJDDEDFDFEEEFHG G IIJIJL L MOQ S V WW V V V V X YYXXZZXXZ Y [[[[[\[[\\]\]]`___abaefghjk noosu"v%x)y*z,|-~/~01ʀ2ʁ3ˁ3̂4˂4́3ʂ4˃5˃5ˁ3ʃ5˃5ɂ4˃5̄6ʂ4˃5ʂ4ʃ5̂4ʂ4ʂ3˄4ʃ4˃5ʂ4˃5ʂ4ʂ4˃5ʂ4˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5ʂ4˃5Ɂ3˃5ʂ4ʂ4ʂ4ʂ4˃5˂5˄3˄4ʄ4̂2̃3̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3Ў΋΋Όяяяύό͊͊͊̈ʆˇ̃̈́ʇˆɄɃǁǀǁȂ~xfտƩzH˙UԠZ٣\٦`ڦ_ۦcۧeܨgܩl۩mݫoݫqܪrܭw߰z߰xݯxݭuޯw߰{ްzݯy߱z}ݮzݬyܭwݭx۬vݪv۬vޯyܬyܭxݭyܬw۬wܭv۬wݭyܬx۬x۩pעa֟T՚IӘ@ӕ:Ҕ4Б.ϒ%͎ˍˊˊɇȇȅDŽƁ|}|}zyvrrqsrpnomnmlkjhihfgdca]Z[WTOOPNOPOPPNL K KJHHHHIHGHHFDBBDEEEDDEDEEFFDCDDDCEDEDEGGJO RUUVRP R Q Q P Q S Q R S LFDDDDCDEFEFFFFH H GH JLMLNRSV XW W U U U W XXYYYYYYXX[Y[[[[Z[[[\\]]_``aceegiil onrt u$x)z*{,~/1ʀ2ʀ2ˁ3ˁ3ˁ3̂4̂4̂4˃4˃5̄6˃5˃5̄6ʆ7̃5̄6˃5˃5˃5̄6̄6˃5ʂ4˃5˃5ʃ5˂5ʄ3̅5ʂ4˃5ʂ4˃5ʂ4˃5˃5ʂ4˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5ʂ4˃5˃5˃5ʂ4˃5ʂ4ʂ4ʂ4˃5˂5˄3˄4˄4˃3˂2̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ό͊΋ύЎяύ΋΋΋Ί̈ˆʇˆˈʆˇɄɃȁȂǁǀ}ur۸퐳6xVl@q7w8s4v5u4w4t8yCWЬLƖWա^٦dܧeڦdۧiܩkݪmݫqݭsݭs۬wܭu߰zްyݮxzzݮ{߰{߰{ݮzޯ{߰|ݭzݮxެwݬu۬w۬vݯyޯyܬxݮxܬvݬw۬wޮzݮyޯyکqڥg՞WӛJ՘EӖ;Г4Б-ϒ)ΑΏ ͌ɉʉɈɆDŽł}}||zxvsrsrqqnlmnmmllihhhfeca^[ZXTPOQPPPPPPNM LKIIHGHHGHHFFEEDECDDFECCCGGDBCBBBCCEEFFGILQTTTUP P P Q P PR R R Q LFDBBBCEEFDFFGGFFIHHJLKLQT V W W W T V V W XXYYYYXXYXZZZ[Z[[Z\\\\]__`bbdfijl oqsw!y&z*|,~/1ɀ2ˁ2ʂ4˃5ʄ5˃6ʄ7ʄ7ʃ6ͅ8̄7Ƀ6˅7ʄ7̆7̆7̆7˅6̇7˅8̅7̄6˃5ͅ7˃5̄6ʂ4̄6ʃ5̃5̂4̃5ʃ4ʃ3˃5ʂ4ʂ4˃5˃5˃5ʂ4˃5ʂ4˃5ʂ4˃5˃5˃5˃5˃5˃5˃5˃5˃5ʂ4ʂ4ʂ4Ɂ3ʂ4ʂ4˃5˃5ʂ4ʂ4˂5˄4ʃ3˄4˃3˂2̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3΋όύϏЎύЎΌΊ͉̈̇̈́ˆʆˇˈ̅ʃʃȃɃĀ}sLuG3v2v5w:|YsXuO~HGA<{2v6v2v1uIڳ[ė[աeۧeۨhܩkܪnݫqܫqܬrܮuݮvݮxްy߰z߰|߰{ް{|߰}߰|}ݮ{ݭzݮzܭw۬vܭvݭyޮzݭyޯyݭyޯy۬vܭwܬyޯyܬxڪsڦmء`ןTәDԗ@ѕ4Д3ϑ/Α$͍̍ˊɈɇɇȅłǁ}{~~zywtssrqpnnmmmmlkihhhhfda][XVSOOPPQPPPNMM KLIGGIHHGIGGFCCDDDCDCCCDEGDEB~B~CDCCCEFFGIKN SUTTPO P Q P Q Q S P R NFC~CCCBBCDDDDFFEFGFIJLLNQ S VV U T T U U WXXWXWX X X YYYZZZ[Y[\\\[^__aadefil mpsv#x'z,|-}1Ɂ3˂5˃5̈́7˅8˅8˄9˅8̅9Ά9̃;̆9˅8˅8˅8̆8˅8̆9͇9̆9ˆ8˅8ʅ7˅8ʅ7˅7˃5̄6˃5˃5̄6ͅ7̄6ʂ4˂4˃5̓5ʃ4˄4ʃ3ʂ4˃5˃5ʂ4˃5ʂ4ʂ4˃5ʂ4ʂ4˃5ʂ4˂5˃4˃4˃4˃4˂5˃5ʂ4ʂ4˃5˃5ʂ4ʂ4˃5ʂ4ʂ4˃5ʂ5˃5ʂ3˄4˃3˂2̃3̃3̃3̃3̃3̃3̃3˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3΋όЎяЎό͊΋΋͈̈ʆ̄ˇˇ̈ˇɅȂɃʃŁ~rŤbնZ2r3w5y;|=}>{?|]k[qa`|\wYpPIC8|6w3v/tP߹߷fș_Ԥgۧj۩mܬp۫q۫qޭuޯyްzްyޯzޯz߰|ޯ{߰|߰|߰|߰|߰|ݮzޮzܭyݮxܭvݭvޮzݭyݭyݮxޮzݮxܭxޮzݭzݭyܭx۩pأ^֝QԛJԗ>ҕ8Д6ϒ1ϑ&АʌˊʉʉʈȅƂ}||~|ywrrrrqqnmnnnlmljhhgffd`^ZZWQOPPPQRQOOM LJKIHGIGHHHGHFDDCCCCCDDCDFFDDBBC~BBBBDEFFHLQUUTRQ PQ OP P R R R OIC}B~B~C~C~BBCDCDDDEFGGHHIJMQS V V U U T S V V W XX V V W XXYXYYZYY[[[\]]^_acegglnpsv"x(|,|/2˂6ˁ7˄9ͅ:ʆ:ˇ;ˆ:̇;͇=̇<̇<̇9̇:̈:̈=͇:̆9̆9̆9̆9̆9̆9̆9˅8̆9˅8˅8˄8ˆ7˅6˃5˃5˃5̄6˃5˃5˄6̂4˂4ʃ5̓5ʃ4˄4ʄ3˃4ʂ4˃5˃5˃5ʂ4ʂ4˃5˃5˃5ʂ4˃5ʂ4˄3˄4˄4˄3˂5˃5˃5˃5ʂ4˃5˃5ʂ4˃5˃5˃5ʂ4˃5ʂ4ʂ4˄3˃3˂2̃3̃3̃3̃3̃3̃3̃3˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ώЎЎύύ΋΋΋͊̈ˇˇʇ̈ˇʇʆʂȂʃȂ~uX߶]/s:vIuUpMt<~H{HJMNRXuuqcwa}YB9y6x5x,s޹ܴ߱fƘcԥlܩlݫqݭtݮuޯyޯ{ޯ{߯|߰|ް|߰|߰|}߰|ޯ{ޯ{ܭyݮzݮyݭyݮyݮyޯz߯{߯{ݭyޭzݭyܮwݭyݭyޮzܬx۪uڦf֞XԚLҘGԖ>ҕ7ϓ1Б1Ώ͎̋ˉˊɇȆȅƀ~|}~|{xtrsrsrpnnmmmlkjihhgfea]ZYWROPQQQQPQPNLLJKGGHIHFFHFDDDECDCDCCBEFFDBCBCCBCCDDFGJO TTTSRN O P Q P O P Q QJC~A}A|A}B}C}B~CABDDDDDEFFHIIMQR T U U S ST V WYXXW X V XXYXYYXYZZ[\[]__aceeij oqt"w&|+}0ɀ2ˁ6ʄ8ˆ:ˆ;͇=̇<͈=͈=Ί?͉>͉>͉>͉>͉>͉=̈<͉=Έ<͈;ʇ:͈;͇:̆9˅8̆9̆9͇:̆9˅8˅8˅8˅8ʅ6˅7˃5̄6̄6˃5̄6̄6˄6͂4̓5ʂ4̓5ʃ4˄4˄3˃4˃5ʂ4ʂ4˃5˃5˃5ʂ4ʂ4ʂ4˃5ʂ4˂5ʄ3˄4˄4˄3˂5˃5˃5˃5ʂ4ʂ4˃5˃5˃5ʂ4˃5ʂ4˃5Ɂ3˂5˄4ʂ2̃3̃3̃3̃3̃3̃3̃3̃3̃3˂2ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3яЎяύύύ΋Ί̈ˇˇˇˈˇʆʅʅʂɃȂ€s=ܴڴ߹NJ*p5yEuHxYlKuRwW{XuKPPPPRU|dxn|l]P;}:y5z.s߹ݵ۱޲aɜh٨mܫsܮvޯxޯyݮzޯ{߰|߰|߯{߰|߰|߰|~ް}ޯ{ݮzޮzޮy۬xܭyݭ{ݮ{߯{ݮzݮzݭyݭzݭyݬyݬyܭyܪvڨkؠZԜN՘EԖ@Ҕ6є6Г.ϑ"͎ΌˊɊˊɇȆǁ~~~~yxtrrssromlnmmlliijhffea][YWROPQSSPPQOL JLJHHHHHGEGHEECEECDBDDBCDFEBB~AB~ABCCCFFGILRSTTQN OP Q Q Q P Q P KD|A}A}A}A|A}BB~BCBDDDDCFGGHJLPRU T T R QS V W WWV W W X XYXYXYXYZZZ^\]_`ccfilnrv!z+|/4˂7ʄ:̆<͇>·?Ή@Ή@͉@͉@͉@ΊA͊?όA΋@͉>΋@ϋ@Ί?͉=͉>͈=·=̇:ˇ:͈;̆9̆9̆9˅8̆9˅8̆9̆9˅8˅8ʄ8ˆ7˅6˃5˃5˃5̄6˃5˃5˄6̂4˂4ʃ5̓5ʃ4˄4ʄ3˃4˃5ʂ4˃5˃5ʂ4ʂ4˃5˃5˃5ʂ4˃5ʂ4˄3˄4˄4˄3˂5˃5˃5˃5˃5ʂ4ʂ4ʂ4ʂ4˃5ʂ4˃5ʂ4˃5ʂ4˄4ʂ2̃3̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3яяύύ΋ό͊Ή̇̇ˆ̇ʆ̈ˆʅɃȂʃŀx}#޲ܮݵM4w>yOqYnDMTNYv`t]Z\Ybt\bh]X|֣鍶hWB;z7y.t߸ߴܯ٪ۭ`ϣmݭsܮwޯz߱|߰|}߰|߰|߯{|ޯ{߰|}ᲁޯ{ޮzݮzޮzޮz߯{ޮzޯ{ޯ{ޯ{ܭyݮzݮzܬyݬzݬy۬xۨqآ`՞TӜK՘Bҕ8Ҕ7Г3ё+Ύ͍ ˊ̋ˊɇȅǃ~}~~}{xtsrrrqpnomnnmljiihgeca]\[XQPRPQSQPONL LJKHHHHHHGGFDDEEDDCCCBBCEDD~C}?~@AA~ABACDEHKP TUTRP N P O O O P P Q ME|A|A{A{A{@}A}A}A~CCCCCDEDEHGHKNRS U T SRS U VX V W V V X XXWXXXYXYZ[\]\`cehjmos x&{.~2ʂ8˅<ˇ>͉@ΉA͊B΋C΍C΍D΍DЌCϋBЌCЌCϋBό@΋@όA͊?Ί@΋@͊?͉<͈>·=·>ˈ9ˇ:·;̆9̆9˅8̇9̆9̆9̅8̅8˅7˄7ʅ8ʆ6˅7˄5˄6˃5̄6̄6ͅ7̄6˂4˂4˃5̂4˃4ʃ3ʃ3ʂ4ʂ4˂5˂5ʂ4ʃ5ʂ4ʃ4ʂ4˃4˃4˃4ʃ4˄3˃4˃4˃4ʂ4˂5ʃ4˃4ʃ4˃5ʂ4ʂ4˃5˃5˃5˃5˃5ʂ4ʂ4ʃ3˃3˂2̃3̃3̃3˃3˃3̃3̃3̂3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3яЎЎЎύ΋̈̈ˇˇˇˈˇ̈͆ʄɄȃŁ}n ۮڧۯݳݸڸ9w5x<|?}DYrV}_tZ}]Z_}[bfwcraudpa`[[ZǜaB>|6y+sŹ߹ܵܭڭ٨Ŕbէsݭx߯{ޯ{߰|}}߰|}Ⳁ߰}߰}߰|ޯ{ݮzޮzޮ{ޯ{ݮzޯ{ݮ|ݮ{ݮ{ݭyޮ{ݮ{ݮ{ݭzܬv٤f֟XԜNӚDі<ӗ7ҕ8Г.ΐ̌ˊɉʉɈȅɂŁ~}}zursrrrppmpnnmlijhhgeca][ZWSQPQQQRRRNL KKLJHHHHGFFFDBFDDDDDCBCCDEC~A|A~ABBBBDBDGHLRSTTQN O N O O O P RNH~B{@{@{@{@{@|@{A}@}AD~D~D}CCCEGHGIOQU R Q PPS T V W WV W V W W X W YXXXYYZZ[]`aefglpt!w*z.4Ƀ:˅@̇AϊDϋF͋EЎGώGΎGЎGЎGΎGύFώEьCэDϋBϋBϋAϋAό@΋@Ί?Ί?Ί?̊?̈=̈=Έ=̈=Έ:͇:͇9̆9˅8͆7˅9˅8ˆ8̆9ʅ6ˆ7̆8̅7̈́6̈́6̄6˃5˃5̄6˃5̅7ʃ4˃5ʄ3ʂ5ʂ4ʂ5ʁ3ʃ4ʃ4˃4ʃ4̓4ʂ4̃5ʂ4ʂ4Ɂ3ʃ4ʂ4Ƀ4ʃ3˃4˂4Ɂ3ʂ4ʂ4ʃ3ʃ4ʃ4̃4˂3˃4ʂ4˃5˃5˃5˃5˃5˂5ʄ4˂2̃3̃3̃3˃3̃3̃3˃3̃3̂3˂3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3яύύЎΌ͉̈ˇˇ͉ˇˇ̈ˇ˃ɂɄȃ~qæeΠӤի֯ܵ:g-V}7k>zM~_iX}_p^u^y^`mbd~cjduccadff_mbWۼj@z@z5x9xڵ׮ح֬Ҥ͟wÜn٪z߯~ݱ~᱁߰|ޯ{~᳀ޱ~ೀ߲~ޯ{ܭyܭyݮzݮzޯ{ޯ{߰|ݮzܭzݭzݮzݭy߯{ݮyݭ{ګuۨmס]՝MԘHӘ;ԗ=ҕ8Г4ΐ"ϐ͋ LJ|~~~~|yupkhhijnpmmmmjec`_^__]][[VRPOLLKLLNMN JH DABDEHHED@y?z?z@BBCCCCBCCC{?u<p;p:s<w>{@}?BDEFGGJ NOQQO N O O M L J JM KBw=x@x=u>q;p9s;v={@~B~B~C~C~DDDFGFILPO N K IJN P T UUV W V W W VSQQSWZYZ[]_adfhmns!x(y/y1z6z:{??AĆBɊG͍IЏJώIώIώIϐIАIϏHώGяHϏDώD͍BϋBϋBϊBϋAΉ@ʈ?Ä<~:9À9Ʌ<͉>ˇ:ˈ;̈;˅8˄:ƃ86|6y3{4|5~5ǂ5Ȅ7ʄ7̄7˄6̈́5˄6̄6̃6̄5ʂ63|2x0v0w0z0|12ʂ4ʂ4ʂ4ʂ4ȁ32{0y0|1ƀ3Ɂ3ǁ3~1z1x/w1y0z/{0~1ȁ3ʂ4ʂ4ʁ4ʂ4˃5˃5˃5˃5˃5˂5˄4ʂ2̃3̃3̃3̃3̃3̃3̃3Ƀ3˂3̂3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ЎЎЎύ͉̈̈ˇ̈̈̈̈ʅɅʃɃɃȃ{z,?x""'$(49VEmL[ObXrXOiOTNWThfbmcrboZbReVtdf]QdS|YzQzӝ▩Ċ\6e:h1rEuͽɛqWj۬|}߰}}㳀߲ᴁᴀ߱ఀޯ{ݮzޯ|ݮ{߰|ޯ|߰~ݮ}ޯ|ݮzޯ{ݮz߯{ݭ{ܮ{ݭzܩoآ^֞S֚Mӗ=Җ@ӕ9є5ϑ'Ϗ͍ Ɋndepy~~{zxodZSOT^honnkd^UPLIJLNU[[VRQOID|?t;x<BHJ K GAm9f4g4p:~AEHDz=h5`1`1e5q;|@CDBCCBx>p:c4[/Y.Y.]1d5m9w>BDDHH FABFLNOM O O M G z?u= p<q:w>x?w>r:h7]0Z.b3q<z@}A|A}A~BDDEFHLN M H B v= p; p: s= |AEIN R U V W WWSJBCKT[\_`cfgko sx&|0}6{:q;l8g8f6f7h8l9qc1T+K'T*d2{? I JCj7Q* A C! U+ o:CG~Al7S+C" < G&]1u=BBBCBt<a3P)E$ F&U-f4u=CIN L~@a1[-o9E M P O O P Kz> S* D# T-i9u<y>o;c3P) B! B" V. j7v={@|ACCEEGKOO I y> c3 U.O)N'M(N*P)[0h7|@JPUV WVM{?`2_0|?Q^aegin sy'|07ˆ@ˈGÅFs>^4pN*hI*cE&aE&aE&fJ'oN+Y/i7y?†F̏JѐKяKБIϏHώGЎGόCώDΌBϋBϋBϋAϋAʈ>{8b-rK#oK _*x5ˇ<̆9̈=ǃ9w3i,W$pJeDa@`@hCqKU"g+u1À5ʃ5̄6̈́6˃5À5u/f(S"pHc@a>a?e@tIU!g'v/2Ȃ4{1h)zPqIV"p,}2w.a'sJc?a>b>d@lFRa%r-|2ʂ4˃4˃5˃5˃5ʂ4˃5˂5ʄ3̂2̂3̃3̃3̃3ʃ3Ƀ3̃3̃3̂3˂3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ЎЎύ͉͉͊̈̈̈ˇˇˇɄȂɅɄł{{/ D>9u"#=T8n!&)1@DWSu#'.""'Ol6DU!#*!#''4DKqhw~t"HYFJy8HX^a&'+T|#=BJ&',$'09m$"'}s_-,. #---piQeϨwް޳޲߲೅ൄಁೀ߰߰|߰}ܭyݭz߰}ް}ްݯ߰|ݮz߱{ޯ{ޯ|ޮ~ޯ|ګwئkآ]֞R՚IԙCї>Җ<ђ4ϑ(Ϗ͍ ɋƒcg@A)Y;Wo~~{xsmYd8@ +(O0uD]mi]Lg;Q,H$F!K#M%M'W,e7FQQPQL~?X*:36G"]/ {> GHs7S#2! />! _2y?Bt:U$5 9 R)l9}ADDDr;Z/E" /) ),08 1 @ P(g4D OU=h,;E"b1C N N O O P {7S"+4I&b4t=t=g6G.& 6V0 k8y@|ACDCFKNR P C l9 V,?678<=A!@!H$Y-t;ISW V X?f+=L'n:Qchlou&|0Ɂ7˄?ΊGόKώNђQJj:oM'W:O4P5P6R8S< Q:!W>"iH']/s>FˎIЎIώJҐIяHώEЌEЎD΍CЋBΊAϋAό@ɇ?m)wKK- X;T%t4ʄ;͉>ʃ9z4b)rK V4J,K, P0 V3W9R8\;uL c*t/Ā4̄6̓5Ɓ5t.a(oIS2 I)M+P. S5U8S7_=uJa&u-À2r&W^6 Y9sJm)|2n&Tc: P/ T0 V3X6S7[8oG]%s-2ʂ4˃5˃5ʂ4˃5˃5ʂ4ʃ5́4̃2̃3̃3˃3̃3̃3˃3̃3̃2̃2ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3Ў΋͉͈ˇˇ̈ˇ̈̈ˈʅɄɄʆʅns IE>Øs1Op#(-7CS &Vnq{hw)+6! #',2uAN_ #7CQ*.513?xWcyENX7:C*+0m=x &vOLC ]VG(('qhSȯƝsٮಆ޴᳅᳃߲ಂ߲ᰁޯ|ޯzޯ{߰}߰ޱްޯ{ݮz߰}ޯ|ް߰|ܭyۨoע^՞SӛHҘFҖ<Ԗ>Д5А+ΐ Ώ͋̊׭SS5Vp}{xtph8pC\i`Lc<y@GORQQD`gIo9 BGAvja8T+o9~?g-H' g7{ABCu=\2iPA๬<5 <X,~?NH? `0B O O P M~?8"G$ a6o:k8d<rc4s=|ACEFJNRRO Ei4eC&»S1?A"S+p;KUXM9l>Ym u{-5ʅ?̊H΍NϑQҔVѕWҗYӖVБ|fM4N7_B!Z/v>ĈFΏIЎJҐIЎGѐGЍEЍCΌBϋBϋBϋBόAǁ2D'yO$r3ȃ:ʆ;|8g-e?÷fAP4U9qJd*y1ʂ5Ȃ4{2d)lGɻ]:P5T8uLe't+K- mFg*r'z^=Q2P5pHe(z0ʂ3ʂ4˃5˃5ʂ4ʂ4˃5ʂ4ˁ3̃2̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ύ΋Ήˇ̈̈̈̈̈ˇˇʆʅʅʆʅ{y֛ٟբդ֫AsLtXrP_y`~]udzhl݃׀Ί݌ߊⒷUf~=ESԙ蛺Ѝ݃sԅs}̮`!#1h٬֤×̚њΒkլ᳃߳ᴄ߲޳ߴుް߯߯~ޱ~޲~޲߱ޯ|ݮzݭyޯ{}ూۮvܪt٣c֟U՜OәHӗAӗAҔ:ϒ,ϐ&Ϗˍˋ̊֫QS5Vo{yvrnj;qB\bOʶJMPQRNnvODFGL»3K(j8y;¶9!C"`2z?CzAj7oU>=J%m6GD@ ^2B ON JzBq79!F$c3j7U'].s=|A~BEHLPR Q OIl/6A!W/BR[P:pA e{2˄=̉HώMБTѕXԘZԙ\ՙ\֛^֚]ϘW^H-N6cE$b4BʌHАHЏHЎGЎEΌEΎCόBЌCΊAΊA΋@Ȁ3C&|Q$s3Ʌ<Ȅ:r/íz`K0X9S#o-~3À4o,ɵlQM/[9U k&վK. oGj*u$J._<[#v.ʁ3ʂ4˃5ʂ4ʂ4ʂ4ʂ4ʃ5ˁ3̃2̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ΌΊ̈̈̈̈ˇ̈̈̈ˇˇˇʅʅłvϲkїӛ֟ا7y?}LZ_chzqixxs΃ۋ⎰㓳哳咲擶瘻ꔹ葶援㐳䝼듶焮zOXÕ7c3d3tȬاբ՞әҕĨ|ͥxݱߴ߳ⴆ᳄അಂ~ீ߰}ఀޱ~~ూݯ߰}ݮzޭ{߰}ްݮzܪvۧkסX՜MњHԗCӗBӗ>ђ5͐*ϐ͌ ̋̋ˊԩQS6Uoywsrh;oC[ZҴ’[Ŗ_ӰϷзNNQQSW طĤi;HHI]74F$ d5o7R9+? Y/u<}@p:xܿҺ^?? W,y>?? ^2BJCu=s=o49 C# ^2b3oS* m:}?DGLOPQPOM?«Ĭ8I&o9R_[> tL"p8ȉKӒTӖYӘ\՛_՜a֝b֞a֞a֞aԜ_Ӛ[X@(Q9yT-u=ƉGЏIϏIЎGЏEΌEώDьCϋBΊAϋAόAĀ4E({R$s3ȃ:7tçϳgOL2hEd({4{0ĢдmT9L2kFa!ԿM- mHi+v#ÞƢ{iSV6X!t-ǁ3ʂ4Ɂ3˃5̄6ʂ4ʂ4˃5ˁ3˃2̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͊̈ˇ͉͉͉̈̈̈ʆɄɄʆˇƅĂjɇѕϘϜԤ>{<{HR[}cdhgyrjzwؑͅݐߐ㚲阵蚹柹뜽ꟿ嚸蘸袿固욹ꎱxsFvҪn?}4yJӢԡЛʕ͒v۰ߵ᳇᳈߳ಃ߰~߰ݰ᳃޴ᴅ߱ޯ߰}ޯ|ݯ}ீ߰~ܭzڨlנ\֞RәIәEӖCӗCє6ϐ,ё$Ώ͍ʋʉʆըPT6Ukvsuqm<qBTQa1{BNNNKC;CEGKPxyH'\+ z>DBGѽ? H$l8 ;A!`1 v>u?r<r<t=o68!D# V-dA'{^Gk8{?FIPP QPNNQO ǧMIRSO_սjB#b4Rgd@' xT/{J͔\՜b՞c֞d֟dנdנdןd֟b֟b՟aԛ]ݸԗWЗUҗUՖUԖTҔOяJͯE.jI%n9EϏHΏGЎGЎGώCЏEϋBϋBϋBϋA΋@Ƃ4E'{Q$s3Ʉ;{4±_|3̄7˄6ɀ2ؽR4\<['v.{:_{0˂5̂2ʃ1O3]=XҾK. pIj*~3|+ʁ0˃4ȁ2|/q%ԺY6[$v-Ȃ3ʂ4˃5˃5ʂ4˄3˄3˄3Ƀ2̂3̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͈͉͉̈̈ˇ̈ˇ̈ʇˆˆˆˇɄ}uіϔ±x.s5e@fVqbYgR`Q[]|UZl~ҍk~iyzޝꓪ{}Ԝ⃔wǗ䘺独ma}a~{DtYۗȉ;{9x0aμsǶɌnخߵߵߵ߳޲߱߯ް߲޳߳߳ްްްݯ߱ݰ~ܭ|۫p٣cןX՜MәHӗCҖ<ѕ9В1Б(΍ˌˌ̋ɆȃӦPT6Ujtsrdâ=oAXA%U0b6f7g8d6b4a1]0a2c1o7CL”dG$o7CHKIA;t^O= R*hQ_J:¹4D% a3t:ƿJ% o:~AGL RX_I3A"e3 ::N)b5o;s<s=s=l66 > E b4x?HMQQ PNNPS S Jd/JT UVWWP̲<[4Ur(v-C,zZ:UϚcءhءiءh٣jآg٣gآf١fנc՞aԝ_؞`֝[ӛ]ҙX՘XӗVӗUӖSҗR߱bM7eH$l7EϏHϏHяHЎGώDϏEЋBϋBΊAϋAΌ@Ƃ4E( zR#s3DŽ:հpFo0Ɓ7̇8ˆ8Ά8ȅ5xeV8T"o-ָtKn+ǀ2ʃ4˄4Ƀ3Ʉ4v_GV9RнL. nGk+~2ʂ4ɀ2~3u.k*_&~S!kBg(y1ɂ4˃5˃5˃5˂5˄3˄4˄4ɂ2̃3̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͉͉̈̈̈̈̈̈ʆˇʆʆˇȇǃzNэל 31-.f59VQw^m!$)$#1BOc%'0/2>x@Ma25@w#!$! $8?GxSZm hw͓;@N 7@P5LOQ PNKOR S R Q p;I$x<NUUWX[^kiP5Y7^.~ELJHC.rV:{Q]ÔbÔaŖcɘcϞeԠf֠eנd֟bԝ`֝_՝_Ԝ^֚]ӚX՘XՙVӗUӔQєSʎLiJ(n8EϏHϏHЎGЎGώDώDЋBΊAЌCϋAόAƂ4E'zR#s3ă9v\@U%r0ǃ7͈8̆8Ά9І9ݴ¶P0~T#m)dG(U!r.ǁ3̃6̃4˃4ʂ4⽖R3~OнL. oHi*~2Ɓ3y2l+]#xMc?qՎ[u.À3ʃ3˃5˃5˃5˂5˄3˄4˄4˂2˃3̃3̃3̃3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͉͉̈̈̈̈ˇ͉̈ˇˇˇˇ̈ńx׽wϑؙ732y2_ &4Ic]IU ! $ % "w9>R!cpǣYcv$"'x "gw%gw15A7=Gu{5;Fu&$*++3Z^07>}:p"$$'-g`NxĊϐŨyͦ|ݳߵᴈ߳ౄ߰߳޲߳ಇ޲ಂ߰ݰް߱ް۬wڧiנ[՞OԛLӗFԘDѕ>ҕ7ϐ-͏"΍͍ ˍʈȄƁŀӥPR1Nfsqgƭh<<m>ģy~}D l7FhzmE$ h6DHHGa$h?X̔];)bK1aApJrMtLwN}QV[ɗb՞d֟bԞaԜ^ל^ם\ԛ\ԚX՘XԘWӗU˔QȎLFvS*v<ƉGАIΏHяHЍGώDЏEϋBϋBΊAϋAΌ@Ƃ4D' {S$s3ȅ=_AR#r1Ȅ8̆7̆9Ά8φ9|-L- R!s5_>V#s/ɀ4˅3͂6ʃ3̂5Ā5P0~PнL. nGi)}0{0j*T"eB]B"lr,1Ȃ3ʂ5˃5˃5˃5˂5˄3˄3ʄ4̂2̃3˂2̃3̃2˂2˂2̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͉΋΋΋͉̈ˇˇˇˇˇ̈ˇɇăr}Џڞ)&&79>#(/"O{dm/5C""(GRe! $;AYo}7=`&$+!#,.:vEM[]h{!&&,⌡euNVh #FRe06? !'sv[9>EgsoFSŒ]Лb؟aӞ_֝_ם]ԛZԚYїYΓUǎPJzCe6c4@ʍIϐIяHЎGяHЏDώDΌBϋBϋBϋAόAƂ4C'zQ$r3LjAN0xO o0Ɓ6˅8Ά8ɇ7φ:~0M, W#}>Q5|Q n,3͂5̈́4ʂ3̈́5~2Q0 RҽL. pIj)z/r.WtYӾu+3Ɂ4˃5˃4˃5˃5˃5˂5˃4˃4˃5ɂ3ˁ2̃3˂2˂3̃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͉͉͉͉̉̈̈̈̈̈̈ˇˇʉÁqƃБЗΘҞqQlXv_whhxzтׁЖጣ۪67Fʱ꒱܏܉݄݆Pv͜Z!!C_ǽҙ̕ϓ͎Ňğyڰ߶അಂೄ᳅ߴഈᴇ߲޲ೄಃްݰް۩sפeםZԜOӛJԘGҖBҖ>є5Α)Ώ!͎͍ˊɇǁĀŁǁԦQQ0OfqiĤrn?N<k;J!p:Fk{nG$ j7DIF~=ź8 ]0sZjTEcNBI%e22F#uK+<Z.BNOL MK K >X/_+ ,A#]1m:r=s=s=m5ȿ=C$]0 y>INP R P R Q S S STsaT+FWcglsz*ɂ<ЎP࿡\J3vTÚmҡm*A0Q;$ZB'\D)[D*YC,YB+WB,cL0`<|MYћ_֝_՜^֜^ҙ\ϕWnjRJvEg‡E͏JϐIҐIЎGюHώD΍CΌCϋBϋBϋAόAƂ4C'}Q&t5ʈAJ0lFe+|3Ʉ7̇8ͅ9ˆ7w*S0 \&BN1kFe*z2˂4˃4ʃ3ǂ3{0W4YӾL. pFj*y/q3̙c~4ȁ3ɂ3ʂ4ʂ5˃4˃5˃5˃5˃5˃5˃5˃5Ɂ3̂3˂2̈́4̃3̃3̃3˂2̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3΋͊̈̈̈ˇ̈ˇˇ̈ˇˇ̈Ɉ„oɇϐЖҜ֠u@~Rbgzwiyvckzuq|t~ś阸뢾w،ᗺ6m1pâӟӚΔΑŇyڰߵ಄ᲃᴄ಄ߴഈ߳ೇ߳ݲ޲ܱݰܬxڦiע_֞UӜK՚JӘDҖCГ7ϑ-Ύ%͍͍ˌˆƂƂĀŁǀҤPQ1Nen]ɿ|LW<l<j^=BY+{=GKNJL V(w? Gm{nD$ i6CEDu6? d4q9|qulkWKP(l7+D# k?"B$I%l4@HK K E }A 8X.`- ': V,i6q;r;r>m6WA2b? < I%h6 E O Q R Q R R R S TTt`W-J`ot}2ɇCΐRӗbםjȭ^K6zWƝqգq䲥T=&Q=%[D*}^<~NƒZӜ^՜^ԛ]̕XOvCc8pR.[@"xem3F̌KЏJАIѐIЎGЎGЏD΍CύCϋBϋBϋA΋@Ƃ4C({P#s4ņ@X;W9T#n.~5Ƃ6Ń7~5b!c<e):R8Z:T!m,z23~2y1i)hAa!ԾL.jFi*mʹJz2€1}3~2ƀ3Ɂ3˃5ʃ3˃5˃5˃5˃5˃5˃5ʃ5ˁ3ˁ3̃3̃3˂3̂3̃3̈́4˂2̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3Ί͉͉͉̈̈̈̈̈̈̈̈̈ʊ„mˉАЕʖʖm>wSblhvesӧ饾鑧ڗݒڢ䠹墻褿饿壼更⚴ᕯݓݓފڍn~ˣГ2ϐ*͏"΍ʊʈɃƂŁƂŁ~ѢQQ1~MdhĠnlF U];k;r/D"J$a1y=DE~@~`sf3BFmyn@ _1r;x>x@`BF% e5x;/W+p;ȮW@/>! `/ N+ = K&d3 x;}? |> u<wE! ]2^) $0 F%Y0c4j8p<o6A(C?!S+r<K P Q R R SSTUUw`X2Tk~2͇DϏVԙe֟kإu۬|ͳ^M8{YǟrէsxiWN9$`H-iAUϘ]՜^˕XOm=rR-U;tbEϏKАJЏJяHяHяHЎGώD΍CύCЌCΊA΋AόAƂ4C'|Q%s3Ʉ9qV&xY7~K̗Yϗ]Rl O)f6~<D&X- }? rWG$Q(l8GPSSTW[^b}laB"nDǑbأu۪}ް߳൉උᶋӻ`O:{ZɠtէsG4eD^ӣoקoڠgßH4kN0vFƑXȒXuB³жnjM̐MБNђMђLϒLяJАIΎGяHяHϏD΍C΍CЋBΊAϋAό@Ƃ4E'{Q$s3Ȅ=ˆ:[8U7W8X7R4l4w1ȁ4˄5ϊAqY6W6V7V7W7Źh/w.|+L. qGi*ѹĴV2 R6T6W8W4S6tKc&x/Ƀ3ʂ4ʂ4ʂ4ʂ4ʂ4˃5ʂ4˄4˂2ɂ2̃3ɂ2˃3̂2̂2̂2̂2̂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3΋͉ˇ͉͉͉͉͉̈̈̈̈̈ΎLjrɈϐїϘʸ;eOnbi}ƒؗሠƈq|ŰԘҢ➶Йȓŗϥꍱ|ي㒷䗻8l1aZt{ċΏƈuگᴈആߴ޴ⴈೇೇ޳޵ߴ߲ݮzڨmآa՞UԛOԚLҚIҕBҕ<Г7͏)͏&Ў̋ɇȂĀƂłŁ~ywϟPP1zHOwD\j`9h:MV{kMg{DDIRX0F4&R8)Y<*R-MK"e6z?B~@|Y.p:AA])p8AβǏvahO~vS?b3j6wN5a<#V9#M.Y=)U+w>DC([/C s@b8 [/k6DPSX[_ahpvgM6|Y̡xݲߵḍ⸎ḍ㹎⹎ս`O:{ZɠtէsG4cE_ӣoڧqרnץná\K7`I/qDVO¡ȉGВOϕPғOғNВLВLѐKѐJАIΎGяHЎGЏDώD΍CЋCΊAϋAό@Ƃ4E' {R#r3Dž9ȇ<ުu|blw2ŀ4Ʉ5ʄ5ȃ2ǧҢpy^Sw,4.տL. mFi)Κ`iz_lɼͿ~Pi*z0ʂ4˃4˃5ʂ4˃5ʂ4˃4ʂ3˃4ʂ3˃2̃3ʃ3ʃ3Ƀ3Ƀ3Ƀ3Ƀ3˃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͉͉͉͉͉͊̈̈̈̈̈΋΍ΏȊuȅАѕzJF=:86#-:*5BR_vvJTp01B+,9++:KPjó⇕>CE),,+,3@GThtYdr:?K8;C6;BWaoӨnRsҏޛS[g$)0#-$%'/-.d]JΐŅy۰ᴊߵᵋߴ߶ᵉᴈഈഈݱܭ{ڪpףd֟\֝UԛNҙIҘEѕ?Ҕ:Α,Ύ'ΐ(̊ ɇDŽɂƂŁƃ~yvvϟQP1uGHnDSdh^8e6HRXT&FIJwT\@S7g3v>~A~Bz9tL0p9~@EJMAG J p\f3n8c*xfhx? G D H) \1D M ȣ~~>BJTZ^_fnu}0}jS>hҪṑ⹒⼒⻔㼒㼐⼏ս`O:{ZɠtէsG4bF`Ԥp٧r٧oڧjԛbaI,pEQּ䱌eÉJҕSЖTѕRԔOєOѓMѓMВLВLяJАIΎGяHяHώD΍C΍CΌCΊAϋAόAƂ4D'{R$s2ʅ<Љ;̃:ֺѬ{0ǁ7ʅ6̓6̄5ʅ6̓3ɟsz01˂3-K- jGk.|-եi&w.1ʂ4ʂ5˃5Ɂ3ʂ4ʂ5˄4˄3ʃ5́4̃2̃3̂2̃3̂2̂2̂2̂2̂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͉͉͉̈̉Ί͉̈ˈ͉͉ύяϑˎzŀϐїl # $""'YzyԒ<@L#!# #NU`w!"!$# #"67>#!!"CKX̧mϠ" ' #!""!!"ZVGǵϏğy۱ᵊ߶ൊߴߵ޵޳޴ߵݰܫvڦjס]՝SԛP՚NӗHѕAғ;ђ4Џ*Ύ'̋ljɄŃǂŁ}yxuu͝QK/j=p=\fh_7c4GSUNٹƀ;HLKGyReEů{@A}?@}@Ⱦp4 AFM SGcJ L N L Ki7m7o:o9b*bHzhgI ICF* \0 C N JӴQU\`gmv~1ˋJҕ`mYFpհ侗㿗侗俓佑归Խ`O:{ZɠtէsG4cFaӤo٩qڨo٦m՞fdL1tERlK$xEʑSєTӖSѓPєOϓNѓNϑKѓMБKяJАIϏHЎGЎGЏD΍D΍C΍CϊBϋA΋AƂ4E' yQ"r3ɂ<Ή;ˈ8·:ןcȃ<Ʉ5ȃ7ͅ8˅9˄5˄6ɂ5ȅ5˃6פj5ǁ3̃4ʃ3ʂ3~.K. oHj*}2ˁ0ݵͿ{.ŀ1ȃ4ʃ4̃4ʃ4˃4˃4ʃ4ʃ4˃4ʂ4ˁ3˃3̃3ɂ2ʃ3̃3̃3̃3̃3̃3˂2ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3̈̈΋΋΋͉̈Ί͊̊Όύяϑΐھyϑѕm!!#"""!%S[n{..@!# #!EJXִ $#!"9@Ges|$"!HM\ұ}?}@DINVTTMKK M N N ON Dq:j6m6i6k8n8j:l9n9n9p:j6m7n8p9y=BFL K IIKIE) ]/CNQRPQV[adlt {,̈Jԕ`ןqک}m\JtԳ⿕侔㽑㼐Խ`O:|[ɡuէsG4dDaӣoاp٥oџjƖatW4}LǏPeS>mN-o=OˑPДRГQϒP͑OˎLʍK͎JΐKЏIҐIϐIюGЎEЎE΍DώDΌCΊAΊA͉AĂ4D&{P%s4ƅ;ʆ9͆8ˇ:̆:Ʉ<ͅ5ͅ5˅3ȃ5̇7̇7ˆ8˅7˅7ʄ8˅6˃5̄6̄6̄6̄6̃5Ʉ4ɂ2́2ʀ1ʂ2ȃ2̃3Ʉ3ʂ4ʂ5ʄ3ʂ4.տL. oHj*~2˃4ʄ3˃4Ȃ3Ȃ0̂1ʂ0ǀ2ɂ4˃4˃5˃5Ɂ3ʂ4˄4˄4˄4˄3ʂ4˃5˃5ʁ3̃3ʃ3̃3˂2̃3̂2Ƀ3̂2̈́4˃2ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3̈̈΋΋͊͊Ί͉̈̊ΏΎяГЏ ȩcВѕm !!$#%Q]bijy47H ! " NSaѵ #! !"LPX"#" "JQ\ͧ쉯}ۖꎬ$#tʘҘЖϐtҪߵൊᶋߵ߶ߴ޴൉߲ޮ}ڨlأaןXԜU՚TӚLјGЖ<ғ9ё2Β*͎̋ȆƂŁǃŁ{wwvts͜P>$o>\febW4e4HTTTQON L LJKKIIHHGDsuf7v?}?DACC{A~A}A{A@B~ADCGISVVQLLN M L O OK|Ao<m;j8m9l8l8m:i8n8j9l9n9o;p;s=w?ELPLIKMO GF( _1FPSTZ\_eku})̉EГ`աqܪܱᷔn^Lwض›š⿕侔㽑㼐Խ_N9|[ɠtէsE2w]@WĕeǚfŖb_yLƺeAQ̔TE-X>${V2n>~EJHG~C{BDÇHˍIяJяHϏHюGяFύE͋DȇA=<=~:v-A%tL"j/y4}7|6}68Ł7ʅ8Ά7Ά8̆9Ά8̆6ȅ6ʆ7˅6˅8˅6˃5̄6̄6̄6̄6˄6̈́6ʃ4̓5̓5̓5Ɂ4ʄ4Ʉ4ʄ4˂5˄3ʁ4},ԿK- oHj*}1˄4ʃ3̄4̃5˃5Ȅ4˃3˅2Ȅ2ʂ3˃5ʂ4˃5˃4˄4˄4˄4˄3˂5ʂ4˃5ʁ3̃3ʃ3̃3˂2˂2̓3ɂ2̃3˂2̃2ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͊Ί΋͊΋΋΋͊ό͍͎ϐђҒ ђ ‰;ҒҖm! "#$!$KssЏ-dN7iHvQyQrNkFeGyJđZјXy`FP9!V?$lO+Z2a6d6c6^1\0f4}AȋHѐKҐIϏHЎGЎHύFʉC}DJNLIJLM O N J t8H( a2HW]cgqz"ɅD͑Xנtک޳ທġƧǤtcPzַ›侔佒㼐ԽbQ<}]ɡuէs8'N=+_I2hO5hP5eM3X@&p@XК^՝_\>U=$R;!V>#]C$^D#]B#X<bC!Z/v>NJHЏJҏHϏHЎGЎFώEÄ@p7W,jG"bBbAX61L2Y;b@aAb?kGV&m/~5̆8·8І8̇8͇9ͅ8ʅ7ˆ8̅9̆7˃5˃5̄6̄6̄6̃6̄6̃5˃5̈́5̃5̂4ʃ5ʄ4˃4ʂ4ͅ5Ā3m$̼G* pJj*}1ȃ4˂4˄4ʃ5΄4Ƀ3Ʉ5ͅ5̄2˃5˃5ʂ4ʂ4ʂ3˄3˄3˄3˄3˂5˃5ʂ4ʁ4̃3ʃ3̃3˂2̃3̂2ɂ2̂2̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3΋̋όύ͌̋ό̋ΎАВҒѓђ#ӓ%͑)'ּ|іm#! &-MiKma%'0!#!X_k ! #!JQ\ " #"HP^ϩ~۝uf} # "xapuнȰ̥޴ൊᶋൊൊᶋඋ޳ݬyإj٣f՞Y֝R՜RӘJҗCӖ@ѓ5Α.Α-΋ʊȅDŽɄǂƀ|yxvussqq͛PWO^ba`[MJs:JPNLL LKKKJIHFFEEEEEDDBDFDC@|B~A|AAACBEIQUUSMN J M L M OJy?o9m;n;l9l9k8k8m8l8l8k9m8p;r=s={AHLMJHKMO O O N Bo0Y2q<P_gnxǂ8̏V՞qةݲ㹖ĤǪɩ˪ȩr_ۺ㿘⽒佑㼐տzbHc̣wըsE.Q;#U=&V>"r^Fһ[ћ`՞a՝`٪tu^tYBpX?nXҠp`2}@ɋJώIϏIАIЎHюHώD}5d'rHZ6Q0 P0 G%<I, M, Q. Q. P. `=|R#l/6̇9ˆ7˅9˅9˅9˅8̅8ʄ7ˆ6̅7˃5̄6˃5̄6̄6̄6̄6ʂ4ʂ4˃5ʂ4ʂ5˂5˃3˂3˃4̄3z-dʸX7Q o+~2ʂ4˃4˃4˃4ʃ4ʂ4Ɂ3ʂ4Ɂ4˃5ʂ4˃5˃5˃5˂5˂5˂5˂5˄3ʄ3˄4ʃ2ˁ3̃3̈́4̃3˂3̈́4̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ϋ̋όόύ͎̊̋БВӔϒє ҕ+ҕ+ѕ0Ë1Mәm"" "! '&/:&'-"""dmɼ"! "#LS]"!# LT]ҰCGw# '##&" " #!%#&&"'RNB~pԫഋൊൊൊᶋൊ߳ݯ}ۨp٥fء`֝X֝RӚMӗGӖBє;В2͐+͎$̋ɆDŽȅʅǂzxxttsrqrМQRYab_[VLl0CLNM M KJLKIHIHFEFFEDDCBCFDB|B|A|AABBCDHL SVURLL L MMNM Gr<m:l:n;m9m8m9l8m9m9k7i8n9p:p<t=EJMKHKMO P O NO G|DL[ju Ɓ3͎TҜhڨ~޳໛¥ƨʭʬˮΰͯͮyȭ޽Ý㿘㽓佑㼐׿`oөzڪvѽÏWԝaՠc֟bמ`֜_{y@‡FˏIѐKАIϏHЎHώFΉ?}c(u2ā5̇8̇8̅9˅8̆9˅8˅8ʄ7ʅ6̆7˃5̄6̄6̄6˃5˃5̄6ʂ4˃5ʂ4˃5˃5˂5˄3Ƀ3˃5˂5ὕSe(v.ǀ2ʃ3˂5˂5˂5˂5˃5ʂ4˃5ʂ4˃5˃5˃5˃5˃5˃5˃5˃5˂5˄3˄4˄4ʂ2˂3̃3̃3̓4˂3˂2̃3˂2̃3˂2ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ύ΍Ўώ͍̌ΎЏϑѓєҔӕ*ј/Ӗ4ҕ3̒3x0ʎh854OJE "! JPjڤNTYZcuA\!$ $" aZH}Þzܱ߳ⷌᶋൊൊ޴᳄۬u٥g֠`՞WמRԚOҘKіBҖ<ђ8Α1Џ&̌ɈDŽȅȅɃ~zxxvsssrrr͞Qŝd[_aaYUTMAMLML LJKKJIIGFFFFFEEDCDEC~B{A}A~A}B~ABDFGNTVTOL L NNL NLAp;l:m:m9l8m9j8j8l9k8k7l8l9p;q<{AHLLHHJM M P O P OPF\ `o)ȉKәfק~ݱ๚Ȭ˯̯ϲίΰϱΰͮιγ۽Ü㿗㾔伒Ốȣyө|گ~۪w޼Θ_֡fנc֡b֠d֞a՝]ԛZް~ҭȊG͏MΑLяKёJАIЏGҎH̉?Ϫx48Ʉ7̇8̇9̆9̆9̆9ʄ7ʄ7˅8ʅ6˅7˃5̄6̄6˃5̄6˃5̄6ʂ4˃5˃5˃5˃5˂5ʄ3˃4˃5Ʉ2ϱo'w0~2Ɂ3˃5ʄ3˄3˄3˄3˂5˃5˃5˃5˃5˃5˃5˃5˃5˃5ʂ4˃5ʂ4˄3˄4˄4ʃ2˂3̃3̃3˂2̂3˂2̃3˂2˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3Ў΍ЍώΎ͍яВђѓ ҕ&ҕ+җ4Ҙ1җ1ԙ7Ε9>ĥjɒȷķȷܲ:Tp:SnXp~{˒xŅڱ׸ץٴԥӞF[ņ՞ҙ # # }fÐyѪൌᶋൊൊൊൊ޳ܬyڦjעbؠ]՝V՜RҙKӖDѕ@Г;ϒ3ΐ)ύˇȆɅDŽƂ{wxvtrsrrqpȐ;׹ֹֹ׹ڿk `b`ZWUVQѽѺǘINL N KKLKJJIFEEFEEEDCCCEDA|A}ABA@CDFHPVVRPNM M OMOHu>m9l:m:l9j8h7l8n:k8i7h7n9p:p:t=CKMKHHLN O N O O P QQJѺҹոֹs zȆFϕ_֤y߱ߺũ̳͵жϴеѳввί̫ԽĠàğÜ⾗῔伒亏дݳݳ޳ݭ{˫۰ԟcؤk٣i٣fסe֠d՟aן`՝^Ԝ]ԛ]ՖR֟c⿚ˬซҖXАIϑNёKґLЏJАIΎGЎHЏF΋@˪קpʄ7ˆ:̇8͈9˅8ˆ8̆9̆9ʄ7ʄ7ʄ8ˆ7˅6˃5̃5̄6˃5̄6̄6̄6ʂ4ʃ5ʂ4˃5˂5˂5˄3˃5̃4ʃ4⻑}.Ɂ2Ɂ3ʂ4ʃ3˃4ʃ4˃4˃4˂5˂5˂5˂5˂5˃5˃5˃5˃5˃5˃5Ɂ3Ɂ4˄3˄3˄4ʃ2̂4̃3̃3̃3˂2˂2̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ύ͎͍ώЍЏБϓҔӖ$ҕ0Ԗ1ԗ8Ӗ6Ӗ4՚;қEʕD};Қՠץ٫ܮݲ޹߽FoѐO|ש?64'&(yֿ̛zٲ߷෌උ᷌උߵݭ{٨mأgן\֝X֜TԚOҗGҕ?є>Г8ϑ0͎ɈɈǃɇDŽŁ{xyxursssrponlmkkedb_\VSWWWWVSOM L KKKKJIHHFFEEEFECEECC~A}A}BBBCCDFKRWWQNMMMMNL Er=j9m9n;m:m8l7l7k9k9i7j9o8o;r<zAFKLHHJMN O N P ORQQQVZaflxǃ<͐X֡uۮ޹êƬ̳϶ѹҹԻҷӷввϲίͭͪʩɦȥƣĠߜš㿘㾔㼒⼏㻎⸌්෇െ೅ݳ᱂ݰ~ܮ{ݭyܬx۬wܩvרrܩq٦o٧mڥl٣l٤g٣gסeؠc֟b՞b՜^ԛ]ԛ]՛Y֘Y՗WӘUҖTҖTҕQєPѓOғNВLВLБLѐKАIϐIЎGяHЏD΍C͍CЋCϊAϋA΋@΋@΋@͊?͊?͉>̈>Έ>̉>Ά<ˇ:̈;̆9̆9̆9˅8ˆ9̅9˅8˅8ʄ7˅8ͅ8ˆ7̆7̃5ʅ6˃5˃5̄6̃5˄6͂4̓5˃5ʂ4˃4˄3ʂ5ʂ4˂5˂5˃5ʃ4˄4ʄ3˃3˄4˃4˃4ʃ4˃4ʃ3˄4ʃ3˄3˄3˄3˄3˄3˃4˃5˃5˃5ʂ4ʂ4˃5˃5ʂ4˂5˂5ʃ5́4̃2̃3˂2̃3̃3̃3̃3̃3̈́4˂2ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ЎΎύύяБДԕ ѕ$ӗ3ї3Ӗ7Ԛ;Ӗ9՘:כC՜FљFC`ףפتݯܲнHsӠ`ȓ񩷲޴޲,*)Ӟ{Ѫߴൎ߷ോඌൊްܨs٤g՟\֟V՝TӚOӚGіAϕ=ϐ4ϓ-͍ˌɇDŽȆDŽƂ|yyxusrssrponnmljfdc`ZUTWWWWVSMM M KJKJKKHHEFEEFFFCDECBACA~@@CADHL TYTOMN M MNML|@o9l9n;k9j8l8j7k9l8k8j8m8p;q<t>BJLIIGMNM N N N OPQSTX[cks1͎Uӝo٫บ࿥ƯзѸӻҺ׾սּչչѳввίͭͪɩɦȥƣĠߜš㿘㾔伒⼏㻎ḋ්ඈെ೅޳߱ޱݮ|ܬxܬx۬wܩuרr۩q٦n٧mڥl٣k٤h٣g֠dנc֟b՞a֝_՜^ԛ]ӚX֘YԗWӗUԘVҕTҕQҕQѓOђMѓMѓMБKяKϏHϏHяHЎGЏEэD΍CϋBϋBϋAό@΋@΋@͊?̉>Ί?̈=Έ>̉=ψ>ˇ:̇:̆9̆9͈8͈9ˆ7̇8͆:͇:ʄ7˅8ʄ8ʆ6˅6̄6̃6̄6̄6̄6̃6˄6ʂ4ʂ4˂4ʃ5˃4˄3˂5˃5˃5˃5˃5˃4ʃ3˄4˄4ʃ3ʂ4ʂ4ʂ4˂5˄3˄4˄4˄4˄4˄4˄4˄4˃4ʂ4˃5ʂ4ʂ4˃5ʂ4˃5˃5˃5˃5ʃ5́4̃3˂2̃3̃3˂2̃3̃3̃3˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ϐϐϐϏΑғҔӖ,ҕ2ԗ7ӗ6Ԙ6ԗ8՘:՚A՛HӛIӛJ͘HDŒץتݯݳ߸M|٧혺󂢳޳۱ڬا֡˳á۳ᴍ᷋᷍ⷌᶋްܪr٥hأbՠZ՜W՜QӘHӘFҕAѓ;ϒ3ϐʊʆȅɆDŽȁ}yxyvsssrrronnlmkgcb`\VUWXVWWSNNM KKLLKKHGDGFFEFDBDEDBBB~@~@BCBFHNUXSPMMMPNNJs>m9n8j9n:k9j7l8m9i7g7j8k;o:s=z@FLLIHLNN M NO O QPQUW]ago| ȉJҖiکݶ⽥Ʈ͵ҼԾֽٿ־׽չչѳввίͭͪɩɦȥƣĠߜš㿘㾔体⻏㻎ḋ්ඈെ೅޳ݲް~ܮ{ݭyܬx۬wܩuרr۩q٦n٧mڥl٣lؤgآf֠dנc֟bԞa֝_՜^ԛ]ԚY֘YԗWԘVӗUҕTєPҕQѓOѓMѓMѓMБKѐKАIАIЎGяIϏDьCЌCЌCϊA΋AΌ@ЌAόA͊?̉>Ί?̈=Έ>̉>͆<ˈ:ˇ:̇:͆:̇8͈9ˆ7ˇ7̆:͇:ʄ7˅8˄8ʆ7̆7̓5̄6̄6̄6̄6̄6̄6ʂ4˄6͂4ʃ5˃4˄3˂5˃5˃5˃5˃5˃4˄4˄4˄4˄4˄4˄4˄4˄4˄4˄4˄4˄4˄4˄4˄4˄4ʂ3˃5Ɂ3˃5ʂ4˃5˃5˃5˃5˃5˃5ʃ5́3̃2̃3˂2̃3˂2̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3Ύ͍͎ϏДДҕ$җ0җ3ԙ5֚=ԙ<ԗ9ԚAԛF՜G֛JԝK՜NƓMOݫרܮݳ޸Rǂکqvӱ۵۱۫بџxծ޵ߵⵍ᷍߶ೇ۫zۧl٣d֢_֟[՜QҙJӗEє@ҕ?Α6А,ˊ ɈȅɇȆǃ~{xxvsrsrsrpnnlmjgdb_[WVWWWWVRMN KKKKKKJIGEGFEFEECCCCBCCBCBCCFIPWWRNMMMMM NEq;o:n9n:j8h9h8m8l8k8i7l8n9o9s;}AHMKHIJMLNN O PPPRVZ_dkw ǁ>͑\פ|ܰἥĭ̴Ҿٿ׾ּչչѳввίͭͪɩɦȥƣĠߜš㿘㾔体⻏㻎ḋ්ඈെ೅޳߱ݰ~ܮ{ݭyܬx۬wܩuרr۩q٦n٧mڥlأkؤg٣gסdנc֟b՞a֝_՜^Ӛ]ԚY֙YԗWԘVӗUҕTєPҕQђNғNВLВLђLЏJАIϏHяHЎGЏEώD΍CЋCϊAϋA΋@ϋ@΋@͊?͋@Ή>̈=Έ>͉>͆<ˇ:ˇ:͈;̆9ˆ8̆9ˆ8̆8̆9̆9ʄ7ʄ7˄8ʅ6̆7̃5̄6˃5̄6̄6˃5̄6˃5˃5̃5ʃ5˃4˄3ʂ5ʂ4˃5˃5˃5˃4˄4˄4˄4˄3˄4˄3˄3ʄ3ʃ3˄4ʃ3˄4˄4˄4˄4˄4ʂ3˃5Ɂ3˃5ʂ4˃5ʂ4˃5ʂ4˃5˃5ʂ4́4̃2̃3˂2̃3̃3̈́4̃3̃3̃3̈́4ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3͎ϏҎѓғҔ)ӕ.Ԙ7ә6ԗ;֚?֛@ԙCԛE՜H՜J֞PןR؟SћR‘Qa٪ۮܲ޸>}vթ폳匳߸߸ݵگڬܪ}Ыߴᶍᶋോ᷌ඊޯ۪rڤfע`՞X՜V՚NӘGҖDѕ=ҕ9Α4̏ɉ̈ʆɆƃ~{xxvsssrsqpponmkgdc`\WVXWXWWRNM K KKLJKKJFEFFEFEDDFFCBAABCBBBGIRWXQMMNNLOK}Aq:n9m9m9k9k9k9k:l9m9i7l:o9q;u<DKLIGJML O N O OPRQRY^cit0̍O՞oܯ⻞ê̴վؿؿ׽׽չԹѳдвίͭͫɨɦȥƢšßœš㿘㾔体⻏㻎⹌්ඇඇߵ޴߱߱~ޯ|ܭyܬxܬx۩uةs۩q٦n٧mۥm٣kأi٣fנdנcנc֝a֝_ԛ^ԛ]ԚYՙYӘWԘVӗUҖTєPҕQѓOѓNГLӒMБLЏJЏIАIяHЎGώDΎCЌCЌCΊAϋBόA΋@΋@͊?͊?͉>ˈ=Ή>̈=ˇ<̆9͇:͇:ˆ9̅8̆9̆9̆9ˆ8̆9ʄ7ʄ8˅7ʅ7̇8̄6˃5̄6̄6̄6̄6˃5˃5˃5˃5˃5ʃ4˄4ʃ4ʂ4ʂ4˃5˃5˃4˃4˃4ʂ4ʃ4ʂ4ʁ4ʂ4ʂ4˃4ʃ3˃5˃4ʃ4˃4˃4˃4˃4ʃ4˃4˃4ʂ3˃5ʂ4ʃ3˂5˃4˃5ʂ4ˁ4ʃ2ʂ2ʃ3ʃ2̂3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ϐϏГғҕ"֗0Ӗ5֘=Ԙ;՛B֛E՛B՜GԛGԛJןMמSؠUؠVסWϛURƩzܱ޴޹Ґ҇}oԟ޹޴ݰ۬Ȧ۳ᶎߵᶌ⸎᷍ޱکu٦k٤e֠\ןX՜RԘIјDѕ<Ӕ;Α-͏ɉɆȅȅȅŁzxywtssssroonnlkhdca\WVXWXWVROMJKKKJJJIGGFFEFFDCEDCCABBCBDEHM SYVPNMMMOOIw>n9m9m9n9l8k9i7l:j8i7h7l9p:q;z?GLLGGIM N M M P OQRQU\agnzʉHϙgۧḚ«ɳѽؿٿֽ׽չԹѳϴвίͮͫʩɦȥƢĠߜš㿘㾔体⻏㻎ḋḋඇඇ޵޳߱߱}ޯ|ܭyܬx۬wܪuةs۩q٦n٧mۦmأjأi٣fןdסc՞a֞a՜^՜_ԛ]ԚYՙYӘWԘVҖTӖTҕQҕQѓOѓMϓMԒMБKЏJАIΎGЎGύGώDΎDЌCЌCΊAϋBΌ@όA΋@͊?Ί?͉>͉>Έ=Έ>ˈ<Έ;͇:͆9͇:̆9̆9˅8̆9̇8˅8ʄ7ʄ8̇8˅8ˆ7˃5̄6̄6̄6̄6˃5̄6˃5˃5˃5ʃ5Ɂ3ʃ3ʃ3˃5ʂ4ʂ4˃5˃5˃5˃5ʂ4ʂ4ʂ4ʂ4ʂ4˃5ʃ4ʃ3˂5˃4ʂ5˃5˃5˃5˃4˄4ʃ3ʃ3˃4ʂ4ʃ4˄4ʄ3˂5˃5˃5ʁ3̃3̃3̃3̃3˂3̃3̃3̃4̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3АѓѓҖ$ҕ1՘8֙;Ԙ:՚A՜GԛF֛F֝G֝KןPؠRءVءXؠYڢZסZΛURֽ޳޹ٺS߸k͉ܸtֺ߹޷ܰīŢٰᶐᶋඌ⸎⸎ߴ۬wۨm٣eסb֞ZԜSҙKӗFЖ@є=ѓ9Ώ$ʉˇȅɇDŽƂ|xxyutsssrponnllhecc\WWWXXWVPML L LLJLKJHHFGGEFEDDDDBCBBBCDDEINVXUPLMMMOL Es;p:o9n9l7l9m:n:k8k9h8l9o:p;s<DKNKGJN N L L M MOQQSX_dju ă;Γ\գx޴㿥ȴоؿٿֽ׽չԹѳϴвίͮͫʩʦȥƢšßœš㿘㾔体㼐㻎ḋḋආඇ޵޳߱߱}ޯ|ܭyܬxܭxܩtةs۩q٦n٧mۦmأjأi٣f؟dנc֟b֞a՜^ԛ^ԛ^ԚYՙYӘWԘVҖTӖTҕQҕQѓOѓMϓMԒMБKѐKЏIАIяHύGώDΎDЌCϋBϋBϋAό@όA΋@͊?Ί?͉>͉>χ>·=Ά<͆9ˇ:̇:̆9̆9˅8̆9̆9̇8̆9ʄ7ʄ8ˆ7˅8ˆ7̄6̄6̄6̄6̄6̄6˃5ʂ4˃5˃5̂4˃5̅5ʃ3Ɂ3˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5˃5ʂ4˃4˄3ʂ4˃4˂5˃5˃5˃5˃4ʃ3˄4˄4ʃ3ʂ3˃4ʃ4˃4˂5˃5˃5ʁ4˂2˂2˂2˂2ˁ3̃3̃3̃4̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ϑёӖ$Ҕ2Ӗ6՚>ՙ@՘E՜G՜G՜G՜IԜKמO֞QנVءU٢YעY٣[أ^נ[͜][ߺ߷T}ڡ됹ᐹ}޹ߵɱƢرฐḏ⷏㸏⷏ᴉܮ{ڨo٥g֠bן\ԝV՜QҘHїBӕ@Д6Ϗ'ʊ džȆɇȅƂ|yyxwtsssqqomnmkhecb\WXWXWXVRNNL KLKJJIGGEHFFEFCDEDBBBCCBCDEGPWWSNMMMONM ~Bq;o9m9n9m8l8m9m8l8k9i7j9q;r;w>GKMIGKL L L L L NORRW\bip~"ʍOӜn٭ỡDz͸ؿٿֽ׽չԹѳϴвίͮͫʩʧȥƢĠߜš㿘㾔体㼐⺍ḋ⹌ߵඈ޵ߴ߰߱}ݮ{ݮzܬxܬxܪuةs۩q٦n٧mۦmأjأi٣f؟d֟b֟b֞a֝_ԛ^ԛ]ԚYՙYӘWԘVҖTӖTҕQҕQѓOѓMϓMԒMБKЏJАIΎGЎGύGώDΎDЌCЌCΊAϋBΌ@όA΋@͊?Ί?͉>̈=Έ=Έ>ˈ<̈;ˇ:̆9͇:̆9˅8̆9̆9̇8̆9˅8ʄ8ʅ6˅8ˆ7̄6̄6̄6̄6̄6˃5̄6ʂ4˃5ʂ4˃5ʂ4ʃ3˄4˃5ʂ4ʂ4˃5ʂ4ʂ4ʂ4˃5ʂ4ʂ4ʂ4ʂ4˃5ʃ4˄3˃5ʃ4˂5˃5˃5˃5ʂ3˄4˄4˄4˄4ʃ3ʃ4˃5˃5ʂ4˃5˃5ʁ3̃3̃3̃3̃3ˁ3̃3̃3̃4̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ҒӕӖ,ԗ8ә:Ӛ?՝CԛF՜H֞H՜I֝LؠPןTڠY١Y٢ZڣZآ\٣_٣b٦bڥhΡdaѺ皸iYlsxz|׀֓퐹hIƯƢ۳එ⹑ෑḏⷐᶍಃܫt٤hأeס`՟Y՜TҙKӗFѕ?ҕ:ΐ2͌ ɇʈɇɆƂyyywtssrrqpmonlifcc]YWWXXXVTNNL IKKKLKGFFFFDEFEDEDCC~ABBCCCGJSWWQNNMMMNLz>o:n:o:m9m8l9l9m:j8h7j:l9p;q<}CJMKGHLN M M L MPRRTX_emwDž9Зa٧ෛí̻ؿٿֽ׽չԹѳϴвίͭͪʩʧȥƢšßœš㿘㾔体⻏⺍ḋḌߵඇ޵ݳూ߰~ݮ{ܭzܬxܬx۩tةs۩q٦n٧mۦm٤kأi٣gנdءd֟b֞a՜^ԛ^՜^ԚXՙYӘWԘVӗUҖTҕQҕQѓOѓNђLӑLϒLЏJЏIϏHЎGЎGώDΎCЌCЌCΊAϋBόAόA΋@͊?Ί?͉=̈=Ή>͈=ʇ;ˆ9̇:͇:̆9̆8̆9ˆ8ˆ8̇9̆9ʄ7ʄ7ˆ7˅7ˆ7̄6̄6˃5̄6̄6̄6̄6˂4˂4˃5˃5˃5ʄ3ʃ3˃4˃5˃5ʂ4ʂ4˃5ʂ4˃5˃4˃5ʂ3ʃ4ʂ4˃4ʃ4ʂ4˃4ʂ4ʂ4˃5ʂ4˃4ʃ4˃4ʃ3˃4ʃ3˃4ʂ4ʂ4ʂ4˃5ʂ4ˁ3ʃ2ʂ2ʃ3ʃ3˂3̃3̃3̃3˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3Ҕӕ-Ԙ5ԙ9՛C֚G՝H՛J՜HמI֞OؠTؠUءVסZآ[ء\آ]ؤ^٤bڦbܨi۩k٧lӤokȯ7y:|C~KNSPHFVݺǤزḒ⸒㺓㹑㸐⷏޲۫s٧mףeء^֠]֝UӛNҗGЕBҕ<В6ʋɇɈʈɇǃĀ{xxvtsqssqnomllifda]WXWYYXWQOMLLMKKKIGGGGEFDEEBECCCBABBBFHJUYVPNNMNNQHt=m:m:m9n:l8k8m8l8j8j9k9n:p:s=EKMIFIM O M LN OORSU\bksŀ*͑W՟uݱ忥ȳؿٿֽ׽չԹҳϴвίͭͪʩʧȥƣšßš㿘㾔体㼏㻎ḋ᷌ߵߵݳ޳߱߰~ݮ{ܭzܬxܬxܩtةs۩qڧo٧mۦm٤kأiآfءeנc՞a֞a֝_՜^՛]ԚYԙYӘWԙVӗUҖTҕQҕQВNѓNҒMҒMΑKѐKАIΎGяHяIϏD΍CЌCЌCϋB΋A΋@όA΋@Ί?Ί?Ί=̈=χ>Έ=ʆ9̇:͇:͇:̆9̇8̇8̇8̇8͇:̆9̆9˅8ʅ7˅8ʅ7̄6˃5̄6˃5˃5̄6˄6͂4˂4̃5˃5˃5ʄ3˃5˃5ʂ4˃5ʂ4˃5˃5˃5ʂ4˃4ʃ3˄4ʃ3˃4˄3ʂ4˃5ʄ3˂5˃5ʂ4˃5˃5˃5˃5˃5˃5ʂ4˃5˃5ʂ4˃5ʂ4ʃ5̂4̃3̃3˂2˂2˂2̃3˂2̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ҕ*ӗ6֚;֚A՜GԚIԞGԝKԜI՞JמQנVآYעZנ\٢]١`٤aڤcڦfڦgܩk۬oܫs۫wثuǡsjۼ}}zǣͬxЩ۵⺖⹒⸒Ḓ⸏ⷍߵݭxۦjؤh֡bמ]םX՛SԚIДAѕ@ђ:Ύ"ˊȇʆɇȅŀ{yxwsrrssqpmnmmiddc]XXWXYYWSOMK JKKKKKIGHGEEEFDDEDCCBCCDCGFNUXWNNMLNOM Dn<p:o;m:n:l8l8m9l8j9j8k9p:o<w?FLLHHMN M L N NPQQSY_emyˈGҘhڬ߹Ǵؿٿֽ׽չԹҳϴвίͭͪʩʧȥƢšßœ㿙㿘㾔体㼐⻎ḋ᷌ᶇߵݳ޳߱߰~ޯ{ܭzܬx۬wܩtةs۩qڧo٧mۦm٤kأi٣gנdנcנc֞a֝_ԛ]՛]ԚYԙYԙXԘVӗUҖTҕQҕQђNѓNВLВLБKѐKАIΎGяHюHЏD΍CЌCЌCϋBϋBό@΋@΋@Ί?Ί?Ί=̈=χ>Έ=̈;̇:͇:͇:̆9̇9̇9ˆ7ˆ8˅8̆9ʄ7˅8ʅ7˅8ʅ7̄6̄6˃5˃5̄6˃5˄6͂4˂4̃5̓5ʃ4ʃ3˃5ʂ4˃5˃5˃5˃5˃5ʂ4˃5˃4ʄ3˄4˄4˄3ʂ5˃5Ɂ3˃5ʃ4˃5ʂ4˃5ʂ4˃5˃5ʂ4˃5ʂ4ʂ4˃5˃5ʂ4ʂ4ʃ5ˁ4̃3̃3̃3˂2˂2̃3˂2˂2˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3Җ5ӗ9֚AלH֞H՜F՝L֞MמQ֞OؠV֡YסYآ]٥_آ]٤aڤfۦgڦgۨiݫmݬpݮvޯyްyڮ~ҧyqīǸƠׯᶒ㻗⸑乒ⷒᷓ㸑ൊݯ~ڨnڤgסdנa֞WԜQӘIЕCі?ђ8͎!ɉȇɈɇDžŁ|{yxurtsssppmnlhecb]XWYYYXXTNL L JLJKLJGFGFFGFDDFFCBCBCBCDEFPU[VOMN MMNL~Bs<p:o9m9k9l8n:m:l:k9j8n:p:r<~AJKIHIMM M L N OQRRW\cjtł/͑^ף|ݴIJ̼ؿٿֽ׽չԹҳϴвίͭͪʩʧȥƣšßœš㿘俕体㼐⻎ḋ᷌ߵߵݴ޳߱߰~ޯ{ܭzܬx۬wܩtةs۩qڧo٧mۦm٤kأiآfءeנc֟b֞a՜^՜^՛]ԚYԙXԙXԘVӗUҖTҕQҕQВNғNВLВLҐKѐKЏIΏHЎGяHЏD΍CЌCЌCΊAЌB΋@όA΋@͊?Ί?͉=̉=χ>Έ=ˇ:̇:͇:͇:̆9͇:͇:˅8̆9̆9̆9˅8̆9ʅ7˅8˅7̄6̄6˃5̄6˃5̄6˄6͂4˂4̃5̃5ʃ4˄3ʂ5ʂ4˃5˃5˃5ʂ4˃5˃5˃5ʂ3˄3˄4ʃ3ʄ3˂5˄3˄3ʂ4˃5ʂ4˃5˃5ʂ4˃5˃5˃5˃5˃5˃5Ɂ3Ɂ3˃5ʂ4ʂ4Ɂ4̃2˂2̈́4̃3̃3̃3̃3˂2̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3֙9֙C؝G֝I֛J֞LםS֞OٟVןT֠Uآ[ء]ע_آaڥbۥdۧgۥhڧiުnݬtޯwܭyޯ{ް}ߴޱد̣ztĮӾ~Ҭܴ߹⺔ḒḒ⸒ᷓ⸏ⷋ߲۫tۨjףe١`נ]֝RәMԘGіAҕ?ϐ-ˊdžʇ͉ƅǁ}yyyvsrssrqnnmmkecc^XWYYWWWRPMLML JLKKHFGFFEFEEDFECCCCCCCEJQWXSMLNLLOKz@n:o;q:n:m9j6l8m9l7j7j8o;r;u<DLLGIKM N M L OPQRTZ`flyˍLКoۮɸؿٿֽ׽չӹҳϴвίͮͪʩʧȥƢšğœ㿘俕体⻏㻎ḋ᷌ߵߵݴ޳߱߱ޯ|ܭyݬx۫wܩtتs۩qڧo٧mۦm٤kأi٣gנdנcנcןb՜^ԛ]֛^՛ZԙXԙXԘVӗUҖTҕQҕQВNғNВLђMӐKѐKАIΎGяHЎGЏD΍CЌCЌCΊAϋA΋@όA΋@΋@Ί?͉=͉>Ά=Έ=ʆ9̇:͇:͇:̆9͇:̆9˅9˅8̆9˅8˅8˅8ʅ7ʄ7ˆ8̄6̄6̄6˃5̄6˃5˄6͂4˂4̃5ʃ5ʂ4˄4ʂ5ʂ4ʂ4˃5ʂ4˃5ʂ4˃5ʂ4˃4˄3˄4ʃ4ʄ3˂5˄3˄3˂5ʃ4˃5˃5˃5˃5ʂ4˂5˂5˂5˃5˃5Ɂ3ʂ4˃5Ɂ3˃5Ɂ3̃2̃3˂2˂2̃3˂2̃3˂2̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3՚=՛E֝G՜HԝK֞N֟R֟QؠWס[٣_٤a٣aڤcڥfۦgܧhڧh۩jۨlܬrݮx߯{ޯ{}ಂⶆ޴ߵݳ֮ͦ|͸Ϫױ᷒㺓⻕㺓⸒㹔⹓㹔ⷑߴݭxئkڤhסb֡a՞U՛OЖFԗCѕ@ё2͋LjɈʈʇƂ~zzyvtssrrpnnmmjdfb^XXXYZXWSNOL KKLLJIHGHGFFEEDEFDBCBBBCEFIQWYRMNMNNMHv>o:p;n:m9n:l8n9k:m9k8k9m9q;{?HJJHHLN N N N OPPTW]dirȃ7Β^ԥ}ฟİؾ׼׽ӹԸҵбвίˬͫʩʧȥƢƢß㿘侔㽓㻏㺏ṋḋඇߵߴܳಂ߱ޯ|ܭyݬx۫wܩtۨs٩qۨp٧mۦm٤kأi٣f؟dנc֟bԞa՜^՜^ԛ]՛Z֘X՘XӖVӗUӖTєPҕQѓOғNϓLӑLϑKҐKЏIϐIύFЎGЏFώCΎDЋBϋB΋AόA΋@΋@͊?͉>Ί?͈=Έ=̉=ˇ:ˈ;̆9Έ;̆9˅8̆8̇8̆9˅8̆9ʄ7ʄ7˅8ʄ7˅7˃5̄6̄6̄6˃5̄6̄6ʂ4̓5̓5ʂ4˂5ʄ3˄3˃4˃5˃5˃5ʂ4˃5ʂ4˃5ʂ4ʂ5˄3˄3˂5˄3ʃ3˄4ʃ3ʂ5ʂ4˃5ʂ4˃4˄3˄3˄3˃4˃5ʂ4˃5ʂ4ʂ4˃5˃5ʁ3̈́3̓3̓3̓3̃3̃3˂2̃3˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3՝G֝J֞KמMןR՞R֟TנVآYآ\סaעbۦeݨi٥gۨiިkڧjܩjکnݬtݮz߯{߰|ಂߵᶊ෋෉ൊඌݵڴѮƣϾɴƥձڴถ⺖㻗付ổ㺓ḑ⸓⹑ḑߴܮ|ܨp٥gסdנa՝XӜOԙJӗCҕ@Г6͌ˉɇʉɇǃ}zyywtssssppoomjeec^YXZZ[ZXSPN L KKMJJKGGGGFEFDDEFDCCBCDBFGL UYWQNLLOOOEs<m:o<o;n:m9l8m9k9j9k6m9p:s<AKLHGILM N N OPSSUY_fmzLjGҞnܭ⼧̺ؾ׽׽ԺչҵбвίͮͫʩʧȥƣĠߜš㿘侔㽓㻏㺏ṋḋඇߵߴܳಂ߱ޯ{ܭzܬx۬wܩtڨs٩qڧo٧mۦm٤kףiؤfנdנc֟b՞a՜^՜^ԛ^ԛY֘X֙YԗWӗUӖTєOҕQѓOђMϒLԒMВLҐLАIϏHЎGЎGώEώC΍C͌BϊA΋AόA΋@΋@Ί?Ί?Ί?͈=Έ>̈=ˇ:ˈ;̆9Έ;̆9͇:̆9̇8̆9͇:̆9˅8˅8˅8˅8˄7̄6̄6̄6̄6̄6̄6̄6ʂ4͂4̓5ʂ4˂5˄3˄4˃4˃5˃5˃5˃5ʂ4˃5ʂ4ʂ4ʂ4˃4˃4ʂ5˄4ʃ3˄4ʃ3ʂ4˃5ʂ4ʂ4˃4˄4˄4˄4˃4˃5˃5˃5˃5˃5˃5˃5ʁ3˃2˂2˂2˂2˂2̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3֜IםL֞NנTנW֟TנWסY֠]٣b٣cڦeڦgۨiݪlܩkݪmکl۫mݬuްzްz߱{ᲁߴᴇᵌᶋ᷌⸎㹏弒廑⹔๕ٳհͩš~ǫīĪȧϭֳܶṘ㺘ẗ⺘伙㻙㼘乕⸓⸓⸓⹔᷍ޮ}ܪr٥k٣f֟b֞\ԜQҘHӗEЕ@ѕ;Ύ'ʊ Ȇɇʈǃ~{zyxuttsqqpopmlffc_XXZZ[YWSONK LLKKLIGGGGGEFEEFEDCCBCCCCHM WYVRLMNNPMBm:p;o;o:l9k8m9n:l9k8l9n:n:w=CKLGGKM M MN MOSST]cisƂ0̓aץ}๢ǵؾؽ׽Ժչҵбвί̭ͫʩʧȥƢšßœ㿙š㿘侔㽓㻏㺏ṋḋඇߵߴܳಂ߱ޯ{ܭzܬx۬wܩtڨs٩qڧo٧mۦm٤kףi٣fנdנc֟bԝ`֝_՜^ԛ]՛Y֘X՘X՘XӗUӖTҕQєPѓOғNϒLԑLϑKяJЏIϏHяHЎGώEώC΍CΌBϋB΋AόA΋@΋@Ί?Ί?Ί?͈=Έ>̈=ˇ:ˈ;̆9Έ;̆9̆9̇9̇8˅8͇:̆9̆9˅8˅8˅8˅7̄6̄6̄6̄6̄6̄6̄6ʂ4΄6̂4˃5˃5˄3ʃ3ʃ4˃5˃5˃5ʂ4˃5ʂ4˃5˃4ʃ4ʂ4˂5˃4˄3˄4ʃ3˄4˂5˃5˃5˃5˃4˄4˄4˄4˃4˃5˃5˃5˃5˃5˃5˃5ʁ4˂2˂2˂2˂2˂2̃3̃3̃3˂2̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3֝LؠPؠU٢YןYנVןY֠\ףa٥dۦfۨiۨjܩkܩkݩl۩mۨlݭrݭyޯ{߰}~Ⳇ൉ߵᶋᶋⷌ㹎亓㺕㻕㽗⻕㺔ṓດỗ޸޸ڷܷ۸ܸݸ޻໙⻚㼛⼛㽚⼚Ἑ⺗⻘⼖⻘⻗丑㸓㹖井ⶏ߲ܫuۦi٤fآdן^֞VԚOӘGіAҔ=ϐ,ˌ ɈɉɇȄ{zxxvssrrqrnmokfee_ZXYZZYWSPNLLM KKKIHGGHEFEEEEDCBCBCCCFJOXXVPMMNOOKy?q<n:n:m:l9l9m9n:m9j8k9m:o:z@GKIGHKL L M NOPSTY^hoẙJӝoܱ㿪λؾ׽Ժչҵбϱί̭ͫʩʧȥƢšÞÝ㿙š侔㽓㻏㺏ṋḋඇߵߴܳಂ߱ޯ{ܭzܬx۬wܩtڨs٩qڧo٧mۦmأjأi٣fןdנbנc՞a՜^՜^ԛ]ԛY֘X՘XԗWԘVӖTҕQєPѓOѓNϒLԒMВLяJЏIϏHяHЎGЏFώCΎDЋBϊA΋AόA΋@΋@Ί?Ί?Ί?͈=Έ=͉=ˇ:ˈ;̆9Έ;̆9̆9̇9̇8̆9˅8̆9ʄ7ʄ7˅8˅8˄7̄6̄6̄6̄6̄6̄6̄6ʂ4̓5̓5ʂ4˃5˄4ʄ3˃4˃5˃5˃5˃5ʂ4˃5ʂ4˃4˄4Ɂ3˂5˄4ʃ3˄4˄4˄3ʂ4˃5˃5ʂ4˃4˄4˄4˄4˃4˃5˃5˃5˃5˃5˃5˃5ʁ3˃3˃3˃3˃3˃3̃3̃3̃3̃3̃3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3ʃ3nut-2.8.3/scripts/Windows/Installer/ImageFiles/Others/0000755000200500020050000000000015001555412017644 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/Others/StartService.bat0000644000200500020050000000003514777534446022717 00000000000000net start "Network UPS Tools"nut-2.8.3/scripts/Windows/Installer/ImageFiles/Others/StopService.bat0000644000200500020050000000003414777534446022546 00000000000000net stop "Network UPS Tools"nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/0000755000200500020050000000000015001555412017513 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/repairic.ico0000644000200500020050000000566614777534446021771 00000000000000 & ( @w{px{wp({w(xxx(w(w~xx(~www(zxxw w p  wp wwwwwxpx"DDDDDOxvflOxwffOxvflOxwffOxwxvfOxw~wfOxwvOxw~wOxDDDDDOxwxw?0 ( @ʦkH%zbJs2PkHs%WUI=1%sPkkHH%%sPDZksHW%UI=1%sPԎkH%zbJs2PkH%ssPPkH%zbsJP2kHs%WUI=1s%PkkHH%%sPDZksHW%UI=1s%PԎkH%ܒzbsJP2kH%ssPPkH%zbJs2PksHW%UI=1%sPkkHH%%sPkHs%WUI=1s%PkH%ܒzbsJP2kH%ssPPzzznnnbbbVVVJJJ>>>222&&&ززؕ؉º嗜ĺºĺº㜜ĺ㜕ºĺºĺº*-*-*--{{{{{{?0 nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/powernut_Stop.ico0000644000200500020050000001613614777534446023055 00000000000000-2H(-d 2QK>=7UO X~"./  AA"' HG +0(;@2NT;`dDquMHuy(;@!.2  )) 3SWemoonooookW"'" LK:hkyoopoonnoonnsS".3 YZ$KM1[\opoppoonononmv5OS*,+ww)HJlpopppnnonnmmnJrv E|c"?@"=?^sooppononnmmo@bf 8`epq`"9;$FHPppopoonnnmnmp:X[8afupqqI#QR#NP>y{sooponoonmnll"#cpqqrw=z}'`b&Y[3`cnpoponnomnnlT  )AFspqrqqs)RU.,}}'FHmoponoonmmlo)8=dN_qwtrrt)KM25WtoononmmmlDgk v'MO$HIAC/acSpprj @BEoonnnmnmm\,HMqm4jl%NO,'SU4knFP%LO4^`qmonnmmlj$) @&' *A@3111&59>dEsYU8SxFoRONKIJ?~.K%[\F:m(&:Z] 0178$>? 0KuDrecc_\[YXURPK:Z&.*QJ#.+pO{ #Eln%5NErlnmkigdba^\YV*Jn6N6=r#/4l1IQ .Dj4JNErrzxwtqpnljgecfBi#8+D(4q+@W;e6MQA^a ,?fʈԄՂՀ~{zxutqnmlZ%;,, g2JpDrCae8_ؐ׍؋؉ڇڅۃ܁}zxvtm'5K(UhFj0Mz$/4"/Fi̛ڙۗەܓݐݎތފވކބނ}|;Oj 76.K $#2Kݥݢޠߞߝߚޏߍފވ݆ۆPf*4F /08T⥾⣽᡼៻᝺ᚸߖߔޒݏېm+3A2 >`⤾⡼៺ޛޙܚ_~tr?d᧾ऻT!,('2QUÌҿ蛴z3Q  4O}Fp>>222&&&ززؕ؉嗜㜜㜕{{{{{{p ??????nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/exclamic.ico0000644000200500020050000000137614777534446021752 00000000000000 ( @33133233333333333333$DDDDDDDDDDD@12DDDDDDDDDDDDD2DDDDDD@DDDDDDC2DDDDDD34DDDDDC2DDDDD@30DDDDD3$DDDDD34DDDDD13$DDDDD@DDDDD@1332DDDDDDDDDDDC332DDDDDCDDDDD333$DDDDDDDD1333$DDDD#$DDD@133332DDDD34DDDC33332DDD@30DDD33333$DDB32DDD133333$DDC33DD@13333332DDC33DDC3333332DDC33DD3333333$DC33DD13333333$DC33D@1333333332D@30DC333333332DDDDD333333333$DDDD1333333333$DDD@133333333332DDDC33333333332DDD33333333333$DD133333333333$D@13333333333332D3333333333333"#33333333333333333333333??nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/custicon.ico0000644000200500020050000000566614777534446022022 00000000000000 & ( @w{px{wp{wxxxww~xx~wwwzxxwwpwpwwwwwxxDDDDDOxvflOxwffOxvflOxwffOxvfOx~wfOxwvOxw~wOxDDDDDOxx?( @ʦkH%zbJs2PkHs%WUI=1%sPkkHH%%sPDZksHW%UI=1%sPԎkH%zbJs2PkH%ssPPkH%zbsJP2kHs%WUI=1s%PkkHH%%sPDZksHW%UI=1s%PԎkH%ܒzbsJP2kH%ssPPkH%zbJs2PksHW%UI=1%sPkkHH%%sPkHs%WUI=1s%PkH%ܒzbsJP2kH%ssPPzzznnnbbbVVVJJJ>>>222&&&ززؕ؉嗜㜜㜕{{{{{{?nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/removico.ico0000644000200500020050000000566614777534446022016 00000000000000 & ( @pwwwwfwwvvfwnfflwww|wgwwwg|wgw|wwg|wwwwwwgtDDw~www~ww|wwwwwllw~fftwwvlgtwwwwwwwwwwtwwwwwwwwxD\wwwwGwwwwwep;wv_{{pwegv\!0~v{7pogp8p{4o?o803F??( @ʦkH%zbJs2PkHs%WUI=1%sPkkHH%%sPDZksHW%UI=1%sPԎkH%zbJs2PkH%ssPPkH%zbsJP2kHs%WUI=1s%PkkHH%%sPDZksHW%UI=1s%PԎkH%ܒzbsJP2kH%ssPPkH%zbJs2PksHW%UI=1%sPkkHH%%sPkHs%WUI=1s%PkH%ܒzbsJP2kH%ssPPzzznnnbbbVVVJJJ>>>222&&&j""j""jj"m{j"yymmm{jyymj"joomym"jjojymm"j~mm"jj~jy"j"jj~my"jjj"jm{o~~m"j{oo~j"j"jo~~m""j{oo~jmm{{{oo~~mmm{{o~gj{oojgmjjg""jm" u"mj""uj"u"""juj"y y""uju yuyy"jju y ujE""u??nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/New.ico0000644000200500020050000000047614777534446020716 00000000000000((   }nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/Up.ico0000644000200500020050000000047614777534446020551 00000000000000((  nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/powernut_logo.ico0000644000200500020050000002236614777534446023072 00000000000000-2 $(-d /.`V~s(2QK*>=M7UO̩} X~"./  -ɩAA "' TAN! HG( b+0(;@2NT;`dDquMHuy(;@!.2  7 r))  O3SWemoonooookW"'" | LK#:hkyoopoonnoonnsS".3 vYZ2<$KM1[\opoppoonononmv5OS*,2<:+ww)HJlpopppnnonnmmnJrv E|c"?@7<<0"=?^sooppononnmmo@bf |8`epq`"9;:<;7$FHPppopoonnnmnmp:X[#8afupqqI#QR=;;7#NP>y{sooponoonmnll"#%cpqqrw=z}'`b;<;;&Y[3`cnpoponnomnnlT  )AFspqrqqs)RU.<;<:,}}'FHmoponoonmmlo)8=[dN_qwtrrt)KM1;<<=225WtoononmmmlDgk v'MO$HIAC/acSpprj @B8;;8*8!>AEoonnnmnmm\,HMqm4jl%NO4,'SU4knFP%LO7;"#::%SU4^`qmonnmmlj$) @&' *A@3;111&59(>dEsYU8SxFoRONKIJ?~.Kf.--!'%[\F:m(&:Z] 0178$>? i]0KuDrecc_\[YXURPK:ZWq,-& &.*QJ#.+pO{ #Eln$%5NErlnmkigdba^\YV*Jn6N0.*6=r#/4l1IQ .Dj4JNErrzxwtqpnljgecfBi#8/$%3.+D(4q+@W;e6MQA^a! ,?f~{zxutqnmlZ%;,655, g2JpDrCae8_}zxvtm'5K(Uh:88xFj0Mz$/4E"/Fi}|;Oj'J[:<0 76.K $n.#2KPf*4F`_~tr 8?dT!,8('#ԩ 2QUz3Qs ک  4O}Fp ^0M-??_??x8nut-2.8.3/scripts/Windows/Installer/ImageFiles/icons/completi.ico0000644000200500020050000000566614777534446022007 00000000000000 & ( @w{px{wp{wxxxww~xx~wwwzxxwwpwpwwwwwxxDDDDDOxvflOxwffOxvflOxwffOxvfOx~wfOxwvOxw~wOxDDDDDOxx?( @ʦkH%zbJs2PkHs%WUI=1%sPkkHH%%sPDZksHW%UI=1%sPԎkH%zbJs2PkH%ssPPkH%zbsJP2kHs%WUI=1s%PkkHH%%sPDZksHW%UI=1s%PԎkH%ܒzbsJP2kH%ssPPkH%zbJs2PksHW%UI=1%sPkkHH%%sPkHs%WUI=1s%PkH%ܒzbsJP2kH%ssPPzzznnnbbbVVVJJJ>>>222&&&ززؕ؉嗜㜜㜕{{{{{{?nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/0000755000200500020050000000000015001555412020175 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/include/0000755000200500020050000000000015001555412021620 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/include/temp.txt0000644000200500020050000000000014777534446023263 00000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/man3/0000755000200500020050000000000015001555412021033 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/man3/temp.txt0000644000200500020050000000000014777534446022476 00000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/html/0000755000200500020050000000000015001555412021141 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/html/temp.txt0000644000200500020050000000000014777534446022604 00000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/pkgconfig/0000755000200500020050000000000015001555412022144 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/pkgconfig/temp.txt0000644000200500020050000000000014777534446023607 00000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/cgi-bin/0000755000200500020050000000000015001555412021505 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/cgi-bin/temp.txt0000644000200500020050000000000014777534446023150 00000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/man1/0000755000200500020050000000000015001555412021031 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/man1/temp.txt0000644000200500020050000000000014777534446022474 00000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/run/0000755000200500020050000000000015001555412021001 500000000000000nut-2.8.3/scripts/Windows/Installer/ImageFiles/emptyDir/run/temp.txt0000644000200500020050000000000014777534446022444 00000000000000nut-2.8.3/scripts/Windows/Makefile0000644000200500020050000007666715001555033014043 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # scripts/Windows/Makefile. Generated from Makefile.in by configure. # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. # Network UPS Tools: scripts/Windows am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/nut pkgincludedir = $(includedir)/nut pkglibdir = $(libdir)/nut pkglibexecdir = $(libexecdir)/nut am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = x86_64-pc-linux-gnu host_triplet = x86_64-pc-linux-gnu target_triplet = x86_64-pc-linux-gnu bin_PROGRAMS = $(am__EXEEXT_1) # Some binutils packages (e.g. on Slackware 15) include windres and windmc # tools, even though they do not deliver the rest of files such as windows.h # that would be needed for actual builds targeting Windows. ##am__append_1 = nut halt #am__append_2 = winevent.rc winevent.o winevent.h subdir = scripts/Windows ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = ##am__EXEEXT_1 = \ ## nut$(EXEEXT) \ ## halt$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am__halt_SOURCES_DIST = halt.c ##am_halt_OBJECTS = \ ## halt.$(OBJEXT) halt_OBJECTS = $(am_halt_OBJECTS) halt_LDADD = $(LDADD) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent am__v_lt_1 = am__nut_SOURCES_DIST = wininit.c ##am_nut_OBJECTS = \ ## wininit.$(OBJEXT) nut_OBJECTS = $(am_nut_OBJECTS) ##nut_DEPENDENCIES = $(top_builddir)/common/libcommon.la \ ## winevent.o AM_V_P = $(am__v_P_$(V)) am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I. -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/halt.Po ./$(DEPDIR)/wininit.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_$(V)) am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_$(V)) am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(halt_SOURCES) $(nut_SOURCES) DIST_SOURCES = $(am__halt_SOURCES_DIST) $(am__nut_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = /usr/bin/a2x ACLOCAL = ${SHELL} '/export/home/jim/nut/missing' aclocal-1.16 ALTPIDPATH = /var/state/ups AMTAR = $${TAR-tar} AM_DEFAULT_VERBOSITY = 0 AR = /usr/bin/ar ASCIIDOC = /usr/bin/asciidoc ASPELL = /usr/bin/aspell ASPELL_FILTER_LIB_PATH = /usr/lib/aspell ASPELL_FILTER_SHARE_PATH = /usr/share/aspell ASPELL_FILTER_TEX_PATH = /usr/lib/aspell/x86_64-linux-gnu AUGPARSE = /usr/bin/augparse AUTOCONF = ${SHELL} '/export/home/jim/nut/missing' autoconf AUTOHEADER = ${SHELL} '/export/home/jim/nut/missing' autoheader AUTOMAKE = ${SHELL} '/export/home/jim/nut/missing' automake-1.16 AWK = mawk BINDIR = /usr/local/ups/bin BSDKVMPROCLIBS = CC = gcc CCACHE_BASEDIR = CCACHE_DIR = CCACHE_NAMESPACE = nut:x86_64-linux-gnu CCACHE_PATH = CCDEPMODE = depmode=gcc3 CFLAGS = -isystem /usr/local/include -g -O2 -Wno-reserved-identifier -Wno-unknown-warning-option -std=gnu99 -Wno-system-headers -Wall -Wextra -Wsign-compare -pedantic -Werror CONFIG_CFLAGS = CONFIG_CPPFLAGS = CONFIG_CXXFLAGS = CONFIG_FLAGS = --with-all --with-dev --with-doc --enable-spellcheck --enable-warnings --enable-Werror --enable-maintainer-mode CONFIG_LDFLAGS = CONFPATH = /usr/local/ups/etc CPP = gcc -E CPPCHECK = /usr/bin/cppcheck CPPFLAGS = CPPUNIT_CFLAGS = CPPUNIT_LIBS = -lcppunit CPPUNIT_NUT_CXXFLAGS = -g -O0 CXX = g++ CXXCPP = g++ -E CXXDEPMODE = depmode=gcc3 CXXFLAGS = -isystem /usr/local/include -g -O2 -Wno-reserved-identifier -Wno-unknown-warning-option -std=gnu++11 -Wno-system-headers -Wall -Wextra -Werror CYGPATH = CYGPATH_W = echo DBLATEX = /usr/bin/dblatex DEFS = -DHAVE_CONFIG_H DEPDIR = .deps DEPLOYED_DUMMYUPS = DEPLOYED_UPSC = DEPLOYED_UPSD = DEPLOYED_UPSIMAGE = DLLTOOL = false DOC_BUILD_LIST = man-man html-single html-chunked pdf DOC_CHECK_LIST = check-man check-html-single check-html-chunked check-pdf DRIVER_BUILD_LIST = all DRIVER_INSTALL_TARGET = DRIVER_MAN_LIST = all DRIVER_MAN_LIST_PAGES = DRVPATH = /usr/local/ups/bin DSYMUTIL = DUMPBIN = ECHO_C = ECHO_N = -n ECHO_T = EGREP = /usr/bin/grep -E EXEEXT = FGREP = /usr/bin/grep -F FORCE_NUT_VERSION = FORCE GDLIB_CONFIG = GETENT = getent GREP = /usr/bin/grep HAVE_SYS_SOCKET_H = 1 HAVE_WINSOCK2_H = 0 HAVE_WS2TCPIP_H = 0 ID = id INSTALL = /usr/bin/install -c INSTALL_DATA = ${INSTALL} -m 644 INSTALL_PROGRAM = ${INSTALL} INSTALL_SCRIPT = ${INSTALL} INSTALL_STRIP_PROGRAM = $(install_sh) -c -s LD = /usr/bin/ld -m elf_x86_64 LDD = /usr/bin/ldd LDFLAGS = LDFLAGS_NUT_RPATH = -Wl,-rpath -Wl,${libdir} LDFLAGS_NUT_RPATH_CXX = -Wl,-rpath -Wl,${libdir} LIBAVAHI_CFLAGS = -D_REENTRANT LIBAVAHI_LIBS = -lavahi-common -lavahi-core -lavahi-common -lavahi-client LIBDIR = /usr/local/ups/lib LIBGD_CFLAGS = LIBGD_LDFLAGS = -lgd LIBGPIO_CFLAGS = LIBGPIO_LIBS = -lgpiod LIBI2C_LIBS = -li2c LIBIPMI_CFLAGS = LIBIPMI_LIBS = -lfreeipmi -lipmimonitoring LIBLTDL_CFLAGS = LIBLTDL_LIBS = -lltdl LIBMODBUS_CFLAGS = -I/usr/include/modbus LIBMODBUS_LIBS = -lmodbus LIBNEON_CFLAGS = -I/usr/include/neon LIBNEON_LIBS = -lneon-gnutls LIBNETSNMP_CFLAGS = LIBNETSNMP_LIBS = -lnetsnmp LIBOBJS = LIBPOWERMAN_CFLAGS = LIBPOWERMAN_LIBS = -lpowerman LIBREGEX_LIBS = LIBS = -lpthread LIBSSL_CFLAGS = LIBSSL_LDFLAGS_RPATH = LIBSSL_LIBS = -lssl -lcrypto LIBSSL_REQUIRES = openssl LIBSYSTEMD_CFLAGS = LIBSYSTEMD_LIBS = -lsystemd LIBTOOL = $(SHELL) $(top_builddir)/libtool LIBTOOL_DEPS = ./ltmain.sh LIBUSB_CFLAGS = -I/usr/include/libusb-1.0 LIBUSB_CONFIG = /usr/bin/libusb-config LIBUSB_LIBS = -lusb-1.0 LIBWRAP_CFLAGS = LIBWRAP_LIBS = -lnsl -lwrap LIPO = LN_S = ln -s LN_S_R = ln -s -r LTLIBOBJS = LT_SYS_LIBRARY_PATH = MAINT = MAKEINFO = ${SHELL} '/export/home/jim/nut/missing' makeinfo MANIFEST_TOOL = : MAN_SECTION_API = 3 MAN_SECTION_API_BASE = 3 MAN_SECTION_CFG = 5 MAN_SECTION_CFG_BASE = 5 MAN_SECTION_CMD_SYS = 8 MAN_SECTION_CMD_SYS_BASE = 8 MAN_SECTION_CMD_USR = 1 MAN_SECTION_CMD_USR_BASE = 1 MKDIR_P = /usr/bin/mkdir -p MSGFMT = /usr/bin/msgfmt NETLIBS = NETLIBS_GETADDRS = NET_SNMP_CONFIG = /usr/bin/net-snmp-config NM = /usr/bin/nm -B NMEDIT = NUT_AM_EXPORT_CCACHE_BASEDIR = # NUT_AM_EXPORT_CCACHE_DIR = # NUT_AM_EXPORT_CCACHE_NAMESPACE = NUT_AM_EXPORT_CCACHE_PATH = # NUT_AM_MAKE_CAN_EXPORT = NUT_CONFIG_CFLAGS = NUT_CONFIG_CPPFLAGS = NUT_CONFIG_CXXFLAGS = NUT_CONFIG_LDFLAGS = NUT_DATADIR = /usr/local/ups/share NUT_LIBEXECDIR = /usr/local/ups/libexec NUT_MANDIR = /usr/local/ups/share/man NUT_NETVERSION = 1.3 NUT_SOURCE_GITREV = 2.8.3 NUT_SOURCE_GITREV_IS_PRERELEASE = false NUT_SOURCE_GITREV_IS_RELEASE = true NUT_SOURCE_GITREV_NUMERIC = 2.8.3 NUT_SOURCE_GITREV_SEMVER = 2.8.3 NUT_WEBSITE_BASE = https://www.networkupstools.org/historic/v2.8.3 OBJDUMP = objdump OBJEXT = o OS_NAME = debian OTOOL = OTOOL64 = PACKAGE = nut PACKAGE_BUGREPORT = https://github.com/networkupstools/nut/issues PACKAGE_NAME = nut PACKAGE_STRING = nut 2.8.3 PACKAGE_TARNAME = nut PACKAGE_URL = https://www.networkupstools.org/historic/v2.8.3/index.html PACKAGE_VERSION = 2.8.3 PATH_DURING_CONFIGURE = /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games PATH_SEPARATOR = : PIDPATH = /run PKGCONFIGDIR = /usr/local/ups/lib/pkgconfig PKG_CONFIG = /usr/bin/pkg-config PKG_CONFIG_LIBDIR = PKG_CONFIG_PATH = PORT = 3493 POWERDOWNFLAG = /etc/killpower PREFIX = /usr/local/ups PWDTOOL = PYTHON = /usr/bin/python PYTHON2 = /usr/bin/python2.7 PYTHON2_SITE_PACKAGES = /usr/local/lib/python2.7/dist-packages PYTHON3 = /usr/bin/python3 PYTHON3_SITE_PACKAGES = /usr/lib/python3.9/site-packages PYTHON_SITE_PACKAGES = /usr/local/lib/python2.7/dist-packages RANLIB = ranlib REALPATH = realpath RUN_AS_GROUP = nogroup RUN_AS_USER = nobody SBINDIR = /usr/local/ups/sbin SED = /usr/bin/sed SEMLIBS = -lpthread SERLIBS = SET_MAKE = SHELL = /bin/bash SOURCE_HIGHLIGHT = /usr/bin/source-highlight STATEPATH = /var/state/ups STRIP = strip SUN_LIBUSB = SYSTEMCTL = systemctl SYSTEMD_ANALYZE_PROGRAM = /usr/bin/systemd-analyze SYSTEMD_DAEMON_ARGS_DRIVER = -FF SYSTEMD_DAEMON_ARGS_UPSD = -FF SYSTEMD_DAEMON_ARGS_UPSLOG = -F SYSTEMD_DAEMON_ARGS_UPSMON = -F SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = NotifyAccess=all SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = NotifyAccess=main SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = NotifyAccess=main SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = NotifyAccess=all SYSTEMD_DAEMON_TYPE_DRIVER = notify SYSTEMD_DAEMON_TYPE_UPSD = notify SYSTEMD_DAEMON_TYPE_UPSLOG = notify SYSTEMD_DAEMON_TYPE_UPSMON = notify SYSTEMD_DAEMON_WATCHDOG_DRIVER = #WatchdogSec=240s SYSTEMD_DAEMON_WATCHDOG_UPSD = #WatchdogSec=240s SYSTEMD_DAEMON_WATCHDOG_UPSLOG = #WatchdogSec=240s SYSTEMD_DAEMON_WATCHDOG_UPSMON = #WatchdogSec=240s SYSTEMD_SYSTEMCTL_PROGRAM = /usr/bin/systemctl SYSTEMD_TMPFILES_PROGRAM = /usr/bin/systemd-tmpfiles TREE_VERSION = 2.8 VALGRIND = /usr/bin/valgrind VERSION = 2.8.3 WINDMC = none WINDRES = none WORDS_BIGENDIAN = XMLLINT = /usr/bin/xmllint XSLTPROC = /usr/bin/xsltproc abs_builddir = /export/home/jim/nut/scripts/Windows abs_srcdir = /export/home/jim/nut/scripts/Windows abs_top_builddir = /export/home/jim/nut abs_top_srcdir = /export/home/jim/nut ac_ct_AR = ac_ct_CC = gcc ac_ct_CXX = g++ ac_ct_DLLTOOL = ac_ct_DUMPBIN = ac_ct_LD = ac_ct_OBJDUMP = objdump am__include = include am__leading_dot = . am__quote = am__tar = $${TAR-tar} chof - "$$tardir" am__untar = $${TAR-tar} xf - auglensdir = /usr/share/augeas/lenses/dist auglenstestsdir = /usr/share/augeas/lenses/dist/tests bindir = ${exec_prefix}/bin build = x86_64-pc-linux-gnu build_alias = build_cpu = x86_64 build_os = linux-gnu build_vendor = pc builddir = . cgiexecdir = ${exec_prefix}/cgi-bin datadir = ${datarootdir} datarootdir = ${prefix}/share devddir = docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} driverexecdir = ${exec_prefix}/bin dummy_PKG_CONFIG = dummy_PKG_CONFIG_CFLAGS = dummy_PKG_CONFIG_LIBS = dvidir = ${docdir} exec_prefix = ${prefix} freebsdquirksdir = host = x86_64-pc-linux-gnu host_alias = host_cpu = x86_64 host_os = linux-gnu host_vendor = pc hotplugdir = htmldir = ${prefix}/html htmldocdir = ${docdir}/html-doc htmlmandir = ${docdir}/html-man includedir = ${prefix}/include infodir = ${datarootdir}/info install_sh = ${SHELL} /export/home/jim/nut/install-sh libdir = ${exec_prefix}/lib libexecdir = ${exec_prefix}/libexec localedir = ${datarootdir}/locale localstatedir = ${prefix}/var mandir = ${datarootdir}/man mkdir_p = $(MKDIR_P) now = 2025-04-21 nut_with_nut_monitor = yes nut_with_nut_monitor_desktop = desktop-file-install nut_with_nut_monitor_dir = ${prefix}/share/nut-monitor nut_with_nut_monitor_py2gtk2 = nut_with_nut_monitor_py3qt5 = yes nut_with_pynut = yes nut_with_pynut_py = yes nut_with_pynut_py2 = yes nut_with_pynut_py3 = yes oldincludedir = /usr/include pdfdir = ${docdir} pkgconfigdir = ${libdir}/pkgconfig prefix = /usr/local/ups program_transform_name = s,x,x, psdir = ${docdir} runstatedir = ${localstatedir}/run sbindir = ${exec_prefix}/sbin sharedstatedir = ${prefix}/com srcdir = . sysconfdir = ${prefix}/etc systemdshutdowndir = /lib/systemd/system-shutdown systemdsystempresetdir = /lib/systemd/system-preset systemdsystemunitdir = /lib/systemd/system systemdtmpfilesdir = /usr/lib/tmpfiles.d target = x86_64-pc-linux-gnu target_alias = target_cpu = x86_64 target_os = linux-gnu target_vendor = pc top_build_prefix = ../../ top_builddir = ../.. top_srcdir = ../.. udevdir = /lib/udev AM_CFLAGS = -I$(top_srcdir)/include EXTRA_DIST = \ winevent.mc \ build-mingw-nut.sh \ build-mingw-prereqs.sh \ dllldd.sh \ README.adoc \ DriverInstaller/wdi-simple.c \ DriverInstaller/README.adoc \ Installer/README.adoc \ Installer/BuildInstaller.bat \ Installer/NUT-Installer.xml.in \ Installer/ImageFiles/icons/completi.ico \ Installer/ImageFiles/icons/info.ico \ Installer/ImageFiles/icons/custicon.ico \ Installer/ImageFiles/icons/Up.ico \ Installer/ImageFiles/icons/exclamic.ico \ Installer/ImageFiles/icons/powernut_Stop.ico \ Installer/ImageFiles/icons/repairic.ico \ Installer/ImageFiles/icons/New.ico \ Installer/ImageFiles/icons/removico.ico \ Installer/ImageFiles/icons/powernut_logo.ico \ Installer/ImageFiles/icons/insticon.ico \ Installer/ImageFiles/Images/NUT_wix_vertical.bmp \ Installer/ImageFiles/Images/NUT_wix_horizontal.bmp \ Installer/ImageFiles/Others/StopService.bat \ Installer/ImageFiles/Others/StartService.bat \ Installer/ImageFiles/emptyDir/man1/temp.txt \ Installer/ImageFiles/emptyDir/cgi-bin/temp.txt \ Installer/ImageFiles/emptyDir/pkgconfig/temp.txt \ Installer/ImageFiles/emptyDir/include/temp.txt \ Installer/ImageFiles/emptyDir/html/temp.txt \ Installer/ImageFiles/emptyDir/man3/temp.txt \ Installer/ImageFiles/emptyDir/run/temp.txt CLEANFILES = *-spellchecked */*-spellchecked $(am__append_2) ##nut_SOURCES = wininit.c ##nut_LDADD = $(top_builddir)/common/libcommon.la winevent.o ##halt_SOURCES = halt.c SPELLCHECK_SRC = README.adoc DriverInstaller/README.adoc Installer/README.adoc MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .c .in .in-spellchecked .lo .o .obj .sample .sample-spellchecked $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Windows/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Windows/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list halt$(EXEEXT): $(halt_OBJECTS) $(halt_DEPENDENCIES) $(EXTRA_halt_DEPENDENCIES) @rm -f halt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(halt_OBJECTS) $(halt_LDADD) $(LIBS) nut$(EXEEXT): $(nut_OBJECTS) $(nut_DEPENDENCIES) $(EXTRA_nut_DEPENDENCIES) @rm -f nut$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nut_OBJECTS) $(nut_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c include ./$(DEPDIR)/halt.Po # am--include-marker include ./$(DEPDIR)/wininit.Po # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ $(am__mv) $$depbase.Tpo $$depbase.Po # $(AM_V_CC)source='$<' object='$@' libtool=no \ # DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ # $(AM_V_CC_no)$(COMPILE) -c -o $@ $< .c.obj: $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ $(am__mv) $$depbase.Tpo $$depbase.Po # $(AM_V_CC)source='$<' object='$@' libtool=no \ # DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ # $(AM_V_CC_no)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ $(am__mv) $$depbase.Tpo $$depbase.Plo # $(AM_V_CC)source='$<' object='$@' libtool=yes \ # DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ # $(AM_V_CC_no)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/halt.Po -rm -f ./$(DEPDIR)/wininit.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/halt.Po -rm -f ./$(DEPDIR)/wininit.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS .PRECIOUS: Makefile $(top_builddir)/common/libcommon.la: FORCE +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) FORCE: # Avoid "Using $< in a non-suffix rule context is a GNUmake idiom" by $? #winevent.rc winevent.h: winevent.mc # $(WINDMC) $? #winevent.o: winevent.rc winevent.h # $(WINDRES) winevent.rc winevent.o #wininit.$(OBJEXT): winevent.h # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/Windows/halt.c0000644000200500020050000000342214777534446013502 00000000000000/* gcc -mwindows -mno-cygwin -o halt.exe halt.c NAME halt - stopping the system SYNOPSIS halt [-pq] DESCRIPTION The halt utility logs off the current user, flushes the file system buffers to disk, stops all processes (non-responsive processes are only forced to stop in Windows 2000), and shuts the system down. The options are as follows -p Attempt to powerdown the system. If the powerdown fails, or the system does not support software powerdown, the system will halt. -q Do not give processes a chance to shut down before halting or restarting. This option should not normally be used. AUTHOR Ben Collver Jim Klimov - slight adjustments for NUT builds */ #include "config.h" /* should be first */ #include "common.h" #include #ifndef EWX_FORCEIFHUNG #define EWX_FORCEIFHUNG 0x00000010 #endif int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { TOKEN_PRIVILEGES privileges = {1, {{{0, 0}, SE_PRIVILEGE_ENABLED}}}; HANDLE my_token; UINT my_flags; NUT_UNUSED_VARIABLE(hInstance); NUT_UNUSED_VARIABLE(hPrevInstance); NUT_UNUSED_VARIABLE(nCmdShow); my_flags = EWX_SHUTDOWN | EWX_FORCEIFHUNG; if (strstr(lpCmdLine, "q") != NULL) { my_flags |= EWX_FORCE; } if (strstr(lpCmdLine, "p") != NULL) { my_flags |= EWX_POWEROFF; } if (!LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid)) { exit(1); } if (!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &my_token)) { exit(2); } if (!AdjustTokenPrivileges( my_token, FALSE, &privileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { exit(3); } CloseHandle(my_token); if (!ExitWindowsEx(my_flags, 0)) { exit(4); } exit(0); } nut-2.8.3/scripts/hotplug/0000755000200500020050000000000015001555411012465 500000000000000nut-2.8.3/scripts/hotplug/libhidups.in0000644000200500020050000000067214553676503014746 00000000000000#!/bin/sh # This script changes the permissions and ownership of a USB device under # /proc/bus/usb to grant access to this device to users in the nut group. # # Ownership is set to root.@RUN_AS_GROUP@, permissions are set to 0664. # # Arguments : # ----------- # ACTION=[add|remove] # DEVICE=/proc/bus/usb/BBB/DDD # TYPE=usb if [ "$ACTION" = "add" -a "$TYPE" = "usb" ]; then chown root:@RUN_AS_GROUP@ "$DEVICE" chmod 0664 "$DEVICE" fi nut-2.8.3/scripts/hotplug/libhid.usermap0000644000200500020050000006674415001555411015257 00000000000000# This file is generated and installed by the Network UPS Tools package. # # Sample entry (replace 0xVVVV and 0xPPPP with vendor ID and product ID respectively) : # libhidups 0x0003 0xVVVV 0xPPPP 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # # usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info # SNR-UPS-LID-XXXX UPSes libhidups 0x0003 0x0001 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Hewlett Packard # e.g. ? libhidups 0x0003 0x03f0 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # T500 libhidups 0x0003 0x03f0 0x1f01 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # T750 libhidups 0x0003 0x03f0 0x1f02 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T750 INTL libhidups 0x0003 0x03f0 0x1f06 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T1000 INTL libhidups 0x0003 0x03f0 0x1f08 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T1500 INTL libhidups 0x0003 0x03f0 0x1f09 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP R/T 2200 INTL (like SMART2200RMXL2U) libhidups 0x0003 0x03f0 0x1f0a 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP R1500 G2 and G3 INTL libhidups 0x0003 0x03f0 0x1fe0 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T750 G2 libhidups 0x0003 0x03f0 0x1fe1 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x03f0 0x1fe2 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # HP T1500 G3 libhidups 0x0003 0x03f0 0x1fe3 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # R/T3000 libhidups 0x0003 0x03f0 0x1fe5 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # R/T3000 libhidups 0x0003 0x03f0 0x1fe6 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various models libhidups 0x0003 0x03f0 0x1fe7 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various models libhidups 0x0003 0x03f0 0x1fe8 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Eaton # various models libhidups 0x0003 0x0463 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various models libhidups 0x0003 0x0463 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Dell # various models libhidups 0x0003 0x047c 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # ST Microelectronics # TS Shara UPSes; vendor ID 0x0483 is from ST Microelectronics - with product IDs delegated to different OEMs libhidups 0x0003 0x0483 0x0035 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # USB IDs device table libhidups 0x0003 0x0483 0xa113 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Cyber Energy branded devices by CPS libhidups 0x0003 0x0483 0xa430 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # IBM # 6000 VA LCD 4U Rack UPS; 5396-1Kx libhidups 0x0003 0x04b3 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Riello (Cypress Semiconductor Corp.) # various models libhidups 0x0003 0x04b4 0x5500 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Minibox # openUPS Intelligent UPS (minimum required firmware 1.4) libhidups 0x0003 0x04d8 0xd004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # openUPS Intelligent UPS (minimum required firmware 1.4) libhidups 0x0003 0x04d8 0xd005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Belkin # F6H375-USB libhidups 0x0003 0x050d 0x0375 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C550-AVR libhidups 0x0003 0x050d 0x0551 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C1250-TW-RK libhidups 0x0003 0x050d 0x0750 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C1500-TW-RK libhidups 0x0003 0x050d 0x0751 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C900-UNV libhidups 0x0003 0x050d 0x0900 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C100-UNV libhidups 0x0003 0x050d 0x0910 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C120-UNV libhidups 0x0003 0x050d 0x0912 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C800-UNV libhidups 0x0003 0x050d 0x0980 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Regulator PRO-USB libhidups 0x0003 0x050d 0x0f51 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # F6C1100-UNV, F6C1200-UNV libhidups 0x0003 0x050d 0x1100 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # APC # APC AP9584 Serial->USB kit libhidups 0x0003 0x051d 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various models libhidups 0x0003 0x051d 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # USB IDs device table libhidups 0x0003 0x051d 0x0003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # various 5G models libhidups 0x0003 0x051d 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Powerware # various models libhidups 0x0003 0x0592 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PW 9140 libhidups 0x0003 0x0592 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Agiler UPS libhidups 0x0003 0x05b8 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Delta UPS # Delta UPS Amplon R Series, Single Phase UPS, 1/2/3 kVA libhidups 0x0003 0x05dd 0x041b 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Delta/Minuteman Enterprise Plus E1500RM2U libhidups 0x0003 0x05dd 0xa011 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Delta/Minuteman PRO1500RT2U libhidups 0x0003 0x05dd 0xa0a0 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Belkin F6C1200-UNV/Voltronic Power UPSes libhidups 0x0003 0x0665 0x5161 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Phoenixtec Power Co., Ltd # Online Yunto YQ450 libhidups 0x0003 0x06da 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Mustek Powermust libhidups 0x0003 0x06da 0x0003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Phoenixtec Innova 3/1 T libhidups 0x0003 0x06da 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Phoenixtec Innova RT libhidups 0x0003 0x06da 0x0005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Phoenixtec Innova T libhidups 0x0003 0x06da 0x0201 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Online Zinto A libhidups 0x0003 0x06da 0x0601 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PROTECT B / NAS libhidups 0x0003 0x06da 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # iDowell # iDowell libhidups 0x0003 0x075d 0x0300 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Cyber Power Systems # 900AVR/BC900D libhidups 0x0003 0x0764 0x0005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Dynex DX-800U?, CP1200AVR/BC1200D, CP825AVR-G, CP1000AVRLCD, CP1000PFCLCD, CP1500C, CP550HG, etc. libhidups 0x0003 0x0764 0x0501 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # OR2200LCDRM2U, OR700LCDRM1U, PR6000LCDRTXL5U, CP1350EPFCLCD libhidups 0x0003 0x0764 0x0601 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Sweex 1000VA libhidups 0x0003 0x0925 0x1234 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # TrippLite # e.g. OMNIVS1000, SMART550USB, ... libhidups 0x0003 0x09ae 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite AVR550U libhidups 0x0003 0x09ae 0x1003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite AVR750U libhidups 0x0003 0x09ae 0x1007 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite ECO550UPS libhidups 0x0003 0x09ae 0x1008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite ECO550UPS libhidups 0x0003 0x09ae 0x1009 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite ECO550UPS libhidups 0x0003 0x09ae 0x1010 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SU3000LCD2UHV libhidups 0x0003 0x09ae 0x1330 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite OMNI1000LCD libhidups 0x0003 0x09ae 0x2005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite OMNI900LCD libhidups 0x0003 0x09ae 0x2007 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite Smart1000LCD libhidups 0x0003 0x09ae 0x2009 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2010 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2011 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2012 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2013 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x2014 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3009 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3010 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3011 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite smart2200RMXL2U libhidups 0x0003 0x09ae 0x3012 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3013 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3014 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x3015 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite Smart1500LCD (newer unit) libhidups 0x0003 0x09ae 0x3016 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite AVR750U (newer unit) libhidups 0x0003 0x09ae 0x3024 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SmartOnline SU1500RTXL2UA (older unit?) libhidups 0x0003 0x09ae 0x4001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SmartOnline SU6000RT4U? libhidups 0x0003 0x09ae 0x4002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SmartOnline SU1500RTXL2ua libhidups 0x0003 0x09ae 0x4003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. TrippLite SmartOnline SU1000XLA libhidups 0x0003 0x09ae 0x4004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x4005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x4006 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x4007 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # e.g. ? libhidups 0x0003 0x09ae 0x4008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # KSTAR under Berkeley Varitronics Systems ID # 6000 VA LCD 4U Rack UPS; 5396-1Kx libhidups 0x0003 0x09d6 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM # PowerCOM Vanguard and BNT-xxxAP libhidups 0x0003 0x0d9f 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM Vanguard and BNT-xxxAP libhidups 0x0003 0x0d9f 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM IMP - IMPERIAL Series libhidups 0x0003 0x0d9f 0x00a2 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM SKP - Smart KING Pro (all Smart series) libhidups 0x0003 0x0d9f 0x00a3 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM WOW libhidups 0x0003 0x0d9f 0x00a4 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM VGD - Vanguard libhidups 0x0003 0x0d9f 0x00a5 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # PowerCOM BNT - Black Knight Pro libhidups 0x0003 0x0d9f 0x00a6 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Unitek Alpha 1200Sx libhidups 0x0003 0x0f03 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Liebert # Liebert GXT4 UPS libhidups 0x0003 0x10af 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Liebert PowerSure PSA UPS libhidups 0x0003 0x10af 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Liebert PowerSure PST UPS libhidups 0x0003 0x10af 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Liebert PowerSure PSI 1440 libhidups 0x0003 0x10af 0x0004 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Liebert GXT3 libhidups 0x0003 0x10af 0x0008 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # GE EP series libhidups 0x0003 0x14f0 0x00c9 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Legrand # Legrand Keor SP libhidups 0x0003 0x1cb0 0x0032 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Legrand Daker DK / DK Plus libhidups 0x0003 0x1cb0 0x0035 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Legrand Keor PDU libhidups 0x0003 0x1cb0 0x0038 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2341 0x0036 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2341 0x8036 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2a03 0x0036 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2a03 0x0040 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2a03 0x8036 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Arduino Leonardo, Leonardo ETH and Pro Micro libhidups 0x0003 0x2a03 0x8040 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # AEG # PROTECT B / NAS libhidups 0x0003 0x2b2d 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Ever # USB IDs device table libhidups 0x0003 0x2e51 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # USB IDs device table libhidups 0x0003 0x2e51 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Salicru # https://www.salicru.com/sps-3000-adv-rt2.html libhidups 0x0003 0x2e66 0x0101 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 libhidups 0x0003 0x2e66 0x0201 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 libhidups 0x0003 0x2e66 0x0202 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # SLC TWIN PRO2<=3KVA per https://github.com/networkupstools/nut/issues/450 libhidups 0x0003 0x2e66 0x0203 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # https://www.salicru.com/sps-home.html libhidups 0x0003 0x2e66 0x0300 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # https://www.salicru.com/sps-850-adv-t.html libhidups 0x0003 0x2e66 0x0302 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # EcoFlow # EcoFlow libhidups 0x0003 0x3746 0xffff 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Powervar # Powervar libhidups 0x0003 0x4234 0x0002 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 # Ablerex 625L USB (Note: earlier best-fit was "krauler_subdriver" before PR #1135) libhidups 0x0003 0xffff 0x0000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000 nut-2.8.3/scripts/hotplug/Makefile.am0000644000200500020050000000477514777767434014513 00000000000000# Network UPS Tools: scripts/hotplug EXTRA_DIST = README.adoc if WITH_HOTPLUG hotplugusbdir = $(hotplugdir)/usb dist_hotplugusb_DATA = libhid.usermap hotplugusb_SCRIPTS = libhidups else # Part of dist tarball, regardless of use for current build: EXTRA_DIST += libhid.usermap endif MAINTAINERCLEANFILES = Makefile.in .dirstamp # Generated by configure script: DISTCLEANFILES = libhidups # We should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES += libhid.usermap SPELLCHECK_SRC = README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked nut-2.8.3/scripts/hotplug/README.adoc0000644000200500020050000000231014777767434014223 00000000000000Hotplug script for NUT USB drivers ================================== Arnaud Quette v1.0, 8 January 2007 (start date) This document introduces Linux Hotplug script for NUT USB drivers (`usbhid-ups`, `bcmxcp_usb` and `tripplite_usb`). These are needed, on older Linux systems, to ensure the right privileges are set on the USB device node files (i.e. allowing `nut` user to read AND write to the UPS device). Alternative ----------- For newer 2.6 kernels with the `udev` mechanism, you should use the scripts in `scripts/udev` instead of this one. Installation ------------ For most users, these files will be automatically installed in `/etc/hotplug` upon `make install`, if that directory exists. You can specify an alternate directory by running: ---- :; ./configure --with-hotplug-dir=DIR ---- Manual installation ------------------- These scripts can be used with Linux 2.4 to 2.6.13. - possibly change `libhidups` to match NUT user - copy `libhidups` and `libhid.usermap` to `/etc/hotplug/usb/` - make `libhidups` executable with: + ---- :; chmod a+x /etc/hotplug/usb/libhidups ---- - call `update-usb.usermap` or equivalent if needed You can then plug your UPS, and start NUT. nut-2.8.3/scripts/hotplug/Makefile.in0000644000200500020050000006722015001555011014455 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: scripts/hotplug VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_HOTPLUG_FALSE@am__append_1 = libhid.usermap subdir = scripts/hotplug ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_hotplugusb_DATA_DIST) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = libhidups CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(hotplugusbdir)" \ "$(DESTDIR)$(hotplugusbdir)" SCRIPTS = $(hotplugusb_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__dist_hotplugusb_DATA_DIST = libhid.usermap DATA = $(dist_hotplugusb_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/libhidups.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = README.adoc $(am__append_1) @WITH_HOTPLUG_TRUE@hotplugusbdir = $(hotplugdir)/usb @WITH_HOTPLUG_TRUE@dist_hotplugusb_DATA = libhid.usermap @WITH_HOTPLUG_TRUE@hotplugusb_SCRIPTS = libhidups # We should never remove this one, apart from a distclean-check # or stronger... # Generated by autogen.sh and needed to run the configure script # (technically, generated by tools/nut-usbinfo.pl script among # GENERATED_USB_OS_FILES): MAINTAINERCLEANFILES = Makefile.in .dirstamp libhid.usermap # Generated by configure script: DISTCLEANFILES = libhidups SPELLCHECK_SRC = README.adoc CLEANFILES = *-spellchecked all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/hotplug/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/hotplug/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): libhidups: $(top_builddir)/config.status $(srcdir)/libhidups.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-hotplugusbSCRIPTS: $(hotplugusb_SCRIPTS) @$(NORMAL_INSTALL) @list='$(hotplugusb_SCRIPTS)'; test -n "$(hotplugusbdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(hotplugusbdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(hotplugusbdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(hotplugusbdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(hotplugusbdir)$$dir" || exit $$?; \ } \ ; done uninstall-hotplugusbSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(hotplugusb_SCRIPTS)'; test -n "$(hotplugusbdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(hotplugusbdir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_hotplugusbDATA: $(dist_hotplugusb_DATA) @$(NORMAL_INSTALL) @list='$(dist_hotplugusb_DATA)'; test -n "$(hotplugusbdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(hotplugusbdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(hotplugusbdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(hotplugusbdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(hotplugusbdir)" || exit $$?; \ done uninstall-dist_hotplugusbDATA: @$(NORMAL_UNINSTALL) @list='$(dist_hotplugusb_DATA)'; test -n "$(hotplugusbdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(hotplugusbdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: for dir in "$(DESTDIR)$(hotplugusbdir)" "$(DESTDIR)$(hotplugusbdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_hotplugusbDATA install-hotplugusbSCRIPTS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_hotplugusbDATA \ uninstall-hotplugusbSCRIPTS .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_hotplugusbDATA install-dvi install-dvi-am \ install-exec install-exec-am install-hotplugusbSCRIPTS \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am \ uninstall-dist_hotplugusbDATA uninstall-hotplugusbSCRIPTS .PRECIOUS: Makefile @WITH_HOTPLUG_FALSE@ # Part of dist tarball, regardless of use for current build: # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/scripts/upower/0000755000200500020050000000000015001555411012324 500000000000000nut-2.8.3/scripts/upower/95-upower-hid.hwdb0000644000200500020050000000736115001555411015437 00000000000000############################################################################################################## # Uninterruptible Power Supplies with USB HID interfaces # # This file was automatically generated by NUT: # https://github.com/networkupstools/nut/ # # To keep up to date, monitor upstream NUT # https://github.com/networkupstools/nut/commits/master/scripts/upower/95-upower-hid.hwdb # or checkout the NUT repository and call 'tools/nut-usbinfo.pl' # Hewlett Packard usb:v03F0p0001* usb:v03F0p1F06* usb:v03F0p1F08* usb:v03F0p1F09* usb:v03F0p1F0A* usb:v03F0p1FE0* usb:v03F0p1FE1* usb:v03F0p1FE2* usb:v03F0p1FE3* usb:v03F0p1FE5* usb:v03F0p1FE6* usb:v03F0p1FE7* usb:v03F0p1FE8* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Hewlett Packard # Eaton usb:v0463p0001* usb:v0463pFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Eaton # Dell usb:v047CpFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Dell # ST Microelectronics usb:v0483pA113* usb:v0483pA430* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=ST Microelectronics # IBM usb:v04B3p0001* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=IBM # Minibox usb:v04D8pD004* usb:v04D8pD005* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Minibox # Belkin usb:v050Dp0375* usb:v050Dp0551* usb:v050Dp0750* usb:v050Dp0751* usb:v050Dp0900* usb:v050Dp0910* usb:v050Dp0912* usb:v050Dp0980* usb:v050Dp0F51* usb:v050Dp1100* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Belkin # APC usb:v051Dp0000* usb:v051Dp0002* usb:v051Dp0003* usb:v051Dp0004* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=APC # Powerware usb:v0592p0004* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Powerware # Delta UPS usb:v05DDp041B* usb:v05DDpA011* usb:v05DDpA0A0* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Delta UPS # Phoenixtec Power Co., Ltd usb:v06DApFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Phoenixtec Power Co., Ltd # iDowell usb:v075Dp0300* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=iDowell # Cyber Power Systems usb:v0764p0005* usb:v0764p0501* usb:v0764p0601* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Cyber Power Systems # TrippLite usb:v09AEp1003* usb:v09AEp1007* usb:v09AEp1008* usb:v09AEp1009* usb:v09AEp1010* usb:v09AEp1330* usb:v09AEp2005* usb:v09AEp2007* usb:v09AEp2008* usb:v09AEp2009* usb:v09AEp2010* usb:v09AEp2011* usb:v09AEp2012* usb:v09AEp2013* usb:v09AEp2014* usb:v09AEp3008* usb:v09AEp3009* usb:v09AEp3010* usb:v09AEp3011* usb:v09AEp3012* usb:v09AEp3013* usb:v09AEp3014* usb:v09AEp3015* usb:v09AEp3016* usb:v09AEp3024* usb:v09AEp4001* usb:v09AEp4002* usb:v09AEp4003* usb:v09AEp4004* usb:v09AEp4005* usb:v09AEp4006* usb:v09AEp4007* usb:v09AEp4008* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=TrippLite # KSTAR under Berkeley Varitronics Systems ID usb:v09D6p0001* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=KSTAR under Berkeley Varitronics Systems ID # PowerCOM usb:v0D9Fp0001* usb:v0D9Fp0004* usb:v0D9Fp00A2* usb:v0D9Fp00A3* usb:v0D9Fp00A4* usb:v0D9Fp00A5* usb:v0D9Fp00A6* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=PowerCOM # Liebert usb:v10AFp0000* usb:v10AFp0001* usb:v10AFp0002* usb:v10AFp0004* usb:v10AFp0008* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Liebert # Legrand usb:v1CB0p0032* usb:v1CB0p0038* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Legrand # Arduino usb:v2341p0036* usb:v2341p8036* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Arduino # Arduino usb:v2A03p0036* usb:v2A03p0040* usb:v2A03p8036* usb:v2A03p8040* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Arduino # AEG usb:v2B2DpFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=AEG # Ever usb:v2E51p0000* usb:v2E51pFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Ever # Salicru usb:v2E66p0101* usb:v2E66p0201* usb:v2E66p0202* usb:v2E66p0203* usb:v2E66p0300* usb:v2E66p0302* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Salicru # EcoFlow usb:v3746pFFFF* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=EcoFlow # Powervar usb:v4234p0002* UPOWER_BATTERY_TYPE=ups UPOWER_VENDOR=Powervar nut-2.8.3/scripts/upower/95-upower-hid.rules0000644000200500020050000000031714777534446015667 00000000000000# Copy some attributes from the USB device to the hiddev device SUBSYSTEM=="usbmisc", SUBSYSTEMS=="usb", KERNEL=="hiddev*", IMPORT{parent}="UPOWER_*", IMPORT{parent}="ID_VENDOR", IMPORT{parent}="ID_PRODUCT" nut-2.8.3/scripts/Aix/0000755000200500020050000000000015001555410011523 500000000000000nut-2.8.3/scripts/Aix/nut-aix.spec.in0000644000200500020050000002221614777534446014345 00000000000000%define nut_id @RUN_AS_USER@ %define nut_group @RUN_AS_GROUP@ %define _prefix /usr/local/ups %define _docdir %{_datadir}/doc %define confdir %{_prefix}/etc %define rcdir /etc/rc.d %define initdir %{rcdir}/init.d %define cgidir /var/www/nut-cgi-bin %define piddir /var/run/nut Summary: Network UPS Tools Name: nut Version: @PACKAGE_VERSION@ Release: 1 Group: Applications/System License: GPLv2+ Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Url: https://www.networkupstools.org/ Source: https://www.networkupstools.org/source/@TREE_VERSION@/%{name}-%{version}.tar.gz Source1: nut.init #Source2: ups.sysconfig #Source3: nut-client.tmpfiles # FIXME: adjust according to what is available through RPM on Aix BuildRequires: libtool BuildRequires: net-snmp-devel BuildRequires: openssl-devel BuildRequires: pkgconfig # AIX BUILDERS, PLEASE NOTE: # If building with xlc version 3.6.X rather than gcc, you must ensure # you have the following PTF's installed on your system, or # you will see a runtime error that says: # "Expected but saw " # PTFS needed: U462006 U462007 U462023 U462024 U462025 U462026 U462027 # Refer to http://service.software.ibm.com/support/rs6000, or # set CC=gcc to force use of the GCC compiler. # # %define stdlib lib # %define liblink ../.. # %define DEFCC xlc %description Network UPS Tools (NUT) is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes. %package client Group: Applications/System Summary: Network UPS Tools client monitoring utilities #Requires(post): chkconfig #Requires(preun): chkconfig #Requires(pre): shadow-utils %description client This package includes the client utilities that are required to monitor a ups that the client host has access to, but where the UPS is physically attached to a different computer on the network. %package devel Group: Development/Libraries Summary: Development files for NUT Client Requires: %{name}-client = %{version}-%{release} webserver openssl-devel %description devel This package contains the development header files and libraries necessary to develop NUT client applications. %prep %setup -q %build /usr/bin/rm configure.in %configure \ --with-all \ --without-powerman \ --without-avahi \ --without-usb \ --without-ipmi \ --without-cgi \ --datadir=%{_datadir}/%{name} \ --with-user=%{nut_id} \ --with-group=%{nut_group} \ --with-statepath=%{piddir} \ --with-pidpath=%{piddir} \ --with-altpidpath=%{piddir} \ --sysconfdir=%{confdir} \ --with-cgipath=%{cgidir} \ --with-drvpath=%{_sbindir} \ --with-pkgconfig-dir=%{_libdir}/pkgconfig \ --disable-static \ --libdir=%{_libdir} \ --program-transform-name=s,^%{_target_platform}-,, \ LDFLAGS="$LDFLAGS -Wl,-brtl" \ # --with-libltdl-includes=/opt/freeware/share/libtool/libltdl/libltdl/ \ # --with-libltdl-libs=/opt/freeware/lib \ # --with-doc \ asciidoc >= 8.6.3 is required # FIXME: remove rpath? #sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool #sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool make %{?_smp_mflags} %install /usr/bin/rm -rf %{buildroot} /usr/bin/mkdir -p %{buildroot}%{_sbindir} \ %{buildroot}%{piddir} \ %{buildroot}%{_libdir}/ups \ %{buildroot}%{initdir} \ %{buildroot}%{_libexecdir} make install DESTDIR=%{buildroot} install -m 755 %{SOURCE1} %{buildroot}%{initdir}/ups /usr/bin/rm -f %{buildroot}%{_libdir}/*.la # Remove ".sample" suffix from the config filenames #pushd conf; #make install DESTDIR=%{buildroot} #for file in %{buildroot}%{confdir}/*.sample #do # mv $file %{buildroot}%{confdir}/`basename $file .sample` #done #popd %pre /usr/bin/test -L %{_libdir}/ups || \ /usr/bin/mkdir -p %{_libdir}/ups /usr/bin/grep -qc %{nut_group} /etc/group || \ /usr/bin/mkgroup %{nut_group} /usr/bin/grep -qc %{nut_id} /etc/passwd || \ /usr/sbin/useradd -c "Network UPS Tools" \ -g %{nut_group} -d %{_libdir}/ups %{nut_id} /usr/bin/test -L %{piddir} || \ /usr/bin/mkdir -p %{piddir} /usr/bin/chmod 750 %{piddir} /usr/bin/chown %{nut_id}:%{nut_group} %{piddir} %post /usr/bin/test -L %{rcdir}/rc2.d/Sups || \ /usr/bin/ln -s %{initdir}/ups %{rcdir}/rc2.d/Sups /usr/bin/test -L %{rcdir}/rc2.d/Kups || \ /usr/bin/ln -s %{initdir}/ups %{rcdir}/rc2.d/Kups exit 0 %preun %{initdir}/ups stop if [ "$1" = "0" ]; then /usr/bin/rm -f %{rcdir}/rc2.d/[SK]ups fi exit 0 %postun if [ "$1" = "0" ]; then /usr/bin/grep -qc %{nut_id} /etc/passwd && \ /usr/sbin/userdel %{nut_id} /usr/bin/grep -qc %{nut_group}: /etc/group && \ /usr/sbin/rmgroup %{nut_group} /usr/bin/test -L %{piddir} && \ /usr/bin/rm -rf %{piddir} /usr/bin/test -L %{_libdir}/ups && \ /usr/bin/rm -rf %{_libdir}/ups fi exit 0 %pre client /usr/bin/grep -qc %{nut_group}: /etc/group || \ /usr/bin/mkgroup %{nut_group} /usr/bin/grep -qc %{nut_id} /etc/passwd || \ /usr/sbin/useradd -c "Network UPS Tools" \ -g %{nut_group} -d %{_libdir}/ups %{nut_id} /usr/bin/test -L %{piddir} || \ /usr/bin/mkdir -p %{piddir} /usr/bin/chmod 750 %{piddir} /usr/bin/chown %{nut_id}:%{nut_group} %{piddir} %post client /usr/bin/test -L %{rcdir}/rc2.d/Sups || \ /usr/bin/ln -s %{initdir}/ups %{rcdir}/rc2.d/Sups /usr/bin/test -L %{rcdir}/rc2.d/Kups || \ /usr/bin/ln -s %{initdir}/ups %{rcdir}/rc2.d/Kups #%{initdir}/ups start exit 0 %preun client %{initdir}/ups stop remove="no" if /usr/bin/rpm -q nut >/dev/null 2>&1; then remove="no" elif [ "$1" = "0" ]; then remove="yes" fi if [ "$remove" = "yes" ]; then /usr/bin/rm -f %{rcdir}/rc2.d/[SK]ups /usr/bin/test -L %{piddir} && \ /usr/bin/rm -rf %{piddir} fi exit 0 %postun client remove="no" if /usr/bin/rpm -q nut >/dev/null 2>&1; then remove="no" elif [ "$1" = "0" ]; then remove="yes" fi if [ "$remove" = "yes" ]; then /usr/bin/grep -qc %{nut_id} /etc/passwd && \ /usr/sbin/userdel %{nut_id} /usr/bin/grep -qc %{nut_group}: /etc/group && \ /usr/sbin/rmgroup %{nut_group} #else # %{initdir}/ups start fi exit 0 %clean /usr/bin/rm -rf %{buildroot} %files %defattr(-,root,root,-) %attr(755,root,root) %{initdir}/ups %doc COPYING ChangeLog AUTHORS MAINTAINERS README docs UPGRADING INSTALL NEWS %config(noreplace) %attr(640,root,%nut_group) %{confdir}/nut.conf.sample %config(noreplace) %attr(640,root,%nut_group) %{confdir}/ups.conf.sample %config(noreplace) %attr(640,root,%nut_group) %{confdir}/upsd.conf.sample %config(noreplace) %attr(640,root,%nut_group) %{confdir}/upsd.users.sample %dir %attr(750,%nut_id,%nut_group) %{_libdir}/ups #%ghost %{piddir} %{_sbindir}/* %{_bindir}/upslog %{_bindir}/nutconf %{_libdir}/libnutscan.so* %{_libdir}/libupsclient.so* %{_datadir}/%{name}/cmdvartab %{_datadir}/%{name}/driver.list %{_mandir}/man5/nut.conf.5 %{_mandir}/man5/ups.conf.5 %{_mandir}/man5/upsd.conf.5 %{_mandir}/man5/upsd.users.5 %{_mandir}/man8/apcsmart.8 %{_mandir}/man8/bcmxcp.8 #%{_mandir}/man8/bcmxcp_usb.8 %{_mandir}/man8/belkin.8 %{_mandir}/man8/bestfcom.8 %{_mandir}/man8/belkinunv.8 %{_mandir}/man8/bestfortress.8 %{_mandir}/man8/bestups.8 %{_mandir}/man8/bestuferrups.8 %{_mandir}/man8/blazer.8 %{_mandir}/man8/clone.8 %{_mandir}/man8/dummy-ups.8 %{_mandir}/man8/everups.8 %{_mandir}/man8/etapro.8 %{_mandir}/man8/gamatronic.8 %{_mandir}/man8/genericups.8 %{_mandir}/man8/isbmex.8 %{_mandir}/man8/ivtscd.8 %{_mandir}/man8/liebert.8 %{_mandir}/man8/liebert-esp2.8 %{_mandir}/man8/masterguard.8 %{_mandir}/man8/metasys.8 %{_mandir}/man8/microdowell.8 %{_mandir}/man8/mge-utalk.8 %{_mandir}/man8/mge-shut.8 %{_mandir}/man8/nutupsdrv.8 %{_mandir}/man8/oneac.8 %{_mandir}/man8/optiups.8 %{_mandir}/man8/powercom.8 #%{_mandir}/man8/powerman-pdu.8 %{_mandir}/man8/powerpanel.8 %{_mandir}/man8/rhino.8 #%{_mandir}/man8/richcomm_usb.8 %{_mandir}/man8/safenet.8 %{_mandir}/man8/snmp-ups.8 %{_mandir}/man8/solis.8 %{_mandir}/man8/tripplite.8 #%{_mandir}/man8/tripplite_usb.8 %{_mandir}/man8/tripplitesu.8 %{_mandir}/man8/victronups.8 %{_mandir}/man8/upscode2.8 %{_mandir}/man8/upsd.8 %{_mandir}/man8/upsdrvctl.8 %files client %doc COPYING %defattr(-,root,root) %attr(755,root,root) %{initdir}/ups %dir %{confdir} %config(noreplace) %attr(640,root,%nut_group) %{confdir}/upsmon.conf.sample %config(noreplace) %attr(640,root,%nut_group) %{confdir}/upssched.conf.sample %dir %attr(750,%nut_id,%nut_group) %{_libdir}/ups #%ghost %{piddir} %{_bindir}/upsc %{_bindir}/upscmd %{_bindir}/upsrw %{_sbindir}/upsmon %{_sbindir}/upssched %{_bindir}/upssched-cmd %{_libdir}/libupsclient.so* %{_mandir}/man5/upsmon.conf.5 %{_mandir}/man5/upssched.conf.5 %{_mandir}/man8/upsc.8 %{_mandir}/man8/upscmd.8 %{_mandir}/man8/upsrw.8 %{_mandir}/man8/upslog.8 %{_mandir}/man8/upsmon.8 %{_mandir}/man8/upssched.8 %files devel %defattr(-,root,root,-) %{_includedir}/* %{_mandir}/man3/upscli* %{_libdir}/libupsclient.so* %{_libdir}/pkgconfig/libupsclient.pc %changelog * Tue Jul 12 2014 Arnaud Quette - 2.7.2-1.master - Minor adjustments * Tue Jul 12 2011 Arnaud Quette - 2.6.5-1.trunk - derive from RHEL 2.6.1-2, and adapt for Aix 6.1 nut-2.8.3/scripts/Aix/nut.init.in0000755000200500020050000000772414777534446013611 00000000000000#! /bin/sh # # ups: Starts the Network UPS Tools # # chkconfig: - 26 74 # description: Network UPS Tools is a collection of programs which provide a common \ # interface for monitoring and administering UPS hardware. # processname: upsd # config: /usr/local/ups/etc # config: /etc/rc.ups # ### BEGIN INIT INFO # Provides: ups # Required-Start: $syslog $network $named # Required-Stop: $local_fs # Default-Stop: 0 1 6 # Short-Description: Starts the Network UPS tools # Description: Network UPS Tools is a collection of programs which provide a common \ # interface for monitoring and administering UPS hardware. ### END INIT INFO success() { echo OK } failure() { echo FAILED } # Resolve what processes should run SERVER="no" CLIENT="no" NUT_DIR="@prefix@" NUT_SBIN_DIR="${NUT_DIR}/sbin" NUT_LIB_DIR="${NUT_DIR}/lib" NUT_RUN_DIR="@ALTPIDPATH@" CONFIG="@CONFPATH@/nut.conf" NUTUSER="@RUN_AS_USER@" NUTGROUP="@RUN_AS_GROUP@" NUT_VAR_LOCK="/var/locks/ups" NUT_QUIET_INIT_UPSNOTIFY=true export NUT_QUIET_INIT_UPSNOTIFY if [ -f "$CONFIG" ] ; then . "$CONFIG" case "$MODE" in standalone|netserver) SERVER="yes" ;; esac rpm -q nut-client >/dev/null 2>&1 && CLIENT="yes" fi do_start() { RETVAL=0 if [ ! -d "$NUT_RUN_DIR" ]; then mkdir -p "$NUT_RUN_DIR" && \ chown "root:$NUTGROUP" "$NUT_RUN_DIR" && \ chmod 770 "$NUT_RUN_DIR" RETVAL=$? fi if [ "$SERVER" = "yes" ]; then echo "Starting UPS driver controller: \c" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsdrvctl start >/dev/null 2>&1 && success || { RETVAL=$?; failure; } echo "Starting upsd: \c" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsd $UPSD_OPTIONS >/dev/null 2>&1 && success || { RETVAL=$?; failure; } fi if [ "$CLIENT" = "yes" ]; then echo "Starting UPS monitor: \c" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsmon >/dev/null 2>&1 && success || { RETVAL=$?; failure; } fi [ "$RETVAL" = 0 ] && touch "${NUT_VAR_LOCK}" return $RETVAL } do_stop() { RETVAL=0 if test -e "${NUT_RUN_DIR}"/upsmon.pid; then echo "Stopping UPS monitor: \c" PID="`cat "${NUT_RUN_DIR}"/upsmon.pid`" kill -15 $PID && success || { RETVAL=$?; failure; } rm "${NUT_RUN_DIR}"/upsmon.pid fi if [ "$SERVER" = "yes" ]; then if test -e "${NUT_RUN_DIR}"/upsd.pid; then echo "Stopping upsd: \c" PID="`cat "${NUT_RUN_DIR}"/upsd.pid`" kill -15 $PID && success || { RETVAL=$?; failure; } rm "${NUT_RUN_DIR}"/upsd.pid fi echo "Shutting down UPS driver controller: \c" "${NUT_SBIN_DIR}"/upsdrvctl stop > /dev/null 2>&1 && success || { RETVAL=$?; failure; } fi [ "$RETVAL" = 0 ] && rm -f "${NUT_VAR_LOCK}" return $RETVAL } do_restart() { do_stop waitmore=5 while [ -n "$(ls "${NUT_RUN_DIR}"/)" -a $waitmore -ge 1 ] do sleep 1 waitmore="$(expr $waitmore - 1)" done do_start } do_reload() { # FIXME: upsd and upsmon always return 0 # => can't tell if reload was successful RETVAL=0 if [ "$SERVER" = "yes" ]; then echo "Reloading upsd" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsd -c reload && success || { RETVAL=$?; failure; } fi echo "Reloading upsmon" LD_LIBRARY_PATH="${NUT_LIB_DIR}:$LD_LIBRARY_PATH" "${NUT_SBIN_DIR}"/upsmon -c reload && success || { RETVAL=$?; failure; } return $RETVAL } # See how we are called. case "$1" in start) do_start ;; stop) do_stop ;; restart) do_restart ;; try-restart) [ -f "${NUT_VAR_LOCK}" ] && do_restart || true ;; reload) do_reload ;; force-reload) do_restart ;; status) if [ "$SERVER" = "yes" ]; then if test -f "${NUT_VAR_LOCK}"; then echo "upsd is running with PID" `cat "${NUT_RUN_DIR}"/upsd.pid` fi fi if test -e "${NUT_RUN_DIR}"/upsmon.pid; then echo "upsmon is running with PID" `cat "${NUT_RUN_DIR}"/upsmon.pid` elif rpm -q nut-client >/dev/null 2>&1; then echo "upsmon isn't running" fi ;; *) echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}" RETVAL=3 esac exit $RETVAL nut-2.8.3/tests/0000755000200500020050000000000015001555412010457 500000000000000nut-2.8.3/tests/getvaluetest.c0000644000200500020050000002527614777767434013327 00000000000000/* getvaluetest - check that the bitness/endianness dependent conversions * of representation of numeric types between wire protocols and different * CPU computations produce expected results. * * See also: * https://github.com/networkupstools/nut/pull/1055 * https://github.com/networkupstools/nut/pull/1040 * https://github.com/networkupstools/nut/pull/1024 * https://github.com/networkupstools/nut/issues/1023 * * Copyright (C) * 2021 Nick Briggs * 2022-2024 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nut_stdint.h" #include #include #include #include "hidtypes.h" #include "usb-common.h" #include "common.h" void GetValue(const unsigned char *Buf, HIDData_t *pData, long *pValue); static void Usage(char *name) { printf("%s [ ]\n", name); printf(" - string of hex digit pairs, space separated\n"); printf(" - offset of the report item value in bits, typically 0..31\n"); printf(" - size of the report item value in bits: typically 1..32\n"); printf(" - logical minimum value for report item\n"); printf(" - logical maximum value for report item\n"); printf(" - expected value\n"); printf("\n"); printf("%s \"0c 64 11 0d\" 8 16 0 65535 3345\n", name); printf("\nIf no arguments are given a builtin set of tests are run.\n"); } static void PrintBufAndData(uint8_t *buf, size_t bufSize, HIDData_t *pData) { size_t i; printf("buf \""); for (i = 0; i < bufSize - 1; i++) { printf("%02x ", buf[i]); } printf("%02x\"", buf[bufSize - 1]); printf(" offset %u size %u logmin %ld (0x%lx) logmax %ld (0x%lx)", pData->Offset, pData->Size, pData->LogMin, (unsigned long)pData->LogMin, pData->LogMax, (unsigned long)pData->LogMax); } static int RunBuiltInTests(char *argv[]) { int exitStatus = 0; size_t i; char *next; uint8_t reportBuf[64]; size_t bufSize; HIDData_t data; long value; static struct { char *buf; /* item data, starts with report id byte, then remaining report bytes */ uint8_t Offset; /* item offset in bits, typically 0..31 */ uint8_t Size; /* item size in bits, typically 1..32 */ long LogMin, LogMax; /* logical minimum and maximum values */ long expectedValue; /* the expected result of decoding the value in the buffer */ } testData[] = { {.buf = "00 ff ff ff ff", .Offset = 0, .Size = 32, .LogMin = -1, .LogMax = 2147483647, .expectedValue = -1}, {.buf = "00 ff", .Offset = 0, .Size = 8, .LogMin = -1, .LogMax = 127, .expectedValue = -1}, {.buf = "00 ff", .Offset = 0, .Size = 8, .LogMin = 0, .LogMax = 127, .expectedValue = 127}, {.buf = "00 ff", .Offset = 0, .Size = 8, .LogMin = 0, .LogMax = 255, .expectedValue = 255}, {.buf = "33 00 0a 08 80", .Offset = 0, .Size = 32, .LogMin = 0, .LogMax = 65535, .expectedValue = 2560}, {.buf = "00 00 08 00 00", .Offset = 0, .Size = 32, .LogMin = 0, .LogMax = 65535, .expectedValue = 2048}, {.buf = "06 00 00 08", .Offset = 0, .Size = 8, .LogMin = 0, .LogMax = 255, .expectedValue = 0}, {.buf = "06 00 00 08", .Offset = 8, .Size = 8, .LogMin = 0, .LogMax = 255, .expectedValue = 0}, {.buf = "06 00 00 08", .Offset = 16, .Size = 8, .LogMin = 0, .LogMax = 255, .expectedValue = 8}, {.buf = "16 0c 00 00 00", .Offset = 0, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 1, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 2, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 1}, {.buf = "16 0c 00 00 00", .Offset = 3, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 1}, {.buf = "16 0c 00 00 00", .Offset = 4, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 5, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 6, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 7, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 8, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 9, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0}, {.buf = "16 0c 00 00 00", .Offset = 10, .Size = 1, .LogMin = 0, .LogMax = 1, .expectedValue = 0} }; /* See comments below about rdlen calculation emulation for tests */ usb_ctrl_char bufC[2]; signed char bufS[2]; unsigned char bufU[2]; int rdlen; NUT_UNUSED_VARIABLE(argv); for (i = 0; i < SIZEOF_ARRAY(testData); i++) { next = testData[i].buf; for (bufSize = 0; *next != 0; bufSize++) { reportBuf[bufSize] = (uint8_t) strtol(next, (char **)&next, 16); } memset((void *)&data, 0, sizeof(data)); data.Offset = testData[i].Offset; data.Size = testData[i].Size; data.LogMin = testData[i].LogMin; data.LogMax = testData[i].LogMax; GetValue(reportBuf, &data, &value); printf("Test #%" PRIuSIZE " ", i + 1); PrintBufAndData(reportBuf, bufSize, &data); if (value == testData[i].expectedValue) { printf(" value %ld PASS\n", value); } else { printf(" value %ld FAIL expected %ld\n", value, testData[i].expectedValue); exitStatus = 1; } } /* Emulate rdlen calculations in libusb{0,1}.c or * langid calculations in nutdrv_qx.c; in these * cases we take two bytes (cast from usb_ctrl_char * type, may be signed depending on used API version) * from the protocol buffer, and build a platform * dependent representation of a two-byte word. */ /* Example from issue https://github.com/networkupstools/nut/issues/1261 * where resulting length 0x01a9 should be "425" but ended up "-87" */ bufC[0] = (usb_ctrl_char)0xa9; bufC[1] = (usb_ctrl_char)0x01; bufS[0] = (signed char)0xa9; bufS[1] = (signed char)0x01; bufU[0] = (unsigned char)0xa9; bufU[1] = (unsigned char)0x01; /* Check different conversion methods and hope current build CPU, * C implementation etc. do not mess up bit-shifting vs. rotation, * zeroing high bits, int type width extension et al. If something * is mismatched below, the production NUT code may need adaptations * for that platform to count stuff correctly! */ printf("\nTesting bit-shifting approaches used in codebase to get 2-byte int lengths from wire bytes:\n"); printf("(Expected correct value is '425', incorrect '-87' or other)\n"); #define REPORT_VERDICT(expected) { if (expected) { printf(" - PASS\n"); } else { printf(" - FAIL\n"); exitStatus = 1; } } rdlen = bufC[0] | (bufC[1] << 8); printf(" * reference: no casting, usb_ctrl_char :\t%d\t(depends on libusb API built against)", rdlen); REPORT_VERDICT (rdlen == 425 || rdlen == -87) rdlen = bufS[0] | (bufS[1] << 8); printf(" * reference: no casting, signed char :\t%d\t(expected '-87' here)", rdlen); REPORT_VERDICT (rdlen == -87) rdlen = bufU[0] | (bufU[1] << 8); printf(" * reference: no casting, unsigned char :\t%d\t(expected '425')", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = (uint8_t)bufC[0] | ((uint8_t)bufC[1] << 8); printf(" * uint8_t casting, usb_ctrl_char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = (uint8_t)bufS[0] | ((uint8_t)bufS[1] << 8); printf(" * uint8_t casting, signed char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = (uint8_t)bufU[0] | ((uint8_t)bufU[1] << 8); printf(" * uint8_t casting, unsigned char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint8_t)bufC[0]) | (((uint8_t)bufC[1]) << 8); printf(" * uint8_t casting with parentheses, usb_ctrl_char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint8_t)bufS[0]) | (((uint8_t)bufS[1]) << 8); printf(" * uint8_t casting with parentheses, signed char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint8_t)bufU[0]) | (((uint8_t)bufU[1]) << 8); printf(" * uint8_t casting with parentheses, unsigned char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint16_t)(bufC[0]) & 0x00FF) | (((uint16_t)(bufC[1]) & 0x00FF) << 8); printf(" * uint16_t casting with 8-bit mask, usb_ctrl_char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint16_t)(bufS[0]) & 0x00FF) | (((uint16_t)(bufS[1]) & 0x00FF) << 8); printf(" * uint16_t casting with 8-bit mask, signed char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = ((uint16_t)(bufU[0]) & 0x00FF) | (((uint16_t)(bufU[1]) & 0x00FF) << 8); printf(" * uint16_t casting with 8-bit mask, unsigned char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = 256 * (uint8_t)(bufC[1]) + (uint8_t)(bufC[0]); printf(" * uint8_t casting with multiplication, usb_ctrl_char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = 256 * (uint8_t)(bufS[1]) + (uint8_t)(bufS[0]); printf(" * uint8_t casting with multiplication, signed char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) rdlen = 256 * (uint8_t)(bufU[1]) + (uint8_t)(bufU[0]); printf(" * uint8_t casting with multiplication, unsigned char :\t%d", rdlen); REPORT_VERDICT (rdlen == 425) return (exitStatus); } static int RunCommandLineTest(char *argv[]) { uint8_t reportBuf[64]; size_t bufSize; char *start, *end; HIDData_t data; long value, expectedValue; start = argv[1]; end = NULL; for (bufSize = 0; *start != 0; bufSize++) { reportBuf[bufSize] = (uint8_t) strtol(start, (char **)&end, 16); if (start == end) break; start = end; } memset((void *)&data, 0, sizeof(data)); data.Offset = (uint8_t) atoi(argv[2]); data.Size = (uint8_t) atoi(argv[3]); data.LogMin = strtol(argv[4], 0, 0); data.LogMax = strtol(argv[5], 0, 0); expectedValue = strtol(argv[6], 0, 0); GetValue(reportBuf, &data, &value); printf("Test #0 "); PrintBufAndData(reportBuf, bufSize, &data); if (value == expectedValue) { printf(" value %ld PASS\n", value); return (0); } else { printf(" value %ld FAIL expected %ld\n", value, expectedValue); return (1); } } int main (int argc, char *argv[]) { int status; switch (argc) { case 1: status = RunBuiltInTests(argv); break; case 7: status = RunCommandLineTest(argv); break; default: Usage(argv[0]); status = 2; } return(status); } nut-2.8.3/tests/cpputest.cpp0000644000200500020050000001616414777767434013016 00000000000000/* cpputest - basic runner for unit tests Copyright (C) 2012 Emilien Kia 2020-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include #include /* Current CPPUnit offends the honor of C++98 and maybe later versions */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ZERO_AS_NULL_POINTER_CONSTANT_BESIDEFUNC) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC # pragma GCC diagnostic ignored "-Wweak-vtables" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC # pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC # pragma GCC diagnostic ignored "-Wextra-semi" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC # pragma GCC diagnostic ignored "-Wold-style-cast" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ZERO_AS_NULL_POINTER_CONSTANT_BESIDEFUNC /* Note: this silencer is only needed here due to test bodies */ # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" # endif #endif #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma clang diagnostic push "-Wdeprecated-declarations" # endif #endif #include #include #include #include #include extern "C" { #include "timehead.h" /* Let tests also see this flag */ extern bool verbose; } bool verbose = false; // Inspired by https://stackoverflow.com/a/66702001 class MyCustomProgressTestListener : public CppUnit::TextTestProgressListener { public: virtual void startTest(CppUnit::Test *test) override; }; // Implement out of class declaration to avoid // error: 'MyCustomProgressTestListener' has no out-of-line virtual method // definitions; its vtable will be emitted in every translation unit // [-Werror,-Wweak-vtables] void MyCustomProgressTestListener::startTest(CppUnit::Test *test) { //fprintf(stderr, "starting test %s\n", test->getName().c_str()); std::cerr << "starting test " << (test == nullptr ? "" : test->getName()) << std::endl << std::flush; } int main(int argc, char* argv[]) { if (argc > 1) { if (strcmp("-v", argv[1]) == 0 || strcmp("--verbose", argv[1]) == 0 ) { verbose = true; } } ::srand(static_cast(::time(nullptr))); /* Get the top level suite from the registry */ std::cerr << "D: Getting test suite..." << std::endl; CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); /* Adds the test to the list of test to run */ std::cerr << "D: Preparing test runner..." << std::endl; CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); /* Change the default outputter to a compiler error format outputter */ std::cerr << "D: Setting test runner outputter..." << std::endl; runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); if (verbose) { /* Add a listener to report test names */ std::cerr << "D: Setting test runner listener for test names..." << std::endl; /* Only allocate when needed; static to avoid freeing */ static MyCustomProgressTestListener progress; runner.eventManager().addListener(&progress); } /* Run the tests. */ bool wasSucessful = false; try { std::cerr << "D: Launching the test run..." << std::endl; wasSucessful = runner.run(); } catch ( std::invalid_argument &e ) // Test path not resolved { std::cerr << std::endl << "ERROR: " << e.what() << std::endl; wasSucessful = false; } /* Return error code 1 if the one of test failed. */ std::cerr << "D: Got to the end of test suite with code " << "'" << ( wasSucessful ? "true" : "false" ) << "'" << std::endl; return wasSucessful ? 0 : 1; } #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ZERO_AS_NULL_POINTER_CONSTANT_BESIDEFUNC) # pragma GCC diagnostic pop #endif nut-2.8.3/tests/generic_gpio_utest.c0000644000200500020050000003260514777767434014463 00000000000000/* tests/generic_gpio_utest.c - gpio NUT driver code test tool * * Copyright (C) * 2023 - 2025 Modris Berzonis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "main.h" #include "dstate.h" #include "attribute.h" #include "nut_stdint.h" #include "generic_gpio_utest.h" #include #include #include extern struct gpioups_t *gpioupsfd; static int done=0; static int test_with_exit; static jmp_buf env_buffer; static FILE * testData; static int fEof; static int cases_passed; static int cases_failed; static char * pass_fail[2] = {"pass", "fail"}; void getWithoutUnderscores(char *var) { int i; fEof=fscanf(testData, "%s", var); for (i=0; var[i]; i++) { if (var[i]=='_') var[i]=' '; } } #define MFR "CyberPower" #define MODEL "CyberShield CSN27U12V" #define DESCRIPTION "modem and DNS server UPS" int get_test_status(struct gpioups_t *result, int on_fail_path) { int expecting_failure; int upsLinesCount; /* no of lines used in rules */ int upsMaxLine; /* maximum line number referenced in rules */ int rulesCount; /* rules subitem count: no of NUT states defined in rules*/ char stateName[12]; /* NUT state name for rules in cRules */ int subCount; /* element count in translated rules subitem */ int ruleInt; int i, j; fEof = fscanf(testData, "%d", &expecting_failure); if (on_fail_path) { if(expecting_failure) cases_failed++; else cases_passed++; return expecting_failure; } if (!expecting_failure) { cases_failed++; printf("expecting case to fail\n"); return 1; } fEof = fscanf(testData, "%d", &upsLinesCount); if (result->upsLinesCount!=upsLinesCount) { cases_failed++; printf("expecting upsLinesCount %d, got %d\n", upsLinesCount, result->upsLinesCount); return 1; } fEof = fscanf(testData, "%d", &upsMaxLine); if (result->upsMaxLine!=upsMaxLine) { cases_failed++; printf("expecting rulesCount %d, got %d\n", upsMaxLine, result->upsMaxLine); return 1; } fEof = fscanf(testData, "%d", &rulesCount); if (result->rulesCount!=rulesCount) { cases_failed++; printf("expecting rulesCount %d, got %d\n", rulesCount, result->rulesCount); return 1; } for (i=0; irulesCount; i++) { fEof=fscanf(testData, "%s", stateName); if(strcmp(result->rules[i]->stateName,stateName)) { cases_failed++; printf("expecting stateName %s, got %s for rule %d\n", stateName, result->rules[i]->stateName, i); return 1; } fEof=fscanf(testData, "%d", &subCount); if(result->rules[i]->subCount!=subCount) { cases_failed++; printf("expecting subCount %d, got %d for rule %d\n", result->rules[i]->subCount, subCount, i); return 1; } for (j=0; jrules[i]->cRules[j]!=ruleInt) { cases_failed++; printf("expecting cRule %d, got %d for rule %d subRule %d\n", ruleInt, result->rules[i]->cRules[j], i, j); return 1; } } } cases_passed++; return 0; } void exit(int code) { if (!done) { longjmp(env_buffer, 1); } else { _exit(code); } } int main(int argc, char **argv) { int jmp_result; char rules[128]; char testType[128]; char testDescFileNameBuf[LARGEBUF]; char *testDescFileName = "generic_gpio_test.txt"; unsigned int i; unsigned long version = WITH_LIBGPIO_VERSION; printf("Tests running for libgpiod library version %lu\n", version); test_with_exit=0; if(argc==2) { testDescFileName=argv[1]; } testData = fopen (testDescFileName, "r"); if(!testData) { /* FIXME NUT_WIN32_INCOMPLETE : Actually modern Windows * supports both slashes, but revise this code so we do * not mix them (maybe enforce a specific one - e.g. some * other code does replace / with \ in common.c) */ if (!strchr(testDescFileName, '/')) { /* "srcdir" may be set by automake test harness, see * https://www.gnu.org/software/automake/manual/1.12.2/html_node/Scripts_002dbased-Testsuites.html */ char *testDescFileDir = getenv("srcdir"); if (testDescFileDir) { printf("failed to open test description file %s " "in current working directory, " "retrying with srcdir %s\n", testDescFileName, testDescFileDir); if (snprintf(testDescFileNameBuf, sizeof(testDescFileNameBuf), "%s/%s", testDescFileDir, testDescFileName) > 0 ) { testDescFileName = testDescFileNameBuf; testData = fopen (testDescFileName, "r"); } } } if(!testData) { done = 1; printf("failed to open test description file %s\n", testDescFileName); exit(EXIT_FAILURE); } } cases_passed=0; cases_failed=0; fEof = 1; for (i=0; fEof!=EOF; i++) { char fmt[16]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* To avoid safety warnings, must provide a limit * here (bufsize - 1), and use fixed format strings * because scanf() does not support asterisk for * width specifier; have to create it on the fly. */ snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(rules)-1); do { fEof=fscanf(testData, fmt, rules); } while(strcmp("*", rules)); snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(testType)-1); fEof=fscanf(testData, fmt, testType); snprintf(fmt, sizeof(fmt), "%%%" PRIuSIZE "s", sizeof(rules)-1); fEof=fscanf(testData, fmt, rules); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if(fEof!=EOF) { if(!strcmp(testType, "rules")) { struct gpioups_t *upsfdtest = xcalloc(1, sizeof(*upsfdtest)); /* NOTE: here and below, freed by generic_gpio_close(&upsfdtest) */ jmp_result = setjmp(env_buffer); if(jmp_result) { /* test case exiting */ printf("%s %s test rule %u [%s]\n", pass_fail[get_test_status(upsfdtest, 1)], testType, i, rules); } else { /* run test case */ get_ups_rules(upsfdtest, (unsigned char *)rules); printf("%s %s test rule %u [%s]\n", pass_fail[get_test_status(upsfdtest, 0)], testType, i, rules); } generic_gpio_close(&upsfdtest); } if(!strcmp(testType, "states")) { int expectedStateValue; int calculatedStateValue; struct gpioups_t *upsfdtest = xcalloc(1, sizeof(*upsfdtest)); int j; get_ups_rules(upsfdtest, (unsigned char *)rules); upsfdtest->upsLinesStates = xcalloc(upsfdtest->upsLinesCount, sizeof(int)); for (j=0; j < upsfdtest->upsLinesCount; j++) { fEof=fscanf(testData, "%d", &upsfdtest->upsLinesStates[j]); } for (j=0; j < upsfdtest->rulesCount; j++) { fEof=fscanf(testData, "%d", &expectedStateValue); calculatedStateValue=calc_rule_states(upsfdtest->upsLinesStates, upsfdtest->rules[j]->cRules, upsfdtest->rules[j]->subCount, 0); if (expectedStateValue==calculatedStateValue) { printf("%s %s test rule %u [%s]\n", pass_fail[0], testType, i, rules); cases_passed++; } else { int k; printf("%s %s test rule %u [%s] %s", pass_fail[1], testType, i, rules, upsfdtest->rules[j]->stateName); for(k=0; kupsLinesCount; k++) { printf(" %d", upsfdtest->upsLinesStates[k]); } printf("\n"); cases_failed++; } } generic_gpio_close(&upsfdtest); } if(!strcmp(testType, "update")) { char upsStatus[256]; char chargeStatus[256]; char chargeLow[256]; char charge[256]; struct gpioups_t *upsfdtest = xcalloc(1, sizeof(*upsfdtest)); int j; /* "volatile" trickery to avoid the likes of: * error: variable 'failed' might be clobbered by 'longjmp' or 'vfork' [-Werror=clobbered] * due to presence of setjmp(). */ int volatile failed = 0; const char * volatile currUpsStatus = NULL; const char * volatile currChargerStatus = NULL; const char * volatile currCharge = NULL; get_ups_rules(upsfdtest, (unsigned char *)rules); upsfdtest->upsLinesStates = xcalloc(upsfdtest->upsLinesCount, sizeof(int)); for (j = 0; j < upsfdtest->upsLinesCount; j++) { fEof=fscanf(testData, "%d", &upsfdtest->upsLinesStates[j]); } getWithoutUnderscores(upsStatus); getWithoutUnderscores(chargeStatus); getWithoutUnderscores(chargeLow); getWithoutUnderscores(charge); if (strcmp(chargeLow, ".")) dstate_setinfo("battery.charge.low", "%s", chargeLow); jmp_result = setjmp(env_buffer); if (jmp_result) { failed=1; } else { update_ups_states(upsfdtest); currUpsStatus=dstate_getinfo("ups.status"); currChargerStatus=dstate_getinfo("battery.charger.status"); currCharge=dstate_getinfo("battery.charge"); if(strcmp(currUpsStatus, upsStatus)) failed=1; if( strcmp(chargeStatus,".") && (!currChargerStatus || strcmp(currChargerStatus, chargeStatus))) failed=1; if(!strcmp(chargeStatus,".") && currChargerStatus!=NULL) failed=1; if( strcmp(chargeLow,".") && strcmp(charge,".") && (!currCharge || strcmp(currCharge, charge))) failed=1; if(!strcmp(chargeLow,".") && !strcmp(charge,".") && currCharge!=NULL) failed=1; } generic_gpio_close(&upsfdtest); printf("%s %s test rule %u [%s] ([%s] %s %s (%s)) ([%s] %s %s)\n", pass_fail[failed], testType, i, rules, upsStatus, chargeStatus, charge, chargeLow, NUT_STRARG(currUpsStatus), NUT_STRARG(currChargerStatus), NUT_STRARG(currCharge)); if (!failed) { cases_passed++; } else { cases_failed++; } vartab_free(); vartab_h = NULL; } if(!strcmp(testType, "library")) { char chipNameLocal[NUT_GPIO_CHIPNAMEBUF]; int expecting_failure, failed; char subType[NUT_GPIO_SUBTYPEBUF]; fEof=fscanf(testData, "%d", &expecting_failure); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* To avoid safety warnings, must provide a limit * here (bufsize - 1), and use fixed format strings * because scanf() does not support asterisk for * width specifier; have to create it on the fly. */ snprintf(fmt, sizeof(fmt), "%%%us", (unsigned int)NUT_GPIO_CHIPNAMEBUF-1); fEof=fscanf(testData, fmt, chipNameLocal); snprintf(fmt, sizeof(fmt), "%%%us", (unsigned int)NUT_GPIO_SUBTYPEBUF-1); fEof=fscanf(testData, fmt, subType); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif jmp_result = setjmp(env_buffer); failed = expecting_failure; if(jmp_result) { /* test case exiting */ if(expecting_failure) failed=0; upsdrv_cleanup(); } else { if(expecting_failure) failed=1; device_path = chipNameLocal; if(strcmp(subType, "initinfo") || !expecting_failure) { addvar(VAR_VALUE, "rules", ""); storeval("rules", rules); } addvar(VAR_VALUE, "mfr", MFR); storeval("mfr", MFR); addvar(VAR_VALUE, "model", MODEL); storeval("model", MODEL); dstate_setinfo("device.description", DESCRIPTION); upsdrv_initups(); if(!strcmp(subType, "initinfo")) { upsdrv_makevartable(); if(expecting_failure) setNextLinesReadToFail(); upsdrv_initinfo(); if(!dstate_getinfo("device.mfr") || strcmp(dstate_getinfo("device.mfr"), MFR) || !dstate_getinfo("device.model") || strcmp(dstate_getinfo("device.model"), MODEL) || !dstate_getinfo("device.description") || strcmp(dstate_getinfo("device.description"), DESCRIPTION)) failed=1; } if(!strcmp(subType, "updateinfo")) { int k; for(k=0; kupsLinesCount; k++) { gpioupsfd->upsLinesStates[k]=-1; } if(expecting_failure) setNextLinesReadToFail(); upsdrv_updateinfo(); for(k=0; kupsLinesCount && failed!=1; k++) { if(gpioupsfd->upsLinesStates[k]<0) failed=1; } } upsdrv_cleanup(); } printf("%s %s %s test rule %u [%s] %s %d\n", pass_fail[failed], testType, subType, i, rules, chipNameLocal, expecting_failure); if (!failed) { cases_passed++; } else { cases_failed++; } vartab_free(); vartab_h = NULL; } } } printf("test_rules completed. Total cases %d, passed %d, failed %d\n", cases_passed+cases_failed, cases_passed, cases_failed); fclose(testData); done = 1; dstate_free(); /* Should be safe if we happen to run this twice for * generic_gpio_common.c, it only frees driver variables once */ upsdrv_cleanup(); /* Return 0 (exit-code OK, boolean false) if no tests failed and some ran */ if ( (cases_failed == 0) && (cases_passed > 0) ) return 0; return 1; } nut-2.8.3/tests/nutstream_ut.cpp0000644000200500020050000003334514777767434013701 00000000000000/* NUT stream unit test Copyright (C) 2012 Vaclav Krpec 2024-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nutstream.hpp" #include "nutipc.hpp" /* Used in a test to "freeze" a writer child process */ #include #include #include extern "C" { #ifndef WIN32 # include # include #else /* WIN32 */ # if !(defined random) && !(defined HAVE_RANDOM) /* WIN32 names it differently: */ # define random() rand() # endif #endif /* WIN32 */ #include #include #include extern bool verbose; } /* Current CPPUnit offends the honor of C++98 and maybe later versions */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC # pragma GCC diagnostic ignored "-Wweak-vtables" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC # pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC # pragma GCC diagnostic ignored "-Wextra-semi" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC # pragma GCC diagnostic ignored "-Wold-style-cast" # endif #endif #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma clang diagnostic push "-Wdeprecated-declarations" # endif #endif #include namespace nut { /** Test data */ static const std::string test_data( "And the mother of Jesus said unto the Lord, ""They have no more wine.""\n" "And Jesus said unto the servants, ""Fill six water pots with water.""\n" "And they did so.\n" "And when the steward of the feast did taste of the water from the pots, it had become wine.\n" "And he knew not whence it had come.\n" "But the servants did know, and they applauded loudly in the kitchen.\n" "And they said unto the Lord, ""How the Hell did you do that!?""\n" "And inquired of him ""Do you do children’s parties?""\n" "And the Lord said ""No.""\n" ); /** * \brief Read and check test data from a stream * * \param stream Input stream * * \retval true in case of success * \retval false in case of failure */ static bool readTestData(nut::NutStream * stream) { assert(nullptr != stream); // Read characters from the stream for (size_t pos = 0, iter = 0; ; ++iter) { char ch; nut::NutStream::status_t status = stream->getChar(ch); if (nut::NutStream::NUTS_ERROR == status) { if (verbose) std::cerr << "readTestData(): status==nut::NutStream::NUTS_ERROR" << std::endl; return false; } if (nut::NutStream::NUTS_EOF == status) break; if (nut::NutStream::NUTS_OK != status) { if (verbose) std::cerr << "readTestData(): status!=nut::NutStream::NUTS_OK: " << status << std::endl; return false; } if (ch != test_data.at(pos)) { if (verbose) std::cerr << "readTestData(): unexpected char '" << ch << "' at pos " << pos << ": want '" << test_data.at(pos) << "'" << std::endl; return false; } // Every other character shall be checked twice if (0 == iter % 8) continue; // Consume current character stream->readChar(); ++pos; } return true; } /** * \brief Write test data to a stream * * \param stream Output stream * * \retval true in case of success * \retval false in case of failure */ static bool writeTestData(nut::NutStream * stream) { assert(nullptr != stream); size_t pivot = static_cast(0.5 * static_cast(test_data.size())); // Write characters to the stream for (size_t i = 0; i < pivot; ++i) { char ch = test_data.at(i); nut::NutStream::status_t status = stream->putChar(ch); if (nut::NutStream::NUTS_OK != status) { if (verbose) std::cerr << "writeTestData(): status!=nut::NutStream::NUTS_OK: " << status << std::endl; return false; } } // Write string to the stream const std::string str = test_data.substr(pivot); nut::NutStream::status_t status = stream->putString(str); CPPUNIT_ASSERT(nut::NutStream::NUTS_OK == status); return true; } /** * \brief NUT stream unit test suite (abstract) */ class NutStreamUnitTest: public CppUnit::TestFixture { protected: /** * \brief Read test data from stream * * \c CPPUNIT_ASSERT macro is used to resolve error. * * \param stream Input stream */ inline void readx(nut::NutStream * stream) { CPPUNIT_ASSERT(readTestData(stream)); } /** * \brief Write test data to stream * * \c CPPUNIT_ASSERT macro is used to resolve error. * * \param stream Output stream */ inline void writex(nut::NutStream * stream) { CPPUNIT_ASSERT(writeTestData(stream)); } virtual ~NutStreamUnitTest() override; }; // end of class NutStreamUnitTest /** * \brief NUT memory stream unit test suite */ class NutMemoryUnitTest: public NutStreamUnitTest { private: CPPUNIT_TEST_SUITE(NutMemoryUnitTest); CPPUNIT_TEST(test); CPPUNIT_TEST_SUITE_END(); public: inline void setUp() override {} inline void tearDown() override {} virtual void test(); }; // end of class NutMemoryUnitTest void NutMemoryUnitTest::test() { nut::NutMemory input_mstream(test_data); nut::NutMemory output_mstream; readx(&input_mstream); writex(&output_mstream); readx(&output_mstream); } /** * \brief NUT file stream unit test suite */ class NutFileUnitTest: public NutStreamUnitTest { private: CPPUNIT_TEST_SUITE(NutFileUnitTest); CPPUNIT_TEST(test); CPPUNIT_TEST_SUITE_END(); public: inline void setUp() override {} inline void tearDown() override {} virtual void test(); }; // end of class NutFileUnitTest void NutFileUnitTest::test() { nut::NutFile fstream(nut::NutFile::ANONYMOUS); writex(&fstream); fstream.flushx(); readx(&fstream); } /** * \brief NUT socket stream unit test suite */ class NutSocketUnitTest: public NutStreamUnitTest { private: /** NUT socket stream unit test: writer */ class Writer { private: /** Remote listen address */ nut::NutSocket::Address m_remote_address; public: /** * \brief Constructor * * \param addr Remote address */ Writer(const nut::NutSocket::Address & addr): m_remote_address(addr) {} /** * \brief Writer routine * * Writer shall write contents of the test data * to its connection socket. * * \retval true in case of success * \retval false otherwise */ bool run(); }; // end of class Writer /** TCP listen address IPv4 */ static const nut::NutSocket::Address m_listen_address; CPPUNIT_TEST_SUITE(NutSocketUnitTest); CPPUNIT_TEST(test); CPPUNIT_TEST_SUITE_END(); public: inline void setUp() override {} inline void tearDown() override {} virtual void test(); }; // end of class NutSocketUnitTest /* Static initializer below may run before methods of the test, * so it tends to repeat the same port for parallel CI runs */ static long reallyRandom() { ::srand(static_cast(::time(nullptr))); return ::random(); } /* Randomize to try avoiding collisions in parallel testing */ static uint16_t getFreePort() { int tries = 100; #ifdef WIN32 WSADATA wsaData; static int wsaStarted = 0; if (!wsaStarted) { if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { std::cerr << "WIN32: Failed to WSAStartup() the socket layer" << std::endl << std::flush; } // well, at least attempted wsaStarted = 1; } #endif /* WIN32 */ while (tries > 0) { uint16_t port = 10000 + static_cast(reallyRandom() % 40000); nut::NutSocket::Address addr(127, 0, 0, 1, port); nut::NutSocket sock; int ec; std::string em; if (sock.bind(addr, ec, em)) { /* FWIW, "verbose" is only set in main() and this method currently * is part of static initialization before that. So no trace. */ if (verbose) std::cerr << "getFreePort() could bind() port " << port << "; is FD valid?=" << sock.valid() << std::endl; /* Let the destructor close it */ sock.closex(); return port; } if (verbose) std::cerr << "getFreePort() failed to bind() port " << port << ": code " << ec << " aka " << em << ": will try another" << std::endl; sock.closex(); tries--; } // Well, gotta try something... if (verbose) std::cerr << "getFreePort() failed to bind(), falling back to 10000" << std::endl; return 10000; } const nut::NutSocket::Address NutSocketUnitTest::m_listen_address( 127, 0, 0, 1, getFreePort()); bool NutSocketUnitTest::Writer::run() { nut::NutSocket conn_sock; if (!conn_sock.connect(m_remote_address)) return false; if (!writeTestData(&conn_sock)) return false; if (!conn_sock.close()) return false; return true; } void NutSocketUnitTest::test() { #ifdef WIN32 /* FIXME NUT_WIN32_INCOMPLETE: * get Process working in the first place */ std::cout << "NutSocketUnitTest::test(): skipped on this platform" << std::endl; #else /* !WIN32 */ // Fork writer pid_t writer_pid = ::fork(); if (!writer_pid) { // Wait for listen socket ::sleep(1); // Run writer CPPUNIT_ASSERT(Writer(m_listen_address).run()); exit(0); } // Freeze the writer until we bind the port CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::STOP, writer_pid)); // Listen nut::NutSocket listen_sock; std::stringstream msg_bind; msg_bind << "Expected to listen on " << m_listen_address.str(); bool bound = listen_sock.bind(m_listen_address); int retries = 5; while (!bound && retries > 0) { retries--; if (verbose) std::cerr << msg_bind.str() << ": will retry test in 15 sec (" << retries << " retries remaining)" << std::endl; sleep(15); bound = listen_sock.bind(m_listen_address); } // Un-freeze the writer as we have bound the port (or will fail next line) CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::CONT, writer_pid)); CPPUNIT_ASSERT_MESSAGE(msg_bind.str(), bound); CPPUNIT_ASSERT(listen_sock.listen(10)); // Accept connection nut::NutSocket conn_sock(nut::NutSocket::ACCEPT, listen_sock); // Read the test data readx(&conn_sock); // Wait for writer int writer_exit; pid_t wpid = ::waitpid(writer_pid, &writer_exit, 0); CPPUNIT_ASSERT(wpid == writer_pid); std::stringstream msg_writer_exit; msg_writer_exit << "Got writer_exit=" << writer_exit << ", expected 0"; CPPUNIT_ASSERT_MESSAGE(msg_writer_exit.str(), 0 == writer_exit); #endif /* !WIN32 */ } // Register the test suite CPPUNIT_TEST_SUITE_REGISTRATION(NutMemoryUnitTest); CPPUNIT_TEST_SUITE_REGISTRATION(NutFileUnitTest); CPPUNIT_TEST_SUITE_REGISTRATION(NutSocketUnitTest); // Implement out of class declaration to avoid // error: 'SomeClass' has no out-of-line virtual method // definitions; its vtable will be emitted in every translation unit // [-Werror,-Wweak-vtables] NutStreamUnitTest::~NutStreamUnitTest() {} } // namespace nut {} #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) # pragma GCC diagnostic pop #endif nut-2.8.3/tests/cpputest-client.cpp0000644000200500020050000003653714777767434014300 00000000000000/* cpputest-client - CppUnit libnutclient active test Module for NUT `cpputest` runner, to check client-server interactions as part of NIT (NUT Integration Testing) suite and similar scenarios. This is an "active" NUT client talking to an `upsd` on $NUT_PORT, as opposed to nutclienttest.cpp which unit-tests the class API etc. in isolated-binary fashion. Copyright (C) 2022-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include #include #include #include /* Current CPPUnit offends the honor of C++98 and maybe later versions */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC # pragma GCC diagnostic ignored "-Wweak-vtables" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC # pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC # pragma GCC diagnostic ignored "-Wextra-semi" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC # pragma GCC diagnostic ignored "-Wold-style-cast" # endif #endif #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma clang diagnostic push "-Wdeprecated-declarations" # endif #endif #include namespace nut { class NutActiveClientTest : public CppUnit::TestFixture { /* Note: is "friend" of nut::TcpClient class * to test a few of its protected methods */ CPPUNIT_TEST_SUITE( NutActiveClientTest ); CPPUNIT_TEST( test_query_ver ); CPPUNIT_TEST( test_list_ups ); CPPUNIT_TEST( test_list_ups_clients ); CPPUNIT_TEST( test_auth_user ); CPPUNIT_TEST( test_auth_primary ); CPPUNIT_TEST_SUITE_END(); private: /* Fed by caller via envvars: */ uint16_t NUT_PORT = 0; std::string NUT_USER = ""; std::string NUT_PASS = ""; std::string NUT_PRIMARY_DEVICE = ""; std::string NUT_SETVAR_DEVICE = ""; public: void setUp() override; void tearDown() override; void test_query_ver(); void test_list_ups(); void test_list_ups_clients(); void test_auth_user(); void test_auth_primary(); }; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( NutActiveClientTest ); } // namespace nut {} #ifndef _NUTCLIENTTEST_BUILD # define _NUTCLIENTTEST_BUILD 1 #endif #include "../clients/nutclient.h" #include "../clients/nutclientmem.h" namespace nut { extern "C" { strarr stringset_to_strarr(const std::set& strset); strarr stringvector_to_strarr(const std::vector& strset); } // extern "C" void NutActiveClientTest::setUp() { /* NUT_PORT etc. are provided by external test suite driver */ char * s; s = std::getenv("NUT_PORT"); if (s) { long l = atol(s); if (l < 1 || l > 65535) { throw std::runtime_error("NUT_PORT specified by caller is out of range"); } NUT_PORT = static_cast(l); } else { throw std::runtime_error("NUT_PORT not specified by caller, NIT should call this test"); } s = std::getenv("NUT_USER"); if (s) { NUT_USER = s; } // else stays empty s = std::getenv("NUT_PASS"); if (s) { NUT_PASS = s; } // else stays empty s = std::getenv("NUT_PRIMARY_DEVICE"); if (s) { NUT_PRIMARY_DEVICE = s; } // else stays empty s = std::getenv("NUT_SETVAR_DEVICE"); if (s) { NUT_SETVAR_DEVICE = s; } // else stays empty } void NutActiveClientTest::tearDown() { } void NutActiveClientTest::test_query_ver() { nut::TcpClient c("localhost", NUT_PORT); std::string s; std::cerr << "[D] C++ NUT Client lib test running against Data Server at: " << c.getHost() << ':' << c.getPort() << std::endl; CPPUNIT_ASSERT_MESSAGE( "TcpClient is not connected after constructor", c.isConnected()); /* Note: generic client code can not use protected methods * like low-level sendQuery(), list(), get() and some more, * but this NutActiveClientTest is a friend of TcpClient: */ s = c.sendQuery("VER"); std::cerr << "[D] Got Data Server VER: " << s << std::endl; try { s = c.sendQuery("PROTVER"); std::cerr << "[D] Got PROTVER: " << s << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Did not get PROTVER: " << ex.what() << std::endl; } try { s = c.sendQuery("NETVER"); std::cerr << "[D] Got NETVER (obsolete): " << s << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Did not get NETVER (obsolete): " << ex.what() << std::endl; } try { c.logout(); } catch(nut::NutException& ex) { std::cerr << "[D] Could not get LOGOUT: " << ex.what() << std::endl; } try { c.disconnect(); } catch(nut::NutException& ex) { /* NUT_UNUSED_VARIABLE(ex); */ std::cerr << "[D] Could not get disconnect(): " << ex.what() << std::endl; } } void NutActiveClientTest::test_list_ups() { nut::TcpClient c("localhost", NUT_PORT); std::set devs; bool noException = true; try { devs = c.getDeviceNames(); std::cerr << "[D] Got device list (" << devs.size() << "): ["; for (std::set::iterator it = devs.begin(); it != devs.end(); it++ ) { if (it != devs.begin()) { std::cerr << ", "; } std::cerr << '"' << *it << '"'; } std::cerr << "]" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not device list: " << ex.what() << std::endl; noException = false; } c.logout(); c.disconnect(); CPPUNIT_ASSERT_MESSAGE( "Failed to list UPS with TcpClient: threw NutException", noException); } void NutActiveClientTest::test_list_ups_clients() { nut::TcpClient c("localhost", NUT_PORT); std::map> deviceClients; bool noException = true; try { c.authenticate(NUT_USER, NUT_PASS); std::cerr << "[D] Authenticated without exceptions" << std::endl; /* Note: no high hopes here, credentials are checked by server * when running critical commands, not at auth request itself */ } catch(nut::NutException& ex) { std::cerr << "[D] Could not authenticate as a simple user: " << ex.what() << std::endl; /* no failure here */ } try { c.deviceLogin(NUT_PRIMARY_DEVICE); } catch(nut::NutException& ex) { std::cerr << "[D] Could not log into primary device (envvars not set?) so test below should return empty client lists: " << ex.what() << std::endl; /* no failure here */ } try { deviceClients = c.listDeviceClients(); std::cerr << "[D] Got device client list (" << deviceClients.size() << "): ["; for (std::map>::iterator itM = deviceClients.begin(); itM != deviceClients.end(); itM++ ) { if (itM != deviceClients.begin()) { std::cerr << "," << std::endl; } std::cerr << "{ \"" << itM->first << "\" : "; for (std::set::iterator it = itM->second.begin(); it != itM->second.end(); it++ ) { if (it != itM->second.begin()) { std::cerr << ", "; } std::cerr << '"' << *it << '"'; } std::cerr << " }"; } std::cerr << " ]" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not device client list: " << ex.what() << std::endl; noException = false; } c.logout(); c.disconnect(); CPPUNIT_ASSERT_MESSAGE( "Failed to list UPS with TcpClient: threw NutException", noException); } void NutActiveClientTest::test_auth_user() { if (NUT_USER.empty()) { std::cerr << "[D] SKIPPING test_auth_user()" << std::endl; return; } nut::TcpClient c("localhost", NUT_PORT); bool noException = true; try { c.authenticate(NUT_USER, NUT_PASS); std::cerr << "[D] Authenticated without exceptions" << std::endl; /* Note: no high hopes here, credentials are checked by server * when running critical commands, not at auth request itself */ } catch(nut::NutException& ex) { std::cerr << "[D] Could not authenticate as a simple user: " << ex.what() << std::endl; noException = false; } if (!NUT_SETVAR_DEVICE.empty()) { try { TrackingResult tres; TrackingID tid; int i; std::string nutVar = "ups.status"; /* Has a risk of flip-flop with NIT dummy setup */ std::string s1 = c.getDeviceVariableValue(NUT_SETVAR_DEVICE, nutVar)[0]; std::string sTest = s1 + "-test"; std::cerr << "[D] Got initial device '" << NUT_SETVAR_DEVICE << "' variable '" << nutVar << "' value: " << s1 << std::endl; CPPUNIT_ASSERT_MESSAGE( "Did not expect empty value here", !s1.empty()); tid = c.setDeviceVariable(NUT_SETVAR_DEVICE, nutVar, sTest); while ( (tres = c.getTrackingResult(tid)) == PENDING) { usleep(100); } if (tres != SUCCESS) { std::cerr << "[D] Failed to set device variable: " << "tracking result is " << tres << std::endl; noException = false; } /* Check what we got after set */ /* Note that above we told the server to tell the driver * to set a dstate entry; below we ask the server to ask * the driver and relay the answer to us. The dummy-ups * driver may also be in a sleeping state between cycles. * Data propagation may be not instantaneous, so we loop * for a while to see the expected value (or give up). */ std::string s2; for (i = 0; i < 100 ; i++) { s2 = c.getDeviceVariableValue(NUT_SETVAR_DEVICE, nutVar)[0]; if (s2 == sTest) break; usleep(100000); } std::cerr << "[D] Read back: " << s2 << " after " << (100 * i) << "msec" << std::endl; /* Fix it back */ tid = c.setDeviceVariable(NUT_SETVAR_DEVICE, nutVar, s1); while ( (tres = c.getTrackingResult(tid)) == PENDING) { usleep(100); } if (tres != SUCCESS) { std::cerr << "[D] Failed to set device variable: " << "tracking result is " << tres << std::endl; noException = false; } std::string s3; for (i = 0; i < 100 ; i++) { s3 = c.getDeviceVariableValue(NUT_SETVAR_DEVICE, nutVar)[0]; if (s3 == s1) break; usleep(100000); } std::cerr << "[D] Read back: " << s3 << " after " << (100 * i) << "msec" << std::endl; if (s3 != s1) { std::cerr << "[D] Final device variable value '" << s3 << "' differs from original '" << s1 << "'" << std::endl; noException = false; } if (s2 == s1) { std::cerr << "[D] Tweaked device variable value '" << s2 << "' does not differ from original '" << s1 << "'" << std::endl; noException = false; } if (noException) { std::cerr << "[D] Tweaked device variable value OK" << std::endl; } } catch(nut::NutException& ex) { std::cerr << "[D] Failed to set device variable: " << ex.what() << std::endl; noException = false; } } else { std::cerr << "[D] SKIPPING test_auth_user() active test " << "(got no NUT_SETVAR_DEVICE to poke)" << std::endl; } c.logout(); c.disconnect(); CPPUNIT_ASSERT_MESSAGE( "Failed to auth as user with TcpClient or tweak device variable", noException); } void NutActiveClientTest::test_auth_primary() { if (NUT_USER.empty() || NUT_PRIMARY_DEVICE.empty()) { std::cerr << "[D] SKIPPING test_auth_primary()" << std::endl; return; } nut::TcpClient c("localhost", NUT_PORT); bool noException = true; try { c.authenticate(NUT_USER, NUT_PASS); std::cerr << "[D] Authenticated without exceptions" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not authenticate as an upsmon primary user: " << ex.what() << std::endl; noException = false; } try { Device d = c.getDevice(NUT_PRIMARY_DEVICE); bool gotPrimary = false; bool gotMaster = false; try { c.deviceMaster(NUT_PRIMARY_DEVICE); gotMaster = true; std::cerr << "[D] Elevated as MASTER without exceptions" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not elevate as MASTER for " << "NUT_PRIMARY_DEVICE " << NUT_PRIMARY_DEVICE << ": " << ex.what() << std::endl; } try { c.devicePrimary(NUT_PRIMARY_DEVICE); gotPrimary = true; std::cerr << "[D] Elevated as PRIMARY without exceptions" << std::endl; } catch(nut::NutException& ex) { std::cerr << "[D] Could not elevate as PRIMARY for " << "NUT_PRIMARY_DEVICE " << NUT_PRIMARY_DEVICE << ": " << ex.what() << std::endl; } if (!gotMaster && !gotPrimary) noException = false; } catch(nut::NutException& ex) { std::cerr << "[D] NUT_PRIMARY_DEVICE " << NUT_PRIMARY_DEVICE << " not found on Data Server: " << ex.what() << std::endl; noException = false; } c.logout(); c.disconnect(); CPPUNIT_ASSERT_MESSAGE( "Failed to auth as user with TcpClient: threw NutException", noException); } } // namespace nut {} #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) # pragma GCC diagnostic pop #endif nut-2.8.3/tests/Makefile.in0000644000200500020050000033337015001555011012450 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: tests VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ TESTS = $(am__append_3) nuttimetest$(EXEEXT) nutbooltest$(EXEEXT) \ $(am__EXEEXT_1) $(am__EXEEXT_2) driver_methods_utest$(EXEEXT) \ $(am__EXEEXT_4) check_PROGRAMS = $(am__EXEEXT_5) $(am__EXEEXT_6) @REQUIRE_NUT_STRARG_TRUE@am__append_1 = nutlogtest-nofail.sh @REQUIRE_NUT_STRARG_TRUE@am__append_2 = nutlogtest-nofail.sh nutlogtest$(EXEEXT) nutlogtest # NOTE: Keep the line above empty! @REQUIRE_NUT_STRARG_FALSE@am__append_3 = nutlogtest$(EXEEXT) @WITH_USB_TRUE@am__append_4 = getvaluetest getexponenttest-belkin-hid # We only need to call a few methods, not use the whole source - so # not linking it as a getvaluetest_SOURCE file (has too many deps): @WITH_USB_TRUE@am__append_5 = libdriverstubusb.la @WITH_USB_FALSE@am__append_6 = getvaluetest.c hidparser.c @WITH_GPIO_TRUE@am__append_7 = gpiotest @WITH_GPIO_FALSE@am__append_8 = generic_gpio_utest.c generic_gpio_liblocal.c # Note: per configure script this "SHOULD" also assume # that we HAVE_CXX11 - but better have it explicit @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am__append_9 = $(TESTS_CXX11) # Note: we only build it, but do not run directly (NIT prepares the sandbox) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am__append_10 = cppnit # Currently nutconf and related codebase causes woes for static analysis # so we do not build it unless explicitly asked to. @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@@WITH_LIBNUTCONF_TRUE@am__append_11 = $(CPPUNITTESTSRC_NUTCONF) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@@WITH_LIBNUTCONF_TRUE@am__append_12 = $(top_builddir)/common/libnutconf.la # Just redistribute test source into tarball if not building tests @HAVE_CPPUNIT_FALSE@@HAVE_CXX11_TRUE@am__append_13 = $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) $(CPPUNITTESTSRC_NUTCONF) # Just redistribute test source into tarball if not building C++ at all @HAVE_CXX11_FALSE@am__append_14 = $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) $(CPPUNITTESTSRC_NUTCONF) subdir = tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @WITH_USB_TRUE@am__EXEEXT_1 = getvaluetest$(EXEEXT) \ @WITH_USB_TRUE@ getexponenttest-belkin-hid$(EXEEXT) @WITH_GPIO_TRUE@am__EXEEXT_2 = gpiotest$(EXEEXT) am__EXEEXT_3 = cppunittest$(EXEEXT) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am__EXEEXT_4 = $(am__EXEEXT_3) am__EXEEXT_5 = $(am__append_3) nuttimetest$(EXEEXT) \ nutbooltest$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) \ driver_methods_utest$(EXEEXT) $(am__EXEEXT_4) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am__EXEEXT_6 = cppnit$(EXEEXT) LTLIBRARIES = $(noinst_LTLIBRARIES) libdriverstubusb_la_LIBADD = @WITH_USB_TRUE@nodist_libdriverstubusb_la_OBJECTS = \ @WITH_USB_TRUE@ libdriverstubusb_la-driver-stub-usb.lo libdriverstubusb_la_OBJECTS = $(nodist_libdriverstubusb_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libdriverstubusb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libdriverstubusb_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ @WITH_USB_TRUE@am_libdriverstubusb_la_rpath = am__cppnit_SOURCES_DIST = cpputest-client.cpp cpputest.cpp am__objects_1 = cppnit-cpputest-client.$(OBJEXT) am__objects_2 = cppnit-cpputest.$(OBJEXT) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am_cppnit_OBJECTS = \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_1) \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_2) cppnit_OBJECTS = $(am_cppnit_OBJECTS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_DEPENDENCIES = $(top_builddir)/clients/libnutclient.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(top_builddir)/clients/libnutclientstub.la cppnit_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(cppnit_CXXFLAGS) \ $(CXXFLAGS) $(cppnit_LDFLAGS) $(LDFLAGS) -o $@ am__cppunittest_SOURCES_DIST = example.cpp nutclienttest.cpp \ cpputest.cpp nutconf_parser_ut.cpp nutstream_ut.cpp \ nutconf_ut.cpp nutipc_ut.cpp am__objects_3 = cppunittest-example.$(OBJEXT) \ cppunittest-nutclienttest.$(OBJEXT) am__objects_4 = cppunittest-cpputest.$(OBJEXT) am__objects_5 = cppunittest-nutconf_parser_ut.$(OBJEXT) \ cppunittest-nutstream_ut.$(OBJEXT) \ cppunittest-nutconf_ut.$(OBJEXT) \ cppunittest-nutipc_ut.$(OBJEXT) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@@WITH_LIBNUTCONF_TRUE@am__objects_6 = $(am__objects_5) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@am_cppunittest_OBJECTS = \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_3) \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_4) \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__objects_6) cppunittest_OBJECTS = $(am_cppunittest_OBJECTS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_DEPENDENCIES = $(top_builddir)/clients/libnutclient.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(top_builddir)/clients/libnutclientstub.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__append_12) cppunittest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(cppunittest_CXXFLAGS) \ $(CXXFLAGS) $(cppunittest_LDFLAGS) $(LDFLAGS) -o $@ am_driver_methods_utest_OBJECTS = \ driver_methods_utest-driver_methods_utest.$(OBJEXT) driver_methods_utest_OBJECTS = $(am_driver_methods_utest_OBJECTS) driver_methods_utest_DEPENDENCIES = \ $(top_builddir)/drivers/libdummy_mockdrv.la driver_methods_utest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(driver_methods_utest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__getexponenttest_belkin_hid_SOURCES_DIST = \ getexponenttest-belkin-hid.c @WITH_USB_TRUE@am_getexponenttest_belkin_hid_OBJECTS = getexponenttest_belkin_hid-getexponenttest-belkin-hid.$(OBJEXT) getexponenttest_belkin_hid_OBJECTS = \ $(am_getexponenttest_belkin_hid_OBJECTS) @WITH_USB_TRUE@getexponenttest_belkin_hid_DEPENDENCIES = \ @WITH_USB_TRUE@ $(top_builddir)/common/libcommon.la \ @WITH_USB_TRUE@ libdriverstubusb.la getexponenttest_belkin_hid_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(getexponenttest_belkin_hid_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am__getvaluetest_SOURCES_DIST = getvaluetest.c @WITH_USB_TRUE@am_getvaluetest_OBJECTS = \ @WITH_USB_TRUE@ getvaluetest-getvaluetest.$(OBJEXT) @WITH_USB_TRUE@nodist_getvaluetest_OBJECTS = \ @WITH_USB_TRUE@ getvaluetest-hidparser.$(OBJEXT) getvaluetest_OBJECTS = $(am_getvaluetest_OBJECTS) \ $(nodist_getvaluetest_OBJECTS) @WITH_USB_TRUE@getvaluetest_DEPENDENCIES = \ @WITH_USB_TRUE@ $(top_builddir)/common/libcommon.la getvaluetest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(getvaluetest_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__gpiotest_SOURCES_DIST = generic_gpio_utest.c \ generic_gpio_liblocal.c @WITH_GPIO_TRUE@am_gpiotest_OBJECTS = \ @WITH_GPIO_TRUE@ gpiotest-generic_gpio_utest.$(OBJEXT) \ @WITH_GPIO_TRUE@ gpiotest-generic_gpio_liblocal.$(OBJEXT) @WITH_GPIO_TRUE@nodist_gpiotest_OBJECTS = \ @WITH_GPIO_TRUE@ gpiotest-generic_gpio_libgpiod.$(OBJEXT) \ @WITH_GPIO_TRUE@ gpiotest-generic_gpio_common.$(OBJEXT) gpiotest_OBJECTS = $(am_gpiotest_OBJECTS) $(nodist_gpiotest_OBJECTS) @WITH_GPIO_TRUE@gpiotest_DEPENDENCIES = \ @WITH_GPIO_TRUE@ $(top_builddir)/drivers/libdummy_mockdrv.la gpiotest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(gpiotest_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_nutbooltest_OBJECTS = nutbooltest.$(OBJEXT) nutbooltest_OBJECTS = $(am_nutbooltest_OBJECTS) nutbooltest_LDADD = $(LDADD) am_nutlogtest_OBJECTS = nutlogtest.$(OBJEXT) nutlogtest_OBJECTS = $(am_nutlogtest_OBJECTS) nutlogtest_DEPENDENCIES = $(top_builddir)/common/libcommon.la am_nuttimetest_OBJECTS = nuttimetest.$(OBJEXT) nuttimetest_OBJECTS = $(am_nuttimetest_OBJECTS) nuttimetest_DEPENDENCIES = $(top_builddir)/common/libcommon.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/cppnit-cpputest-client.Po \ ./$(DEPDIR)/cppnit-cpputest.Po \ ./$(DEPDIR)/cppunittest-cpputest.Po \ ./$(DEPDIR)/cppunittest-example.Po \ ./$(DEPDIR)/cppunittest-nutclienttest.Po \ ./$(DEPDIR)/cppunittest-nutconf_parser_ut.Po \ ./$(DEPDIR)/cppunittest-nutconf_ut.Po \ ./$(DEPDIR)/cppunittest-nutipc_ut.Po \ ./$(DEPDIR)/cppunittest-nutstream_ut.Po \ ./$(DEPDIR)/driver_methods_utest-driver_methods_utest.Po \ ./$(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Po \ ./$(DEPDIR)/getvaluetest-getvaluetest.Po \ ./$(DEPDIR)/getvaluetest-hidparser.Po \ ./$(DEPDIR)/gpiotest-generic_gpio_common.Po \ ./$(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po \ ./$(DEPDIR)/gpiotest-generic_gpio_liblocal.Po \ ./$(DEPDIR)/gpiotest-generic_gpio_utest.Po \ ./$(DEPDIR)/libdriverstubusb_la-driver-stub-usb.Plo \ ./$(DEPDIR)/nutbooltest.Po ./$(DEPDIR)/nutlogtest.Po \ ./$(DEPDIR)/nuttimetest.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(nodist_libdriverstubusb_la_SOURCES) $(cppnit_SOURCES) \ $(cppunittest_SOURCES) $(driver_methods_utest_SOURCES) \ $(getexponenttest_belkin_hid_SOURCES) $(getvaluetest_SOURCES) \ $(nodist_getvaluetest_SOURCES) $(gpiotest_SOURCES) \ $(nodist_gpiotest_SOURCES) $(nutbooltest_SOURCES) \ $(nutlogtest_SOURCES) $(nuttimetest_SOURCES) DIST_SOURCES = $(am__cppnit_SOURCES_DIST) \ $(am__cppunittest_SOURCES_DIST) \ $(driver_methods_utest_SOURCES) \ $(am__getexponenttest_belkin_hid_SOURCES_DIST) \ $(am__getvaluetest_SOURCES_DIST) $(am__gpiotest_SOURCES_DIST) \ $(nutbooltest_SOURCES) $(nutlogtest_SOURCES) \ $(nuttimetest_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ check recheck distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' RECHECK_LOGS = $(TEST_LOGS) TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ $(top_srcdir)/test-driver DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ # Compiler flags for cppunit tests CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ SUBDIRS = . NIT EXTRA_DIST = nut-driver-enumerator-test.sh \ nut-driver-enumerator-test--ups.conf $(am__append_6) \ driver-stub-usb.c $(am__append_8) generic_gpio_utest.h \ generic_gpio_test.txt $(am__append_13) $(am__append_14) noinst_LTLIBRARIES = $(am__append_5) CLEANFILES = *.trs *.log $(am__append_2) generic_gpio_libgpiod.c \ generic_gpio_common.c $(LINKED_SOURCE_FILES) $(TESTS) \ $(TESTS_CXX11) AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/drivers AM_CXXFLAGS = -I$(top_srcdir)/include check_SCRIPTS = $(am__append_1) nutlogtest_SOURCES = nutlogtest.c nutlogtest_LDADD = $(top_builddir)/common/libcommon.la nuttimetest_SOURCES = nuttimetest.c nuttimetest_LDADD = $(top_builddir)/common/libcommon.la nutbooltest_SOURCES = nutbooltest.c #nutbooltest_LDADD = $(top_builddir)/common/libcommon.la # Separate the .deps of other dirs from this one LINKED_SOURCE_FILES = hidparser.c @WITH_USB_TRUE@nodist_libdriverstubusb_la_SOURCES = driver-stub-usb.c @WITH_USB_TRUE@libdriverstubusb_la_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) @WITH_USB_TRUE@getexponenttest_belkin_hid_SOURCES = getexponenttest-belkin-hid.c @WITH_USB_TRUE@getexponenttest_belkin_hid_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) @WITH_USB_TRUE@getexponenttest_belkin_hid_LDADD = $(top_builddir)/common/libcommon.la libdriverstubusb.la @WITH_USB_TRUE@getvaluetest_SOURCES = getvaluetest.c @WITH_USB_TRUE@nodist_getvaluetest_SOURCES = hidparser.c # Pull the right include path for chosen libusb version: @WITH_USB_TRUE@getvaluetest_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) @WITH_USB_TRUE@getvaluetest_LDADD = $(top_builddir)/common/libcommon.la @WITH_GPIO_TRUE@gpiotest_SOURCES = generic_gpio_utest.c generic_gpio_liblocal.c @WITH_GPIO_TRUE@nodist_gpiotest_SOURCES = generic_gpio_libgpiod.c generic_gpio_common.c @WITH_GPIO_TRUE@gpiotest_LDADD = $(top_builddir)/drivers/libdummy_mockdrv.la $(LIBGPIO_LDFLAGS) @WITH_GPIO_TRUE@gpiotest_CFLAGS = $(LIBGPIO_CFLAGS) $(AM_CFLAGS) -I$(top_srcdir)/tests -DDRIVERS_MAIN_WITHOUT_MAIN=1 driver_methods_utest_SOURCES = driver_methods_utest.c driver_methods_utest_LDADD = $(top_builddir)/drivers/libdummy_mockdrv.la driver_methods_utest_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/tests -DDRIVERS_MAIN_WITHOUT_MAIN=1 ### Optional tests which can not be built everywhere # List of src files for CppUnit tests CPPUNITTESTSRC = example.cpp nutclienttest.cpp # These are an optional part of cppunittest, if building WITH_LIBNUTCONF CPPUNITTESTSRC_NUTCONF = nutconf_parser_ut.cpp nutstream_ut.cpp nutconf_ut.cpp nutipc_ut.cpp # The test driver which orchestrates running those tests above CPPUNITTESTERSRC = cpputest.cpp CPPCLIENTTESTSRC = cpputest-client.cpp TESTS_CXX11 = cppunittest @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) ###cppunittest_CXXFLAGS += -I$(top_srcdir)/include -DTOP_SRCDIR="\"$(top_srcdir)\"" @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_LDADD = $(top_builddir)/clients/libnutclient.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(top_builddir)/clients/libnutclientstub.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__append_12) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppunittest_SOURCES = \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(CPPUNITTESTSRC) \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(CPPUNITTESTERSRC) \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(am__append_11) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_LDADD = $(top_builddir)/clients/libnutclient.la $(top_builddir)/clients/libnutclientstub.la @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit_SOURCES = $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) BUILT_SOURCES = $(LINKED_SOURCE_FILES) MAINTAINERCLEANFILES = Makefile.in .dirstamp all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libdriverstubusb.la: $(libdriverstubusb_la_OBJECTS) $(libdriverstubusb_la_DEPENDENCIES) $(EXTRA_libdriverstubusb_la_DEPENDENCIES) $(AM_V_CCLD)$(libdriverstubusb_la_LINK) $(am_libdriverstubusb_la_rpath) $(libdriverstubusb_la_OBJECTS) $(libdriverstubusb_la_LIBADD) $(LIBS) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@cppnit$(EXEEXT): $(cppnit_OBJECTS) $(cppnit_DEPENDENCIES) $(EXTRA_cppnit_DEPENDENCIES) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ @rm -f cppnit$(EXEEXT) @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ $(AM_V_CXXLD)$(cppnit_LINK) $(cppnit_OBJECTS) $(cppnit_LDADD) $(LIBS) cppunittest$(EXEEXT): $(cppunittest_OBJECTS) $(cppunittest_DEPENDENCIES) $(EXTRA_cppunittest_DEPENDENCIES) @rm -f cppunittest$(EXEEXT) $(AM_V_CXXLD)$(cppunittest_LINK) $(cppunittest_OBJECTS) $(cppunittest_LDADD) $(LIBS) driver_methods_utest$(EXEEXT): $(driver_methods_utest_OBJECTS) $(driver_methods_utest_DEPENDENCIES) $(EXTRA_driver_methods_utest_DEPENDENCIES) @rm -f driver_methods_utest$(EXEEXT) $(AM_V_CCLD)$(driver_methods_utest_LINK) $(driver_methods_utest_OBJECTS) $(driver_methods_utest_LDADD) $(LIBS) getexponenttest-belkin-hid$(EXEEXT): $(getexponenttest_belkin_hid_OBJECTS) $(getexponenttest_belkin_hid_DEPENDENCIES) $(EXTRA_getexponenttest_belkin_hid_DEPENDENCIES) @rm -f getexponenttest-belkin-hid$(EXEEXT) $(AM_V_CCLD)$(getexponenttest_belkin_hid_LINK) $(getexponenttest_belkin_hid_OBJECTS) $(getexponenttest_belkin_hid_LDADD) $(LIBS) getvaluetest$(EXEEXT): $(getvaluetest_OBJECTS) $(getvaluetest_DEPENDENCIES) $(EXTRA_getvaluetest_DEPENDENCIES) @rm -f getvaluetest$(EXEEXT) $(AM_V_CCLD)$(getvaluetest_LINK) $(getvaluetest_OBJECTS) $(getvaluetest_LDADD) $(LIBS) gpiotest$(EXEEXT): $(gpiotest_OBJECTS) $(gpiotest_DEPENDENCIES) $(EXTRA_gpiotest_DEPENDENCIES) @rm -f gpiotest$(EXEEXT) $(AM_V_CCLD)$(gpiotest_LINK) $(gpiotest_OBJECTS) $(gpiotest_LDADD) $(LIBS) nutbooltest$(EXEEXT): $(nutbooltest_OBJECTS) $(nutbooltest_DEPENDENCIES) $(EXTRA_nutbooltest_DEPENDENCIES) @rm -f nutbooltest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nutbooltest_OBJECTS) $(nutbooltest_LDADD) $(LIBS) nutlogtest$(EXEEXT): $(nutlogtest_OBJECTS) $(nutlogtest_DEPENDENCIES) $(EXTRA_nutlogtest_DEPENDENCIES) @rm -f nutlogtest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nutlogtest_OBJECTS) $(nutlogtest_LDADD) $(LIBS) nuttimetest$(EXEEXT): $(nuttimetest_OBJECTS) $(nuttimetest_DEPENDENCIES) $(EXTRA_nuttimetest_DEPENDENCIES) @rm -f nuttimetest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nuttimetest_OBJECTS) $(nuttimetest_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppnit-cpputest-client.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppnit-cpputest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-cpputest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-example.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-nutclienttest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-nutconf_parser_ut.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-nutconf_ut.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-nutipc_ut.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppunittest-nutstream_ut.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver_methods_utest-driver_methods_utest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getvaluetest-getvaluetest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getvaluetest-hidparser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpiotest-generic_gpio_common.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpiotest-generic_gpio_liblocal.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpiotest-generic_gpio_utest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdriverstubusb_la-driver-stub-usb.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutbooltest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutlogtest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nuttimetest.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libdriverstubusb_la-driver-stub-usb.lo: driver-stub-usb.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdriverstubusb_la_CFLAGS) $(CFLAGS) -MT libdriverstubusb_la-driver-stub-usb.lo -MD -MP -MF $(DEPDIR)/libdriverstubusb_la-driver-stub-usb.Tpo -c -o libdriverstubusb_la-driver-stub-usb.lo `test -f 'driver-stub-usb.c' || echo '$(srcdir)/'`driver-stub-usb.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdriverstubusb_la-driver-stub-usb.Tpo $(DEPDIR)/libdriverstubusb_la-driver-stub-usb.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='driver-stub-usb.c' object='libdriverstubusb_la-driver-stub-usb.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdriverstubusb_la_CFLAGS) $(CFLAGS) -c -o libdriverstubusb_la-driver-stub-usb.lo `test -f 'driver-stub-usb.c' || echo '$(srcdir)/'`driver-stub-usb.c driver_methods_utest-driver_methods_utest.o: driver_methods_utest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_methods_utest_CFLAGS) $(CFLAGS) -MT driver_methods_utest-driver_methods_utest.o -MD -MP -MF $(DEPDIR)/driver_methods_utest-driver_methods_utest.Tpo -c -o driver_methods_utest-driver_methods_utest.o `test -f 'driver_methods_utest.c' || echo '$(srcdir)/'`driver_methods_utest.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/driver_methods_utest-driver_methods_utest.Tpo $(DEPDIR)/driver_methods_utest-driver_methods_utest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='driver_methods_utest.c' object='driver_methods_utest-driver_methods_utest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_methods_utest_CFLAGS) $(CFLAGS) -c -o driver_methods_utest-driver_methods_utest.o `test -f 'driver_methods_utest.c' || echo '$(srcdir)/'`driver_methods_utest.c driver_methods_utest-driver_methods_utest.obj: driver_methods_utest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_methods_utest_CFLAGS) $(CFLAGS) -MT driver_methods_utest-driver_methods_utest.obj -MD -MP -MF $(DEPDIR)/driver_methods_utest-driver_methods_utest.Tpo -c -o driver_methods_utest-driver_methods_utest.obj `if test -f 'driver_methods_utest.c'; then $(CYGPATH_W) 'driver_methods_utest.c'; else $(CYGPATH_W) '$(srcdir)/driver_methods_utest.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/driver_methods_utest-driver_methods_utest.Tpo $(DEPDIR)/driver_methods_utest-driver_methods_utest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='driver_methods_utest.c' object='driver_methods_utest-driver_methods_utest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_methods_utest_CFLAGS) $(CFLAGS) -c -o driver_methods_utest-driver_methods_utest.obj `if test -f 'driver_methods_utest.c'; then $(CYGPATH_W) 'driver_methods_utest.c'; else $(CYGPATH_W) '$(srcdir)/driver_methods_utest.c'; fi` getexponenttest_belkin_hid-getexponenttest-belkin-hid.o: getexponenttest-belkin-hid.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getexponenttest_belkin_hid_CFLAGS) $(CFLAGS) -MT getexponenttest_belkin_hid-getexponenttest-belkin-hid.o -MD -MP -MF $(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Tpo -c -o getexponenttest_belkin_hid-getexponenttest-belkin-hid.o `test -f 'getexponenttest-belkin-hid.c' || echo '$(srcdir)/'`getexponenttest-belkin-hid.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Tpo $(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getexponenttest-belkin-hid.c' object='getexponenttest_belkin_hid-getexponenttest-belkin-hid.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getexponenttest_belkin_hid_CFLAGS) $(CFLAGS) -c -o getexponenttest_belkin_hid-getexponenttest-belkin-hid.o `test -f 'getexponenttest-belkin-hid.c' || echo '$(srcdir)/'`getexponenttest-belkin-hid.c getexponenttest_belkin_hid-getexponenttest-belkin-hid.obj: getexponenttest-belkin-hid.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getexponenttest_belkin_hid_CFLAGS) $(CFLAGS) -MT getexponenttest_belkin_hid-getexponenttest-belkin-hid.obj -MD -MP -MF $(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Tpo -c -o getexponenttest_belkin_hid-getexponenttest-belkin-hid.obj `if test -f 'getexponenttest-belkin-hid.c'; then $(CYGPATH_W) 'getexponenttest-belkin-hid.c'; else $(CYGPATH_W) '$(srcdir)/getexponenttest-belkin-hid.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Tpo $(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getexponenttest-belkin-hid.c' object='getexponenttest_belkin_hid-getexponenttest-belkin-hid.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getexponenttest_belkin_hid_CFLAGS) $(CFLAGS) -c -o getexponenttest_belkin_hid-getexponenttest-belkin-hid.obj `if test -f 'getexponenttest-belkin-hid.c'; then $(CYGPATH_W) 'getexponenttest-belkin-hid.c'; else $(CYGPATH_W) '$(srcdir)/getexponenttest-belkin-hid.c'; fi` getvaluetest-getvaluetest.o: getvaluetest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -MT getvaluetest-getvaluetest.o -MD -MP -MF $(DEPDIR)/getvaluetest-getvaluetest.Tpo -c -o getvaluetest-getvaluetest.o `test -f 'getvaluetest.c' || echo '$(srcdir)/'`getvaluetest.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getvaluetest-getvaluetest.Tpo $(DEPDIR)/getvaluetest-getvaluetest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getvaluetest.c' object='getvaluetest-getvaluetest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -c -o getvaluetest-getvaluetest.o `test -f 'getvaluetest.c' || echo '$(srcdir)/'`getvaluetest.c getvaluetest-getvaluetest.obj: getvaluetest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -MT getvaluetest-getvaluetest.obj -MD -MP -MF $(DEPDIR)/getvaluetest-getvaluetest.Tpo -c -o getvaluetest-getvaluetest.obj `if test -f 'getvaluetest.c'; then $(CYGPATH_W) 'getvaluetest.c'; else $(CYGPATH_W) '$(srcdir)/getvaluetest.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getvaluetest-getvaluetest.Tpo $(DEPDIR)/getvaluetest-getvaluetest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getvaluetest.c' object='getvaluetest-getvaluetest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -c -o getvaluetest-getvaluetest.obj `if test -f 'getvaluetest.c'; then $(CYGPATH_W) 'getvaluetest.c'; else $(CYGPATH_W) '$(srcdir)/getvaluetest.c'; fi` getvaluetest-hidparser.o: hidparser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -MT getvaluetest-hidparser.o -MD -MP -MF $(DEPDIR)/getvaluetest-hidparser.Tpo -c -o getvaluetest-hidparser.o `test -f 'hidparser.c' || echo '$(srcdir)/'`hidparser.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getvaluetest-hidparser.Tpo $(DEPDIR)/getvaluetest-hidparser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hidparser.c' object='getvaluetest-hidparser.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -c -o getvaluetest-hidparser.o `test -f 'hidparser.c' || echo '$(srcdir)/'`hidparser.c getvaluetest-hidparser.obj: hidparser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -MT getvaluetest-hidparser.obj -MD -MP -MF $(DEPDIR)/getvaluetest-hidparser.Tpo -c -o getvaluetest-hidparser.obj `if test -f 'hidparser.c'; then $(CYGPATH_W) 'hidparser.c'; else $(CYGPATH_W) '$(srcdir)/hidparser.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getvaluetest-hidparser.Tpo $(DEPDIR)/getvaluetest-hidparser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hidparser.c' object='getvaluetest-hidparser.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(getvaluetest_CFLAGS) $(CFLAGS) -c -o getvaluetest-hidparser.obj `if test -f 'hidparser.c'; then $(CYGPATH_W) 'hidparser.c'; else $(CYGPATH_W) '$(srcdir)/hidparser.c'; fi` gpiotest-generic_gpio_utest.o: generic_gpio_utest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_utest.o -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_utest.Tpo -c -o gpiotest-generic_gpio_utest.o `test -f 'generic_gpio_utest.c' || echo '$(srcdir)/'`generic_gpio_utest.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_utest.Tpo $(DEPDIR)/gpiotest-generic_gpio_utest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_utest.c' object='gpiotest-generic_gpio_utest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_utest.o `test -f 'generic_gpio_utest.c' || echo '$(srcdir)/'`generic_gpio_utest.c gpiotest-generic_gpio_utest.obj: generic_gpio_utest.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_utest.obj -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_utest.Tpo -c -o gpiotest-generic_gpio_utest.obj `if test -f 'generic_gpio_utest.c'; then $(CYGPATH_W) 'generic_gpio_utest.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_utest.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_utest.Tpo $(DEPDIR)/gpiotest-generic_gpio_utest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_utest.c' object='gpiotest-generic_gpio_utest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_utest.obj `if test -f 'generic_gpio_utest.c'; then $(CYGPATH_W) 'generic_gpio_utest.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_utest.c'; fi` gpiotest-generic_gpio_liblocal.o: generic_gpio_liblocal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_liblocal.o -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_liblocal.Tpo -c -o gpiotest-generic_gpio_liblocal.o `test -f 'generic_gpio_liblocal.c' || echo '$(srcdir)/'`generic_gpio_liblocal.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_liblocal.Tpo $(DEPDIR)/gpiotest-generic_gpio_liblocal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_liblocal.c' object='gpiotest-generic_gpio_liblocal.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_liblocal.o `test -f 'generic_gpio_liblocal.c' || echo '$(srcdir)/'`generic_gpio_liblocal.c gpiotest-generic_gpio_liblocal.obj: generic_gpio_liblocal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_liblocal.obj -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_liblocal.Tpo -c -o gpiotest-generic_gpio_liblocal.obj `if test -f 'generic_gpio_liblocal.c'; then $(CYGPATH_W) 'generic_gpio_liblocal.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_liblocal.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_liblocal.Tpo $(DEPDIR)/gpiotest-generic_gpio_liblocal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_liblocal.c' object='gpiotest-generic_gpio_liblocal.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_liblocal.obj `if test -f 'generic_gpio_liblocal.c'; then $(CYGPATH_W) 'generic_gpio_liblocal.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_liblocal.c'; fi` gpiotest-generic_gpio_libgpiod.o: generic_gpio_libgpiod.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_libgpiod.o -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Tpo -c -o gpiotest-generic_gpio_libgpiod.o `test -f 'generic_gpio_libgpiod.c' || echo '$(srcdir)/'`generic_gpio_libgpiod.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Tpo $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_libgpiod.c' object='gpiotest-generic_gpio_libgpiod.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_libgpiod.o `test -f 'generic_gpio_libgpiod.c' || echo '$(srcdir)/'`generic_gpio_libgpiod.c gpiotest-generic_gpio_libgpiod.obj: generic_gpio_libgpiod.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_libgpiod.obj -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Tpo -c -o gpiotest-generic_gpio_libgpiod.obj `if test -f 'generic_gpio_libgpiod.c'; then $(CYGPATH_W) 'generic_gpio_libgpiod.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_libgpiod.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Tpo $(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_libgpiod.c' object='gpiotest-generic_gpio_libgpiod.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_libgpiod.obj `if test -f 'generic_gpio_libgpiod.c'; then $(CYGPATH_W) 'generic_gpio_libgpiod.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_libgpiod.c'; fi` gpiotest-generic_gpio_common.o: generic_gpio_common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_common.o -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_common.Tpo -c -o gpiotest-generic_gpio_common.o `test -f 'generic_gpio_common.c' || echo '$(srcdir)/'`generic_gpio_common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_common.Tpo $(DEPDIR)/gpiotest-generic_gpio_common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_common.c' object='gpiotest-generic_gpio_common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_common.o `test -f 'generic_gpio_common.c' || echo '$(srcdir)/'`generic_gpio_common.c gpiotest-generic_gpio_common.obj: generic_gpio_common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -MT gpiotest-generic_gpio_common.obj -MD -MP -MF $(DEPDIR)/gpiotest-generic_gpio_common.Tpo -c -o gpiotest-generic_gpio_common.obj `if test -f 'generic_gpio_common.c'; then $(CYGPATH_W) 'generic_gpio_common.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_common.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gpiotest-generic_gpio_common.Tpo $(DEPDIR)/gpiotest-generic_gpio_common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='generic_gpio_common.c' object='gpiotest-generic_gpio_common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gpiotest_CFLAGS) $(CFLAGS) -c -o gpiotest-generic_gpio_common.obj `if test -f 'generic_gpio_common.c'; then $(CYGPATH_W) 'generic_gpio_common.c'; else $(CYGPATH_W) '$(srcdir)/generic_gpio_common.c'; fi` .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< cppnit-cpputest-client.o: cpputest-client.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -MT cppnit-cpputest-client.o -MD -MP -MF $(DEPDIR)/cppnit-cpputest-client.Tpo -c -o cppnit-cpputest-client.o `test -f 'cpputest-client.cpp' || echo '$(srcdir)/'`cpputest-client.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppnit-cpputest-client.Tpo $(DEPDIR)/cppnit-cpputest-client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest-client.cpp' object='cppnit-cpputest-client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -c -o cppnit-cpputest-client.o `test -f 'cpputest-client.cpp' || echo '$(srcdir)/'`cpputest-client.cpp cppnit-cpputest-client.obj: cpputest-client.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -MT cppnit-cpputest-client.obj -MD -MP -MF $(DEPDIR)/cppnit-cpputest-client.Tpo -c -o cppnit-cpputest-client.obj `if test -f 'cpputest-client.cpp'; then $(CYGPATH_W) 'cpputest-client.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest-client.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppnit-cpputest-client.Tpo $(DEPDIR)/cppnit-cpputest-client.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest-client.cpp' object='cppnit-cpputest-client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -c -o cppnit-cpputest-client.obj `if test -f 'cpputest-client.cpp'; then $(CYGPATH_W) 'cpputest-client.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest-client.cpp'; fi` cppnit-cpputest.o: cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -MT cppnit-cpputest.o -MD -MP -MF $(DEPDIR)/cppnit-cpputest.Tpo -c -o cppnit-cpputest.o `test -f 'cpputest.cpp' || echo '$(srcdir)/'`cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppnit-cpputest.Tpo $(DEPDIR)/cppnit-cpputest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest.cpp' object='cppnit-cpputest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -c -o cppnit-cpputest.o `test -f 'cpputest.cpp' || echo '$(srcdir)/'`cpputest.cpp cppnit-cpputest.obj: cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -MT cppnit-cpputest.obj -MD -MP -MF $(DEPDIR)/cppnit-cpputest.Tpo -c -o cppnit-cpputest.obj `if test -f 'cpputest.cpp'; then $(CYGPATH_W) 'cpputest.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppnit-cpputest.Tpo $(DEPDIR)/cppnit-cpputest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest.cpp' object='cppnit-cpputest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppnit_CXXFLAGS) $(CXXFLAGS) -c -o cppnit-cpputest.obj `if test -f 'cpputest.cpp'; then $(CYGPATH_W) 'cpputest.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest.cpp'; fi` cppunittest-example.o: example.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-example.o -MD -MP -MF $(DEPDIR)/cppunittest-example.Tpo -c -o cppunittest-example.o `test -f 'example.cpp' || echo '$(srcdir)/'`example.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-example.Tpo $(DEPDIR)/cppunittest-example.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='example.cpp' object='cppunittest-example.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-example.o `test -f 'example.cpp' || echo '$(srcdir)/'`example.cpp cppunittest-example.obj: example.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-example.obj -MD -MP -MF $(DEPDIR)/cppunittest-example.Tpo -c -o cppunittest-example.obj `if test -f 'example.cpp'; then $(CYGPATH_W) 'example.cpp'; else $(CYGPATH_W) '$(srcdir)/example.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-example.Tpo $(DEPDIR)/cppunittest-example.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='example.cpp' object='cppunittest-example.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-example.obj `if test -f 'example.cpp'; then $(CYGPATH_W) 'example.cpp'; else $(CYGPATH_W) '$(srcdir)/example.cpp'; fi` cppunittest-nutclienttest.o: nutclienttest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutclienttest.o -MD -MP -MF $(DEPDIR)/cppunittest-nutclienttest.Tpo -c -o cppunittest-nutclienttest.o `test -f 'nutclienttest.cpp' || echo '$(srcdir)/'`nutclienttest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutclienttest.Tpo $(DEPDIR)/cppunittest-nutclienttest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutclienttest.cpp' object='cppunittest-nutclienttest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutclienttest.o `test -f 'nutclienttest.cpp' || echo '$(srcdir)/'`nutclienttest.cpp cppunittest-nutclienttest.obj: nutclienttest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutclienttest.obj -MD -MP -MF $(DEPDIR)/cppunittest-nutclienttest.Tpo -c -o cppunittest-nutclienttest.obj `if test -f 'nutclienttest.cpp'; then $(CYGPATH_W) 'nutclienttest.cpp'; else $(CYGPATH_W) '$(srcdir)/nutclienttest.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutclienttest.Tpo $(DEPDIR)/cppunittest-nutclienttest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutclienttest.cpp' object='cppunittest-nutclienttest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutclienttest.obj `if test -f 'nutclienttest.cpp'; then $(CYGPATH_W) 'nutclienttest.cpp'; else $(CYGPATH_W) '$(srcdir)/nutclienttest.cpp'; fi` cppunittest-cpputest.o: cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-cpputest.o -MD -MP -MF $(DEPDIR)/cppunittest-cpputest.Tpo -c -o cppunittest-cpputest.o `test -f 'cpputest.cpp' || echo '$(srcdir)/'`cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-cpputest.Tpo $(DEPDIR)/cppunittest-cpputest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest.cpp' object='cppunittest-cpputest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-cpputest.o `test -f 'cpputest.cpp' || echo '$(srcdir)/'`cpputest.cpp cppunittest-cpputest.obj: cpputest.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-cpputest.obj -MD -MP -MF $(DEPDIR)/cppunittest-cpputest.Tpo -c -o cppunittest-cpputest.obj `if test -f 'cpputest.cpp'; then $(CYGPATH_W) 'cpputest.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-cpputest.Tpo $(DEPDIR)/cppunittest-cpputest.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cpputest.cpp' object='cppunittest-cpputest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-cpputest.obj `if test -f 'cpputest.cpp'; then $(CYGPATH_W) 'cpputest.cpp'; else $(CYGPATH_W) '$(srcdir)/cpputest.cpp'; fi` cppunittest-nutconf_parser_ut.o: nutconf_parser_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutconf_parser_ut.o -MD -MP -MF $(DEPDIR)/cppunittest-nutconf_parser_ut.Tpo -c -o cppunittest-nutconf_parser_ut.o `test -f 'nutconf_parser_ut.cpp' || echo '$(srcdir)/'`nutconf_parser_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutconf_parser_ut.Tpo $(DEPDIR)/cppunittest-nutconf_parser_ut.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutconf_parser_ut.cpp' object='cppunittest-nutconf_parser_ut.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutconf_parser_ut.o `test -f 'nutconf_parser_ut.cpp' || echo '$(srcdir)/'`nutconf_parser_ut.cpp cppunittest-nutconf_parser_ut.obj: nutconf_parser_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutconf_parser_ut.obj -MD -MP -MF $(DEPDIR)/cppunittest-nutconf_parser_ut.Tpo -c -o cppunittest-nutconf_parser_ut.obj `if test -f 'nutconf_parser_ut.cpp'; then $(CYGPATH_W) 'nutconf_parser_ut.cpp'; else $(CYGPATH_W) '$(srcdir)/nutconf_parser_ut.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutconf_parser_ut.Tpo $(DEPDIR)/cppunittest-nutconf_parser_ut.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutconf_parser_ut.cpp' object='cppunittest-nutconf_parser_ut.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutconf_parser_ut.obj `if test -f 'nutconf_parser_ut.cpp'; then $(CYGPATH_W) 'nutconf_parser_ut.cpp'; else $(CYGPATH_W) '$(srcdir)/nutconf_parser_ut.cpp'; fi` cppunittest-nutstream_ut.o: nutstream_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutstream_ut.o -MD -MP -MF $(DEPDIR)/cppunittest-nutstream_ut.Tpo -c -o cppunittest-nutstream_ut.o `test -f 'nutstream_ut.cpp' || echo '$(srcdir)/'`nutstream_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutstream_ut.Tpo $(DEPDIR)/cppunittest-nutstream_ut.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutstream_ut.cpp' object='cppunittest-nutstream_ut.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutstream_ut.o `test -f 'nutstream_ut.cpp' || echo '$(srcdir)/'`nutstream_ut.cpp cppunittest-nutstream_ut.obj: nutstream_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutstream_ut.obj -MD -MP -MF $(DEPDIR)/cppunittest-nutstream_ut.Tpo -c -o cppunittest-nutstream_ut.obj `if test -f 'nutstream_ut.cpp'; then $(CYGPATH_W) 'nutstream_ut.cpp'; else $(CYGPATH_W) '$(srcdir)/nutstream_ut.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutstream_ut.Tpo $(DEPDIR)/cppunittest-nutstream_ut.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutstream_ut.cpp' object='cppunittest-nutstream_ut.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutstream_ut.obj `if test -f 'nutstream_ut.cpp'; then $(CYGPATH_W) 'nutstream_ut.cpp'; else $(CYGPATH_W) '$(srcdir)/nutstream_ut.cpp'; fi` cppunittest-nutconf_ut.o: nutconf_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutconf_ut.o -MD -MP -MF $(DEPDIR)/cppunittest-nutconf_ut.Tpo -c -o cppunittest-nutconf_ut.o `test -f 'nutconf_ut.cpp' || echo '$(srcdir)/'`nutconf_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutconf_ut.Tpo $(DEPDIR)/cppunittest-nutconf_ut.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutconf_ut.cpp' object='cppunittest-nutconf_ut.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutconf_ut.o `test -f 'nutconf_ut.cpp' || echo '$(srcdir)/'`nutconf_ut.cpp cppunittest-nutconf_ut.obj: nutconf_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutconf_ut.obj -MD -MP -MF $(DEPDIR)/cppunittest-nutconf_ut.Tpo -c -o cppunittest-nutconf_ut.obj `if test -f 'nutconf_ut.cpp'; then $(CYGPATH_W) 'nutconf_ut.cpp'; else $(CYGPATH_W) '$(srcdir)/nutconf_ut.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutconf_ut.Tpo $(DEPDIR)/cppunittest-nutconf_ut.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutconf_ut.cpp' object='cppunittest-nutconf_ut.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutconf_ut.obj `if test -f 'nutconf_ut.cpp'; then $(CYGPATH_W) 'nutconf_ut.cpp'; else $(CYGPATH_W) '$(srcdir)/nutconf_ut.cpp'; fi` cppunittest-nutipc_ut.o: nutipc_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutipc_ut.o -MD -MP -MF $(DEPDIR)/cppunittest-nutipc_ut.Tpo -c -o cppunittest-nutipc_ut.o `test -f 'nutipc_ut.cpp' || echo '$(srcdir)/'`nutipc_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutipc_ut.Tpo $(DEPDIR)/cppunittest-nutipc_ut.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutipc_ut.cpp' object='cppunittest-nutipc_ut.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutipc_ut.o `test -f 'nutipc_ut.cpp' || echo '$(srcdir)/'`nutipc_ut.cpp cppunittest-nutipc_ut.obj: nutipc_ut.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -MT cppunittest-nutipc_ut.obj -MD -MP -MF $(DEPDIR)/cppunittest-nutipc_ut.Tpo -c -o cppunittest-nutipc_ut.obj `if test -f 'nutipc_ut.cpp'; then $(CYGPATH_W) 'nutipc_ut.cpp'; else $(CYGPATH_W) '$(srcdir)/nutipc_ut.cpp'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cppunittest-nutipc_ut.Tpo $(DEPDIR)/cppunittest-nutipc_ut.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutipc_ut.cpp' object='cppunittest-nutipc_ut.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cppunittest_CXXFLAGS) $(CXXFLAGS) -c -o cppunittest-nutipc_ut.obj `if test -f 'nutipc_ut.cpp'; then $(CYGPATH_W) 'nutipc_ut.cpp'; else $(CYGPATH_W) '$(srcdir)/nutipc_ut.cpp'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: $(check_PROGRAMS) $(check_SCRIPTS) @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all $(check_PROGRAMS) $(check_SCRIPTS) @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? nutlogtest.log: nutlogtest$(EXEEXT) @p='nutlogtest$(EXEEXT)'; \ b='nutlogtest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) nuttimetest.log: nuttimetest$(EXEEXT) @p='nuttimetest$(EXEEXT)'; \ b='nuttimetest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) nutbooltest.log: nutbooltest$(EXEEXT) @p='nutbooltest$(EXEEXT)'; \ b='nutbooltest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) getvaluetest.log: getvaluetest$(EXEEXT) @p='getvaluetest$(EXEEXT)'; \ b='getvaluetest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) getexponenttest-belkin-hid.log: getexponenttest-belkin-hid$(EXEEXT) @p='getexponenttest-belkin-hid$(EXEEXT)'; \ b='getexponenttest-belkin-hid'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) gpiotest.log: gpiotest$(EXEEXT) @p='gpiotest$(EXEEXT)'; \ b='gpiotest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) driver_methods_utest.log: driver_methods_utest$(EXEEXT) @p='driver_methods_utest$(EXEEXT)'; \ b='driver_methods_utest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) cppunittest.log: cppunittest$(EXEEXT) @p='cppunittest$(EXEEXT)'; \ b='cppunittest'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done @WITH_VALGRIND_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check-local check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(LTLIBRARIES) installdirs: installdirs-recursive installdirs-am: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-recursive -rm -f ./$(DEPDIR)/cppnit-cpputest-client.Po -rm -f ./$(DEPDIR)/cppnit-cpputest.Po -rm -f ./$(DEPDIR)/cppunittest-cpputest.Po -rm -f ./$(DEPDIR)/cppunittest-example.Po -rm -f ./$(DEPDIR)/cppunittest-nutclienttest.Po -rm -f ./$(DEPDIR)/cppunittest-nutconf_parser_ut.Po -rm -f ./$(DEPDIR)/cppunittest-nutconf_ut.Po -rm -f ./$(DEPDIR)/cppunittest-nutipc_ut.Po -rm -f ./$(DEPDIR)/cppunittest-nutstream_ut.Po -rm -f ./$(DEPDIR)/driver_methods_utest-driver_methods_utest.Po -rm -f ./$(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Po -rm -f ./$(DEPDIR)/getvaluetest-getvaluetest.Po -rm -f ./$(DEPDIR)/getvaluetest-hidparser.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_common.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_liblocal.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_utest.Po -rm -f ./$(DEPDIR)/libdriverstubusb_la-driver-stub-usb.Plo -rm -f ./$(DEPDIR)/nutbooltest.Po -rm -f ./$(DEPDIR)/nutlogtest.Po -rm -f ./$(DEPDIR)/nuttimetest.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/cppnit-cpputest-client.Po -rm -f ./$(DEPDIR)/cppnit-cpputest.Po -rm -f ./$(DEPDIR)/cppunittest-cpputest.Po -rm -f ./$(DEPDIR)/cppunittest-example.Po -rm -f ./$(DEPDIR)/cppunittest-nutclienttest.Po -rm -f ./$(DEPDIR)/cppunittest-nutconf_parser_ut.Po -rm -f ./$(DEPDIR)/cppunittest-nutconf_ut.Po -rm -f ./$(DEPDIR)/cppunittest-nutipc_ut.Po -rm -f ./$(DEPDIR)/cppunittest-nutstream_ut.Po -rm -f ./$(DEPDIR)/driver_methods_utest-driver_methods_utest.Po -rm -f ./$(DEPDIR)/getexponenttest_belkin_hid-getexponenttest-belkin-hid.Po -rm -f ./$(DEPDIR)/getvaluetest-getvaluetest.Po -rm -f ./$(DEPDIR)/getvaluetest-hidparser.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_common.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_libgpiod.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_liblocal.Po -rm -f ./$(DEPDIR)/gpiotest-generic_gpio_utest.Po -rm -f ./$(DEPDIR)/libdriverstubusb_la-driver-stub-usb.Plo -rm -f ./$(DEPDIR)/nutbooltest.Po -rm -f ./$(DEPDIR)/nutlogtest.Po -rm -f ./$(DEPDIR)/nuttimetest.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all check check-am install install-am \ install-exec install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--depfiles check check-TESTS check-am check-local clean \ clean-checkPROGRAMS clean-generic clean-libtool \ clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \ uninstall uninstall-am .PRECIOUS: Makefile # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ # Note: a few duplicate mentions are possible here, but a decent make should # handle that properly all: $(TESTS) $(check_PROGRAMS) $(check_SCRIPTS) # NUT Integration Testing suite check-NIT check-NIT-devel: +cd "$(builddir)/NIT" && $(MAKE) $(AM_MAKEFLAGS) $@ @REQUIRE_NUT_STRARG_TRUE@nutlogtest-nofail.sh: nutlogtest$(EXEEXT) @REQUIRE_NUT_STRARG_TRUE@ @echo '#!/bin/sh' > $@ @REQUIRE_NUT_STRARG_TRUE@ @echo 'echo "WARNING: Your C library requires workarounds to print NULL values!" >&2' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @echo 'echo "If nutlogtest below, or generally some NUT program, crashes with" >&2' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @echo 'echo "a segmentation fault (especially during verbose debug) - that may be why" >&2' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @echo 'SCRIPT_DIR="`dirname "$$0"`"' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @echo '"$${SCRIPT_DIR}/nutlogtest" "$$@" || echo "nutlogtest FAILED but it was expected"' >> $@ @REQUIRE_NUT_STRARG_TRUE@ @chmod +x $@ # NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver # of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS hidparser.c: $(top_srcdir)/drivers/hidparser.c test -s "$@" || ln -s -f "$(top_srcdir)/drivers/hidparser.c" "$@" #libdriverstubusb_la_LIBADD = $(top_builddir)/common/libcommon.la @WITH_USB_TRUE@getexponenttest-belkin-hid.c: $(top_srcdir)/drivers/belkin-hid.c # NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver # of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS @WITH_GPIO_TRUE@generic_gpio_libgpiod.c: $(top_srcdir)/drivers/generic_gpio_libgpiod.c @WITH_GPIO_TRUE@ test -s "$@" || ln -s -f "$(top_srcdir)/drivers/generic_gpio_libgpiod.c" "$@" @WITH_GPIO_TRUE@generic_gpio_common.c: $(top_srcdir)/drivers/generic_gpio_common.c @WITH_GPIO_TRUE@ test -s "$@" || ln -s -f "$(top_srcdir)/drivers/generic_gpio_common.c" "$@" # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/drivers/libdummy_mockdrv.la \ $(top_builddir)/common/libnutconf.la \ $(top_builddir)/common/libcommonclient.la \ $(top_builddir)/common/libcommon.la: dummy +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # Make sure out-of-dir C++ dependencies exist (especially when dev-building # only some parts of NUT): @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@$(top_builddir)/clients/libnutclient.la \ @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@$(top_builddir)/clients/libnutclientstub.la: dummy @HAVE_CPPUNIT_TRUE@@HAVE_CXX11_TRUE@ +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) @HAVE_CPPUNIT_FALSE@@HAVE_CXX11_TRUE@cppnit: @HAVE_CPPUNIT_FALSE@@HAVE_CXX11_TRUE@ @echo " SKIP $@ : not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 @HAVE_CXX11_FALSE@cppnit: @HAVE_CXX11_FALSE@ @echo " SKIP $@ : not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 # NOTE: "cppnit", if built, requires running from NIT (with NUT_PORT, etc.) # Note that FAILED value begins with a space, so we do not echo another @HAVE_VALGRIND_TRUE@memcheck: $(check_PROGRAMS) @HAVE_VALGRIND_TRUE@ @RES=0; FAILED=""; \ @HAVE_VALGRIND_TRUE@ for P in $? ; do \ @HAVE_VALGRIND_TRUE@ case "$$P" in \ @HAVE_VALGRIND_TRUE@ cppnit|cppnit$(EXEEXT)) \ @HAVE_VALGRIND_TRUE@ if [ "$${NUT_PORT-}" -gt 0 ] 2>/dev/null ; then : ; else \ @HAVE_VALGRIND_TRUE@ echo " SKIP $@ : $(VALGRIND) ./$$P : NUT_PORT not prepared" ; \ @HAVE_VALGRIND_TRUE@ continue ; \ @HAVE_VALGRIND_TRUE@ fi ;; \ @HAVE_VALGRIND_TRUE@ esac ; \ @HAVE_VALGRIND_TRUE@ '$(top_builddir)/scripts/valgrind/valgrind.sh' "./$$P" \ @HAVE_VALGRIND_TRUE@ || { RES=$$? ; \ @HAVE_VALGRIND_TRUE@ echo "FAILED: '$(top_builddir)/scripts/valgrind/valgrind.sh' './$$P'" >&2; \ @HAVE_VALGRIND_TRUE@ FAILED="$$FAILED $$P" ; \ @HAVE_VALGRIND_TRUE@ } ; \ @HAVE_VALGRIND_TRUE@ done; \ @HAVE_VALGRIND_TRUE@ if [ -n "$$FAILED" ] ; then echo "OVERALL FAILED:$$FAILED" >&2 ; fi ; \ @HAVE_VALGRIND_TRUE@ exit $$RES @HAVE_VALGRIND_FALSE@memcheck: @HAVE_VALGRIND_FALSE@ @echo " SKIP $@ : valgrind was not detected on this system by configure script" >&2 @WITH_VALGRIND_TRUE@check-local: memcheck dummy: # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! #clean-local: # $(AM_V_at)rm -rf $(builddir)/.deps # Helper for only the enabled libs to get built: all-libs-local: $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) $(EXTRA_LTLIBRARIES) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/tests/nutconf_ut.cpp0000644000200500020050000003627315001552635013306 00000000000000/* NUT configuration unit test Copyright (C) 2012 Vaclav Krpec 2024-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nutstream.hpp" #include "nutconf.hpp" #include "nutwriter.hpp" #include /* Current CPPUnit offends the honor of C++98 and maybe later versions */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC # pragma GCC diagnostic ignored "-Wweak-vtables" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC # pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC # pragma GCC diagnostic ignored "-Wextra-semi" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC # pragma GCC diagnostic ignored "-Wold-style-cast" # endif #endif #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma clang diagnostic push "-Wdeprecated-declarations" # endif #endif #include /** * \brief NUT configuration unit test */ class NutConfigUnitTest: public CppUnit::TestFixture { private: CPPUNIT_TEST_SUITE(NutConfigUnitTest); CPPUNIT_TEST( testNutConfiguration ); CPPUNIT_TEST( testUpsmonConfiguration ); CPPUNIT_TEST( testUpsdConfiguration ); CPPUNIT_TEST( testUpsConfiguration ); CPPUNIT_TEST( testUpsdUsersConfiguration ); CPPUNIT_TEST_SUITE_END(); /** * \brief Load configuration from file * * \param config Configuration object * \param file_name Configuration file name */ void load(nut::Serialisable * config, const std::string & file_name); /** * \brief Check configuration serialization contents * * \param config Configuration object * \param content Expected serialization * \param quote_sensitive Flag to allow stripping double-quotes for fallback comparison */ void check(const nut::Serialisable * config, const std::string & content, const bool quote_sensitive); /** * \brief Check configuration serialization contents (exact) * * \param config Configuration object * \param content Expected serialization */ inline void check(const nut::Serialisable * config, const std::string & content) { check(config, content, true); } public: /** nut.conf test */ void testNutConfiguration(); /** upsmon.conf test */ void testUpsmonConfiguration(); /** upsd.conf test */ void testUpsdConfiguration(); /** ups.conf test */ void testUpsConfiguration(); /** upsd.users test */ void testUpsdUsersConfiguration(); inline void setUp() override {} inline void tearDown() override {} virtual ~NutConfigUnitTest() override; }; // end of class NutConfigUnitTest // Register the test suite CPPUNIT_TEST_SUITE_REGISTRATION(NutConfigUnitTest); void NutConfigUnitTest::load(nut::Serialisable * config, const std::string & file_name) { nut::NutFile file(file_name, nut::NutFile::READ_ONLY); CPPUNIT_ASSERT(config->parseFrom(file)); } void NutConfigUnitTest::check(const nut::Serialisable * config, const std::string & content, const bool quote_sensitive) { nut::NutMemory mem; CPPUNIT_ASSERT(config->writeTo(mem)); std::string str; nut::NutStream::status_t status = mem.getString(str); CPPUNIT_ASSERT(nut::NutStream::NUTS_OK == status); if (content == str) return; if (!quote_sensitive) { // Re-check with quotes stripped (we output paths, passwords etc. quoted) std::string uqStr = str, uqContent = content; uqStr.erase(std::remove(uqStr.begin(), uqStr.end(), '"'), uqStr.end()); uqContent.erase(std::remove(uqContent.begin(), uqContent.end(), '"'), uqContent.end()); if (uqContent == uqStr) return; } // Neither expectation was met std::cerr << "--- expected ---" << std::endl << content << "--- end ---" << std::endl; std::cerr << "--- serialized ---" << std::endl << str << "--- end ---" << std::endl; CPPUNIT_ASSERT_MESSAGE("Configuration serialization check failed", 0); } void NutConfigUnitTest::testNutConfiguration() { nut::NutConfiguration config; load(static_cast(&config), ABS_TOP_SRCDIR "/conf/nut.conf.sample"); config.mode = nut::NutConfiguration::MODE_STANDALONE; config.upsdOptions = "-DDD -B"; config.allowNoDevice = true; config.poweroffQuiet = false; check(static_cast(&config), "MODE=standalone\n" "ALLOW_NO_DEVICE=true\n" "UPSD_OPTIONS='-DDD -B'\n" "POWEROFF_QUIET=false\n" ); } void NutConfigUnitTest::testUpsmonConfiguration() { nut::UpsmonConfiguration config; nut::BoolInt *tmpPtr = nullptr; // Note: this file gets generated from a .in template load(static_cast(&config), ABS_TOP_BUILDDIR "/conf/upsmon.conf.sample"); config.shutdownCmd = "/sbin/shutdown -h +2 'System shutdown in 2 minutes!'"; config.powerDownFlag = "/run/nut/killpower"; config.pollFreqAlert = 10; config.deadTime = 30; config.debugMin = 6; // Note different bool wording expected below // and generally try different input types here. // Hm, maybe we need typed constructors to init // the values for test? ("new" weirdness below // is due to Settable<> formal type mismatch) config.shutdownExit = (*(tmpPtr = new nut::BoolInt()) << "true"); delete tmpPtr; config.oblbDuration = -1; config.overDuration = -1; config.certVerify = (*(tmpPtr = new nut::BoolInt()) << false); delete tmpPtr; config.forceSsl = (*(tmpPtr = new nut::BoolInt()) << "1"); delete tmpPtr; config.alarmCritical = (*(tmpPtr = new nut::BoolInt()) << "1"); delete tmpPtr; config.certIdent.certName = "My test cert"; config.certIdent.certDbPass = "DbPwd!"; nut::CertHost certHost; certHost.host = "remote:3493"; certHost.certName = "NUT server cert"; certHost.certVerify = (*(tmpPtr = new nut::BoolInt()) << "true"); delete tmpPtr; certHost.forceSsl = (*(tmpPtr = new nut::BoolInt()) << 0); delete tmpPtr; config.certHosts.push_back(certHost); certHost.host = "localhost:13493"; certHost.certName = "My NUT server cert"; certHost.certVerify = (*(tmpPtr = new nut::BoolInt()) << "false"); delete tmpPtr; certHost.forceSsl = (*(tmpPtr = new nut::BoolInt()) << false); delete tmpPtr; config.certHosts.push_back(certHost); // Note: More config data points come from the file loaded above check(static_cast(&config), "DEBUG_MIN 6\n" "SHUTDOWNCMD \"/sbin/shutdown -h +2 'System shutdown in 2 minutes!'\"\n" "POWERDOWNFLAG \"/run/nut/killpower\"\n" "MINSUPPLIES 1\n" "POLLFREQ 5\n" "POLLFREQALERT 10\n" "OFFDURATION 30\n" "OBLBDURATION -1\n" "OVERDURATION -1\n" "SHUTDOWNEXIT yes\n" "CERTVERIFY 0\n" "FORCESSL 1\n" "ALARMCRITICAL 1\n" "HOSTSYNC 15\n" "DEADTIME 30\n" "RBWARNTIME 43200\n" "NOCOMMWARNTIME 300\n" "FINALDELAY 5\n" "CERTIDENT \"My test cert\" \"DbPwd!\"\n" "CERTHOST \"remote:3493\" \"NUT server cert\" 1 0\n" "CERTHOST \"localhost:13493\" \"My NUT server cert\" 0 0\n" ); } void NutConfigUnitTest::testUpsdConfiguration() { nut::UpsdConfiguration config; load(static_cast(&config), ABS_TOP_SRCDIR "/conf/upsd.conf.sample"); config.maxAge = 15; config.statePath = "/var/run/nut"; config.maxConn = 1024; config.certFile = "/usr/share/ssl-cert/ssleay.cnf"; nut::UpsdConfiguration::Listen listen; listen.address = "127.0.0.1"; listen.port = 3493; config.listens.push_back(listen); listen.address = "::1"; config.listens.push_back(listen); // NOTE: Three-arg check() here to retry (and succeed) with un-quoted paths check(static_cast(&config), "MAXAGE 15\n" "MAXCONN 1024\n" "STATEPATH \"/var/run/nut\"\n" "CERTFILE /usr/share/ssl-cert/ssleay.cnf\n" "LISTEN 127.0.0.1 3493\n" "LISTEN ::1 3493\n" , false); } void NutConfigUnitTest::testUpsConfiguration() { nut::UpsConfiguration config; load(static_cast(&config), ABS_TOP_SRCDIR "/conf/ups.conf.sample"); static const std::string my_ups("powerpal"); config.setDriver(my_ups, "blazer_ser"); config.setPort(my_ups, "/dev/ttyS0"); config.setDescription(my_ups, "Web server"); // IRL not for a serial-port UPS, but okay for tests; // Note NUT v2.8.1 introduced these as "hexnum" values, // but the strtoul() underneath knows to strip "0x" for // base16 conversions - so can we write them either way: config.setUsbConfigIndex(my_ups, 0x81); config.setUsbHidDescIndex(my_ups, 0x3f); // Note: "maxretry = 3" comes from current ups.conf.sample non-comment lines std::string expected = "maxretry = 3\n\n" "[powerpal]\n" "\tdesc = \"Web server\"\n" "\tdriver = blazer_ser\n" "\tport = /dev/ttyS0\n" "\tusb_config_index = 81\n" "\tusb_hid_desc_index = 3f\n" "\n"; check(static_cast(&config), expected); // Make sure we can parse back the "hexnum" entries correctly config.parseFromString(expected); check(static_cast(&config), expected); // Check that "0x" prefix (and/or quotes) do not matter on // this platform (note that parsing results are strings from // original input; for the check we interpret them as numbers // and save back): std::string input2 = "maxretry = 3\n\n" "[powerpal]\n" "\tdesc = \"Web server\"\n" "\tdriver = blazer_ser\n" "\tport = /dev/ttyS0\n" "\tusb_config_index = 0x81\n" "\tusb_hid_desc_index = \"0x3f\"\n" "\n"; config.parseFromString(input2); config.setUsbConfigIndex (my_ups, config.getUsbConfigIndex(my_ups)); config.setUsbHidDescIndex(my_ups, config.getUsbHidDescIndex(my_ups)); // Should retrieve "-1" for unset value by default in its getter, // and auto-destroy the (missing) entry upon set() because < 0 config.setUsbSetAltInterface (my_ups, config.getUsbSetAltInterface(my_ups)); check(static_cast(&config), expected); CPPUNIT_ASSERT_EQUAL(static_cast(129), config.getUsbConfigIndex(my_ups)); CPPUNIT_ASSERT_EQUAL(static_cast(0x3f), config.getUsbHidDescIndex(my_ups)); // Check default.* and override.* value(!) pre-sets: std::string input3 = "[powerpal]\n" "\tdesc = \"Web server\"\n" "\tdriver = blazer_ser\n" "\tport = /dev/ttyS0\n" "\tdefault.battery.voltage.high = 28.3\n" "\n"; // "high" is inherited from input; "log" added by code: std::string expected3 = "[powerpal]\n" "\tdefault.battery.voltage.high = 28.3\n" "\tdesc = \"Web server\"\n" "\tdriver = blazer_ser\n" "\toverride.battery.voltage.low = 12.4\n" "\tport = /dev/ttyS0\n" "\n"; config.parseFromString(input3); config.setOverrideDouble(my_ups, "battery.voltage.low", 12.4); // "maxretry" is inherited from earlier content of config // (not cleared). Maybe a bug, address later. check(static_cast(&config), "maxretry = 3\n\n" + expected3); CPPUNIT_ASSERT_DOUBLES_EQUAL(28.3, config.getDefaultDouble(my_ups, "battery.voltage.high"), 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL(12.4, config.getOverrideDouble(my_ups, "battery.voltage.low"), 0.0001); // TODO: Wipe method? Fix parse*() to clear global section // like they do clear and repopulate an UPS section? // Re-parse from scratch nut::UpsConfiguration config3; config3.parseFromString(input3); config3.setOverrideDouble(my_ups, "battery.voltage.low", 12.4); check(static_cast(&config3), expected3); } void NutConfigUnitTest::testUpsdUsersConfiguration() { nut::UpsdUsersConfiguration config; load(static_cast(&config), ABS_TOP_SRCDIR "/conf/upsd.users.sample"); config.setPassword("upsmon", "ytrewq"); config.setUpsmonMode(nut::UpsdUsersConfiguration::UPSMON_PRIMARY); config.setPassword("admin", "qwerty=ui"); config.setActions("admin", nut::ConfigParamList(1, "SET")); config.setInstantCommands("admin", nut::ConfigParamList(1, "ALL")); check(static_cast(&config), "[admin]\n" "\tactions = SET\n" "\tinstcmds = ALL\n" "\tpassword = \"qwerty=ui\"\n" "\n" "[upsmon]\n" "\tpassword = ytrewq\n" "\tupsmon primary\n" "\n" ); } // Implement out of class declaration to avoid // error: 'SomeClass' has no out-of-line virtual method // definitions; its vtable will be emitted in every translation unit // [-Werror,-Wweak-vtables] NutConfigUnitTest::~NutConfigUnitTest() {} #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) # pragma GCC diagnostic pop #endif nut-2.8.3/tests/nutconf_parser_ut.cpp0000644000200500020050000011000014777767434014667 00000000000000/* tests/nutconf.cpp - based on CppUnit unit test example Copyright (C) 2012 Emilien Kia 2024-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" // Define to de-activate protection of parsing tool members: #define UNITEST_MODE 1 #include "nutconf.hpp" using namespace nut; #include #include using namespace std; extern "C" { extern bool verbose; } /* Current CPPUnit offends the honor of C++98 and maybe later versions */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC # pragma GCC diagnostic ignored "-Wweak-vtables" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC # pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC # pragma GCC diagnostic ignored "-Wextra-semi" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC # pragma GCC diagnostic ignored "-Wold-style-cast" # endif #endif #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma clang diagnostic push "-Wdeprecated-declarations" # endif #endif #include class NutConfTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( NutConfTest ); CPPUNIT_TEST( testOptions ); CPPUNIT_TEST( testParseCHARS ); CPPUNIT_TEST( testParseSTRCHARS ); CPPUNIT_TEST( testParseBoolInt ); CPPUNIT_TEST( testParseBoolIntStrict ); CPPUNIT_TEST( testParseToken ); CPPUNIT_TEST( testParseTokenWithoutColon ); CPPUNIT_TEST( testGenericConfigParser ); CPPUNIT_TEST( testUpsmonConfigParser ); CPPUNIT_TEST( testNutConfConfigParser ); CPPUNIT_TEST( testUpsdConfigParser ); CPPUNIT_TEST_SUITE_END(); public: void setUp() override; void tearDown() override; void testOptions(); void testParseCHARS(); void testParseSTRCHARS(); void testParseBoolInt(); void testParseBoolIntStrict(); void testParseToken(); void testParseTokenWithoutColon(); void testGenericConfigParser(); void testUpsmonConfigParser(); void testNutConfConfigParser(); void testUpsdConfigParser(); }; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( NutConfTest ); void NutConfTest::setUp() { } void NutConfTest::tearDown() { } void NutConfTest::testOptions() { { NutParser parse("Bonjour monde!", NutParser::OPTION_DEFAULT); CPPUNIT_ASSERT_EQUAL_MESSAGE("Has parsing options", 0u, parse.getOptions()); CPPUNIT_ASSERT_MESSAGE("Has OPTION_IGNORE_COLON parsing option", !parse.hasOptions(NutParser::OPTION_IGNORE_COLON)); } { NutParser parse("Bonjour monde!", NutParser::OPTION_IGNORE_COLON); CPPUNIT_ASSERT_EQUAL_MESSAGE("Has bad parsing options", static_cast(NutParser::OPTION_IGNORE_COLON), parse.getOptions()); CPPUNIT_ASSERT_MESSAGE("Has not OPTION_IGNORE_COLON parsing option", parse.hasOptions(NutParser::OPTION_IGNORE_COLON)); } } void NutConfTest::testParseCHARS() { { NutParser parse("Bonjour monde!"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find first string 'Bonjour'", string("Bonjour"), parse.parseCHARS()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot get a character ''", ' ', parse.get()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find second string 'monde!'", string("monde!"), parse.parseCHARS()); } { NutParser parse("To\\ to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To to'", string("To to"), parse.parseCHARS()); } { NutParser parse("To\"to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To'", string("To"), parse.parseCHARS()); } { NutParser parse("To\\\"to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find escaped string 'To\"to'", string("To\"to"), parse.parseCHARS()); } } void NutConfTest::testParseSTRCHARS() { { NutParser parse("Bonjour\"monde!\""); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find first string 'Bonjour'", string("Bonjour"), parse.parseSTRCHARS()); parse.get(); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find second string 'monde!'", string("monde!"), parse.parseSTRCHARS()); } { NutParser parse("To to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find spaced string 'To tue de l’appareil qui se serait malencontreuo'", string("To to"), parse.parseSTRCHARS()); } { NutParser parse("To\\\"to"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find quoted-escaped string 'To\"to'", string("To\"to"), parse.parseSTRCHARS()); } } void NutConfTest::testParseBoolInt() { // NOTE: Can not use CPPUNIT_ASSERT_EQUAL() below, requires an assertEqual() method BoolInt bi; bi.bool01 = true; CPPUNIT_ASSERT_MESSAGE("BoolInt should be not 'set()' initially", !(bi.set())); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to an int", CPPUNIT_ASSERT(bi == 0)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to an int", CPPUNIT_ASSERT(bi == 1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == false)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a string", CPPUNIT_ASSERT(bi == "2")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a string", CPPUNIT_ASSERT(bi == "on")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a string", CPPUNIT_ASSERT(bi == "no")); /* // Actually not "must throw", just returns false for any comparisons - see above CPPUNIT_ASSERT_THROW_MESSAGE("Unassigned BoolInt comparisons must throw exceptions (string)", if (bi == "1") {}, std::invalid_argument); CPPUNIT_ASSERT_THROW_MESSAGE("Unassigned BoolInt comparisons must throw exceptions (int)", if (bi == 1) {}, std::invalid_argument); CPPUNIT_ASSERT_THROW_MESSAGE("Unassigned BoolInt comparisons must throw exceptions (bool)", if (bi == true) {}, std::invalid_argument); */ bi = 42; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from int", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int", (bi == 42)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of int", (bi == "42")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == false)); bi = true; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from bool", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the bool", (bi == true)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int value of bool", (bi == 1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool", CPPUNIT_ASSERT(bi == false)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to int value of another bool", CPPUNIT_ASSERT(bi == 0)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to old int", CPPUNIT_ASSERT(bi == 42)); bi = false; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from bool", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the bool", (bi == false)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int value of bool", (bi == 0)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to int value of another bool", CPPUNIT_ASSERT(bi == 1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to old int", CPPUNIT_ASSERT(bi == 42)); bi = "1"; CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int", (bi == 1)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int as string", (bi == "1")); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the bool", (bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool", CPPUNIT_ASSERT(bi == false)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the bool as string", (bi == "true")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool as string", CPPUNIT_ASSERT(bi == "false")); CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt comparison to invalid strings must throw exceptions", if (bi == "1.8") {}, std::invalid_argument); bi = "-1"; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from string", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int", (bi == -1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == false)); bi = "off"; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from string", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the bool", (bi == false)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int value of bool", (bi == 0)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of bool", (bi == "off")); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of bool", (bi == "false")); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of bool", (bi == "0")); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of bool", (bi == "no")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "yes")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "true")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "1")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "on")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "ok")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to int value of another bool", CPPUNIT_ASSERT(bi == 1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to old int", CPPUNIT_ASSERT(bi == 42)); CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt assignment from invalid strings must throw exceptions", (bi = "AbraCadabra"), std::invalid_argument); CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt assignment from invalid strings must throw exceptions", (bi = "1.5"), std::invalid_argument); CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt assignment from invalid strings must throw exceptions", (bi = "-3.8"), std::invalid_argument); // Standard casing only CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt assignment from invalid strings must throw exceptions", (bi = "OFF"), std::invalid_argument); // Not-strict comparisons: int or string 0/1 values are bools std::string s; bi << "true"; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value", (s == "yes")); bi << false; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value", (s == "no")); bi << 1; s = bi.toString(); if (verbose) std::cerr << "Non-strict? " << bi.bool01 << " : numeric 1 " << "=> (string)'" << s << "' aka (ostream)'" << bi << "'" << std::endl; CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value (0/1 => bool)", (s == "yes")); bi = 0; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value (0/1 => bool)", (s == "no")); bi = "1"; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value (0/1 => bool)", (s == "yes")); bi = "0"; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value (0/1 => bool)", (s == "no")); bi.clear(); CPPUNIT_ASSERT_MESSAGE("BoolInt should be not 'set()' after 'clear()", !(bi.set())); } void NutConfTest::testParseBoolIntStrict() { // NOTE: Can not use CPPUNIT_ASSERT_EQUAL() below, requires an assertEqual() method BoolInt bi; bi.bool01 = false; CPPUNIT_ASSERT_MESSAGE("BoolInt should be not 'set()' initially", !(bi.set())); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to an int", CPPUNIT_ASSERT(bi == 0)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to an int", CPPUNIT_ASSERT(bi == 1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == false)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a string", CPPUNIT_ASSERT(bi == "2")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a string", CPPUNIT_ASSERT(bi == "on")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Unassigned BoolInt should not be equal to a string", CPPUNIT_ASSERT(bi == "no")); /* // Actually not "must throw", just returns false for any comparisons - see above CPPUNIT_ASSERT_THROW_MESSAGE("Unassigned BoolInt comparisons must throw exceptions (string)", if (bi == "1") {}, std::invalid_argument); CPPUNIT_ASSERT_THROW_MESSAGE("Unassigned BoolInt comparisons must throw exceptions (int)", if (bi == 1) {}, std::invalid_argument); CPPUNIT_ASSERT_THROW_MESSAGE("Unassigned BoolInt comparisons must throw exceptions (bool)", if (bi == true) {}, std::invalid_argument); */ bi = 42; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from int", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int", (bi == 42)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of int", (bi == "42")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == false)); bi = true; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from bool", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the bool", (bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt (strict) should not be equal to the int value of bool", CPPUNIT_ASSERT(bi == 1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool", CPPUNIT_ASSERT(bi == false)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to int value of another bool", CPPUNIT_ASSERT(bi == 0)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to old int", CPPUNIT_ASSERT(bi == 42)); bi = false; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from bool", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the bool", (bi == false)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt (strict) should not be equal to int value of bool", CPPUNIT_ASSERT(bi == 0)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to int value of another bool", CPPUNIT_ASSERT(bi == 1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to old int", CPPUNIT_ASSERT(bi == 42)); bi = "1"; CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int", (bi == 1)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int as string", (bi == "1")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt (strict) should not be equal to the bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt (strict) should not be equal to the bool as string", CPPUNIT_ASSERT(bi == "true")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool", CPPUNIT_ASSERT(bi == false)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt (strict) should not be equal to the bool as string", CPPUNIT_ASSERT(bi == "true")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool as string", CPPUNIT_ASSERT(bi == "false")); CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt comparison to invalid strings must throw exceptions", if (bi == "1.8") {}, std::invalid_argument); bi = "-1"; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from string", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the int", (bi == -1)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of int", (bi == "-1")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to a bool", CPPUNIT_ASSERT(bi == false)); bi = "off"; CPPUNIT_ASSERT_MESSAGE("BoolInt should be 'set()' after assignment from string", bi.set()); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the bool", (bi == false)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt (strict) should not be equal to the int value of bool", CPPUNIT_ASSERT(bi == 0)); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of bool", (bi == "off")); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of bool", (bi == "false")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt (strict) should not be equal to the string value of bool (seemingly int)", CPPUNIT_ASSERT(bi == "0")); CPPUNIT_ASSERT_MESSAGE("BoolInt should be equal to the string value of bool", (bi == "no")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "yes")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "true")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "1")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "on")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to the string value of another bool", CPPUNIT_ASSERT(bi == "ok")); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another bool", CPPUNIT_ASSERT(bi == true)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to int value of another bool", CPPUNIT_ASSERT(bi == 1)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to another int", CPPUNIT_ASSERT(bi == 2)); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("BoolInt should not be equal to old int", CPPUNIT_ASSERT(bi == 42)); CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt assignment from invalid strings must throw exceptions", (bi = "AbraCadabra"), std::invalid_argument); CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt assignment from invalid strings must throw exceptions", (bi = "1.5"), std::invalid_argument); CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt assignment from invalid strings must throw exceptions", (bi = "-3.8"), std::invalid_argument); // Standard casing only CPPUNIT_ASSERT_THROW_MESSAGE("BoolInt assignment from invalid strings must throw exceptions", (bi = "OFF"), std::invalid_argument); // Strict comparisons: int or string 0/1 values are int not bool std::string s; bi << "true"; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value", (s == "yes")); bi << false; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value", (s == "no")); bi << 1; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value (0/1 => int)", (s == "1")); bi = 0; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value (0/1 => int)", (s == "0")); bi = "1"; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value (0/1 => int)", (s == "1")); bi << "0"; s = bi.toString(); CPPUNIT_ASSERT_MESSAGE("BoolInt should get printed as expected string value (0/1 => int)", (s == "0")); bi.clear(); CPPUNIT_ASSERT_MESSAGE("BoolInt should be not 'set()' after 'clear()", !(bi.set())); } void NutConfTest::testParseToken() { static const char* src = "Bonjour monde\n" "[ceci]# Plouf\n" "\n" "titi = \"tata toto\"\n" "NOTIFYFLAG LOWBATT SYSLOG+WALL\n" "::1" ; NutParser parse(src); // NutConfigParser::Token tok = parse.parseToken(); // std::cout << "token = " << tok.type << " - " << tok.str << std::endl; CPPUNIT_ASSERT_MESSAGE("Cannot find 1st token 'Bonjour'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "Bonjour")); CPPUNIT_ASSERT_MESSAGE("Cannot find 2nd token 'monde'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "monde")); CPPUNIT_ASSERT_MESSAGE("Cannot find 3th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); CPPUNIT_ASSERT_MESSAGE("Cannot find 4rd token '['", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_OPEN, "[")); CPPUNIT_ASSERT_MESSAGE("Cannot find 5th token 'ceci'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "ceci")); CPPUNIT_ASSERT_MESSAGE("Cannot find 6th token ']'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_CLOSE, "]")); CPPUNIT_ASSERT_MESSAGE("Cannot find 7th token ' Plouf'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COMMENT, " Plouf")); CPPUNIT_ASSERT_MESSAGE("Cannot find 8th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token 'titi'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "titi")); CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token '='", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EQUAL, "=")); CPPUNIT_ASSERT_MESSAGE("Cannot find 11th token 'tata toto'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_QUOTED_STRING, "tata toto")); CPPUNIT_ASSERT_MESSAGE("Cannot find 12th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); CPPUNIT_ASSERT_MESSAGE("Cannot find 13th token 'NOTIFYFLAG'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "NOTIFYFLAG")); CPPUNIT_ASSERT_MESSAGE("Cannot find 14th token 'LOWBATT'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "LOWBATT")); CPPUNIT_ASSERT_MESSAGE("Cannot find 15th token 'SYSLOG+WALL'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "SYSLOG+WALL")); CPPUNIT_ASSERT_MESSAGE("Cannot find 16th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); CPPUNIT_ASSERT_MESSAGE("Cannot find 17th token ':'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COLON, ":")); CPPUNIT_ASSERT_MESSAGE("Cannot find 18th token ':'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COLON, ":")); CPPUNIT_ASSERT_MESSAGE("Cannot find 19th token '1'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "1")); } void NutConfTest::testParseTokenWithoutColon() { static const char* src = "Bonjour monde\n" "[ceci]# Plouf\n" "\n" "titi = \"tata toto\"\n" "NOTIFYFLAG LOWBATT SYSLOG+WALL\n" "::1" ; NutParser parse(src, NutParser::OPTION_IGNORE_COLON); // NutConfigParser::Token tok = parse.parseToken(); // std::cout << "token = " << tok.type << " - " << tok.str << std::endl; CPPUNIT_ASSERT_MESSAGE("Cannot find 1st token 'Bonjour'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "Bonjour")); CPPUNIT_ASSERT_MESSAGE("Cannot find 2nd token 'monde'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "monde")); CPPUNIT_ASSERT_MESSAGE("Cannot find 3th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); CPPUNIT_ASSERT_MESSAGE("Cannot find 4rd token '['", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_OPEN, "[")); CPPUNIT_ASSERT_MESSAGE("Cannot find 5th token 'ceci'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "ceci")); CPPUNIT_ASSERT_MESSAGE("Cannot find 6th token ']'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_BRACKET_CLOSE, "]")); CPPUNIT_ASSERT_MESSAGE("Cannot find 7th token ' Plouf'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_COMMENT, " Plouf")); CPPUNIT_ASSERT_MESSAGE("Cannot find 8th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); CPPUNIT_ASSERT_MESSAGE("Cannot find 9th token 'titi'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "titi")); CPPUNIT_ASSERT_MESSAGE("Cannot find 10th token '='", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EQUAL, "=")); CPPUNIT_ASSERT_MESSAGE("Cannot find 11th token 'tata toto'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_QUOTED_STRING, "tata toto")); CPPUNIT_ASSERT_MESSAGE("Cannot find 12th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); CPPUNIT_ASSERT_MESSAGE("Cannot find 13th token 'NOTIFYFLAG'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "NOTIFYFLAG")); CPPUNIT_ASSERT_MESSAGE("Cannot find 14th token 'LOWBATT'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "LOWBATT")); CPPUNIT_ASSERT_MESSAGE("Cannot find 15th token 'SYSLOG+WALL'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "SYSLOG+WALL")); CPPUNIT_ASSERT_MESSAGE("Cannot find 16th token '\n'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_EOL, "\n")); CPPUNIT_ASSERT_MESSAGE("Cannot find 17th token '::1'", parse.parseToken() == NutParser::Token(NutParser::Token::TOKEN_STRING, "::1")); } void NutConfTest::testGenericConfigParser() { static const char* src = "glovar1 = toto\n" "glovar2 = \"truc bidule\"\n" "\n" "[section1] # One section\n" "var1 = \"one value\"\n" " \n" "var2\n" "\n" "[section2]\n" "var1 = other value\n" "var toto"; GenericConfiguration conf; conf.parseFromString(src); CPPUNIT_ASSERT_MESSAGE("Cannot find a global section", conf.sections.find("") != conf.sections.end() ); CPPUNIT_ASSERT_MESSAGE("Cannot find global section's glovar1 variable", conf.sections[""]["glovar1"].values.front() == "toto" ); CPPUNIT_ASSERT_MESSAGE("Cannot find global section's glovar2 variable", conf.sections[""]["glovar2"].values.front() == "truc bidule" ); CPPUNIT_ASSERT_MESSAGE("Cannot find section1", conf.sections.find("section1") != conf.sections.end() ); CPPUNIT_ASSERT_MESSAGE("Cannot find section1's var1 variable", conf.sections["section1"]["var1"].values.front() == "one value" ); CPPUNIT_ASSERT_MESSAGE("Cannot find section1's var2 variable", conf.sections["section1"]["var2"].values.size() == 0 ); CPPUNIT_ASSERT_MESSAGE("Cannot find section2", conf.sections.find("section2") != conf.sections.end() ); CPPUNIT_ASSERT_MESSAGE("Cannot find section2's var1 variable", conf.sections["section2"]["var1"].values.front() == "other" ); CPPUNIT_ASSERT_MESSAGE("Cannot find section2's var1 variable", *(++(conf.sections["section2"]["var1"].values.begin())) == "value" ); CPPUNIT_ASSERT_MESSAGE("Cannot find section2's var variable", conf.sections["section2"]["var"].values.front() == "toto" ); } void NutConfTest::testUpsmonConfigParser() { static const char* src = "RUN_AS_USER nutmon\n" "MONITOR myups@bigserver 1 monmaster blah master\n" "MONITOR su700@server.example.com 1 upsmon secretpass slave\n" "MONITOR myups@localhost 1 upsmon pass master\n" "MINSUPPLIES 1\n" "\n" "# MINSUPPLIES 25\n" "SHUTDOWNCMD \"/sbin/shutdown -h +0\"\n" "NOTIFYCMD /usr/local/ups/bin/notifyme\n" "POLLFREQ 30\n" "POLLFREQALERT 5\n" "HOSTSYNC 15\n" "DEADTIME 15\n" "POWERDOWNFLAG /etc/killpower\n" "NOTIFYMSG ONLINE \"UPS %s on line power\"\n" "NOTIFYFLAG LOWBATT SYSLOG+WALL\n" "RBWARNTIME 43200\n" "NOCOMMWARNTIME 300\n" "FINALDELAY 5" ; UpsmonConfiguration conf; conf.parseFromString(src); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find RUN_AS_USER 'nutmon'", string("nutmon"), *conf.runAsUser); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find MINSUPPLIES 1", 1u, *conf.minSupplies); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find SHUTDOWNCMD '/sbin/shutdown -h +0'", string("/sbin/shutdown -h +0"), *conf.shutdownCmd); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find NOTIFYCMD '/usr/local/ups/bin/notifyme'", string("/usr/local/ups/bin/notifyme"), *conf.notifyCmd); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find POWERDOWNFLAG '/etc/killpower'", string("/etc/killpower"), *conf.powerDownFlag); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find POLLFREQ 30", 30u, *conf.pollFreq); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find POLLFREQALERT 5", 5u, *conf.pollFreqAlert); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find HOSTSYNC 15", 15u, *conf.hostSync); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find DEADTIME 15", 15u, *conf.deadTime); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find RBWARNTIME 43200", 43200u, *conf.rbWarnTime); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find NOCOMMWARNTIME 300", 300u, *conf.noCommWarnTime); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find FINALDELAY 5", 5u, *conf.finalDelay); CPPUNIT_ASSERT_MESSAGE("Find a NOTIFYFLAG ONLINE", !conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_ONLINE].set()); CPPUNIT_ASSERT_MESSAGE("Cannot find a NOTIFYFLAG LOWBATT", conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_LOWBATT].set()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a NOTIFYFLAG LOWBATT SYSLOG+WALL", 3u, static_cast(conf.notifyFlags[nut::UpsmonConfiguration::NOTIFY_LOWBATT])); CPPUNIT_ASSERT_MESSAGE("Find a NOTIFYMSG LOWBATT", !conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_LOWBATT].set()); CPPUNIT_ASSERT_MESSAGE("Cannot find a NOTIFYMSG ONLINE", conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_ONLINE].set()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a NOTIFYMSG ONLINE \"UPS %s on line power\"", string("UPS %s on line power"), *conf.notifyMessages[nut::UpsmonConfiguration::NOTIFY_ONLINE]); } void NutConfTest::testNutConfConfigParser() { static const char* src = "\n\nMODE=standalone\n"; NutConfiguration conf; conf.parseFromString(src); CPPUNIT_ASSERT_MESSAGE("Cannot find a MODE", conf.mode.set()); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find a MODE=standalone", nut::NutConfiguration::MODE_STANDALONE, *conf.mode); } void NutConfTest::testUpsdConfigParser() { static const char* src = "MAXAGE 15\n" "STATEPATH /var/run/nut\n" "LISTEN 127.0.0.1 3493\n" "LISTEN ::1 3493\n" "MAXCONN 1024\n" "CERTFILE /home/toto/cert.file" ; UpsdConfiguration conf; conf.parseFromString(src); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find MAXAGE 15", 15u, *conf.maxAge); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find MAXCONN 1024", 1024u, *conf.maxConn); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find STATEPATH /var/run/nut", string("/var/run/nut"), *conf.statePath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Cannot find CERTFILE /home/toto/cert.file", string("/home/toto/cert.file"), *conf.certFile); // Find Listen 127.0.0.1 3493 { typedef std::list ListenList; UpsdConfiguration::Listen listen = {"127.0.0.1", 3493}; ListenList::const_iterator it = find(conf.listens.begin(), conf.listens.end(), listen); CPPUNIT_ASSERT_MESSAGE("LISTEN 127.0.0.1 3493", it != conf.listens.end()); } // Find Listen ::1 3493 { typedef std::list ListenList; UpsdConfiguration::Listen listen = {"::1", 3493}; ListenList::const_iterator it = find(conf.listens.begin(), conf.listens.end(), listen); CPPUNIT_ASSERT_MESSAGE("LISTEN ::1 3493", it != conf.listens.end()); } } #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) # pragma GCC diagnostic pop #endif nut-2.8.3/tests/driver_methods_utest.c0000644000200500020050000001714414777767434015050 00000000000000/* driver_methods_utest.c - NUT driver code test tool * * Copyright (C) * 2025 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "main.h" #include "dstate.h" #include "attribute.h" #include "nut_stdint.h" /* driver version */ #define DRIVER_NAME "Mock driver for unit tests" #define DRIVER_VERSION "0.01" /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Jim Klimov ", DRV_EXPERIMENTAL, { NULL } }; static int cases_passed = 0; static int cases_failed = 0; static char * pass_fail[2] = {"pass", "fail"}; void upsdrv_cleanup(void) {} void upsdrv_shutdown(void) {} static void report_pass(void) { printf("%s", pass_fail[0]); cases_passed++; } static void report_fail(void) { printf("%s", pass_fail[1]); cases_failed++; } static int report_0_means_pass(int i) { if (i == 0) { report_pass(); } else { report_fail(); } return i; } int main(int argc, char **argv) { const char *valueStr = NULL; NUT_UNUSED_VARIABLE(argc); NUT_UNUSED_VARIABLE(argv); cases_passed = 0; cases_failed = 0; /* test case #1 */ status_init(); nut_debug_level = 6; status_set(" OL "); status_set("OL BOOST"); status_set("OB "); status_set(" BOOST"); status_commit(); valueStr = dstate_getinfo("ups.status"); nut_debug_level = 0; report_0_means_pass(strcmp(valueStr, "OL BOOST OB")); printf(" test for ups.status: '%s'; any duplicates?\n", NUT_STRARG(valueStr)); /* test case #2, build on top of #1 */ alarm_init(); alarm_set("Test alarm 1"); alarm_set("[Test alarm 2]"); alarm_set("Test alarm 1"); alarm_commit(); /* Note: normally we re-init and re-set the values */ status_commit(); valueStr = dstate_getinfo("ups.status"); report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB")); printf(" test for ups.status: '%s'; got alarm?\n", NUT_STRARG(valueStr)); /* test case #3, build on top of #2 */ valueStr = dstate_getinfo("ups.alarm"); /* NOTE: no dedup here! */ report_0_means_pass(strcmp(valueStr, "Test alarm 1 [Test alarm 2] Test alarm 1")); printf(" test for ups.alarm: '%s'; got 3 alarms?\n", NUT_STRARG(valueStr)); /* test case #4, build on top of #1 and #2 */ /* Note: normally we re-init and re-set the values */ status_set("BOO"); status_set("BOO"); status_set("OST"); status_set("OST"); status_set("OOS"); status_set("OOS"); status_commit(); valueStr = dstate_getinfo("ups.status"); report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB BOO OST OOS")); printf(" test for ups.status: '%s'; any duplicates?\n", NUT_STRARG(valueStr)); /* test case #5+#6 from scratch */ status_init(); alarm_init(); status_set("OL BOOST"); status_set("ALARM"); status_set("OB"); alarm_set("[Test alarm 2]"); alarm_commit(); status_commit(); valueStr = dstate_getinfo("ups.status"); report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB")); printf(" test for ups.status with explicit ALARM set via status_set() and alarm_set() was not used first: '%s'; any duplicate ALARM?\n", NUT_STRARG(valueStr)); valueStr = dstate_getinfo("ups.alarm"); report_0_means_pass(strcmp(valueStr, "[Test alarm 2]")); printf(" test for ups.alarm with explicit ALARM set via status_set() and alarm_set() was not used first: '%s'; got 1 alarm (injected N/A replaced by later explicit text)\n", NUT_STRARG(valueStr)); /* test case #7+#8 from scratch */ status_init(); alarm_init(); status_set("OL BOOST"); alarm_set("[Test alarm 2]"); status_set("ALARM"); status_set("OB"); alarm_commit(); status_commit(); valueStr = dstate_getinfo("ups.status"); report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB")); printf(" test for ups.status with explicit ALARM set via status_set() and alarm_set() was used first: '%s'; any duplicate ALARM?\n", NUT_STRARG(valueStr)); valueStr = dstate_getinfo("ups.alarm"); report_0_means_pass(strcmp(valueStr, "[Test alarm 2]")); printf(" test for ups.alarm with explicit ALARM set via status_set() and alarm_set() was used first: '%s'; got 1 alarm (none injected)\n", NUT_STRARG(valueStr)); /* test case #9+#10 from scratch */ status_init(); alarm_init(); status_set("OL BOOST"); status_set("ALARM"); status_set("OB"); alarm_commit(); status_commit(); valueStr = dstate_getinfo("ups.status"); report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB")); printf(" test for ups.status with explicit ALARM set via status_set() and no extra alarm_set(): '%s'; any duplicate ALARM?\n", NUT_STRARG(valueStr)); valueStr = dstate_getinfo("ups.alarm"); report_0_means_pass(strcmp(NUT_STRARG(valueStr), "[N/A]")); printf(" test for ups.alarm with explicit ALARM set via status_set() and no extra alarm_set(): '%s'; got 1 (injected) alarm\n", NUT_STRARG(valueStr)); /* test case #11+#12 from scratch */ /* flush ups.alarm report */ alarm_init(); alarm_commit(); status_init(); alarm_init(); status_set("OL BOOST"); status_set("ALARM"); status_set("OB"); status_set("LB"); /* Should be honoured */ status_commit(); valueStr = dstate_getinfo("ups.status"); report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB LB")); printf(" test for ups.status with explicit ALARM set via status_set() and no extra alarm_set() nor alarm_commit(): '%s'; is ALARM reported?\n", NUT_STRARG(valueStr)); valueStr = dstate_getinfo("ups.alarm"); /* report_0_means_pass(valueStr != NULL); // pass if valueStr is NULL printf(" test for ups.alarm with explicit ALARM set via status_set() and no extra alarm_set() nor alarm_commit(): '%s'; got no alarms spelled out\n", NUT_STRARG(valueStr)); */ report_0_means_pass(strcmp(NUT_STRARG(valueStr), "[N/A]")); printf(" test for ups.alarm with explicit ALARM set via status_set() and no extra alarm_set() nor alarm_commit(): '%s'; got 1 (injected) alarm\n", NUT_STRARG(valueStr)); /* test case #13+#14 from scratch */ /* flush ups.alarm report */ alarm_init(); alarm_commit(); dstate_setinfo("driver.flag.ignorelb", "enabled"); status_init(); alarm_init(); status_set("OL BOOST"); alarm_set("[N/A]"); alarm_set("[Test alarm 2]"); status_set("OB"); status_set("LB"); /* Should be ignored */ alarm_commit(); status_commit(); valueStr = dstate_getinfo("ups.status"); report_0_means_pass(strcmp(valueStr, "ALARM OL BOOST OB")); printf(" test for ups.status with explicit alarm_set(N/A) and another alarm_set(): '%s'; is ALARM reported?\n", NUT_STRARG(valueStr)); valueStr = dstate_getinfo("ups.alarm"); report_0_means_pass(strcmp(valueStr, "[N/A] [Test alarm 2]")); printf(" test for ups.alarm with explicit alarm_set(N/A) and another alarm_set(): '%s'; got both alarms, namesake of not-injected is not overwritten\n", NUT_STRARG(valueStr)); /* finish */ printf("test_rules completed. Total cases %d, passed %d, failed %d\n", cases_passed+cases_failed, cases_passed, cases_failed); dstate_free(); upsdrv_cleanup(); /* Return 0 (exit-code OK, boolean false) if no tests failed and some ran */ if ( (cases_failed == 0) && (cases_passed > 0) ) return 0; return 1; } nut-2.8.3/tests/generic_gpio_liblocal.c0000644000200500020050000001573214777767434015102 00000000000000/* tests/generic_gpio_libglocal.c - gpio device emulation library for GPIO attached UPS devices * * Copyright (C) * 2023 - 2025 Modris Berzonis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "common.h" #include #include #include "generic_gpio_utest.h" #if !(defined WITH_LIBGPIO_VERSION) || !(defined WITH_LIBGPIO_VERSION_STR) || (WITH_LIBGPIO_VERSION == 0) # error "This driver can not be built, requires a known API WITH_LIBGPIO_VERSION to build against" #endif static char chipName[NUT_GPIO_CHIPNAMEBUF]; static unsigned int num_lines=0; static int gStatus = 0; static int errReqFor_line_get_value_bulk=0; void setNextLinesReadToFail(void) { errReqFor_line_get_value_bulk=1; } void gpiod_chip_close(struct gpiod_chip *chip) { NUT_UNUSED_VARIABLE(chip); } #if WITH_LIBGPIO_VERSION < 0x00020000 struct gpiod_chip *gpiod_chip_open_by_name(const char *name) { strcpy(chipName, name); if(strcmp(name, "gpiochip1")) return (struct gpiod_chip *)1; else { errno = EACCES; return NULL; } } unsigned int gpiod_chip_num_lines(struct gpiod_chip *chip) { NUT_UNUSED_VARIABLE(chip); if(!strcmp(chipName, "gpiochip2")) return 2; return 32; } int gpiod_chip_get_lines(struct gpiod_chip *chip, unsigned int *offsets, unsigned int num_offsets, struct gpiod_line_bulk *bulk) { NUT_UNUSED_VARIABLE(chip); NUT_UNUSED_VARIABLE(offsets); NUT_UNUSED_VARIABLE(bulk); num_lines=num_offsets; return 0; } int gpiod_line_request_bulk(struct gpiod_line_bulk *bulk, const struct gpiod_line_request_config *config, const int *default_vals) { NUT_UNUSED_VARIABLE(bulk); NUT_UNUSED_VARIABLE(config); NUT_UNUSED_VARIABLE(default_vals); return 0; } int gpiod_line_get_value_bulk(struct gpiod_line_bulk *bulk, int *values) { unsigned int i; int pinPos = 1; NUT_UNUSED_VARIABLE(bulk); if(errReqFor_line_get_value_bulk) { errReqFor_line_get_value_bulk=0; errno = EPERM; return -1; } for(i=0; i= 0x00020000 */ struct gpiod_line_request * gpiod_chip_request_lines(struct gpiod_chip *chip, struct gpiod_request_config *req_cfg, struct gpiod_line_config *line_cfg) { NUT_UNUSED_VARIABLE(chip); NUT_UNUSED_VARIABLE(req_cfg); NUT_UNUSED_VARIABLE(line_cfg); return (struct gpiod_line_request *)1; } struct gpiod_chip *gpiod_chip_open(const char *path) { strcpy(chipName, path); if(!strstr(path, "gpiochip1")) return (struct gpiod_chip *)1; else { errno = EACCES; return NULL; } } struct gpiod_chip_info *gpiod_chip_get_info(struct gpiod_chip *chip) { NUT_UNUSED_VARIABLE(chip); return (struct gpiod_chip_info *)1; } size_t gpiod_chip_info_get_num_lines(struct gpiod_chip_info *info) { NUT_UNUSED_VARIABLE(info); if(strstr(chipName, "gpiochip2")) return 2; return 32; } void gpiod_chip_info_free(struct gpiod_chip_info *info) { NUT_UNUSED_VARIABLE(info); } struct gpiod_line_settings *gpiod_line_settings_new(void) { return (struct gpiod_line_settings *)1; } int gpiod_line_settings_set_direction(struct gpiod_line_settings *settings, enum gpiod_line_direction direction) { NUT_UNUSED_VARIABLE(settings); NUT_UNUSED_VARIABLE(direction); return 0; } int gpiod_line_settings_set_edge_detection(struct gpiod_line_settings *settings, enum gpiod_line_edge edge) { NUT_UNUSED_VARIABLE(settings); NUT_UNUSED_VARIABLE(edge); return 0; } struct gpiod_line_config *gpiod_line_config_new(void) { return (struct gpiod_line_config *)1; } int gpiod_line_config_add_line_settings(struct gpiod_line_config *config, const unsigned int *offsets, size_t num_offsets, struct gpiod_line_settings *settings) { NUT_UNUSED_VARIABLE(config); NUT_UNUSED_VARIABLE(offsets); NUT_UNUSED_VARIABLE(num_offsets); NUT_UNUSED_VARIABLE(settings); return 0; } struct gpiod_request_config *gpiod_request_config_new(void) { return (struct gpiod_request_config *)1; } void gpiod_request_config_set_consumer(struct gpiod_request_config *config, const char *consumer) { NUT_UNUSED_VARIABLE(config); NUT_UNUSED_VARIABLE(consumer); } int gpiod_line_request_get_values(struct gpiod_line_request *request, enum gpiod_line_value *values) { unsigned int i; int pinPos = 1; NUT_UNUSED_VARIABLE(request); if(errReqFor_line_get_value_bulk) { errReqFor_line_get_value_bulk=0; errno = EPERM; return -1; } for(i=0; i * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "common.h" int main(void) { const char *s1 = "!NULL"; const char *s2 = NULL; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wformat-overflow" #endif upsdebugx(0, "D: checking with libc handling of NULL (can segfault for some libc implementations):"); upsdebugx(0, "D: '%s' vs. '%s'", s1, s2); /* This explicitly does not work with -Wformat, due to verbatim NULL without a var: * nutlogtest.c:20:5: error: reading through null pointer (argument 4) [-Werror=format=] * and also due to (void*) vs. (char*) in naive case: * upsdebugx(0, "D: '%s' vs. '%s'", NUT_STRARG(NULL), NULL); * but with casting the explicit NULL remains: * upsdebugx(0, "D: '%s' vs. '%s'", NUT_STRARG((char *)NULL), (char *)NULL); */ upsdebugx(0, "D: checking with NUT_STRARG macro: '%s' vs. '%s'", NUT_STRARG(s2), s2); #ifdef NUT_STRARG #undef NUT_STRARG #endif #define NUT_STRARG(x) (x?x:"") /* This explicitly does not work with -Wformat, due to a NULL in the '%s' * format string expansion (e.g. due to NUT PR #675 conversion to macros): * ../include/common.h:155:41: warning: '%s' directive argument is null [-Wformat-overflow=] * <...snip...> * nutlogtest.c:45:63: note: format string is defined here * 45 | upsdebugx(0, "D: checking with NUT_STRARG macro: '%s' vs. '%s'", NUT_STRARG(s2), s2); * | ^~ */ upsdebugx(0, "D: checking that macro wrap trick works: '%s' vs. '%s'", NUT_STRARG(s2), s2); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) # pragma GCC diagnostic pop #endif return 0; } nut-2.8.3/tests/example.cpp0000644000200500020050000001111014777767434012564 00000000000000/* example - CppUnit unit test example Copyright (C) 2012 Emilien Kia 2020-2024 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" /* Current CPPUnit offends the honor of C++98 and maybe later versions */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC # pragma GCC diagnostic ignored "-Wweak-vtables" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC # pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC # pragma GCC diagnostic ignored "-Wextra-semi" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC # pragma GCC diagnostic ignored "-Wold-style-cast" # endif #endif #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma clang diagnostic push "-Wdeprecated-declarations" # endif #endif #include class ExampleTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ExampleTest ); CPPUNIT_TEST( testOne ); CPPUNIT_TEST_SUITE_END(); public: void setUp() override; void tearDown() override; void testOne(); }; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( ExampleTest ); void ExampleTest::setUp() { } void ExampleTest::tearDown() { } void ExampleTest::testOne() { // Set up int i = 1; float f = 1.0; // Process int cast = static_cast(f); // Check CPPUNIT_ASSERT_EQUAL( i, cast ); } #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) # pragma GCC diagnostic pop #endif nut-2.8.3/tests/nutipc_ut.cpp0000644000200500020050000003142314777767434013154 00000000000000/* NUT IPC unit test Copyright (C) 2012 \author Vaclav Krpec Copyright (C) 2024-2025 \author Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nutipc.hpp" #include "nutstream.hpp" #include extern "C" { #include #include #include extern bool verbose; } /* Current CPPUnit offends the honor of C++98 and maybe later versions */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC # pragma GCC diagnostic ignored "-Wweak-vtables" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC # pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC # pragma GCC diagnostic ignored "-Wextra-semi" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC # pragma GCC diagnostic ignored "-Wold-style-cast" # endif #endif #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma clang diagnostic push "-Wdeprecated-declarations" # endif #endif #include /** * \brief NUT IPC module unit test */ class NutIPCUnitTest: public CppUnit::TestFixture { private: CPPUNIT_TEST_SUITE(NutIPCUnitTest); CPPUNIT_TEST( testExec ); CPPUNIT_TEST( testSignalSend ); CPPUNIT_TEST( testSignalRecvQuick ); CPPUNIT_TEST( testSignalRecvStaggered ); CPPUNIT_TEST_SUITE_END(); /** * \brief Test signal handler * * \param signal Signal caught */ static void testSignalHandler(int signal); public: /** External command execution test */ void testExec(); /** Signal sending test */ void testSignalSend(); /** Signal receiving test */ void testSignalRecvQuick(); void testSignalRecvStaggered(); inline void setUp() override {} inline void tearDown() override {} virtual ~NutIPCUnitTest() override; }; // end of class NutIPCUnitTest // Register the test suite CPPUNIT_TEST_SUITE_REGISTRATION(NutIPCUnitTest); void NutIPCUnitTest::testExec() { #ifdef WIN32 /* FIXME NUT_WIN32_INCOMPLETE: * Some other program, maybe NUT's "message" handler, or "cmd -k" etc.? * And get Process working in the first place */ std::cout << "NutIPCUnitTest::testExec(): skipped on this platform" << std::endl; #else /* !WIN32 */ static const std::string bin = "/bin/sh"; nut::Process::Executor::Arguments args; args.push_back("-c"); args.push_back("exit 123"); nut::Process::Execution child(bin, args); CPPUNIT_ASSERT(123 == child.wait()); CPPUNIT_ASSERT(0 == nut::Process::execute("test 'Hello world' = 'Hello world'")); #endif /* !WIN32 */ } /** Last signal caught */ static int signal_caught = 0; void NutIPCUnitTest::testSignalHandler(int signal) { signal_caught = signal; } void NutIPCUnitTest::testSignalSend() { #ifdef WIN32 /* FIXME NUT_WIN32_INCOMPLETE: * Needs implementation for signals via pipes */ std::cout << "NutIPCUnitTest::testSignalSend(): skipped on this platform" << std::endl; #else /* !WIN32 */ struct sigaction action; pid_t my_pid = nut::Process::getPID(); // Set SIGUSR1 signal handler ::memset(&action, 0, sizeof(action)); # ifdef sigemptyset // no :: here because macro sigemptyset(&action.sa_mask); # else ::sigemptyset(&action.sa_mask); # endif action.sa_handler = &testSignalHandler; CPPUNIT_ASSERT(0 == ::sigaction(static_cast(nut::Signal::USER1), &action, nullptr)); // Send signal directly CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); CPPUNIT_ASSERT(static_cast(nut::Signal::USER1) == signal_caught); signal_caught = 0; std::stringstream my_pid_ss; // Save PID to a PIDfile; use an unique filename as much as we can // (avoid conflicts in parallel running tests on NUT CI farm, etc.) my_pid_ss << nut::NutFile::tmp_dir() << nut::NutFile::path_sep() << "nutipc_ut_" << my_pid << ".pid"; static const std::string pid_file_name(my_pid_ss.str()); my_pid_ss.str(""); my_pid_ss.clear(); my_pid_ss << my_pid; if (verbose) std::cerr << "NutIPCUnitTest::testSignalSend(): using PID file '" << pid_file_name << "' for PID " << my_pid << " to store string '" << my_pid_ss.str() << "'" << std::endl << std::flush; nut::NutFile pid_file(pid_file_name, nut::NutFile::WRITE_ONLY); pid_file.putString(my_pid_ss.str()); pid_file.closex(); // Send signal to process via the PIDfile CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, pid_file_name)); CPPUNIT_ASSERT(static_cast(nut::Signal::USER1) == signal_caught); pid_file.removex(); signal_caught = 0; #endif /* !WIN32 */ } /** Caught signal list */ static nut::Signal::List caught_signals; /** Signal handler routine */ class TestSignalHandler: public nut::Signal::Handler { public: void operator () (nut::Signal::enum_t signal) override { caught_signals.push_back(signal); } virtual ~TestSignalHandler() override; }; // end of class TestSignalHandler // \todo Describe the point of this test. void NutIPCUnitTest::testSignalRecvQuick() { #ifdef WIN32 /* FIXME NUT_WIN32_INCOMPLETE: * Needs implementation for signals via pipes */ std::cout << "NutIPCUnitTest::testSignalRecvQuick(): skipped on this platform" << std::endl; #else /* !WIN32 */ // Create signal handler thread nut::Signal::List signals; caught_signals.clear(); signals.push_back(nut::Signal::USER1); signals.push_back(nut::Signal::USER2); nut::Signal::HandlerThread sig_handler(signals); pid_t my_pid = nut::Process::getPID(); /* * POSIX does not require signals to be delivered in order. * It does not require that signals are like messages, but * rather views them as a software version of hardware * interrupts. Two sent signals might result in only one * handler invocation. However, we (and most other signal * users) expect that signals are usually in order and usually * relatively promptly. * * For now, insist on beyond-POSIX behavior, as a canary that * if triggered, we should examine nut's use of signals. */ /* Send two signals, and pause briefly to allow delivery. */ CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER2, my_pid)); ::sleep(1); /* Send two signals in the other order, and again pause briefly. */ CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER2, my_pid)); CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); ::sleep(1); /* Send a single signal. */ CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); /* * Sleep 1s, assuming that is long enough for all signals to * be delivered (really, the last one) and the handler to have * run to completion. */ ::sleep(1); /* * Check that all 5 sent were received. Note that strictly, * an OS on which USER1 and USER2 are each received once is * not a failure to conform. But a delay of 1s in signal * delivery would generally be seen as not ok. */ CPPUNIT_ASSERT(caught_signals.size() == 5); /* * Loop over the received signal records. Count the number of * USER1 and USER2, and assert that no signals other than * those two were received. */ int countUSER1 = 0; int countUSER2 = 0; while (!caught_signals.empty()) { nut::Signal::enum_t signal = caught_signals.front(); caught_signals.pop_front(); if (signal == nut::Signal::USER1) { countUSER1++; } else if (signal == nut::Signal::USER2) { countUSER2++; } else { std::stringstream msg; msg << "Unexpected signal was received: " << signal; CPPUNIT_ASSERT_MESSAGE(msg.str(), 0); } } /* Check that received count matches sent count from code above. */ CPPUNIT_ASSERT(countUSER1 == 3); CPPUNIT_ASSERT(countUSER2 == 2); #endif /* !WIN32 */ } void NutIPCUnitTest::testSignalRecvStaggered() { #ifdef WIN32 /* FIXME NUT_WIN32_INCOMPLETE: * Needs implementation for signals via pipes */ std::cout << "NutIPCUnitTest::testSignalRecvStaggered(): skipped on this platform" << std::endl; #else /* !WIN32 */ // Create signal handler thread nut::Signal::List signals; caught_signals.clear(); signals.push_back(nut::Signal::USER1); signals.push_back(nut::Signal::USER2); nut::Signal::HandlerThread sig_handler(signals); pid_t my_pid = nut::Process::getPID(); /* NOTE: The signal order delivery is not specified by POSIX if several * ones arrive nearly simultaneously (and/or get confused by multi-CPU * routing). Linux tends to deliver lower-numbered signals first, so we * expect USER1 (10) before USER2 (12) to be consistent. Otherwise CI * builds tend to mess this up a bit. */ CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); ::sleep(1); CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER2, my_pid)); ::sleep(1); CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER2, my_pid)); ::sleep(1); /* Help ensure ordered (one-by-one) delivery before re-posting a * presumably lower-numbered signal after some higher-numbered ones. */ CPPUNIT_ASSERT(0 == nut::Signal::send(nut::Signal::USER1, my_pid)); // Let the sig. handler thread finish... ::sleep(1); CPPUNIT_ASSERT(caught_signals.size() == 4); CPPUNIT_ASSERT(caught_signals.front() == nut::Signal::USER1); caught_signals.pop_front(); CPPUNIT_ASSERT(caught_signals.front() == nut::Signal::USER2); caught_signals.pop_front(); CPPUNIT_ASSERT(caught_signals.front() == nut::Signal::USER2); caught_signals.pop_front(); CPPUNIT_ASSERT(caught_signals.front() == nut::Signal::USER1); #endif /* !WIN32 */ } // Implement out of class declaration to avoid // error: 'SomeClass' has no out-of-line virtual method // definitions; its vtable will be emitted in every translation unit // [-Werror,-Wweak-vtables] TestSignalHandler::~TestSignalHandler() {} NutIPCUnitTest::~NutIPCUnitTest() {} #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) # pragma GCC diagnostic pop #endif nut-2.8.3/tests/generic_gpio_test.txt0000644000200500020050000001456614777534446014674 00000000000000rules expecting_failure upsLinesCount upsMaxLine rulesCount stateName subCount ruleInt ^ -2 & -3 | -4 * rules OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 4 6 6 OL 2 -2 0 OB 1 0 LB 1 1 RB 1 2 DISCHRG 4 0 -3 -2 3 BYPASS 1 3 * rules DISCHRG=0&^6; 1 2 6 1 DISCHRG 4 0 -3 -2 1 * rules DISCHRG=0&^6|^2; 1 3 6 1 DISCHRG 7 0 -3 -2 1 -4 -2 2 * rules ; 0 * rules = 0 * rules 0 0 * rules ^ 0 * rules OB 0 * rules OB= 0 * rules OB=; 0 * rules OB=a; 0 * rules OB=&; 0 * rules OB=^; 0 * rules OB=^a; 0 * rules OB=^=; 0 * rules OB=^&; 0 * rules OB=^|; 0 * rules OB=^2a; 0 * rules OB=^2^1; 0 * rules OB=^2&a; 0 * rules OB=^2&&; 0 * rules OB=^2&|; 0 * rules OB=^2|a; 0 * rules OB=^2|&; 0 * rules OB=^2||; 0 * rules OB=^2 0 * states DISCHRG=0&^6; 0 0 0 * states DISCHRG=0&^6; 1 0 1 * states DISCHRG=0&^6; 0 1 0 * states DISCHRG=0&^6; 1 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 0 0 0 1 0 0 0 0 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 0 0 0 0 1 0 0 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 1 0 0 1 0 1 0 0 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 1 0 0 0 1 1 0 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 0 1 0 1 0 0 1 0 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 0 1 0 0 1 0 1 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 1 1 0 1 0 1 1 0 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 1 1 0 0 1 1 1 1 0 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 0 0 1 1 0 0 0 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 0 0 1 0 1 0 0 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 1 0 1 1 0 1 0 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 1 0 1 0 1 1 0 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 0 1 1 1 0 0 1 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 0 1 1 0 1 0 1 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 1 1 1 1 0 1 1 0 1 * states OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 1 1 1 0 1 1 1 0 1 * states OL=1; 0 0 * states OL=1; 1 1 * states OL=^1; 1 0 * states OL=^1; 0 1 * states OL=1|2; 0 0 0 * states OL=1|2; 1 0 1 * states OL=1|2; 0 1 1 * states OL=1|2; 1 1 1 * states OL=1&2; 0 0 0 * states OL=1&2; 1 0 0 * states OL=1&2; 0 1 0 * states OL=1&2; 1 1 1 * states OL=1&^2; 0 0 0 * states OL=1&^2; 1 0 1 * states OL=1&^2; 0 1 0 * states OL=1&^2; 1 1 0 * states OL=^1&2; 0 0 0 * states OL=^1&2; 1 0 0 * states OL=^1&2; 0 1 1 * states OL=^1&2; 1 1 0 * states OL=^1&^2; 0 0 1 * states OL=^1&^2; 1 0 0 * states OL=^1&^2; 0 1 0 * states OL=^1&^2; 1 1 0 * states OL=^1&^2; 1 1 0 * states TSTAO=1&2|3; 0 0 0 0 * states TSTAO=1&2|3; 1 0 0 0 * states TSTAO=1&2|3; 0 1 0 0 * states TSTAO=1&2|3; 1 1 0 1 * states TSTAO=1&2|3; 0 0 1 1 * states TSTAO=1&2|3; 1 0 1 1 * states TSTAO=1&2|3; 0 1 1 1 * states TSTAO=1&2|3; 1 1 1 1 * states TSTOA=1|2&3; 0 0 0 0 * states TSTOA=1|2&3; 1 0 0 1 * states TSTOA=1|2&3; 0 1 0 0 * states TSTOA=1|2&3; 1 1 0 1 * states TSTOA=1|2&3; 0 0 1 0 * states TSTOA=1|2&3; 1 0 1 1 * states TSTOA=1|2&3; 0 1 1 1 * states TSTOA=1|2&3; 1 1 1 1 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 0 0 OL . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 0 0 OB_DISCHRG discharging . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 0 0 OL_BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 0 0 BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 1 0 OL_LB . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 1 0 OB_LB_DISCHRG discharging . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 1 0 OL_BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 1 0 BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 0 1 OL_RB . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 0 1 OB_RB_DISCHRG discharging . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 0 1 OL_BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 0 1 BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 1 1 OL_LB_RB . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 1 1 OB_LB_RB_DISCHRG discharging . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 1 1 OL_BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 1 1 BYPASS . . . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 0 0 OL . 10 100 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 0 0 OB_DISCHRG discharging 10 100 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 0 0 OL_BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 0 0 BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 1 0 OL_LB . 10 10 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 1 0 OB_LB_DISCHRG discharging 10 10 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 1 0 OL_BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 1 0 BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 0 1 OL_RB . 10 100 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 0 1 OB_RB_DISCHRG discharging 10 100 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 0 1 OL_BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 0 1 BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 0 1 1 OL_LB_RB . 10 10 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 0 1 1 OB_LB_RB_DISCHRG discharging 10 10 * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 0 1 1 1 OL_BYPASS . 10 . * update OL=^0;OB=0&^6;LB=3&^6;RB=1&^6;DISCHRG=0&^6;BYPASS=6; 1 1 1 1 BYPASS . 10 . * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 gpiochip0 openclose * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 gpiochip1 openclose * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 gpiochip2 openclose * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 gpiochip0 initinfo * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 gpiochip0 initinfo * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 0 gpiochip0 updateinfo * library OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6; 1 gpiochip0 updateinfo * nut-2.8.3/tests/Makefile.am0000644000200500020050000002217015001552635012441 00000000000000# Network UPS Tools: tests # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ SUBDIRS = . NIT # Note: a few duplicate mentions are possible here, but a decent make should # handle that properly all: $(TESTS) $(check_PROGRAMS) $(check_SCRIPTS) EXTRA_DIST = nut-driver-enumerator-test.sh nut-driver-enumerator-test--ups.conf TESTS = noinst_LTLIBRARIES = CLEANFILES = *.trs *.log AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/drivers AM_CXXFLAGS = -I$(top_srcdir)/include # Compiler flags for cppunit tests CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ check_PROGRAMS = $(TESTS) check_SCRIPTS = # NUT Integration Testing suite check-NIT check-NIT-devel: +cd "$(builddir)/NIT" && $(MAKE) $(AM_MAKEFLAGS) $@ nutlogtest_SOURCES = nutlogtest.c nutlogtest_LDADD = $(top_builddir)/common/libcommon.la if REQUIRE_NUT_STRARG check_SCRIPTS += nutlogtest-nofail.sh CLEANFILES += nutlogtest-nofail.sh nutlogtest$(EXEEXT) nutlogtest nutlogtest-nofail.sh: nutlogtest$(EXEEXT) @echo '#!/bin/sh' > $@ @echo 'echo "WARNING: Your C library requires workarounds to print NULL values!" >&2' >> $@ @echo 'echo "If nutlogtest below, or generally some NUT program, crashes with" >&2' >> $@ @echo 'echo "a segmentation fault (especially during verbose debug) - that may be why" >&2' >> $@ @echo 'SCRIPT_DIR="`dirname "$$0"`"' >> $@ @echo '"$${SCRIPT_DIR}/nutlogtest" "$$@" || echo "nutlogtest FAILED but it was expected"' >> $@ @chmod +x $@ # NOTE: Keep the line above empty! else !REQUIRE_NUT_STRARG TESTS += nutlogtest$(EXEEXT) endif !REQUIRE_NUT_STRARG TESTS += nuttimetest nuttimetest_SOURCES = nuttimetest.c nuttimetest_LDADD = $(top_builddir)/common/libcommon.la TESTS += nutbooltest nutbooltest_SOURCES = nutbooltest.c #nutbooltest_LDADD = $(top_builddir)/common/libcommon.la # Separate the .deps of other dirs from this one LINKED_SOURCE_FILES = hidparser.c # NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver # of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS hidparser.c: $(top_srcdir)/drivers/hidparser.c test -s "$@" || ln -s -f "$(top_srcdir)/drivers/hidparser.c" "$@" if WITH_USB TESTS += getvaluetest getexponenttest-belkin-hid # We only need to call a few methods, not use the whole source - so # not linking it as a getvaluetest_SOURCE file (has too many deps): noinst_LTLIBRARIES += libdriverstubusb.la nodist_libdriverstubusb_la_SOURCES = driver-stub-usb.c libdriverstubusb_la_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) #libdriverstubusb_la_LIBADD = $(top_builddir)/common/libcommon.la getexponenttest-belkin-hid.c: $(top_srcdir)/drivers/belkin-hid.c getexponenttest_belkin_hid_SOURCES = getexponenttest-belkin-hid.c getexponenttest_belkin_hid_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) getexponenttest_belkin_hid_LDADD = $(top_builddir)/common/libcommon.la libdriverstubusb.la getvaluetest_SOURCES = getvaluetest.c nodist_getvaluetest_SOURCES = hidparser.c # Pull the right include path for chosen libusb version: getvaluetest_CFLAGS = $(AM_CFLAGS) $(LIBUSB_CFLAGS) getvaluetest_LDADD = $(top_builddir)/common/libcommon.la else !WITH_USB EXTRA_DIST += getvaluetest.c hidparser.c endif !WITH_USB EXTRA_DIST += driver-stub-usb.c if WITH_GPIO TESTS += gpiotest # NOTE: Not using "$<" due to a legacy Sun/illumos dmake bug with resolver # of dynamic vars, see e.g. https://man.omnios.org/man1/make#BUGS generic_gpio_libgpiod.c: $(top_srcdir)/drivers/generic_gpio_libgpiod.c test -s "$@" || ln -s -f "$(top_srcdir)/drivers/generic_gpio_libgpiod.c" "$@" generic_gpio_common.c: $(top_srcdir)/drivers/generic_gpio_common.c test -s "$@" || ln -s -f "$(top_srcdir)/drivers/generic_gpio_common.c" "$@" gpiotest_SOURCES = generic_gpio_utest.c generic_gpio_liblocal.c nodist_gpiotest_SOURCES = generic_gpio_libgpiod.c generic_gpio_common.c gpiotest_LDADD = $(top_builddir)/drivers/libdummy_mockdrv.la $(LIBGPIO_LDFLAGS) gpiotest_CFLAGS = $(LIBGPIO_CFLAGS) $(AM_CFLAGS) -I$(top_srcdir)/tests -DDRIVERS_MAIN_WITHOUT_MAIN=1 else !WITH_GPIO EXTRA_DIST += generic_gpio_utest.c generic_gpio_liblocal.c endif !WITH_GPIO CLEANFILES += generic_gpio_libgpiod.c generic_gpio_common.c EXTRA_DIST += generic_gpio_utest.h generic_gpio_test.txt TESTS += driver_methods_utest driver_methods_utest_SOURCES = driver_methods_utest.c driver_methods_utest_LDADD = $(top_builddir)/drivers/libdummy_mockdrv.la driver_methods_utest_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/tests -DDRIVERS_MAIN_WITHOUT_MAIN=1 # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/drivers/libdummy_mockdrv.la \ $(top_builddir)/common/libnutconf.la \ $(top_builddir)/common/libcommonclient.la \ $(top_builddir)/common/libcommon.la: dummy +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) ### Optional tests which can not be built everywhere # List of src files for CppUnit tests CPPUNITTESTSRC = example.cpp nutclienttest.cpp # These are an optional part of cppunittest, if building WITH_LIBNUTCONF CPPUNITTESTSRC_NUTCONF = nutconf_parser_ut.cpp nutstream_ut.cpp nutconf_ut.cpp nutipc_ut.cpp # The test driver which orchestrates running those tests above CPPUNITTESTERSRC = cpputest.cpp CPPCLIENTTESTSRC = cpputest-client.cpp TESTS_CXX11 = cppunittest if HAVE_CXX11 if HAVE_CPPUNIT # Note: per configure script this "SHOULD" also assume # that we HAVE_CXX11 - but better have it explicit TESTS += $(TESTS_CXX11) # Note: we only build it, but do not run directly (NIT prepares the sandbox) check_PROGRAMS += cppnit cppunittest_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) ###cppunittest_CXXFLAGS += -I$(top_srcdir)/include -DTOP_SRCDIR="\"$(top_srcdir)\"" cppunittest_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) cppunittest_LDADD = $(top_builddir)/clients/libnutclient.la cppunittest_LDADD += $(top_builddir)/clients/libnutclientstub.la cppunittest_SOURCES = $(CPPUNITTESTSRC) $(CPPUNITTESTERSRC) # Currently nutconf and related codebase causes woes for static analysis # so we do not build it unless explicitly asked to. if WITH_LIBNUTCONF cppunittest_SOURCES += $(CPPUNITTESTSRC_NUTCONF) cppunittest_LDADD += $(top_builddir)/common/libnutconf.la endif WITH_LIBNUTCONF cppnit_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) cppnit_LDFLAGS = $(CPPUNIT_LDFLAGS) $(CPPUNIT_LIBS) cppnit_LDADD = $(top_builddir)/clients/libnutclient.la $(top_builddir)/clients/libnutclientstub.la cppnit_SOURCES = $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) # Make sure out-of-dir C++ dependencies exist (especially when dev-building # only some parts of NUT): $(top_builddir)/clients/libnutclient.la \ $(top_builddir)/clients/libnutclientstub.la: dummy +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) else !HAVE_CPPUNIT # Just redistribute test source into tarball if not building tests EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) $(CPPUNITTESTSRC_NUTCONF) cppnit: @echo " SKIP $@ : not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 endif !HAVE_CPPUNIT else !HAVE_CXX11 # Just redistribute test source into tarball if not building C++ at all EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPCLIENTTESTSRC) $(CPPUNITTESTERSRC) $(CPPUNITTESTSRC_NUTCONF) cppnit: @echo " SKIP $@ : not implemented without C++11 and CPPUNIT enabled" >&2 ; exit 1 endif !HAVE_CXX11 if HAVE_VALGRIND # NOTE: "cppnit", if built, requires running from NIT (with NUT_PORT, etc.) # Note that FAILED value begins with a space, so we do not echo another memcheck: $(check_PROGRAMS) @RES=0; FAILED=""; \ for P in $? ; do \ case "$$P" in \ cppnit|cppnit$(EXEEXT)) \ if [ "$${NUT_PORT-}" -gt 0 ] 2>/dev/null ; then : ; else \ echo " SKIP $@ : $(VALGRIND) ./$$P : NUT_PORT not prepared" ; \ continue ; \ fi ;; \ esac ; \ '$(top_builddir)/scripts/valgrind/valgrind.sh' "./$$P" \ || { RES=$$? ; \ echo "FAILED: '$(top_builddir)/scripts/valgrind/valgrind.sh' './$$P'" >&2; \ FAILED="$$FAILED $$P" ; \ } ; \ done; \ if [ -n "$$FAILED" ] ; then echo "OVERALL FAILED:$$FAILED" >&2 ; fi ; \ exit $$RES else !HAVE_VALGRIND memcheck: @echo " SKIP $@ : valgrind was not detected on this system by configure script" >&2 endif !HAVE_VALGRIND if WITH_VALGRIND check-local: memcheck endif WITH_VALGRIND dummy: BUILT_SOURCES = $(LINKED_SOURCE_FILES) CLEANFILES += $(LINKED_SOURCE_FILES) CLEANFILES += $(TESTS) $(TESTS_CXX11) MAINTAINERCLEANFILES = Makefile.in .dirstamp # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! #clean-local: # $(AM_V_at)rm -rf $(builddir)/.deps # Helper for only the enabled libs to get built: all-libs-local: $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) $(EXTRA_LTLIBRARIES) nut-2.8.3/tests/NIT/0000755000200500020050000000000015001555412011111 500000000000000nut-2.8.3/tests/NIT/Makefile.in0000644000200500020050000006216415001555011013102 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: NUT Integration Tests (NIT) VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = tests/NIT ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = nit.sh README.adoc # Allow to override with make/env vars; provide sensible defaults (see nit.sh): #NIT_CASE = testcase_sandbox_start_drivers_after_upsd NIT_CASE = testgroup_sandbox_upsmon_master NUT_PORT = 12345 SPELLCHECK_SRC = README.adoc CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .in .in-spellchecked .sample .sample-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/NIT/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/NIT/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ clean-local cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ @WITH_CHECK_NIT_TRUE@check: check-NIT @WITH_CHECK_NIT_FALSE@check: @WITH_CHECK_NIT_FALSE@ @echo "NO-OP: $@ in `pwd` is inactive by default. Run 'configure --enable-check-NIT' or 'make check-NIT' explicitly" >&2 # Run in builddir, use script from srcdir # Avoid running "$<" - not all make implementations handle that check-NIT: $(abs_srcdir)/nit.sh "$(abs_srcdir)/nit.sh" # Make sure pre-requisites for NIT are fresh as we iterate check-NIT-devel: $(abs_srcdir)/nit.sh +@cd .. && ( $(MAKE) $(AM_MAKEFLAGS) -s cppnit$(EXEEXT) || echo "OPTIONAL C++ test client test will be skipped" ) +@cd "$(top_builddir)/clients" && $(MAKE) $(AM_MAKEFLAGS) -s upsc$(EXEEXT) upscmd$(EXEEXT) upsrw$(EXEEXT) upsmon$(EXEEXT) +@cd "$(top_builddir)/server" && $(MAKE) $(AM_MAKEFLAGS) -s upsd$(EXEEXT) sockdebug$(EXEEXT) +@cd "$(top_builddir)/drivers" && $(MAKE) $(AM_MAKEFLAGS) -s dummy-ups$(EXEEXT) upsdrvctl$(EXEEXT) +@$(MAKE) $(AM_MAKEFLAGS) check-NIT check-NIT-sandbox: $(abs_srcdir)/nit.sh [ -n "$${DEBUG_SLEEP-}" ] && [ "$${DEBUG_SLEEP-}" -gt 0 ] || DEBUG_SLEEP=600 ; export DEBUG_SLEEP ; \ LANG=C LC_ALL=C TZ=UTC \ NUT_PORT=$(NUT_PORT) NIT_CASE="$(NIT_CASE)" NUT_FOREGROUND_WITH_PID=true \ "$(abs_srcdir)/nit.sh" check-NIT-sandbox-devel: $(abs_srcdir)/nit.sh +[ -n "$${DEBUG_SLEEP-}" ] && [ "$${DEBUG_SLEEP-}" -gt 0 ] || DEBUG_SLEEP=600 ; export DEBUG_SLEEP ; \ LANG=C LC_ALL=C TZ=UTC \ NUT_PORT=$(NUT_PORT) NIT_CASE="$(NIT_CASE)" NUT_FOREGROUND_WITH_PID=true \ $(MAKE) $(AM_MAKEFLAGS) check-NIT-devel # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ clean-local: $(AM_V_at)rm -rf tmp # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/tests/NIT/README.adoc0000644000200500020050000000367414777767434012664 00000000000000NUT Integration Testing suite (aka NIT) ======================================= This suite aims to simplify running `upsd`, a `dummy-ups` driver and a few clients to query them, as part of regular `make check` routine or separately with existing binaries (should not impact any existing installation data, processes or communications). WARNING: Current working directory when starting the script should be the location where it may create temporary data (e.g. the `BUILDDIR`). See also link:https://git.launchpad.net/ubuntu/+source/nut/tree/debian/tests/test-nut.py[The NUT testing script] available in the link:https://code.edge.launchpad.net/qa-regression-testing[Ubuntu QA Regression Testing suite] and link:https://salsa.debian.org/debian/nut/-/tree/debian/debian/tests[Debian packaging recipe] doing a similar job with NUT installed from packages and configuring it via files in standard path names. A sandbox prepared by this script can be used for `upsmon` testing: ---- :; make check-NIT-sandbox-devel & # Wait for sandbox, e.g. test that "${NUT_CONFPATH}/NIT.env-sandbox-ready" # file appeared; then source the envvars, e.g.: :; sleep 5 ; while ! [ -e ./tests/NIT/tmp/etc/NIT.env-sandbox-ready ] ; do sleep 1 ; done :; . ./tests/NIT/tmp/etc/NIT.env # Prepare upsmon.conf there, e.g.: :; printf 'MINSUPPLIES 1\nPOWERDOWNFLAG "%s/killpower"\nSHUTDOWNCMD "date >> \"%s/nut-shutdown.log\""\nMONITOR "%s@127.0.0.1:%s" 1 "%s" "%s" primary\n' \ "$NUT_STATEPATH" "$NUT_STATEPATH" 'dummy' "$NUT_PORT" \ 'dummy-admin' "${TESTPASS_UPSMON_PRIMARY}" \ > "${NUT_CONFPATH}/upsmon.conf" ---- The `nit.sh` script supports a lot of environment variables to tune its behavior, notably `NIT_CASE`, `NUT_PORT`, `NUT_STATEPATH` and `NUT_CONFPATH`, but also many more. See its sources, as well as the top-level `Makefile.am` recipe and the `./tests/NIT/tmp/etc/NIT.env` file generated during a test run, for more details and examples about the currently supported tunables. nut-2.8.3/tests/NIT/Makefile.am0000644000200500020050000001041214777767434013117 00000000000000# Network UPS Tools: NUT Integration Tests (NIT) # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ EXTRA_DIST = nit.sh README.adoc if WITH_CHECK_NIT check: check-NIT else check: @echo "NO-OP: $@ in `pwd` is inactive by default. Run 'configure --enable-check-NIT' or 'make check-NIT' explicitly" >&2 endif # Run in builddir, use script from srcdir # Avoid running "$<" - not all make implementations handle that check-NIT: $(abs_srcdir)/nit.sh "$(abs_srcdir)/nit.sh" # Make sure pre-requisites for NIT are fresh as we iterate check-NIT-devel: $(abs_srcdir)/nit.sh +@cd .. && ( $(MAKE) $(AM_MAKEFLAGS) -s cppnit$(EXEEXT) || echo "OPTIONAL C++ test client test will be skipped" ) +@cd "$(top_builddir)/clients" && $(MAKE) $(AM_MAKEFLAGS) -s upsc$(EXEEXT) upscmd$(EXEEXT) upsrw$(EXEEXT) upsmon$(EXEEXT) +@cd "$(top_builddir)/server" && $(MAKE) $(AM_MAKEFLAGS) -s upsd$(EXEEXT) sockdebug$(EXEEXT) +@cd "$(top_builddir)/drivers" && $(MAKE) $(AM_MAKEFLAGS) -s dummy-ups$(EXEEXT) upsdrvctl$(EXEEXT) +@$(MAKE) $(AM_MAKEFLAGS) check-NIT # Allow to override with make/env vars; provide sensible defaults (see nit.sh): #NIT_CASE = testcase_sandbox_start_drivers_after_upsd NIT_CASE = testgroup_sandbox_upsmon_master NUT_PORT = 12345 check-NIT-sandbox: $(abs_srcdir)/nit.sh [ -n "$${DEBUG_SLEEP-}" ] && [ "$${DEBUG_SLEEP-}" -gt 0 ] || DEBUG_SLEEP=600 ; export DEBUG_SLEEP ; \ LANG=C LC_ALL=C TZ=UTC \ NUT_PORT=$(NUT_PORT) NIT_CASE="$(NIT_CASE)" NUT_FOREGROUND_WITH_PID=true \ "$(abs_srcdir)/nit.sh" check-NIT-sandbox-devel: $(abs_srcdir)/nit.sh +[ -n "$${DEBUG_SLEEP-}" ] && [ "$${DEBUG_SLEEP-}" -gt 0 ] || DEBUG_SLEEP=600 ; export DEBUG_SLEEP ; \ LANG=C LC_ALL=C TZ=UTC \ NUT_PORT=$(NUT_PORT) NIT_CASE="$(NIT_CASE)" NUT_FOREGROUND_WITH_PID=true \ $(MAKE) $(AM_MAKEFLAGS) check-NIT-devel SPELLCHECK_SRC = README.adoc # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *-spellchecked: Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .sample.sample-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ .in.in-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE="$<" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SPELLCHECK_SRC)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp clean-local: $(AM_V_at)rm -rf tmp nut-2.8.3/tests/NIT/nit.sh0000755000200500020050000020764414777767434012233 00000000000000#!/bin/sh # NUT Integration Testing suite, assumes the codebase was built and # arranges running of the binaries to test driver-client-server # ability to start and their interactions. # # Note: currently it is a PoC-quality mess that gets the job done # but could be refactored for better maintainability and generic # approach. Part of the goal was to let this script set up the # sandbox to run tests which could be defined in other files. # To speed up this practical developer-testing aspect, you can just # `make check-NIT-sandbox{,-devel}` (optionally with custom DEBUG_SLEEP). # # WARNING: Current working directory when starting the script should be # the location where it may create temporary data (e.g. the BUILDDIR). # Caller can export envvars to impact the script behavior, e.g.: # DEBUG=true to print debug messages, running processes, etc. # DEBUG_SLEEP=60 to sleep after tests, with driver+server running # NUT_DEBUG_MIN=3 to set (minimum) debug level for drivers, upsd... # NUT_DEBUG_LEVEL_UPSSCHED=3 to set debug level for particular # NUT daemons or tools # NUT_PORT=12345 custom port for upsd to listen and clients to query # NUT_FOREGROUND_WITH_PID=true default foregrounding is without # PID files, this option tells daemons to save them # TESTDIR=/tmp/nut-NIT to propose a location for "etc" and "run" # mock locations (under some circumstances, the # script can anyway choose to `mktemp` another) # NUT_DEBUG_UPSMON_NOTIFY_SYSLOG=false To *disable* upsmon # notifications spilling to the script's console. # # Common sandbox run for testing goes from NUT root build directory like: # DEBUG_SLEEP=600 NUT_PORT=12345 NIT_CASE=testcase_sandbox_start_drivers_after_upsd NUT_FOREGROUND_WITH_PID=true make check-NIT & # # Design note: written with dumbed-down POSIX shell syntax, to # properly work in whatever different OSes have (bash, dash, # ksh, busybox sh...) # # Copyright # 2022-2025 Jim Klimov # # License: GPLv2+ if [ -z "${BASH_VERSION-}" ] \ && (command -v bash) \ && [ x"${DEBUG_NONBASH-}" != xtrue ] \ ; then # FIXME: detect and pass -x/-v options? echo "WARNING: Re-execing in BASH (export DEBUG_NONBASH=true to avoid)" >&2 exec bash $0 "$@" fi if [ -n "${BASH_VERSION-}" ]; then eval `echo "set -o pipefail"` fi TZ=UTC LANG=C LC_ALL=C export TZ LANG LC_ALL NUT_QUIET_INIT_SSL="true" export NUT_QUIET_INIT_SSL NUT_QUIET_INIT_UPSNOTIFY="true" export NUT_QUIET_INIT_UPSNOTIFY # Avoid noise in syslog and OS console NUT_DEBUG_SYSLOG="stderr" export NUT_DEBUG_SYSLOG # Stash the originally requested value so we can fiddle with envvars (if set) # per daemon, like NUT_DEBUG_LEVEL_UPSD, NUT_DEBUG_LEVEL_UPSMON, # NUT_DEBUG_LEVEL_UPSLOG, NUT_DEBUG_LEVEL_UPSSCHED, NUT_DEBUG_LEVEL_DRIVERS, # or per tool, like NUT_DEBUG_LEVEL_UPSC (not in all cases), # NUT_DEBUG_LEVEL_NUT_SCANNER NUT_DEBUG_LEVEL_ORIG="${NUT_DEBUG_LEVEL-}" # Whether from env or set in script per prog, let it be known to children: export NUT_DEBUG_LEVEL NUT_DEBUG_PID="true" export NUT_DEBUG_PID # Just keep upsdrvctl quiet if used in test builds or with the sandbox NUT_QUIET_INIT_NDE_WARNING="true" export NUT_QUIET_INIT_NDE_WARNING ARG_FG="-F" if [ x"${NUT_FOREGROUND_WITH_PID-}" = xtrue ] ; then ARG_FG="-FF" ; fi TABCHAR="`printf '\t'`" log_separator() { echo "" >&2 echo "================================" >&2 } shouldDebug() { [ -n "$DEBUG" ] || [ -n "$DEBUG_SLEEP" ] } log_debug() { if shouldDebug ; then echo "`TZ=UTC LANG=C date` [DEBUG] $@" >&2 fi return 0 } log_info() { echo "`TZ=UTC LANG=C date` [INFO] $@" >&2 } log_warn() { echo "`TZ=UTC LANG=C date` [WARNING] $@" >&2 } log_error() { echo "`TZ=UTC LANG=C date` [ERROR] $@" >&2 } report_NUT_PORT() { # Try to say which processes deal with current NUT_PORT [ -n "${NUT_PORT}" ] || return log_info "Trying to report users of NUT_PORT=${NUT_PORT}" # Note: on Solarish systems, `netstat -anp` does not report PID info (netstat -an ; netstat -anp || sockstat -l) 2>/dev/null | grep -w "${NUT_PORT}" \ || (lsof -i :"${NUT_PORT}") 2>/dev/null \ || true [ -z "${PID_UPSD}" ] || log_info "UPSD was last known to start as PID ${PID_UPSD}" } isBusy_NUT_PORT() { # Try to say if current NUT_PORT is busy (0 = true) # or available (non-0 = false) [ -n "${NUT_PORT}" ] || return log_debug "isBusy_NUT_PORT() Trying to report if NUT_PORT=${NUT_PORT} is used" if [ -r /proc/net/tcp ] || [ -r /proc/net/tcp6 ]; then # Assume Linux - hex-encoded # IPv4: # sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode # 0: 0100007F:EE48 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 48881 1 00000000ec238d02 100 0 0 10 0 # ^^^ 1.0.0.127 - note reversed byte order! # IPv6: # sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode # 0: 00000000000000000000000000000000:1F46 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 33 0 37451 1 00000000fa3c0c15 100 0 0 10 0 NUT_PORT_HEX="`printf '%04X' "${NUT_PORT}"`" NUT_PORT_HITS="`cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | awk '{print $2}' | grep -E ":${NUT_PORT_HEX}\$"`" \ && [ -n "$NUT_PORT_HITS" ] \ && log_debug "isBusy_NUT_PORT() found that NUT_PORT=${NUT_PORT} is busy per /proc/net/tcp*" \ && return 0 # We had a way to check, and the way said port is available log_debug "isBusy_NUT_PORT() found that NUT_PORT=${NUT_PORT} is not busy per /proc/net/tcp*" return 1 fi (netstat -an || sockstat -l || ss -tn || ss -n) 2>/dev/null | grep -E "[:.]${NUT_PORT}(${TABCHAR}| |\$)" > /dev/null \ && log_debug "isBusy_NUT_PORT() found that NUT_PORT=${NUT_PORT} is busy per netstat, sockstat or ss" \ && return (lsof -i :"${NUT_PORT}") 2>/dev/null \ && log_debug "isBusy_NUT_PORT() found that NUT_PORT=${NUT_PORT} is busy per lsof" \ && return # If the current shell interpreter is bash, it can do a bit of networking: if [ -n "${BASH_VERSION-}" ]; then # NOTE: Probing host names we use in upsd.conf # See generatecfg_upsd_trivial() for a more carefully made list ( # Hide this looped noise: # ./nit.sh: connect: Connection refused # ./nit.sh: line 112: /dev/tcp/localhost/35050: Connection refused if shouldDebug ; then : ; else exec 2>/dev/null fi for H in "localhost" "127.0.0.1" "::1"; do if echo "HELP" > "/dev/tcp/${H}/${NUT_PORT}" ; then # Successfully connected - port isBusy return 0 fi done return 1 ) && return 0 log_warn "isBusy_NUT_PORT() tried with BASH-specific query, and port does not seem busy (or something else errored out)" fi # Not busy... or no tools to confirm? (or no perms, or no lsof plugin)? if (command -v netstat || command -v sockstat || command -v ss || command -v lsof) 2>/dev/null >/dev/null ; then # at least one tool is present, so not busy log_debug "isBusy_NUT_PORT() found that NUT_PORT=${NUT_PORT} is not busy per netstat, sockstat, ss or lsof" return 1 fi # Assume not busy to not preclude testing in 100% of the cases log_warn "isBusy_NUT_PORT() can not say definitively, tools for checking NUT_PORT=$NUT_PORT are not available" return 1 } die() { echo "[FATAL] $@" >&2 exit 1 } # By default, keep stdout hidden but report the errors: [ -n "$RUNCMD_QUIET_OUT" ] || RUNCMD_QUIET_OUT=true [ -n "$RUNCMD_QUIET_ERR" ] || RUNCMD_QUIET_ERR=false runcmd() { # Re-uses a couple of files in test scratch area NUT_STATEPATH # to store the stderr and stdout of the launched program. # Prints the captured output back and returns the exit code. [ -n "${NUT_STATEPATH}" -a -d "${NUT_STATEPATH}" -a -w "${NUT_STATEPATH}" ] \ || die "runcmd() called when NUT_STATEPATH was not yet set up" # Values from variables below may be used until next runcmd(): CMDRES=0 CMDOUT="" CMDERR="" # FIXME: Consider EXEEXT? case "$0" in upsc|*/upsc) if [ -n "${NUT_DEBUG_LEVEL_UPSC-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSC}" fi ;; nut-scanner|*/nut-scanner) if [ -n "${NUT_DEBUG_LEVEL_NUT_SCANNER-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_NUT_SCANNER}" fi ;; esac "$@" > "${NUT_STATEPATH}/runcmd.out" 2>"${NUT_STATEPATH}/runcmd.err" || CMDRES=$? NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" CMDOUT="`cat "${NUT_STATEPATH}/runcmd.out"`" CMDERR="`cat "${NUT_STATEPATH}/runcmd.err"`" [ "$RUNCMD_QUIET_OUT" = true ] || { [ -z "$CMDOUT" ] || echo "$CMDOUT" ; } [ "$RUNCMD_QUIET_ERR" = true ] || { [ -z "$CMDERR" ] || echo "$CMDERR" >&2 ; } return $CMDRES } # Note: current directory is assumed to be writeable for temporary # data, e.g. the $(builddir) from the Makefile. Static resources # from the source codebase are where the script resides, e.g. # the $(srcdir) from the Makefile. If we are not in the source # tree, tests would use binaries in PATH (e.g. packaged install). BUILDDIR="`pwd`" TOP_BUILDDIR="" case "${BUILDDIR}" in */tests/NIT) TOP_BUILDDIR="`cd "${BUILDDIR}"/../.. && pwd`" ;; *) log_info "Current directory '${BUILDDIR}' is not a .../tests/NIT" ;; esac if test ! -w "${BUILDDIR}" ; then log_error "BUILDDIR='${BUILDDIR}' is not writeable, tests may fail below" fi SRCDIR="`dirname "$0"`" SRCDIR="`cd "$SRCDIR" && pwd`" TOP_SRCDIR="" case "${SRCDIR}" in */tests/NIT) TOP_SRCDIR="`cd "${SRCDIR}"/../.. && pwd`" ;; *) log_info "Script source directory '${SRCDIR}' is not a .../tests/NIT" ;; esac # Make these paths known to e.g. upsmon/upssched and handler scripts they call export BUILDDIR TOP_BUILDDIR SRCDIR TOP_SRCDIR # No fuss about LD_LIBRARY_PATH: for most of the (client) binaries that # need it, the PATH entries below would contain libtool wrapper scripts; # for other builds we use system default or caller's env. One exception # so far is nut-scanner that needs to know where libupsclient.so is... PATH_ADD="${BUILDDIR}" if [ x"${SRCDIR}" != x"${BUILDDIR}" ]; then PATH_ADD="${PATH_ADD}:${SRCDIR}" fi if [ x"${TOP_BUILDDIR}" != x ]; then PATH_ADD="${PATH_ADD}:${TOP_BUILDDIR}/clients:${TOP_BUILDDIR}/drivers:${TOP_BUILDDIR}/server:${TOP_BUILDDIR}/tools:${TOP_BUILDDIR}/tools/nut-scanner" fi if [ x"${TOP_SRCDIR}" != x ]; then PATH_ADD="${PATH_ADD}:${TOP_SRCDIR}/clients:${TOP_SRCDIR}/drivers:${TOP_SRCDIR}/server:${TOP_SRCDIR}/tools:${TOP_SRCDIR}/tools/nut-scanner" fi PATH="${PATH_ADD}:${PATH}" export PATH unset PATH_ADD log_debug "Using PATH='$PATH'" LD_LIBRARY_PATH_ORIG="${LD_LIBRARY_PATH-}" LD_LIBRARY_PATH_CLIENT="" if [ x"${TOP_BUILDDIR}" != x ]; then LD_LIBRARY_PATH_CLIENT="${TOP_BUILDDIR}/clients:${TOP_BUILDDIR}/clients/.libs" fi if [ x"${LD_LIBRARY_PATH_CLIENT}" != x ]; then if [ -n "${LD_LIBRARY_PATH_ORIG-}" ]; then LD_LIBRARY_PATH_CLIENT="${LD_LIBRARY_PATH_CLIENT}:${LD_LIBRARY_PATH_ORIG}" fi else LD_LIBRARY_PATH_CLIENT="${LD_LIBRARY_PATH_ORIG}" fi for PROG in upsd upsc dummy-ups upsmon upslog upssched ; do (command -v ${PROG}) || die "Useless setup: ${PROG} not found in PATH: ${PATH}" done PID_UPSD="" PID_UPSMON="" PID_UPSSCHED="" PID_DUMMYUPS="" PID_DUMMYUPS1="" PID_DUMMYUPS2="" # Stash it for some later decisions TESTDIR_CALLER="${TESTDIR-}" [ -n "${TESTDIR-}" ] || TESTDIR="$BUILDDIR/tmp" if [ `echo "${TESTDIR}" | wc -c` -gt 80 ]; then # Technically the limit is sizeof(sockaddr.sun_path) for complete socket # pathname, which varies 104-108 chars max on systems seen in CI farm; # we reserve 17 chars for "/dummy-ups-dummy" longest filename. log_info "'${TESTDIR}' is too long to store AF_UNIX socket files, will mktemp" TESTDIR="" else if [ "`id -u`" = 0 ]; then case "${TESTDIR}" in "${HOME}"/*) log_info "Test script was started by 'root' and '${TESTDIR}' seems to be under its home, will mktemp so unprivileged daemons may access their configs, pipes and PID files" TESTDIR="" ;; esac else if ! mkdir -p "${TESTDIR}" || ! [ -w "${TESTDIR}" ] ; then log_info "'${TESTDIR}' could not be created/used, will mktemp" TESTDIR="" fi fi fi if [ x"${TESTDIR}" = x ] ; then if ( [ -n "${TMPDIR-}" ] && [ -d "${TMPDIR-}" ] && [ -w "${TMPDIR-}" ] ) ; then : else if [ -d /dev/shm ] && [ -w /dev/shm ]; then TMPDIR=/dev/shm ; else TMPDIR=/tmp ; fi fi log_warn "Will now mktemp a TESTDIR under '${TMPDIR}'. It will be wiped when the NIT script exits." log_warn "If you want a pre-determined location, pre-export a usable TESTDIR value." TESTDIR="`mktemp -d "${TMPDIR}/nit-tmp.$$.XXXXXX"`" || die "Failed to mktemp" if [ "`id -u`" = 0 ]; then # Cah be protected as 0700 by default chmod ugo+rx "${TESTDIR}" fi else NUT_CONFPATH="${TESTDIR}/etc" if [ -e "${NUT_CONFPATH}/NIT.env-sandbox-ready" ] ; then log_warn "'${NUT_CONFPATH}/NIT.env-sandbox-ready' exists, do you have another instance of the script still running with same configs?" sleep 3 fi # NOTE: Keep in sync with NIT_CASE handling and the exit-trap below case "${NIT_CASE}" in generatecfg_*|is*) ;; *) rm -rf "${TESTDIR}" || true ;; esac fi log_info "Using '$TESTDIR' for generated configs and state files" if [ x"${TESTDIR_CALLER}" = x"${TESTDIR}" ] && [ x"${TESTDIR}" != x"$BUILDDIR/tmp" ] ; then log_warn "A caller-provided location is used, it would not be automatically removed after tests nor by 'make clean'" fi mkdir -p "${TESTDIR}/etc" "${TESTDIR}/run" && chmod 750 "${TESTDIR}/run" \ || die "Failed to create temporary FS structure for the NIT" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '${TESTDIR}/run' so unprivileged daemons may create pipes and PID files there" chmod 777 "${TESTDIR}/run" fi stop_daemons() { if [ -n "$PID_UPSMON" ] ; then log_info "Stopping test daemons: upsmon via command" upsmon -c stop fi if [ -z "$PID_UPSSCHED" ] && [ -s "$NUT_PIDPATH/upssched.pid" ] ; then PID_UPSSCHED="`head -1 "$NUT_PIDPATH/upssched.pid"`" fi if [ -s "$NUT_PIDPATH/upssched.pid" ] ; then PID_UPSSCHED_NOW="`head -1 "$NUT_PIDPATH/upssched.pid"`" fi if [ -n "$PID_UPSD$PID_UPSMON$PID_DUMMYUPS$PID_DUMMYUPS1$PID_DUMMYUPS2$PID_UPSSCHED$PID_UPSSCHED_NOW" ] ; then log_info "Stopping test daemons" kill -15 $PID_UPSD $PID_UPSMON $PID_DUMMYUPS $PID_DUMMYUPS1 $PID_DUMMYUPS2 $PID_UPSSCHED $PID_UPSSCHED_NOW 2>/dev/null || return 0 wait $PID_UPSD $PID_UPSMON $PID_DUMMYUPS $PID_DUMMYUPS1 $PID_DUMMYUPS2 $PID_UPSSCHED $PID_UPSSCHED_NOW || true fi PID_UPSD="" PID_UPSMON="" PID_UPSSCHED="" PID_DUMMYUPS="" PID_DUMMYUPS1="" PID_DUMMYUPS2="" unset PID_UPSSCHED_NOW } trap 'RES=$?; case "${NIT_CASE}" in generatecfg_*|is*) ;; *) stop_daemons; if [ x"${TESTDIR}" != x"${BUILDDIR}/tmp" ] && [ x"${TESTDIR}" != x"$TESTDIR_CALLER" ] ; then rm -rf "${TESTDIR}" ; else rm -f "${NUT_CONFPATH}/NIT.env-sandbox-ready" ; fi ;; esac; exit $RES;' 0 1 2 3 15 NUT_STATEPATH="${TESTDIR}/run" NUT_PIDPATH="${TESTDIR}/run" NUT_ALTPIDPATH="${TESTDIR}/run" NUT_CONFPATH="${TESTDIR}/etc" export NUT_STATEPATH NUT_PIDPATH NUT_ALTPIDPATH NUT_CONFPATH if [ -e "${NUT_CONFPATH}/NIT.env-sandbox-ready" ] ; then log_warn "'${NUT_CONFPATH}/NIT.env-sandbox-ready' exists, do you have another instance of the script still running?" sleep 3 fi rm -f "${NUT_CONFPATH}/NIT.env-sandbox-ready" || true # TODO: Find a portable way to (check and) grab a random unprivileged port? if [ -n "${NUT_PORT-}" ] && [ "$NUT_PORT" -gt 0 ] && [ "$NUT_PORT" -lt 65536 ] ; then if isBusy_NUT_PORT ; then log_warn "NUT_PORT=$NUT_PORT requested by caller seems occupied; tests may fail below" fi else COUNTDOWN=60 while [ "$COUNTDOWN" -gt 0 ] ; do DELTA1="`date +%S`" || DELTA1=0 DELTA2="`expr $$ % 99`" || DELTA2=0 NUT_PORT="`expr 34931 + $DELTA1 + $DELTA2`" \ && [ "$NUT_PORT" -gt 0 ] && [ "$NUT_PORT" -lt 65536 ] \ || NUT_PORT=34931 if isBusy_NUT_PORT ; then : ; else break fi log_warn "Selected NUT_PORT=$NUT_PORT seems occupied; will try another in a few seconds" COUNTDOWN="`expr "$COUNTDOWN" - 1`" [ "$COUNTDOWN" = 0 ] || sleep 2 done if [ "$COUNTDOWN" = 0 ] ; then COUNTDOWN=60 DELTA1=1025 while [ "$COUNTDOWN" -gt 0 ] ; do DELTA2="`expr $RANDOM % 64000`" \ && [ "$DELTA2" -ge 0 ] || die "Can not pick random port" NUT_PORT="`expr $DELTA1 + $DELTA2`" if isBusy_NUT_PORT ; then : ; else break fi # Loop quickly, no sleep here COUNTDOWN="`expr "$COUNTDOWN" - 1`" done if [ "$COUNTDOWN" = 0 ] ; then die "Can not pick random port" fi fi fi export NUT_PORT # Help track collisions in log, if someone else starts a test in same directory log_info "Using NUT_PORT=${NUT_PORT} for this test run" # This file is not used by the test code, it is an # aid for "DEBUG_SLEEP=X" mode so the caller can # quickly source needed values into their shell. # # WARNING: Variables in this file are not guaranteed # to impact subsequent runs of this script (nit.sh), # e.g. NUT_PORT may be inherited, but paths would not be! # # NOTE: `set` typically wraps the values in quotes, # but (maybe?) not all shell implementations do. # Just in case, we have a fallback with single quotes. # FIXME: We assume no extra quoting or escaping in # the values when fallback is used. If this is a # problem on any platform (Win/Mac and spaces in # paths?) please investigate and fix accordingly. set | grep -E '^(NUT_|TESTDIR|LD_LIBRARY_PATH|DEBUG|PATH).*=' \ | while IFS='=' read K V ; do case "$K" in LD_LIBRARY_PATH_CLIENT|LD_LIBRARY_PATH_ORIG|PATH_*|NUT_PORT_*|TESTDIR_*) continue ;; DEBUG_SLEEP|PATH|LD_LIBRARY_PATH*) printf '### ' ;; esac case "$V" in '"'*'"'|"'"*"'") printf "%s=%s\nexport %s\n\n" "$K" "$V" "$K" ;; *) printf "%s='%s'\nexport %s\n\n" "$K" "$V" "$K" ;; esac done > "$NUT_CONFPATH/NIT.env" log_info "Populated environment variables for this run into $NUT_CONFPATH/NIT.env" ### upsd.conf: ################################################## generatecfg_upsd_trivial() { # Populate the configs for the run cat > "$NUT_CONFPATH/upsd.conf" << EOF STATEPATH "$NUT_STATEPATH" LISTEN localhost $NUT_PORT EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: upsd.conf" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '$NUT_CONFPATH/upsd.conf' so unprivileged daemons (after de-elevation) may read it" chmod 644 "$NUT_CONFPATH/upsd.conf" else chmod 640 "$NUT_CONFPATH/upsd.conf" fi # Some systems listening on symbolic "localhost" actually # only bind to IPv6, and some (Python) client might resolve # IPv4 and fail its connection tests. Others fare well with # both addresses in one command. for LH in 127.0.0.1 '::1' ; do if ( ( cat /etc/hosts || getent hosts ) | grep "$LH" \ || ping -c 1 "$LH" ) 2>/dev/null >/dev/null ; then echo "LISTEN $LH $NUT_PORT" >> "$NUT_CONFPATH/upsd.conf" fi done if [ -n "${NUT_DEBUG_MIN-}" ] ; then echo "DEBUG_MIN ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/upsd.conf" || exit fi } generatecfg_upsd_nodev() { generatecfg_upsd_trivial echo "ALLOW_NO_DEVICE true" >> "$NUT_CONFPATH/upsd.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsd.conf" } ### upsd.users: ################################################## TESTPASS_ADMIN='mypass' TESTPASS_TESTER='pass words' TESTPASS_UPSMON_PRIMARY='P@ssW0rdAdm' TESTPASS_UPSMON_SECONDARY='P@ssW0rd' generatecfg_upsdusers_trivial() { cat > "$NUT_CONFPATH/upsd.users" << EOF [admin] password = $TESTPASS_ADMIN actions = SET instcmds = ALL [tester] password = "${TESTPASS_TESTER}" instcmds = test.battery.start instcmds = test.battery.stop [dummy-admin-m] password = "${TESTPASS_UPSMON_PRIMARY}" upsmon master [dummy-admin] password = "${TESTPASS_UPSMON_PRIMARY}" upsmon primary [dummy-user-s] password = "${TESTPASS_UPSMON_SECONDARY}" upsmon slave [dummy-user] password = "${TESTPASS_UPSMON_SECONDARY}" upsmon secondary EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: upsd.users" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '$NUT_CONFPATH/upsd.users' so unprivileged daemons (after de-elevation) may read it" chmod 644 "$NUT_CONFPATH/upsd.users" else chmod 640 "$NUT_CONFPATH/upsd.users" fi } ### upsmon.conf and upssched.conf: ################################################## updatecfg_upsmon_supplies() { NUMSUP="${1-}" [ -n "$NUMSUP" ] && [ "$NUMSUP" -ge 0 ] || NUMSUP=1 [ -s "$NUT_CONFPATH/upsmon.conf" ] \ || die "Failed to rewrite config - not populated yet: upsmon.conf" # NOTE: "sed -i file" is not ubiquitously portable # Using "cat" to retain FS permissions maybe set above sed -e 's,^\(MINSUPPLIES\) [0-9][0-9]*$,\1 '"$NUMSUP"',' \ -e 's,^\(MONITOR .*\) [0-9][0-9]* \(.*\)$,\1 '"$NUMSUP"' \2,' \ < "$NUT_CONFPATH/upsmon.conf" > "$NUT_CONFPATH/upsmon.conf.tmp" \ && ( cat "$NUT_CONFPATH/upsmon.conf.tmp" > "$NUT_CONFPATH/upsmon.conf" ) \ && rm -f "$NUT_CONFPATH/upsmon.conf.tmp" } generatecfg_upsmon_trivial() { # Populate the configs for the run rm -f "$NUT_STATEPATH/upsmon.sd.log" ( echo 'MINSUPPLIES 0' > "$NUT_CONFPATH/upsmon.conf" || exit echo 'SHUTDOWNCMD "echo \"`date`: TESTING_DUMMY_SHUTDOWN_NOW\" | tee \"'"$NUT_STATEPATH"'/upsmon.sd.log\" "' >> "$NUT_CONFPATH/upsmon.conf" || exit NOTIFYTGT="" if [ -x "${TOP_SRCDIR-}/scripts/misc/notifyme-debug" ] ; then echo "NOTIFYCMD \"TEMPDIR='${NUT_STATEPATH}' ${TOP_SRCDIR-}/scripts/misc/notifyme-debug\"" >> "$NUT_CONFPATH/upsmon.conf" || exit # NOTE: "SYSLOG" typically ends up in console log of the NIT run and # "EXEC" goes to a log file like tests/NIT/tmp/run/notifyme-399.log NOTIFYTGT="EXEC" fi if [ x"$NUT_DEBUG_UPSMON_NOTIFY_SYSLOG" != xfalse ] ; then [ -n "${NOTIFYTGT}" ] && NOTIFYTGT="${NOTIFYTGT}+SYSLOG" || NOTIFYTGT="SYSLOG" fi if [ -n "${NOTIFYTGT}" ]; then if [ -s "${TOP_SRCDIR-}/conf/upsmon.conf.sample.in" ] ; then grep -E '# NOTIFYFLAG .*SYSLOG\+WALL$' \ < "${TOP_SRCDIR-}/conf/upsmon.conf.sample.in" \ | sed 's,^# \(NOTIFYFLAG[^A-Z_]*[A-Z_]*\)[^A-Z_]*SYSLOG.*$,\1\t'"${NOTIFYTGT}"',' \ >> "$NUT_CONFPATH/upsmon.conf" || exit fi fi if [ -n "${NUT_DEBUG_MIN-}" ] ; then echo "DEBUG_MIN ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/upsmon.conf" || exit fi ) || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" sed \ -e 's,[@]TOP_BUILDDIR[@],'"${TOP_BUILDDIR}"',g' \ -e 's,[@]TOP_SRCDIR[@],'"${TOP_SRCDIR}"',g' \ -e 's,[@]NUT_CONFPATH[@],'"${NUT_CONFPATH}"',g' \ -e 's,[@]NUT_STATEPATH[@],'"${NUT_STATEPATH}"',g' \ < "${TOP_SRCDIR-}/tests/NIT/upssched.conf.in" > "$NUT_CONFPATH/upssched.conf" \ || die "Failed to populate temporary FS structure for the NIT: upssched.conf" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '$NUT_CONFPATH/upsmon.conf' and '$NUT_CONFPATH/upssched.conf' so unprivileged daemons (after de-elevation) may read them" chmod 644 "$NUT_CONFPATH/upsmon.conf" "$NUT_CONFPATH/upssched.conf" else chmod 640 "$NUT_CONFPATH/upsmon.conf" "$NUT_CONFPATH/upssched.conf" fi if [ $# -gt 0 ] ; then updatecfg_upsmon_supplies "$1" fi } generatecfg_upsmon_master() { generatecfg_upsmon_trivial echo "MONITOR \"dummy@localhost:$NUT_PORT\" 0 \"dummy-admin-m\" \"${TESTPASS_UPSMON_PRIMARY}\" master" >> "$NUT_CONFPATH/upsmon.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" if [ $# -gt 0 ] ; then updatecfg_upsmon_supplies "$1" fi } generatecfg_upsmon_primary() { generatecfg_upsmon_trivial echo "MONITOR \"dummy@localhost:$NUT_PORT\" 0 \"dummy-admin\" \"${TESTPASS_UPSMON_PRIMARY}\" primary" >> "$NUT_CONFPATH/upsmon.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" if [ $# -gt 0 ] ; then updatecfg_upsmon_supplies "$1" fi } generatecfg_upsmon_slave() { generatecfg_upsmon_trivial echo "MONITOR \"dummy@localhost:$NUT_PORT\" 0 \"dummy-user-s\" \"${TESTPASS_UPSMON_SECONDARY}\" slave" >> "$NUT_CONFPATH/upsmon.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" if [ $# -gt 0 ] ; then updatecfg_upsmon_supplies "$1" fi } generatecfg_upsmon_secondary() { generatecfg_upsmon_trivial echo "MONITOR \"dummy@localhost:$NUT_PORT\" 0 \"dummy-user\" \"${TESTPASS_UPSMON_SECONDARY}\" secondary" >> "$NUT_CONFPATH/upsmon.conf" \ || die "Failed to populate temporary FS structure for the NIT: upsmon.conf" if [ $# -gt 0 ] ; then updatecfg_upsmon_supplies "$1" fi } ### ups.conf: ################################################## generatecfg_ups_trivial() { # Populate the configs for the run ( echo 'maxretry = 3' > "$NUT_CONFPATH/ups.conf" || exit if [ x"${TOP_BUILDDIR}" != x ]; then echo "driverpath = \"${TOP_BUILDDIR}/drivers\"" >> "$NUT_CONFPATH/ups.conf" || exit fi if [ -n "${NUT_DEBUG_MIN-}" ] ; then echo "debug_min = ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/ups.conf" || exit fi ) || die "Failed to populate temporary FS structure for the NIT: ups.conf" if [ "`id -u`" = 0 ]; then log_info "Test script was started by 'root' - expanding permissions for '$NUT_CONFPATH/ups.conf' so unprivileged daemons (after de-elevation) may read it" chmod 644 "$NUT_CONFPATH/ups.conf" else chmod 640 "$NUT_CONFPATH/ups.conf" fi } generatecfg_ups_dummy() { generatecfg_ups_trivial cat > "$NUT_CONFPATH/dummy.seq" << EOF ups.status: OB TIMER 5 ups.status: OL TIMER 5 EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: dummy.seq" cat >> "$NUT_CONFPATH/ups.conf" << EOF [dummy] driver = dummy-ups desc = "Crash Dummy" port = dummy.seq #mode = dummy-loop EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: ups.conf" if [ x"${TOP_SRCDIR}" != x ]; then cp "${TOP_SRCDIR}/data/evolution500.seq" "${TOP_SRCDIR}/data/epdu-managed.dev" "$NUT_CONFPATH/" cat >> "$NUT_CONFPATH/ups.conf" << EOF [UPS1] driver = dummy-ups desc = "Example event sequence" port = evolution500.seq [UPS2] driver = dummy-ups desc = "Example ePDU data dump" port = epdu-managed.dev mode = dummy-once EOF [ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: ups.conf" # HACK: Avoid empty ups.status that may be present in example docs # FIXME: Might we actually want that value (un-)set for tests?.. # TODO: Check if the problem was with dummy-ups looping? [#1385] # Avoid "sed -i", it behaves differently on some platforms # and is completely absent on others [#1736 and earlier] for F in "$NUT_CONFPATH/"*.dev "$NUT_CONFPATH/"*.seq ; do sed -e 's,^ups.status: *$,ups.status: OL BOOST,' "$F" > "$F.bak" mv -f "$F.bak" "$F" grep -E '^ups.status:' "$F" >/dev/null || { echo "ups.status: OL BOOST" >> "$F"; } done fi } ##################################################### isPidAlive() { [ -n "$1" ] && [ "$1" -gt 0 ] || return [ -d "/proc/$1" ] || kill -0 "$1" 2>/dev/null } FAILED=0 FAILED_FUNCS="" PASSED=0 testcase_upsd_no_configs_at_all() { log_separator log_info "[testcase_upsd_no_configs_at_all] Test UPSD without configs at all" if [ -n "${NUT_DEBUG_LEVEL_UPSD-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSD}" fi upsd ${ARG_FG} if [ "$?" = 0 ]; then log_error "[testcase_upsd_no_configs_at_all] upsd should fail without configs" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_no_configs_at_all" else log_info "[testcase_upsd_no_configs_at_all] PASSED: upsd failed to start in wrong conditions" PASSED="`expr $PASSED + 1`" fi NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" } testcase_upsd_no_configs_driver_file() { log_separator log_info "[testcase_upsd_no_configs_driver_file] Test UPSD without driver config file" generatecfg_upsd_trivial if [ -n "${NUT_DEBUG_LEVEL_UPSD-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSD}" fi upsd ${ARG_FG} if [ "$?" = 0 ]; then log_error "[testcase_upsd_no_configs_driver_file] upsd should fail without driver config file" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_no_configs_driver_file" else log_info "[testcase_upsd_no_configs_driver_file] PASSED: upsd failed to start in wrong conditions" PASSED="`expr $PASSED + 1`" fi NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" } testcase_upsd_no_configs_in_driver_file() { log_separator log_info "[testcase_upsd_no_configs_in_driver_file] Test UPSD without drivers defined in config file" generatecfg_upsd_trivial generatecfg_ups_trivial if [ -n "${NUT_DEBUG_LEVEL_UPSD-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSD}" fi upsd ${ARG_FG} if [ "$?" = 0 ]; then log_error "[testcase_upsd_no_configs_in_driver_file] upsd should fail without drivers defined in config file" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_no_configs_in_driver_file" else log_info "[testcase_upsd_no_configs_in_driver_file] PASSED: upsd failed to start in wrong conditions" PASSED="`expr $PASSED + 1`" fi NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" } upsd_start_loop() { TESTCASE="${1-upsd_start_loop}" if isPidAlive "$PID_UPSD" ; then return 0 fi if [ -n "${NUT_DEBUG_LEVEL_UPSD-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSD}" fi upsd ${ARG_FG} & PID_UPSD="$!" NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" log_debug "[${TESTCASE}] Tried to start UPSD as PID $PID_UPSD" sleep 2 # Due to a busy port, server could have died by now COUNTDOWN=60 while [ "$COUNTDOWN" -gt 0 ]; do sleep 1 COUNTDOWN="`expr $COUNTDOWN - 1`" # Is our server alive AND occupying the port? PID_OK=true isPidAlive "$PID_UPSD" || PID_OK=false # not running PORT_OK=true isBusy_NUT_PORT 2>/dev/null >/dev/null || PORT_OK=false # not busy if "${PID_OK}" ; then if "${PORT_OK}" ; then break ; fi continue fi # FIXME: If we are here, even once, then PID_UPSD which we # knew has already disappeared... wait() for its exit-code? # Give some time for ports to time out, if busy and that is # why the server died. PORT_WORD="" ${PORT_OK} || PORT_WORD="not " log_warn "[${TESTCASE}] Port ${NUT_PORT} is ${PORT_WORD}listening and UPSD PID $PID_UPSD is not alive, will sleep and retry" sleep 10 if [ -n "${NUT_DEBUG_LEVEL_UPSD-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSD}" fi upsd ${ARG_FG} & PID_UPSD="$!" NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" log_warn "[${TESTCASE}] Tried to start UPSD again, now as PID $PID_UPSD" sleep 5 done if [ "$COUNTDOWN" -le 50 ] ; then # Should not get to this, except on very laggy systems maybe log_warn "[${TESTCASE}] Had to wait a few retries for the UPSD process to appear" fi # Return code is 0/OK if the server is alive AND occupying the port if isPidAlive "$PID_UPSD" && isBusy_NUT_PORT 2>/dev/null >/dev/null ; then log_debug "[${TESTCASE}] Port ${NUT_PORT} is listening and UPSD PID $PID_UPSD is alive" return fi log_error "[${TESTCASE}] Port ${NUT_PORT} is not listening and/or UPSD PID $PID_UPSD is not alive" return 1 } testcase_upsd_allow_no_device() { log_separator log_info "[testcase_upsd_allow_no_device] Test UPSD allowed to run without driver configs" generatecfg_upsd_nodev generatecfg_upsdusers_trivial generatecfg_ups_trivial if shouldDebug ; then ls -la "$NUT_CONFPATH/" || true fi upsd_start_loop "testcase_upsd_allow_no_device" res_testcase_upsd_allow_no_device=0 if [ "$COUNTDOWN" -gt 0 ] \ && isPidAlive "$PID_UPSD" \ ; then log_info "[testcase_upsd_allow_no_device] OK, upsd is running" PASSED="`expr $PASSED + 1`" log_separator log_info "[testcase_upsd_allow_no_device] Query listing from UPSD by UPSC (no devices configured yet) to test that UPSD responds to UPSC" if runcmd upsc -l localhost:$NUT_PORT ; then : else # Note: avoid exact matching for stderr, because it can have Init SSL messages etc. if echo "$CMDERR" | grep "Error: Server disconnected" >/dev/null ; then log_warn "[testcase_upsd_allow_no_device] Retry once to rule out laggy systems" sleep 3 runcmd upsc -l localhost:$NUT_PORT fi if echo "$CMDERR" | grep "Error: Server disconnected" >/dev/null ; then log_warn "[testcase_upsd_allow_no_device] Retry once more to rule out very laggy systems" sleep 15 runcmd upsc -l localhost:$NUT_PORT fi [ "$CMDRES" = 0 ] || die "[testcase_upsd_allow_no_device] upsd does not respond on port ${NUT_PORT} ($?): $CMDOUT" fi if [ -n "$CMDOUT" ] ; then log_error "[testcase_upsd_allow_no_device] got reply for upsc listing when none was expected: $CMDOUT" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_allow_no_device" res_testcase_upsd_allow_no_device=1 else log_info "[testcase_upsd_allow_no_device] OK, empty response as expected" PASSED="`expr $PASSED + 1`" fi else log_error "[testcase_upsd_allow_no_device] upsd was expected to be running although no devices are defined; is ups.conf populated?" ls -la "$NUT_CONFPATH/" || true FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_upsd_allow_no_device" res_testcase_upsd_allow_no_device=1 report_NUT_PORT fi log_info "[testcase_upsd_allow_no_device] stopping upsd: $PID_UPSD" UPSD_RES=0 kill -15 $PID_UPSD wait $PID_UPSD || UPSD_RES=$? if [ "$res_testcase_upsd_allow_no_device" = 0 ] ; then log_info "[testcase_upsd_allow_no_device] upsd exit-code was: $UPSD_RES" else log_error "[testcase_upsd_allow_no_device] upsd exit-code was: $UPSD_RES" fi if [ "$UPSD_RES" != 0 ]; then return $UPSD_RES fi return $res_testcase_upsd_allow_no_device } testgroup_upsd_invalid_configs() { testcase_upsd_no_configs_at_all testcase_upsd_no_configs_driver_file testcase_upsd_no_configs_in_driver_file } testgroup_upsd_questionable_configs() { testcase_upsd_allow_no_device } ######################################################### ### Tests in a common sandbox with driver(s) + server ### ######################################################### SANDBOX_CONFIG_GENERATED=false sandbox_generate_configs() { if $SANDBOX_CONFIG_GENERATED ; then return ; fi log_info "Generating configs for sandbox" generatecfg_upsd_nodev generatecfg_upsdusers_trivial generatecfg_ups_dummy SANDBOX_CONFIG_GENERATED=true } sandbox_forget_configs() { SANDBOX_CONFIG_GENERATED=false if [ -z "${DEBUG_SLEEP-}" ] ; then stop_daemons fi } sandbox_start_upsd() { if isPidAlive "$PID_UPSD" ; then return 0 fi sandbox_generate_configs log_info "Starting UPSD for sandbox" upsd_start_loop "sandbox" } sandbox_start_drivers() { if isPidAlive "$PID_DUMMYUPS" \ && { [ x"${TOP_SRCDIR}" != x ] && isPidAlive "$PID_DUMMYUPS1" && isPidAlive "$PID_DUMMYUPS2" \ || [ x"${TOP_SRCDIR}" = x ] ; } \ ; then # All drivers expected for this environment are already running return 0 fi sandbox_generate_configs log_info "Starting dummy-ups driver(s) for sandbox" if [ -n "${NUT_DEBUG_LEVEL_DRIVERS-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_DRIVERS}" fi #upsdrvctl ${ARG_FG} start dummy & dummy-ups -a dummy ${ARG_FG} & PID_DUMMYUPS="$!" log_debug "Tried to start dummy-ups driver for 'dummy' as PID $PID_DUMMYUPS" if [ x"${TOP_SRCDIR}" != x ]; then dummy-ups -a UPS1 ${ARG_FG} & PID_DUMMYUPS1="$!" log_debug "Tried to start dummy-ups driver for 'UPS1' as PID $PID_DUMMYUPS1" dummy-ups -a UPS2 ${ARG_FG} & PID_DUMMYUPS2="$!" log_debug "Tried to start dummy-ups driver for 'UPS2' as PID $PID_DUMMYUPS2" fi NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" sleep 5 if shouldDebug ; then (ps -ef || ps -xawwu) 2>/dev/null | grep -E '(ups|nut|dummy|'"`basename "$0"`"')' | grep -vE '(ssh|startups|grep)' || true fi if isPidAlive "$PID_DUMMYUPS" \ && { [ x"${TOP_SRCDIR}" != x ] && isPidAlive "$PID_DUMMYUPS1" && isPidAlive "$PID_DUMMYUPS2" \ || [ x"${TOP_SRCDIR}" = x ] ; } \ ; then # All drivers expected for this environment are already running log_info "Starting dummy-ups driver(s) for sandbox - all expected processes are running" return 0 else log_error "Starting dummy-ups driver(s) for sandbox - finished, but something seems to not be running" return 1 fi } testcase_sandbox_start_upsd_alone() { log_separator log_info "[testcase_sandbox_start_upsd_alone] Test starting UPSD but not a driver before it" sandbox_start_upsd EXPECTED_UPSLIST='dummy' if [ x"${TOP_SRCDIR}" != x ]; then EXPECTED_UPSLIST="$EXPECTED_UPSLIST UPS1 UPS2" # For windows runners (strip CR if any): EXPECTED_UPSLIST="`echo "$EXPECTED_UPSLIST" | tr -d '\r'`" fi log_info "[testcase_sandbox_start_upsd_alone] Query listing from UPSD by UPSC (driver not running yet)" res_testcase_sandbox_start_upsd_alone=0 runcmd upsc -l localhost:$NUT_PORT || die "[testcase_sandbox_start_upsd_alone] upsd does not respond on port ${NUT_PORT} ($?): $CMDOUT" # For windows runners (printf can do wonders, so strip CR if any): if [ x"${TOP_SRCDIR}" != x ]; then CMDOUT="`echo "$CMDOUT" | tr -d '\r'`" fi if [ x"$CMDOUT" != x"$EXPECTED_UPSLIST" ] ; then log_error "[testcase_sandbox_start_upsd_alone] got this reply for upsc listing when '$EXPECTED_UPSLIST' was expected: '$CMDOUT'" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_start_upsd_alone" res_testcase_sandbox_start_upsd_alone=1 else PASSED="`expr $PASSED + 1`" fi log_info "[testcase_sandbox_start_upsd_alone] Query driver state from UPSD by UPSC (driver not running yet)" runcmd upsc dummy@localhost:$NUT_PORT && { log_error "upsc was supposed to answer with error exit code: $CMDOUT" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_start_upsd_alone" res_testcase_sandbox_start_upsd_alone=1 } # Note: avoid exact matching for stderr, because it can have Init SSL messages etc. if echo "$CMDERR" | grep 'Error: Driver not connected' >/dev/null ; then PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_start_upsd_alone] got some other reply for upsc query when 'Error: Driver not connected' was expected on stderr: '$CMDOUT'" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_start_upsd_alone" res_testcase_sandbox_start_upsd_alone=1 fi if [ "$res_testcase_sandbox_start_upsd_alone" = 0 ]; then log_info "[testcase_sandbox_start_upsd_alone] PASSED: got just the failures expected for data server alone (driver not running yet)" else log_error "[testcase_sandbox_start_upsd_alone] got some unexpected failures, see above" fi return $res_testcase_sandbox_start_upsd_alone } testcase_sandbox_start_upsd_after_drivers() { # Historically this is a fallback from testcase_sandbox_start_drivers_after_upsd log_info "[testcase_sandbox_start_upsd_after_drivers] Test starting UPSD after drivers" kill -15 $PID_UPSD 2>/dev/null wait $PID_UPSD # Not calling upsd_start_loop() here, before drivers # If the server starts, fine; if not - we retry below if [ -n "${NUT_DEBUG_LEVEL_UPSD-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSD}" fi upsd ${ARG_FG} & PID_UPSD="$!" NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" log_debug "[testcase_sandbox_start_upsd_after_drivers] Tried to start UPSD as PID $PID_UPSD" sandbox_start_drivers sandbox_start_upsd sleep 5 COUNTDOWN=90 while [ "$COUNTDOWN" -gt 0 ]; do # For query errors or known wait, keep looping runcmd upsc dummy@localhost:$NUT_PORT \ && case "$CMDOUT" in *"ups.status: WAIT"*) ;; *) log_info "Got output:" ; echo "$CMDOUT" ; break ;; esac sleep 1 COUNTDOWN="`expr $COUNTDOWN - 1`" done if [ "$COUNTDOWN" -le 88 ] ; then log_warn "[testcase_sandbox_start_upsd_after_drivers] Had to wait a few retries for the dummy driver to connect" fi if [ "$COUNTDOWN" -le 1 ] ; then report_NUT_PORT die "[testcase_sandbox_start_upsd_after_drivers] upsd does not respond on port ${NUT_PORT} ($?)" fi log_info "[testcase_sandbox_start_upsd_after_drivers] PASSED: upsd responds on port ${NUT_PORT}" } testcase_sandbox_start_drivers_after_upsd() { #sandbox_start_upsd testcase_sandbox_start_upsd_alone sandbox_start_drivers log_info "[testcase_sandbox_start_drivers_after_upsd] Query driver state from UPSD by UPSC after driver startup" # Timing issues: upsd starts, we wait 10 sec, drivers start and init, # at 20 sec upsd does not see them yet, at 30 sec the sockets connect # but info does not come yet => may be "driver stale", finally at # 40+(drv)/50+(upsd) sec a DUMPALL is processed (regular 30-sec loop?) - # so tightly near a minute until we have sturdy replies. COUNTDOWN=90 while [ "$COUNTDOWN" -gt 0 ]; do # For query errors or known wait, keep looping. May get: # driver.state: updateinfo # ups.status: WAIT runcmd upsc dummy@localhost:$NUT_PORT \ && case "$CMDOUT" in *"ups.status: WAIT"*) ;; *) log_info "[testcase_sandbox_start_drivers_after_upsd] Got output:" ; echo "$CMDOUT" ; break ;; esac sleep 1 COUNTDOWN="`expr $COUNTDOWN - 1`" done if [ "$COUNTDOWN" -le 88 ] ; then log_warn "[testcase_sandbox_start_drivers_after_upsd] Had to wait a few retries for the dummy driver to connect" fi if [ "$COUNTDOWN" -le 1 ] ; then # Should not get to this, except on very laggy systems maybe log_error "[testcase_sandbox_start_drivers_after_upsd] Query failed, retrying with UPSD started after drivers" testcase_sandbox_start_upsd_after_drivers fi if [ x"${TOP_SRCDIR}" != x ]; then log_info "[testcase_sandbox_start_drivers_after_upsd] Wait for dummy UPSes with larger data sets to initialize" for U in UPS1 UPS2 ; do COUNTDOWN=90 # TODO: Convert to runcmd()? OUT="" while [ x"$OUT" = x"ups.status: WAIT" ] ; do OUT="`upsc $U@localhost:$NUT_PORT ups.status`" || break [ x"$OUT" = x"ups.status: WAIT" ] || { log_info "[testcase_sandbox_start_drivers_after_upsd] Got output:"; echo "$OUT"; break; } sleep 1 COUNTDOWN="`expr $COUNTDOWN - 1`" # Systemic error, e.g. could not create socket file? [ "$COUNTDOWN" -lt 1 ] && die "[testcase_sandbox_start_drivers_after_upsd] Dummy driver did not start or respond in time" done if [ "$COUNTDOWN" -le 88 ] ; then log_warn "[testcase_sandbox_start_drivers_after_upsd] Had to wait a few retries for the $U driver to connect" fi done fi log_info "[testcase_sandbox_start_drivers_after_upsd] PASSED: Expected drivers are now responding via UPSD" } testcase_sandbox_upsc_query_model() { log_info "[testcase_sandbox_upsc_query_model] Query model from dummy device" runcmd upsc dummy@localhost:$NUT_PORT device.model || die "[testcase_sandbox_upsc_query_model] upsd does not respond on port ${NUT_PORT} ($?): $CMDOUT" if [ x"$CMDOUT" != x"Dummy UPS" ] ; then log_error "[testcase_sandbox_upsc_query_model] got this reply for upsc query when 'Dummy UPS' was expected: $CMDOUT" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_upsc_query_model" else PASSED="`expr $PASSED + 1`" log_info "[testcase_sandbox_upsc_query_model] PASSED: got expected model from dummy device: $CMDOUT" fi } testcase_sandbox_upsc_query_bogus() { log_info "[testcase_sandbox_upsc_query_bogus] Query driver state from UPSD by UPSC for bogus info" runcmd upsc dummy@localhost:$NUT_PORT ups.bogus.value && { log_error "[testcase_sandbox_upsc_query_bogus] upsc was supposed to answer with error exit code: $CMDOUT" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_upsc_query_bogus" } # Note: avoid exact matching for stderr, because it can have Init SSL messages etc. if echo "$CMDERR" | grep 'Error: Variable not supported by UPS' >/dev/null ; then PASSED="`expr $PASSED + 1`" log_info "[testcase_sandbox_upsc_query_bogus] PASSED: got expected reply to bogus query" else log_error "[testcase_sandbox_upsc_query_bogus] got some other reply for upsc query when 'Error: Variable not supported by UPS' was expected on stderr: stderr:'$CMDERR' / stdout:'$CMDOUT'" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_upsc_query_bogus" fi } testcase_sandbox_upsc_query_timer() { log_separator log_info "[testcase_sandbox_upsc_query_timer] Test that dummy-ups TIMER action changes the reported state" # Driver is set up to flip ups.status every 5 sec, so check every 3 sec # with upsc, but we can follow with upslog more intensively. New process # launches can lag a lot on very busy SUTs; hopefully still-running ones # are more responsive in this regard. log_info "Starting upslog daemon" rm -f "${NUT_STATEPATH}/upslog-dummy.log" || true # Start as foregrounded always, so we have a PID to kill easily: if [ -n "${NUT_DEBUG_LEVEL_UPSLOG-}" ]; then NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSLOG}" fi upslog -F -i 1 -d 30 -m "dummy@localhost:${NUT_PORT},${NUT_STATEPATH}/upslog-dummy.log" & PID_UPSLOG="$!" NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" # TODO: Any need to convert to runcmd()? OUT1="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT1" ; sleep 3 OUT2="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT2" OUT3="" OUT4="" OUT5="" # The SUT may be busy, or dummy-ups can have a loop delay # (pollfreq) after reading the file before wrapping around if [ x"$OUT1" = x"$OUT2" ]; then sleep 3 OUT3="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT3" if [ x"$OUT2" = x"$OUT3" ]; then sleep 3 OUT4="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT4" if [ x"$OUT3" = x"$OUT4" ]; then sleep 8 OUT5="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "[testcase_sandbox_upsc_query_timer] upsd does not respond on port ${NUT_PORT} ($?): $OUT4" fi fi fi log_info "Stopping upslog daemon" kill -15 $PID_UPSLOG 2>/dev/null || true wait $PID_UPSLOG || true if (grep " [OB] " "${NUT_STATEPATH}/upslog-dummy.log" && grep " [OL] " "${NUT_STATEPATH}/upslog-dummy.log") \ || (grep " \[OB\] " "${NUT_STATEPATH}/upslog-dummy.log" && grep " \[OL\] " "${NUT_STATEPATH}/upslog-dummy.log") \ || (echo "$OUT1$OUT2$OUT3$OUT4$OUT5" | grep "OB" && echo "$OUT1$OUT2$OUT3$OUT4$OUT5" | grep "OL") \ ; then log_info "[testcase_sandbox_upsc_query_timer] PASSED: ups.status flips over time" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_upsc_query_timer] ups.status did not flip over time" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_upsc_query_timer" fi #rm -f "${NUT_STATEPATH}/upslog-dummy.log" || true } isTestablePython() { # We optionally make python module (if interpreter is found): if [ x"${TOP_BUILDDIR}" = x ] \ || [ ! -x "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ] \ ; then return 1 fi PY_SHEBANG="`head -1 "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py"`" if [ x"${PY_SHEBANG}" = x"#!no" ] ; then return 1 fi log_debug "=======\nDetected python shebang: '${PY_SHEBANG}'" return 0 } testcase_sandbox_python_without_credentials() { isTestablePython || return 0 log_separator log_info "[testcase_sandbox_python_without_credentials] Call Python module test suite: PyNUT (NUT Python bindings) without login credentials" if ( unset NUT_USER || true unset NUT_PASS || true "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ) ; then log_info "[testcase_sandbox_python_without_credentials] PASSED: PyNUT did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_python_without_credentials] PyNUT complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_python_without_credentials" fi } testcase_sandbox_python_with_credentials() { isTestablePython || return 0 # That script says it expects data/evolution500.seq (as the UPS1 dummy) # but the dummy data does not currently let issue the commands and # setvars tested from python script. log_separator log_info "[testcase_sandbox_python_with_credentials] Call Python module test suite: PyNUT (NUT Python bindings) with login credentials" if ( NUT_USER='admin' NUT_PASS="${TESTPASS_ADMIN}" export NUT_USER NUT_PASS "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ) ; then log_info "[testcase_sandbox_python_with_credentials] PASSED: PyNUT did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_python_with_credentials] PyNUT complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_python_with_credentials" fi } testcase_sandbox_python_with_upsmon_credentials() { isTestablePython || return 0 log_separator log_info "[testcase_sandbox_python_with_upsmon_credentials] Call Python module test suite: PyNUT (NUT Python bindings) with upsmon role login credentials" if ( NUT_USER='dummy-admin' NUT_PASS="${TESTPASS_UPSMON_PRIMARY}" export NUT_USER NUT_PASS "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ) ; then log_info "[testcase_sandbox_python_with_upsmon_credentials] PASSED: PyNUT did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_python_with_upsmon_credentials] PyNUT complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_python_with_upsmon_credentials" fi } testcases_sandbox_python() { isTestablePython || return 0 testcase_sandbox_python_without_credentials testcase_sandbox_python_with_credentials testcase_sandbox_python_with_upsmon_credentials } #################################### isTestableCppNIT() { # We optionally make and here can run C++ client tests: if [ x"${TOP_BUILDDIR}" = x ] \ || [ ! -x "${TOP_BUILDDIR}/tests/cppnit" ] \ ; then log_warn "SKIP: ${TOP_BUILDDIR}/tests/cppnit: Not found" return 1 fi return 0 } testcase_sandbox_cppnit_without_creds() { isTestableCppNIT || return 0 log_separator log_info "[testcase_sandbox_cppnit_without_creds] Call libnutclient test suite: cppnit without login credentials" if ( unset NUT_USER || true unset NUT_PASS || true "${TOP_BUILDDIR}/tests/cppnit" ) ; then log_info "[testcase_sandbox_cppnit_without_creds] PASSED: cppnit did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_cppnit_without_creds] cppnit complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_cppnit_without_creds" fi } testcase_sandbox_cppnit_simple_admin() { isTestableCppNIT || return 0 log_separator log_info "[testcase_sandbox_cppnit_simple_admin] Call libnutclient test suite: cppnit with login credentials: simple admin" if ( NUT_USER='admin' NUT_PASS="${TESTPASS_ADMIN}" if [ x"${TOP_SRCDIR}" != x ]; then # Avoid dummies with TIMER flip-flops NUT_SETVAR_DEVICE='UPS2' else # Risks failure when lauching sub-test at the wrong second NUT_SETVAR_DEVICE='dummy' fi unset NUT_PRIMARY_DEVICE export NUT_USER NUT_PASS NUT_SETVAR_DEVICE "${TOP_BUILDDIR}/tests/cppnit" ) ; then log_info "[testcase_sandbox_cppnit_simple_admin] PASSED: cppnit did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_cppnit_simple_admin] cppnit complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_cppnit_simple_admin" fi } testcase_sandbox_cppnit_upsmon_primary() { isTestableCppNIT || return 0 log_separator log_info "[testcase_sandbox_cppnit_upsmon_primary] Call libnutclient test suite: cppnit with login credentials: upsmon-primary" if ( NUT_USER='dummy-admin' NUT_PASS="${TESTPASS_UPSMON_PRIMARY}" NUT_PRIMARY_DEVICE='dummy' unset NUT_SETVAR_DEVICE export NUT_USER NUT_PASS NUT_PRIMARY_DEVICE "${TOP_BUILDDIR}/tests/cppnit" ) ; then log_info "[testcase_sandbox_cppnit_upsmon_primary] PASSED: cppnit did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_cppnit_upsmon_primary] cppnit complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_cppnit_upsmon_primary" fi } testcase_sandbox_cppnit_upsmon_master() { isTestableCppNIT || return 0 log_separator log_info "[testcase_sandbox_cppnit_upsmon_master] Call libnutclient test suite: cppnit with login credentials: upsmon-master" if ( NUT_USER='dummy-admin-m' NUT_PASS="${TESTPASS_UPSMON_PRIMARY}" NUT_PRIMARY_DEVICE='dummy' unset NUT_SETVAR_DEVICE export NUT_USER NUT_PASS NUT_PRIMARY_DEVICE "${TOP_BUILDDIR}/tests/cppnit" ) ; then log_info "[testcase_sandbox_cppnit_upsmon_master] PASSED: cppnit did not complain" PASSED="`expr $PASSED + 1`" else log_error "[testcase_sandbox_cppnit_upsmon_master] cppnit complained, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_cppnit_upsmon_master" fi } testcases_sandbox_cppnit() { isTestableCppNIT || return 0 testcase_sandbox_cppnit_without_creds testcase_sandbox_cppnit_upsmon_primary testcase_sandbox_cppnit_upsmon_master testcase_sandbox_cppnit_simple_admin } #################################### isTestableNutScanner() { # We optionally make and here can run nut-scanner (as NUT client) # tests, which tangentially tests the C client library: if [ x"${TOP_BUILDDIR}" = x ] \ || [ ! -x "${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner" ] \ ; then log_warn "SKIP: ${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner: Not found" return 1 fi return 0 } testcase_sandbox_nutscanner_list() { isTestableNutScanner || return 0 log_separator log_info "[testcase_sandbox_nutscanner_list] Call libupsclient test suite: nut-scanner on localhost:${NUT_PORT}" log_info "[testcase_sandbox_nutscanner_list] Preparing LD_LIBRARY_PATH='${LD_LIBRARY_PATH_CLIENT}'" # Note: for some reason `LD_LIBRARY_PATH=... runcmd ...` loses it :\ LD_LIBRARY_PATH="${LD_LIBRARY_PATH_CLIENT}" export LD_LIBRARY_PATH # NOTE: Currently mask mode is IPv4 only runcmd "${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner" -m 127.0.0.1/32 -O -p "${NUT_PORT}" \ && test -n "$CMDOUT" \ || runcmd "${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner" -s localhost -O -p "${NUT_PORT}" LD_LIBRARY_PATH="${LD_LIBRARY_PATH_ORIG}" export LD_LIBRARY_PATH log_info "[testcase_sandbox_nutscanner_list] findings from nut-scanner:" echo "$CMDOUT" log_info "[testcase_sandbox_nutscanner_list] inspecting these findings from nut-scanner..." # Note: the reported "driver" string is not too helpful as a "nutclient". # In practice this could be a "dummy-ups" repeater or "clone" driver, # or some of the config elements needed for upsmon (lacking creds/role) # Also note that before PR #2247 nut-scanner returned "nutdev" # section names, but now it returns "nutdev-" to differentiate # the scanned buses (serial, snmp, usb, etc.) if ( test -n "$CMDOUT" \ && echo "$CMDOUT" | grep -E '^\[nutdev-nut1\]$' \ && echo "$CMDOUT" | grep 'port = "dummy@' \ || return if [ "${NUT_PORT}" = 3493 ] || [ x"$NUT_PORT" = x ]; then log_info "[testcase_sandbox_nutscanner_list] Note: not testing for suffixed port number" >&2 else echo "$CMDOUT" | grep -E 'dummy@.*'":${NUT_PORT}" \ || { log_error "[testcase_sandbox_nutscanner_list] dummy@... not found" >&2 return 1 } fi if [ x"${TOP_SRCDIR}" = x ]; then log_info "[testcase_sandbox_nutscanner_list] Note: only testing one dummy device" >&2 else echo "$CMDOUT" | grep -E '^\[nutdev-nut2\]$' \ && echo "$CMDOUT" | grep 'port = "UPS1@' \ && echo "$CMDOUT" | grep -E '^\[nutdev-nut3\]$' \ && echo "$CMDOUT" | grep 'port = "UPS2@' \ || { log_error "[testcase_sandbox_nutscanner_list] something about UPS1/UPS2 not found" >&2 return 1 } fi if [ x"${TOP_SRCDIR}" = x ]; then PORTS_WANT=1 else PORTS_WANT=3 fi PORTS_SEEN="`echo "$CMDOUT" | grep -Ec 'port *='`" if [ "$PORTS_WANT" != "$PORTS_SEEN" ]; then log_error "[testcase_sandbox_nutscanner_list] Too many 'port=' lines: want $PORTS_WANT != seen $PORTS_SEEN" >&2 return 1 fi ) >/dev/null ; then log_info "[testcase_sandbox_nutscanner_list] PASSED: nut-scanner found all expected devices" PASSED="`expr $PASSED + 1`" else if ( echo "$CMDERR" | grep -E "Cannot load NUT library.*libupsclient.*found.*NUT search disabled" ) ; then log_warn "[testcase_sandbox_nutscanner_list] SKIP: ${TOP_BUILDDIR}/tools/nut-scanner/nut-scanner: $CMDERR" else log_error "[testcase_sandbox_nutscanner_list] nut-scanner complained or did not return all expected data, check above" FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS testcase_sandbox_nutscanner_list" fi fi } testcases_sandbox_nutscanner() { isTestableNutScanner || return 0 testcase_sandbox_nutscanner_list } #################################### # TODO: Some upsmon tests? upsmon_start_loop() { TESTCASE="${1-upsmon_start_loop}" if isPidAlive "$PID_UPSMON" ; then return 0 fi if [ -n "${NUT_DEBUG_LEVEL_UPSMON-}" ]; then # Note: This is inherited into children of UPSMON process too, # but the sample script honours NUT_DEBUG_LEVEL_UPSSCHED if set NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_UPSMON}" fi upsmon ${ARG_FG} & PID_UPSMON="$!" NUT_DEBUG_LEVEL="${NUT_DEBUG_LEVEL_ORIG}" log_debug "[${TESTCASE}] Tried to start UPSMON as PID $PID_UPSMON" sleep 2 # Due to severe config errors, client could have died by now # TOTHINK: Loop like for upsd? # Return code is 0/OK if the client is alive if isPidAlive "$PID_UPSMON" ; then log_debug "[${TESTCASE}] UPSMON PID $PID_UPSMON is alive after a short while" return fi log_error "[${TESTCASE}] UPSMON PID $PID_UPSMON is not alive after a short while" return 1 } sandbox_start_upsmon_master() { # Optional arg can specify amount of power sources to MONITOR and require if isPidAlive "$PID_UPSMON" ; then # FIXME: Kill and restart? Reconfigure and reload? return 0 fi sandbox_generate_configs generatecfg_upsmon_master "$@" log_info "Starting UPSMON as master for sandbox" upsmon_start_loop "sandbox" } #################################### testgroup_sandbox() { testcase_sandbox_start_drivers_after_upsd testcase_sandbox_upsc_query_model testcase_sandbox_upsc_query_bogus testcase_sandbox_upsc_query_timer testcases_sandbox_python testcases_sandbox_cppnit testcases_sandbox_nutscanner log_separator sandbox_forget_configs } testgroup_sandbox_python() { # Arrange for quick test iterations testcase_sandbox_start_drivers_after_upsd testcases_sandbox_python log_separator sandbox_forget_configs } testgroup_sandbox_cppnit() { # Arrange for quick test iterations testcase_sandbox_start_drivers_after_upsd testcases_sandbox_cppnit log_separator sandbox_forget_configs } testgroup_sandbox_cppnit_simple_admin() { # Arrange for quick test iterations testcase_sandbox_start_drivers_after_upsd testcase_sandbox_cppnit_simple_admin log_separator sandbox_forget_configs } testgroup_sandbox_nutscanner() { # Arrange for quick test iterations testcase_sandbox_start_drivers_after_upsd testcases_sandbox_nutscanner log_separator sandbox_forget_configs } testgroup_sandbox_upsmon_master() { # Arrange for quick test iterations # Optional arg can specify amount of power sources to MONITOR and require testcase_sandbox_start_drivers_after_upsd sandbox_start_upsmon_master "$@" log_separator sandbox_forget_configs } ################################################################ case "${NIT_CASE}" in isBusy_NUT_PORT) DEBUG=yes isBusy_NUT_PORT ;; cppnit) testgroup_sandbox_cppnit ;; python) testgroup_sandbox_python ;; nutscanner|nut-scanner) testgroup_sandbox_nutscanner ;; testcase_*|testgroup_*|testcases_*|testgroups_*) log_warn "========================================================" log_warn "You asked to run just a specific testcase* or testgroup*" log_warn "Be sure to have previously run with DEBUG_SLEEP and" log_warn " have exported the NUT_PORT upsd is listening on!" log_warn "========================================================" # NOTE: Not quoted, can have further arguments # e.g. NIT_CASE="testgroup_sandbox_upsmon_master 1" eval ${NIT_CASE} ;; generatecfg_*|is*) # NOTE: Keep in sync with TESTDIR cleanup above # (at start-up and at the exit-trap) and stop_daemons below log_warn "========================================================" log_warn "You asked to run just a specific helper method: '${NIT_CASE}'" log_warn "Populated environment variables for this run into a file so you can source them: . '$NUT_CONFPATH/NIT.env'" log_warn "Notably, NUT_CONFPATH='$NUT_CONFPATH' now" log_warn "========================================================" # NOTE: Not quoted, can have further arguments eval ${NIT_CASE} if [ $? = 0 ] ; then PASSED="`expr $PASSED + 1`" else FAILED="`expr $FAILED + 1`" FAILED_FUNCS="$FAILED_FUNCS $NIT_CASE" fi unset DEBUG_SLEEP ;; "") # Default test groups: testgroup_upsd_invalid_configs testgroup_upsd_questionable_configs testgroup_sandbox ;; *) die "Unsupported NIT_CASE='$NIT_CASE' was requested" ;; esac log_separator log_info "OVERALL: PASSED=$PASSED FAILED=$FAILED" if [ -n "$FAILED_FUNCS" ]; then for F in $FAILED_FUNCS ; do echo "$F" ; done | sort | uniq -c fi # Allow to leave the sandbox daemons running for a while, # to experiment with them interactively: if [ -n "${DEBUG_SLEEP-}" ] ; then if [ "${DEBUG_SLEEP-}" -gt 0 ] ; then : ; else DEBUG_SLEEP=60 fi if [ -z "$PID_UPSSCHED" ] && [ -s "$NUT_PIDPATH/upssched.pid" ] ; then PID_UPSSCHED="`head -1 "$NUT_PIDPATH/upssched.pid"`" fi log_separator log_info "Sleeping now as asked (for ${DEBUG_SLEEP} seconds starting `date -u`), so you can play with the driver and server running" log_info "Populated environment variables for this run into a file so you can source them: . '$NUT_CONFPATH/NIT.env'" printf "PID_NIT_SCRIPT='%s'\nexport PID_NIT_SCRIPT\n" "$$" >> "$NUT_CONFPATH/NIT.env" set | grep -E '^TESTPASS_|PID_[^ =]*='"'?[0-9][0-9]*'?$" | while IFS='=' read K V ; do V="`echo "$V" | tr -d "'"`" # Dummy comment to reset syntax highlighting due to ' quote above if [ -n "$V" ] ; then printf "%s='%s'\nexport %s\n" "$K" "$V" "$K" fi done >> "$NUT_CONFPATH/NIT.env" log_separator cat "$NUT_CONFPATH/NIT.env" log_separator log_info "See above about important variables from the test sandbox and a way to 'source' them into your shell, e.g.: . '$NUT_CONFPATH/NIT.env'" if [ x"${TESTDIR_CALLER}" != x"${TESTDIR}" ] && [ x"${TESTDIR}" != x"$BUILDDIR/tmp" ] ; then log_warn "A temporary random TESTDIR location is used, it would be automatically removed after this script exits!" fi log_info "You may want to press Ctrl+Z now and command 'bg' to the shell, if you did not start '$0 &' backgrounded already" log_info "To kill the script early, return it to foreground with 'fg' and press Ctrl+C, or 'kill -2 \$PID_NIT_SCRIPT' (kill -2 $$)" log_info "To trace built programs, check scripts/valgrind/README.adoc and LD_LIBRARY_PATH for this build" log_info "Remember that in shell/scripting you can probe for '${NUT_CONFPATH}/NIT.env-sandbox-ready' which only appears at this moment" touch "${NUT_CONFPATH}/NIT.env-sandbox-ready" sleep "${DEBUG_SLEEP}" log_info "Sleep finished" log_separator fi # We have a trap.... but for good measure, do some explicit clean-up: case "${NIT_CASE}" in generatecfg_*|is*) ;; *) stop_daemons ;; esac if [ "$PASSED" = 0 ] || [ "$FAILED" != 0 ] ; then die "Some test scenarios failed!" else log_info "SUCCESS" fi nut-2.8.3/tests/nutclienttest.cpp0000644000200500020050000003741314777767434014054 00000000000000/* nutclienttest - CppUnit nutclient unit test Copyright (C) 2016 Emilien Kia 2020 - 2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" /* Current CPPUnit offends the honor of C++98 and maybe later versions */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma GCC diagnostic ignored "-Wdeprecated-declarations" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wsuggest-destructor-override" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC # pragma GCC diagnostic ignored "-Wweak-vtables" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC # pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC # pragma GCC diagnostic ignored "-Wextra-semi" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC # pragma GCC diagnostic ignored "-Wold-style-cast" # endif #endif #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS # pragma clang diagnostic push "-Wdeprecated-declarations" # endif #endif #include namespace nut { class NutClientTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( NutClientTest ); CPPUNIT_TEST( test_strarr_alloc ); CPPUNIT_TEST( test_stringset_to_strarr ); CPPUNIT_TEST( test_stringvector_to_strarr ); CPPUNIT_TEST( test_copy_constructor_dev ); CPPUNIT_TEST( test_copy_assignment_dev ); CPPUNIT_TEST( test_copy_constructor_cmd ); CPPUNIT_TEST( test_copy_assignment_cmd ); CPPUNIT_TEST( test_copy_constructor_var ); CPPUNIT_TEST( test_copy_assignment_var ); CPPUNIT_TEST( test_nutclientstub_dev ); CPPUNIT_TEST_SUITE_END(); public: void setUp() override; void tearDown() override; void test_strarr_alloc(); void test_stringset_to_strarr(); void test_stringvector_to_strarr(); void test_copy_constructor_dev(); void test_copy_assignment_dev(); void test_copy_constructor_cmd(); void test_copy_assignment_cmd(); void test_copy_constructor_var(); void test_copy_assignment_var(); void test_nutclientstub_dev(); }; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( NutClientTest ); } // namespace nut {} #ifndef _NUTCLIENTTEST_BUILD # define _NUTCLIENTTEST_BUILD 1 #endif #include "../clients/nutclient.h" #include "../clients/nutclientmem.h" namespace nut { extern "C" { strarr stringset_to_strarr(const std::set& strset); strarr stringvector_to_strarr(const std::vector& strset); } // extern "C" void NutClientTest::setUp() { } void NutClientTest::tearDown() { } void NutClientTest::test_strarr_alloc() { bool noException = true; strarr arr = nullptr; try { arr = strarr_alloc(5); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed strarr_alloc(...): throw exception", noException); CPPUNIT_ASSERT_MESSAGE( "Failed strarr_alloc(...): result is null", arr != nullptr); strarr_free(arr); } void NutClientTest::test_stringset_to_strarr() { std::set strset; strset.insert("test"); strset.insert("hello"); strset.insert("world"); strarr arr = stringset_to_strarr(strset); CPPUNIT_ASSERT_MESSAGE( "stringset_to_strarr(...) result is null", arr != nullptr); std::set res; char** ptr = arr; while(*ptr != nullptr) { res.insert(std::string(*ptr)); ptr++; } CPPUNIT_ASSERT_EQUAL_MESSAGE( "stringset_to_strarr(...) result has not 3 items", static_cast(3), res.size()); CPPUNIT_ASSERT_MESSAGE( "stringset_to_strarr(...) result has not item \"test\"", res.find("test") != res.end()); CPPUNIT_ASSERT_MESSAGE( "stringset_to_strarr(...) result has not item \"hello\"", res.find("hello") != res.end()); CPPUNIT_ASSERT_MESSAGE( "stringset_to_strarr(...) result has not item \"world\"", res.find("world") != res.end()); strarr_free(arr); } void NutClientTest::test_stringvector_to_strarr() { std::vector strset; strset.push_back("test"); strset.push_back("hello"); strset.push_back("world"); strarr arr = stringvector_to_strarr(strset); CPPUNIT_ASSERT_MESSAGE( "stringvector_to_strarr(...) result is null", arr != nullptr); char** ptr = arr; CPPUNIT_ASSERT_EQUAL_MESSAGE( "stringvector_to_strarr(...) result has not item 0==\"test\"", std::string("test"), std::string(*ptr)); ++ptr; CPPUNIT_ASSERT_EQUAL_MESSAGE( "stringvector_to_strarr(...) result has not item 1==\"hello\"", std::string("hello"), std::string(*ptr)); ++ptr; CPPUNIT_ASSERT_EQUAL_MESSAGE( "stringvector_to_strarr(...) result has not item 2==\"world\"", std::string("world"), std::string(*ptr)); ++ptr; /* https://stackoverflow.com/a/12565009/4715872 * Can not compare nullptr_t and another data type (char*) * with CPPUNIT template assertEquals() */ CPPUNIT_ASSERT_MESSAGE( "stringvector_to_strarr(...) result has not only 3 items", nullptr == *ptr); strarr_free(arr); } void NutClientTest::test_copy_constructor_dev() { nut::TcpClient c; nut::Device i(&c, "ups1"); nut::Device j(i); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Device variable j by initializing from i", i, j); } void NutClientTest::test_copy_assignment_dev() { nut::TcpClient c; nut::Device i(&c, "ups1"); nut::Device j(nullptr, "ups2"); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE( "Device variables i and j were initialized differently " "but claim to be equal", CPPUNIT_ASSERT_EQUAL(i, j) ); j = i; CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Device Command j by equating to i", i, j); } void NutClientTest::test_copy_constructor_cmd() { nut::TcpClient c; nut::Device d(nullptr, "ups1"); nut::Command i(&d, "cmd1"); nut::Command j(i); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Command variable j by initializing from i", i, j); } void NutClientTest::test_copy_assignment_cmd() { nut::TcpClient c; nut::Device d(nullptr, "ups1"); nut::Command i(&d, "var1"); nut::Command j(nullptr, "var2"); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE( "Command variables i and j were initialized differently " "but claim to be equal", CPPUNIT_ASSERT_EQUAL(i, j) ); j = i; CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Command variable j by equating to i", i, j); } void NutClientTest::test_copy_constructor_var() { nut::TcpClient c; nut::Device d(nullptr, "ups1"); nut::Variable i(&d, "var1"); nut::Variable j(i); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Variable variable j by initializing from i", i, j); } void NutClientTest::test_copy_assignment_var() { nut::TcpClient c; nut::Device d(nullptr, "ups1"); nut::Variable i(&d, "var1"); nut::Variable j(nullptr, "var2"); CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE( "Variable variables i and j were initialized differently " "but claim to be equal", CPPUNIT_ASSERT_EQUAL(i, j) ); j = i; CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to assign value of Variable variable j by equating to i", i, j); } void NutClientTest::test_nutclientstub_dev() { bool noException = true; nut::MemClientStub c; nut::Device d(nullptr, "ups_1"); try { // set mono value c.setDeviceVariable("ups_1", "name_1", "value_1"); // get mono value ListValue values = c.getDeviceVariableValue("ups_1", "name_1"); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: mono wrong values number", values.size() == 1); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: mono bad value", values[0] == std::string("value_1")); // set multi value ListValue values_multi = { "multi_1", "multi_2" }; c.setDeviceVariable("ups_1", "name_multi_1", values_multi); // get multi value values = c.getDeviceVariableValue("ups_1", "name_multi_1"); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: multi wrong values number", values.size() == 2); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: multi first bad value", values[0] == std::string("multi_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: multi second bad value", values[1] == std::string("multi_2")); // get object values ListObject objects = c.getDeviceVariableValues("ups_1"); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects wrong values number", objects.size() == 2); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects mono wrong values number", objects["name_1"].size() == 1); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects mono bad value", objects["name_1"][0] == std::string("value_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects multi wrong values number", objects["name_multi_1"].size() == 2); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects mono bad value", objects["name_multi_1"][0] == std::string("multi_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: objects mono bad value", objects["name_multi_1"][1] == std::string("multi_2")); // get device values std::set devices_name = { "ups_1" }; ListDevice devices = c.getDevicesVariableValues(devices_name); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices wrong values number", devices.size() == 1); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices mono wrong values number", devices["ups_1"]["name_1"].size() == 1); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices mono bad value", devices["ups_1"]["name_1"][0] == std::string("value_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices multi wrong values number", devices["ups_1"]["name_multi_1"].size() == 2); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices mono bad value", devices["ups_1"]["name_multi_1"][0] == std::string("multi_1")); CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: devices mono bad value", devices["ups_1"]["name_multi_1"][1] == std::string("multi_2")); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw exception", noException); // List of functions not implemented (should return exception) noException = true; try { std::set cmd = c.getDeviceCommandNames("ups-1"); CPPUNIT_ASSERT_MESSAGE( "Variable not use", cmd.size() == 0); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { std::string desc = c.getDeviceCommandDescription("ups-1", "cmd-1"); CPPUNIT_ASSERT_MESSAGE( "Variable not use", desc.empty()); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { TrackingID id = c.executeDeviceCommand("ups-1", "cmd-1", "param-1"); CPPUNIT_ASSERT_MESSAGE( "Variable not use", id.empty()); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.deviceLogin("ups-1"); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.deviceMaster("ups-1"); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.deviceForcedShutdown("ups-1"); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.deviceGetNumLogins("ups-1"); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { TrackingResult result = c.getTrackingResult("track-1"); CPPUNIT_ASSERT_MESSAGE( "Variable not use", result == TrackingResult::SUCCESS); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { bool status = c.isFeatureEnabled(Feature("feature-1")); CPPUNIT_ASSERT_MESSAGE( "Variable not use", !status); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); noException = true; try { c.setFeature(Feature("feature-1"), true); } catch(nut::NutException& ex) { NUT_UNUSED_VARIABLE(ex); noException = false; } CPPUNIT_ASSERT_MESSAGE( "Failed stub tcp client: throw no exception", !noException); } } // namespace nut {} #if (defined __clang__) && (defined HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS) # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC) # pragma GCC diagnostic pop #endif nut-2.8.3/tests/nut-driver-enumerator-test--ups.conf0000644000200500020050000000264614553676503017413 00000000000000# This is an ups.conf file for nut-driver-enumerator-test.sh # It is intentionally written in different samples of markup, # do not clean it up ;) maxstartdelay=180 globalflag [dummy1] driver = dummy-ups port = file1.dev desc = "This is ups-1" [epdu-2] # This is an ePDU driver=netxml-ups port="http://172.16.1.2" synchronous=yes [epdu-2-snmp] driver=snmp-ups port=172.16.1.2 synchronous=no [usb_3] driver = "usbhid-ups" port = "auto" [serial.4] driver = serial-ups driverflag port = /dev/ttyS1 # some path [dummy-proxy] driver = "dummy-ups " port = remoteUPS@RemoteHost.local [dummy-proxy-localhost] driver = 'dummy-ups ' port = "localUPS@127.0.0.1" [valueHasEquals] driver = dummy=ups port = file1.dev # key = val, right? [valueHasHashtag] driver = dummy-ups port = file#1.dev [valueHasQuotedHashtag] driver = dummy-ups port = "file#1.dev" [qx-serial] driver=nutdrv_qx port = /dev/ttyb [qx-usb1] driver=nutdrv_qx port = auto [qx-usb2] driver=nutdrv_qx port = /dev/usb/8 [sectionWithComment]# Some comment driver=nutdrv_qx#comment port = /dev/usb/8 desc="value with [brackets]" [brackets with spaces are not sections] # but rather an invalid mess as binary parser may think [sectionWithCommentWhitespace] # Some comment with a space and tab driver=nutdrv_qx # comment port = /dev/usb/8 # comment commentedDriverFlag # This flag gotta mean something nut-2.8.3/tests/nuttimetest.c0000644000200500020050000000776214777534446013173 00000000000000/* nuttimetest.c - test custom NUT routines for time comparison and manipulation * * Copyright (C) * 2023 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "common.h" #include "nut_stdint.h" #include "nut_float.h" #include #include static int check_difftime(void) { time_t tv1, tv2; double d1, d2; int res = 0; printf("=== %s(time_t):\t", __func__); /* Often time_t is a long int, maybe signed */ tv1 = 5; printf(" tv1=%" PRIiMAX, (intmax_t)tv1); tv2 = 8; printf(" tv2=%" PRIiMAX, (intmax_t)tv2); /* like in difftime(): (double)seconds elapsed time between older tv2 and newer tv1 */ d1 = difftime(tv1, tv2); if (!d_equal(d1, -3)) res++; printf(" => diff1(tv1, tv2)=%f (%s)", d1, d_equal(d1, -3) ? "OK" : "FAIL"); d2 = difftime(tv2, tv1); if (!d_equal(d2, 3)) res++; printf(" => diff2(tv2, tv1)=%f (%s)", d2, d_equal(d2, 3) ? "OK" : "FAIL"); if (!d_equal(d1, -d2)) { printf(" => diff1 != -diff2 (FAIL)\n"); res++; } else { printf(" => diff1 == -diff2 (OK)\n"); } return res; } static int check_difftimeval(void) { struct timeval tv1, tv2; double d1, d2; int res = 0; printf("=== %s(struct timeval):\t", __func__); tv1.tv_sec = 5; tv1.tv_usec = 900000; printf(" tv1=%" PRIiMAX ".%06" PRIiMAX, (intmax_t)tv1.tv_sec, (intmax_t)tv1.tv_usec); tv2.tv_sec = 8; tv2.tv_usec = 230000; printf(" tv2=%" PRIiMAX ".%06" PRIiMAX, (intmax_t)tv2.tv_sec, (intmax_t)tv2.tv_usec); /* like in difftime(): (double)seconds elapsed time between older tv2 and newer tv1 */ d1 = difftimeval(tv1, tv2); if (!d_equal(d1, -2.33)) res++; printf(" => diff1(tv1, tv2)=%f (%s)", d1, d_equal(d1, -2.33) ? "OK" : "FAIL"); d2 = difftimeval(tv2, tv1); if (!d_equal(d2, 2.33)) res++; printf(" => diff2(tv2, tv1)=%f (%s)", d2, d_equal(d2, 2.33) ? "OK" : "FAIL"); if (!d_equal(d1, -d2)) { printf(" => diff1 != -diff2 (FAIL)\n"); res++; } else { printf(" => diff1 == -diff2 (OK)\n"); } return res; } static int check_difftimespec(void) { int res = 0; #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC struct timespec tv1, tv2; double d1, d2; printf("=== %s(struct timespec):\t", __func__); tv1.tv_sec = 5; tv1.tv_nsec = 900000000; printf(" tv1=%" PRIiMAX ".%09" PRIiMAX, (intmax_t)tv1.tv_sec, (intmax_t)tv1.tv_nsec); tv2.tv_sec = 8; tv2.tv_nsec = 230000; printf(" tv2=%" PRIiMAX ".%09" PRIiMAX, (intmax_t)tv2.tv_sec, (intmax_t)tv2.tv_nsec); /* like in difftime(): (double)seconds elapsed time between older tv2 and newer tv1 */ d1 = difftimespec(tv1, tv2); if (!d_equal(d1, -2.10023)) res++; printf(" => diff1(tv1, tv2)=%f (%s)", d1, d_equal(d1, -2.10023) ? "OK" : "FAIL"); d2 = difftimespec(tv2, tv1); if (!d_equal(d2, 2.10023)) res++; printf(" => diff2(tv2, tv1)=%f (%s)", d2, d_equal(d2, 2.10023) ? "OK" : "FAIL"); if (!d_equal(d1, -d2)) { printf(" => diff1 != -diff2 (FAIL)\n"); res++; } else { printf(" => diff1 == -diff2 (OK)\n"); } #else printf("=== %s(struct timespec):\tSKIP: NOT IMPLEMENTED for this build (not HAVE_CLOCK_GETTIME or not HAVE_CLOCK_MONOTONIC)\n", __func__); #endif return res; } int main(void) { int ret = 0; ret += check_difftime(); ret += check_difftimeval(); ret += check_difftimespec(); return (ret != 0); } nut-2.8.3/tests/driver-stub-usb.c0000644000200500020050000000447214777767434013643 00000000000000/* placeholder/mock method implementations to just directly use driver * source code as done for belkin-hid.c (and eventually similar code) * for almost-in-vivo testing (and minimal intrusion to that codebase). * See also: getexponenttest-belkin-hid.c * * Copyright (C) * 2024 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "usb-common.h" int is_usb_device_supported(usb_device_id_t *usb_device_id_list, USBDevice_t *device) { NUT_UNUSED_VARIABLE(usb_device_id_list); NUT_UNUSED_VARIABLE(device); return -1; } #include "usbhid-ups.h" hid_dev_handle_t udev = HID_DEV_HANDLE_CLOSED; info_lkp_t beeper_info[] = { { 0, NULL, NULL, NULL } }; info_lkp_t date_conversion[] = { { 0, NULL, NULL, NULL } }; info_lkp_t stringid_conversion[] = { { 0, NULL, NULL, NULL } }; info_lkp_t divide_by_10_conversion[] = { { 0, NULL, NULL, NULL } }; info_lkp_t divide_by_100_conversion[] = { { 0, NULL, NULL, NULL } }; void possibly_supported(const char *mfr, HIDDevice_t *hd) { NUT_UNUSED_VARIABLE(mfr); NUT_UNUSED_VARIABLE(hd); } int fix_report_desc(HIDDevice_t *arg_pDev, HIDDesc_t *arg_pDesc) { NUT_UNUSED_VARIABLE(arg_pDev); NUT_UNUSED_VARIABLE(arg_pDesc); return -1; } #include "libhid.h" usage_lkp_t hid_usage_lkp[] = { {NULL, 0} }; char *HIDGetItemString(hid_dev_handle_t arg_udev, const char *hidpath, char *buf, size_t buflen, usage_tables_t *utab) { NUT_UNUSED_VARIABLE(arg_udev); NUT_UNUSED_VARIABLE(hidpath); NUT_UNUSED_VARIABLE(buf); NUT_UNUSED_VARIABLE(buflen); NUT_UNUSED_VARIABLE(utab); return NULL; } #include "main.h" char *getval(const char *var) { NUT_UNUSED_VARIABLE(var); return NULL; } nut-2.8.3/tests/generic_gpio_utest.h0000644000200500020050000000241314777534446014455 00000000000000/* generic_gpio_utest.h - unit tests for gpiod based NUT driver definitions * for GPIO attached UPS devices * * Copyright (C) * 2023 Modris Berzonis * 2023 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef GENERIC_GPIO_UTEST_H #define GENERIC_GPIO_UTEST_H #include "generic_gpio_common.h" #include "generic_gpio_libgpiod.h" void setNextLinesReadToFail(void); void getWithoutUnderscores(char *var); int get_test_status(struct gpioups_t *result, int on_fail_path); #endif /* GENERIC_GPIO_UTEST_H */ nut-2.8.3/tests/getexponenttest-belkin-hid.c0000644000200500020050000001566214777767434016055 00000000000000/* getexponenttest-belkin-hid - check detection of correct multiplication * exponent value for miniscule readings from USB HID (as used in the * drivers/belkin-hid.c subdriver of usbhid-ups). * Eventually may be extended to similar tests for other drivers' methods, * or more likely cloned to #include them in similar fashion. * * See also: * https://github.com/networkupstools/nut/issues/2370 * * Copyright (C) * 2024 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nut_stdint.h" #include "nut_float.h" #include #include #include #include "common.h" #include "belkin-hid.c" /* from drivers/belkin-hid.c we test: extern double liebert_config_voltage_mult, liebert_line_voltage_mult; const char *liebert_config_voltage_fun(double value); const char *liebert_line_voltage_fun(double value); */ static void Usage(char *name) { /* printf("%s {-c | -l } \n", name); printf("\n"); printf("%s -c 12\n", name); printf("%s -l 0.001212\n", name); printf("%s -l 1.39e-06\n", name); */ printf("%s\nIf no arguments are given a builtin set of tests are run.\n", name); } static int RunBuiltInTests(char *argv[]) { int exitStatus = 0; size_t i; double rawValue, value, mult; const char *valueStr; static char* methodName[2] = { "liebert_config_voltage_mult() ", "liebert_line_voltage_mult() " }; static struct { char *buf; /* raw voltage as a string (from CLI input, e.g. NUT driver log trace) */ double expectedRawValue; /* parsed raw voltage (as seen in USB HID reports) */ char type; /* 1 = config, 2 = line */ double expectedMult; /* expected liebert_config_voltage_mult or liebert_line_voltage_mult */ double expectedValue; /* the expected result of decoding the value in the buffer */ } testData[] = { {.buf = "0.000273", .expectedRawValue = 0.000273, .type = 2, .expectedMult = 1e5, .expectedValue = 27.3 }, {.buf = "0.001212", .expectedRawValue = 0.001212, .type = 2, .expectedMult = 1e5, .expectedValue = 121.2 }, {.buf = "0.002456", .expectedRawValue = 0.002456, .type = 2, .expectedMult = 1e5, .expectedValue = 245.6 }, {.buf = "0.003801", .expectedRawValue = 0.003801, .type = 2, .expectedMult = 1e5, .expectedValue = 380.1 }, {.buf = "0.004151", .expectedRawValue = 0.004151, .type = 2, .expectedMult = 1e5, .expectedValue = 415.1 }, {.buf = "1.39e-06", .expectedRawValue = 0.00000139, .type = 2, .expectedMult = 1e7, .expectedValue = 13.9 }, {.buf = "1.273e-05", .expectedRawValue = 0.00001273, .type = 2, .expectedMult = 1e7, .expectedValue = 127.3 }, {.buf = "2.201e-05", .expectedRawValue = 0.00002201, .type = 2, .expectedMult = 1e7, .expectedValue = 220.1 }, {.buf = "4.201e-05", .expectedRawValue = 0.00004201, .type = 2, .expectedMult = 1e7, .expectedValue = 420.1 }, /* Edge cases - what should not be converted (good enough already) */ {.buf = "12", .expectedRawValue = 12.0, .type = 2, .expectedMult = 1, .expectedValue = 12.0 }, {.buf = "12.3", .expectedRawValue = 12.3, .type = 2, .expectedMult = 1, .expectedValue = 12.3 }, {.buf = "232.1", .expectedRawValue = 232.1, .type = 2, .expectedMult = 1, .expectedValue = 232.1 }, {.buf = "240", .expectedRawValue = 240.0, .type = 2, .expectedMult = 1, .expectedValue = 240.0 }, /* Config values (nominal battery/input/... voltage) are often integers: */ {.buf = "24", .expectedRawValue = 24.0, .type = 1, .expectedMult = 1, .expectedValue = 24.0 }, {.buf = "120", .expectedRawValue = 120.0, .type = 1, .expectedMult = 1, .expectedValue = 120.0 } }; NUT_UNUSED_VARIABLE(argv); for (i = 0; i < SIZEOF_ARRAY(testData); i++) { liebert_line_voltage_mult = 1.0; liebert_config_voltage_mult = 1.0; rawValue = strtod(testData[i].buf, NULL); if (!d_equal(rawValue, testData[i].expectedRawValue)) { printf(" value '%s' parsing FAIL: got %g expected %g\n", testData[i].buf, rawValue, testData[i].expectedRawValue); /* Fix testData definition! */ exitStatus = 1; } switch (testData[i].type) { case 1: valueStr = liebert_config_voltage_fun(rawValue); mult = liebert_config_voltage_mult; /* NOTE: The method does also set a default * liebert_line_voltage_mult if config voltage * is miniscule and not a plain integer */ break; case 2: valueStr = liebert_line_voltage_fun(rawValue); mult = liebert_line_voltage_mult; break; default: printf(" invalid entry\n"); continue; } printf("Test #%" PRIuSIZE " \t", i + 1); value = strtod(valueStr, NULL); if (d_equal(value, testData[i].expectedValue) && d_equal(mult, testData[i].expectedMult)) { printf("%s\tGOT value %9g\tmult %6g PASS\n", (testData[i].type < 1 || testData[i].type > 3 ? "" : methodName[testData[i].type - 1]), value, mult); } else { printf("%s\tGOT value %9g\tmult %6g FAIL" "\tEXPECTED v=%7g\tm=%7g" "\tORIGINAL (string)'%s'\t=> (double)%g\n", (testData[i].type < 1 || testData[i].type > 2 ? "" : methodName[testData[i].type - 1]), value, mult, testData[i].expectedValue, testData[i].expectedMult, testData[i].buf, rawValue); exitStatus = 1; } } return (exitStatus); } /* static int RunCommandLineTest(char *argv[]) { uint8_t reportBuf[64]; size_t bufSize; char *start, *end; HIDData_t data; long value, expectedValue; start = argv[1]; end = NULL; for (bufSize = 0; *start != 0; bufSize++) { reportBuf[bufSize] = (uint8_t) strtol(start, (char **)&end, 16); if (start == end) break; start = end; } memset((void *)&data, 0, sizeof(data)); data.Offset = (uint8_t) atoi(argv[2]); data.Size = (uint8_t) atoi(argv[3]); data.LogMin = strtol(argv[4], 0, 0); data.LogMax = strtol(argv[5], 0, 0); expectedValue = strtol(argv[6], 0, 0); GetValue(reportBuf, &data, &value); printf("Test #0 "); PrintBufAndData(reportBuf, bufSize, &data); if (value == expectedValue) { printf(" value %ld PASS\n", value); return (0); } else { printf(" value %ld FAIL expected %ld\n", value, expectedValue); return (1); } } */ int main (int argc, char *argv[]) { int status; switch (argc) { case 1: status = RunBuiltInTests(argv); break; /* case 7: status = RunCommandLineTest(argv); break; */ default: Usage(argv[0]); status = 2; } return(status); } nut-2.8.3/tests/nut-driver-enumerator-test.sh0000755000200500020050000002712714553676503016222 00000000000000#!/bin/sh # Copyright (C) 2018 Eaton # # 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. # #! \file nut-driver-enumerator-test.sh # \author Jim Klimov # \brief Self-test for nut-driver-enumerator.sh utility # \details Automated sanity test for nut-driver-enumerator.sh(.in) # using different shells (per $SHELL_PROGS) and CLI requests # for regression and compatibility tests as well as for TDD # fueled by pre-decided expected outcomes. ### Use a standard locale setup so sorting in expected results is not confused LANG=C LC_ALL=C TZ=UTC export LANG LC_ALL TZ ### Note: These are relative to where the selftest script lives, ### not the NUT top_srcdir etc. They can be exported by a Makefile. [ -n "${BUILDDIR-}" ] || BUILDDIR="`dirname $0`" [ -n "${SRCDIR-}" ] || SRCDIR="`dirname $0`" [ -n "${SHELL_PROGS-}" ] || SHELL_PROGS="/bin/sh" case "${DEBUG-}" in [Yy]|[Yy][Ee][Ss]) DEBUG=yes ;; [Tt][Rr][Aa][Cc][Ee]) DEBUG=trace ;; *) DEBUG="" ;; esac SYSTEMD_CONFPATH="${BUILDDIR}/selftest-rw/systemd-units" export SYSTEMD_CONFPATH NUT_CONFPATH="${BUILDDIR}/selftest-rw/nut" export NUT_CONFPATH [ -n "${UPSCONF-}" ] || UPSCONF="${SRCDIR}/nut-driver-enumerator-test--ups.conf" [ ! -s "${UPSCONF-}" ] && echo "FATAL : testing ups.conf not found as '$UPSCONF'" >&2 && exit 1 export UPSCONF if [ ! -n "${NDE-}" ] ; then for NDE in \ "${BUILDDIR}/../scripts/upsdrvsvcctl/nut-driver-enumerator.sh" \ "${SRCDIR}/../scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in" \ ; do [ -s "$NDE" ] && break ; done fi [ ! -s "${NDE-}" ] && echo "FATAL : testing nut-driver-enumerator.sh implementation not found as '$NDE'" >&2 && exit 1 # TODO : Add tests that generate configuration files for units #mkdir -p "${NUT_CONFPATH}" "${SYSTEMD_CONFPATH}" || exit FAIL_COUNT=0 GOOD_COUNT=0 callNDE() { case "$DEBUG" in yes) time $USE_SHELL $NDE "$@" ;; trace) time $USE_SHELL -x $NDE "$@" ;; *) $USE_SHELL $NDE "$@" 2>/dev/null ;; esac } run_testcase() { # First 3 args are required as defined below; the rest are # CLI arg(s) to nut-driver-enumerator.sh CASE_DESCR="$1" EXPECT_CODE="$2" EXPECT_TEXT="$3" shift 3 printf "Testing : SHELL='%s'\tCASE='%s'\t" "$USE_SHELL" "$CASE_DESCR" OUT="`callNDE "$@"`" ; RESCODE=$? printf "Got : RESCODE='%s'\t" "$RESCODE" RES=0 if [ "$RESCODE" = "$EXPECT_CODE" ]; then printf "STATUS_CODE='MATCHED'\t" GOOD_COUNT="`expr $GOOD_COUNT + 1`" else printf "STATUS_CODE='MISMATCH' expect_code=%s received_code=%s\t" "$EXPECT_CODE" "$RESCODE" >&2 FAIL_COUNT="`expr $FAIL_COUNT + 1`" RES="`expr $RES + 1`" fi if [ "$OUT" = "$EXPECT_TEXT" ]; then printf "STATUS_TEXT='MATCHED'\n" GOOD_COUNT="`expr $GOOD_COUNT + 1`" else printf "STATUS_TEXT='MISMATCH'\n" printf '\t--- expected ---\n%s\n\t--- received ---\n%s\n\t--- MISMATCH ABOVE\n\n' "$EXPECT_TEXT" "$OUT" >&2 # Give a nice output to help track the problem: ( rm -f "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$" \ && echo "$EXPECT_TEXT" > "/tmp/.nde.text.expected.$$" \ && echo "$OUT" > "/tmp/.nde.text.actual.$$" \ && diff -u "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$" ) 2>/dev/null || true rm -f "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$" FAIL_COUNT="`expr $FAIL_COUNT + 1`" RES="`expr $RES + 2`" fi if [ "$RES" != 0 ] || [ -n "$DEBUG" ] ; then echo "" ; fi return $RES } ################################################################## # Note: expectations in test cases below are tightly connected # # to both the current code in the script and content of the test # # configuration file. # ################################################################## testcase_bogus_args() { run_testcase "Reject unknown args" 1 "" \ --some-bogus-arg } testcase_list_all_devices() { # We expect a list of unbracketed names from the device sections # Note: unlike other outputs, this list is alphabetically sorted run_testcase "List all device names from sections" 0 \ "dummy-proxy dummy-proxy-localhost dummy1 epdu-2 epdu-2-snmp qx-serial qx-usb1 qx-usb2 sectionWithComment sectionWithCommentWhitespace serial.4 usb_3 valueHasEquals valueHasHashtag valueHasQuotedHashtag" \ --list-devices } testcase_show_all_configs() { # We expect whitespace trimmed, comment-only lines removed run_testcase "Show all configs" 0 \ 'maxstartdelay=180 globalflag [dummy1] driver=dummy-ups port=file1.dev desc="This is ups-1" [epdu-2] driver=netxml-ups port=http://172.16.1.2 synchronous=yes [epdu-2-snmp] driver=snmp-ups port=172.16.1.2 synchronous=no [usb_3] driver=usbhid-ups port=auto [serial.4] driver=serial-ups driverflag port=/dev/ttyS1 # some path [dummy-proxy] driver="dummy-ups " port=remoteUPS@RemoteHost.local [dummy-proxy-localhost] driver='"'dummy-ups '"' port=localUPS@127.0.0.1 [valueHasEquals] driver=dummy=ups port=file1.dev # key = val, right? [valueHasHashtag] driver=dummy-ups port=file#1.dev [valueHasQuotedHashtag] driver=dummy-ups port=file#1.dev [qx-serial] driver=nutdrv_qx port=/dev/ttyb [qx-usb1] driver=nutdrv_qx port=auto [qx-usb2] driver=nutdrv_qx port=/dev/usb/8 [sectionWithComment] driver=nutdrv_qx#comment port=/dev/usb/8 desc="value with [brackets]" [brackets with spaces are not sections] # but rather an invalid mess as binary parser may think [sectionWithCommentWhitespace] driver=nutdrv_qx # comment port=/dev/usb/8 # comment commentedDriverFlag # This flag gotta mean something' \ --show-all-configs } testcase_upslist_debug() { # We expect a list of names, ports and decided MEDIA type (for dependencies) run_testcase "List decided MEDIA and config checksums for all devices" 0 \ "INST: 68b329da9893e34099c7d8ad5cb9c940~[]: DRV='' PORT='' MEDIA='' SECTIONMD5='9a1f372a850f1ee3ab1fc08b185783e0' INST: 010cf0aed6dd49865bb49b70267946f5~[dummy-proxy]: DRV='dummy-ups ' PORT='remoteUPS@RemoteHost.local' MEDIA='network' SECTIONMD5='aff543fc07d7fbf83e81001b181c8b97' INST: 1ea79c6eea3681ba73cc695f3253e605~[dummy-proxy-localhost]: DRV='dummy-ups ' PORT='localUPS@127.0.0.1' MEDIA='network-localhost' SECTIONMD5='73e6b7e3e3b73558dc15253d8cca51b2' INST: 76b645e28b0b53122b4428f4ab9eb4b9~[dummy1]: DRV='dummy-ups' PORT='file1.dev' MEDIA='' SECTIONMD5='9e0a326b67e00d455494f8b4258a01f1' INST: a293d65e62e89d6cc3ac6cb88bc312b8~[epdu-2]: DRV='netxml-ups' PORT='http://172.16.1.2' MEDIA='network' SECTIONMD5='0d9a0147dcf87c7c720e341170f69ed4' INST: 9a5561464ff8c78dd7cb544740ce2adc~[epdu-2-snmp]: DRV='snmp-ups' PORT='172.16.1.2' MEDIA='network' SECTIONMD5='2631b6c21140cea0dd30bb88b942ce3f' INST: 16adbdafb22d9fdff1d09038520eb32e~[qx-serial]: DRV='nutdrv_qx' PORT='/dev/ttyb' MEDIA='serial' SECTIONMD5='e3e6e586fbe5b3c0a89432f4b993f4ad' INST: a21bd2b786228b9619f6adba6db8fa83~[qx-usb1]: DRV='nutdrv_qx' PORT='auto' MEDIA='usb' SECTIONMD5='a6139c5da35bef89dc5b96e2296f5369' INST: 0066605e07c66043a17eccecbeea1ac5~[qx-usb2]: DRV='nutdrv_qx' PORT='/dev/usb/8' MEDIA='usb' SECTIONMD5='5722dd9c21d07a1f5bcb516dbc458deb' INST: 1280a731e03116f77290e51dd2a2f37e~[sectionWithComment]: DRV='nutdrv_qx#comment' PORT='/dev/usb/8' MEDIA='' SECTIONMD5='be30e15e17d0579c85eecaf176b4a064' INST: 770abd5659061a29ed3ae4f7c0b00915~[sectionWithCommentWhitespace]: DRV='nutdrv_qx # comment' PORT='/dev/usb/8 # comment' MEDIA='' SECTIONMD5='c757822a331521cdc97310d0241eba28' INST: efdb1b4698215fdca36b9bc06d24661d~[serial.4]: DRV='serial-ups' PORT='/dev/ttyS1 # some path' MEDIA='' SECTIONMD5='9c485f733aa6d6c85c1724f162929443' INST: f4a1c33db201c2ca897a3337993c10fc~[usb_3]: DRV='usbhid-ups' PORT='auto' MEDIA='usb' SECTIONMD5='1f6a24becde9bd31c9852610658ef84a' INST: 8e5686f92a5ba11901996c813e7bb23d~[valueHasEquals]: DRV='dummy=ups' PORT='file1.dev # key = val, right?' MEDIA='' SECTIONMD5='2f04d65da53e3b13771bb65422f0f4c0' INST: 99da99b1e301e84f34f349443aac545b~[valueHasHashtag]: DRV='dummy-ups' PORT='file#1.dev' MEDIA='' SECTIONMD5='6029bda216de0cf1e81bd55ebd4a0fff' INST: d50c3281f9b68a94bf9df72a115fbb5c~[valueHasQuotedHashtag]: DRV='dummy-ups' PORT='file#1.dev' MEDIA='' SECTIONMD5='af59c3c0caaa68dcd796d7145ae403ee'" \ upslist_debug # FIXME : in [valueHasEquals] and [serial.4] the PORT value is quite bogus # with its embedded comments. Check vs. binary config parser, whether in # unquoted case only first token is the valid value, and how comments are # handled in general? # FIXME : in [valueHasHashtag] the line after "#" should likely be dropped # (check in binary config parser first) while in [valueHasQuotedHashtag] # it should stay. } testcase_getValue() { run_testcase "Query a configuration key (SDP)" 0 \ "file1.dev" \ --show-device-config-value dummy1 port run_testcase "Query a configuration key (other)" 0 \ "yes" \ --show-device-config-value epdu-2 synchronous run_testcase "Query a configuration key (originally quoted)" 0 \ 'This is ups-1' \ --show-device-config-value dummy1 desc run_testcase "Query a configuration flag (driver)" 0 \ "driverflag" \ --show-config-value 'serial.4' driverflag run_testcase "Query a missing configuration flag (driver)" 1 \ "" \ --show-config-value 'valueHasQuotedHashtag' nosuchflag run_testcase "Query multiple configuration keys (originally quoted)" 0 \ 'This is ups-1 file1.dev' \ --show-device-config-value dummy1 desc port run_testcase "Query multiple configuration keys with some missing (originally quoted)" 1 \ 'This is ups-1 file1.dev' \ --show-device-config-value dummy1 desc unknownkey port } testcase_globalSection() { run_testcase "Display global config" 0 \ "maxstartdelay=180 globalflag" \ --show-config '' run_testcase "Query a configuration key (global)" 0 \ "180" \ --show-config-value '' maxstartdelay run_testcase "Query a configuration flag (global)" 0 \ "globalflag" \ --show-config-value '' globalflag run_testcase "Query a missing configuration flag (global)" 1 \ "" \ --show-config-value '' nosuchflag } # Combine the cases above into a stack testsuite() { testcase_bogus_args testcase_list_all_devices testcase_show_all_configs testcase_getValue testcase_globalSection # This one can take a while, put it last testcase_upslist_debug } # If no args... for USE_SHELL in $SHELL_PROGS ; do case "$USE_SHELL" in busybox|busybox_sh) USE_SHELL="busybox sh" ;; esac testsuite done # End of loop over shells echo "Test suite for nut-driver-enumerator has completed with $FAIL_COUNT failed cases and $GOOD_COUNT good cases" >&2 [ "$FAIL_COUNT" = 0 ] || { echo "As a developer, you may want to export DEBUG=trace or export DEBUG=yes and re-run the test; also make sure you meant the nut-driver-enumerator.sh implementation as NDE='$NDE'" >&2 ; exit 1; } nut-2.8.3/tests/nutbooltest.c0000644000200500020050000000266614777767434013173 00000000000000/* nutbooltest.c - test custom nut_bool_t usability * * Copyright (C) * 2024 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" #include "nut_bool.h" #include #include int main(void) { nut_bool_t bt = true, bf = false; int ret = 0; /* Check basic boolean operations */ if (bf) ret++; if (!bt) ret++; if (!bt == !bf) ret++; if (bt == bf) ret++; if (!(!bt == bf)) ret++; if (!(bt == !bf)) ret++; if (!(bt != bf)) ret++; if (!(!bt != !bf)) ret++; if (bf && bt) ret++; if (!bf && !bt) ret++; if (!(!bf && bt)) ret++; if (!(bf || bt)) ret++; if (!(!bf || !bt)) ret++; if (ret != 0) printf("nutbooltest collected %i errors", ret); return (ret != 0); } nut-2.8.3/common/0000755000200500020050000000000015001555410010603 500000000000000nut-2.8.3/common/state.c0000644000200500020050000003363414777767434012056 00000000000000/* state.c - Network UPS Tools common state management functions Copyright (C) 2003 Russell Kroll 2008 Arjen de Korte 2012 Arnaud Quette 2020-2024 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be first */ #include #include #include #include #ifndef WIN32 #include #include #endif /* !WIN32 */ #include "common.h" #include "state.h" #include "parseconf.h" /* internal helpers */ static void val_escape(st_tree_t *node) { char etmp[ST_MAX_VALUE_LEN]; /* escape any tricky stuff like \ and " */ pconf_encode(node->raw, etmp, sizeof(etmp)); /* if nothing was escaped, we don't need to do anything else */ if (!strcmp(node->raw, etmp)) { node->val = node->raw; return; } /* if the escaped value grew, deal with it */ if (node->safesize < (strlen(etmp) + 1)) { node->safesize = strlen(etmp) + 1; node->safe = xrealloc(node->safe, node->safesize); } snprintf(node->safe, node->safesize, "%s", etmp); node->val = node->safe; } static void st_tree_enum_free(enum_t *list) { if (!list) { return; } st_tree_enum_free(list->next); free(list->val); free(list); } static void st_tree_range_free(range_t *list) { if (!list) { return; } st_tree_range_free(list->next); free(list); } /* free all memory associated with a node */ static void st_tree_node_free(st_tree_t *node) { free(node->var); free(node->raw); free(node->safe); /* never free node->val, since it's just a pointer to raw or safe */ /* blow away the list of enums */ st_tree_enum_free(node->enum_list); /* and the list of ranges */ st_tree_range_free(node->range_list); /* now finally kill the node itself */ free(node); } /* add a subtree to another subtree */ static void st_tree_node_add(st_tree_t **nptr, st_tree_t *sptr) { if (!sptr) { return; } while (*nptr) { st_tree_t *node = *nptr; if (strcasecmp(node->var, sptr->var) > 0) { nptr = &node->left; continue; } if (strcasecmp(node->var, sptr->var) < 0) { nptr = &node->right; continue; } upsdebugx(1, "%s: duplicate value (shouldn't happen)", __func__); return; } *nptr = sptr; } static int st_tree_node_refresh_timestamp(const st_tree_t *node) { if (!node) return -1; return state_get_timestamp((st_tree_timespec_t *)&node->lastset); } /* interface */ /* As underlying system methods: * return 0 on success, -1 and errno on error */ int state_get_timestamp(st_tree_timespec_t *now) { if (!now) return -1; #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC return clock_gettime(CLOCK_MONOTONIC, now); #else return gettimeofday(now, NULL); #endif } /* Returns -1 if the node->lastset is "older" than cutoff, * 0 if it is equal, or +1 if it is newer. * Returns -2 or -3 if node or cutoff are null. */ int st_tree_node_compare_timestamp( const st_tree_t *node, const st_tree_timespec_t *cutoff ) { double d; if (!node) return -2; if (!cutoff) return -3; /* Like in difftime(), the first arg is "finish" and * the second arg is "start" of a time range (below), * so if the diff is negative, then "lastset" happened * before "cutoff": */ #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC d = difftimespec(node->lastset, *cutoff); #else d = difftimeval(node->lastset, *cutoff); #endif if (d < 0) return -1; if (d > 0) return 1; return 0; } /* remove a variable from a tree * except for variables with ST_FLAG_IMMUTABLE * (for override.* to survive) per issue #737 */ int state_delinfo(st_tree_t **nptr, const char *var) { while (*nptr) { st_tree_t *node = *nptr; if (strcasecmp(node->var, var) > 0) { nptr = &node->left; continue; } if (strcasecmp(node->var, var) < 0) { nptr = &node->right; continue; } if (node->flags & ST_FLAG_IMMUTABLE) { upsdebugx(6, "%s: not deleting immutable variable [%s]", __func__, var); return 0; } /* whatever is on the left, hang it off current right */ st_tree_node_add(&node->right, node->left); /* now point the parent at the old right child */ *nptr = node->right; st_tree_node_free(node); return 1; } return 0; /* not found */ } int state_delinfo_olderthan(st_tree_t **nptr, const char *var, const st_tree_timespec_t *cutoff) { while (*nptr) { st_tree_t *node = *nptr; if (strcasecmp(node->var, var) > 0) { nptr = &node->left; continue; } if (strcasecmp(node->var, var) < 0) { nptr = &node->right; continue; } if (node->flags & ST_FLAG_IMMUTABLE) { upsdebugx(6, "%s: not deleting immutable variable [%s]", __func__, var); return 0; } if (st_tree_node_compare_timestamp(node, cutoff) >= 0) { upsdebugx(6, "%s: not deleting recently updated variable [%s]", __func__, var); return 0; } upsdebugx(6, "%s: deleting variable [%s] last updated too long ago", __func__, var); /* whatever is on the left, hang it off current right */ st_tree_node_add(&node->right, node->left); /* now point the parent at the old right child */ *nptr = node->right; st_tree_node_free(node); return 1; } return 0; /* not found */ } int state_setinfo(st_tree_t **nptr, const char *var, const char *val) { while (*nptr) { st_tree_t *node = *nptr; if (strcasecmp(node->var, var) > 0) { nptr = &node->left; continue; } if (strcasecmp(node->var, var) < 0) { nptr = &node->right; continue; } /* refresh even if "skip-writing" same info value */ st_tree_node_refresh_timestamp(node); /* updating an existing entry */ if (!strcasecmp(node->raw, val)) { return 0; /* no change */ } /* changes should be ignored */ if (node->flags & ST_FLAG_IMMUTABLE) { upsdebugx(6, "%s: not changing immutable variable [%s]", __func__, var); return 0; /* no change */ } /* expand the buffer if the value grows */ if (node->rawsize < (strlen(val) + 1)) { node->rawsize = strlen(val) + 1; node->raw = xrealloc(node->raw, node->rawsize); } /* store the literal value for later comparisons */ snprintf(node->raw, node->rawsize, "%s", val); val_escape(node); return 1; /* changed */ } *nptr = xcalloc(1, sizeof(**nptr)); (*nptr)->var = xstrdup(var); (*nptr)->raw = xstrdup(val); (*nptr)->rawsize = strlen(val) + 1; st_tree_node_refresh_timestamp(*nptr); val_escape(*nptr); return 1; /* added */ } static int st_tree_enum_add(enum_t **list, const char *enc) { enum_t *item; while (*list) { if (strcmp((*list)->val, enc)) { list = &(*list)->next; continue; } return 0; /* duplicate */ } item = xcalloc(1, sizeof(*item)); item->val = xstrdup(enc); item->next = *list; /* now we're done creating it, add it to the list */ *list = item; return 1; /* added */ } int state_addenum(st_tree_t *root, const char *var, const char *val) { st_tree_t *sttmp; char enc[ST_MAX_VALUE_LEN]; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { upslogx(LOG_ERR, "%s: base variable (%s) " "does not exist", __func__, var); return 0; /* failed */ } /* smooth over any oddities in the enum value */ pconf_encode(val, enc, sizeof(enc)); st_tree_node_refresh_timestamp(sttmp); return st_tree_enum_add(&sttmp->enum_list, enc); } static int st_tree_range_add(range_t **list, const int min, const int max) { range_t *item; while (*list) { if (((*list)->min != min) && ((*list)->max != max)) { list = &(*list)->next; continue; } return 0; /* duplicate */ } item = xcalloc(1, sizeof(*item)); item->min = min; item->max = max; item->next = *list; /* now we're done creating it, add it to the list */ *list = item; return 1; /* added */ } int state_addrange(st_tree_t *root, const char *var, const int min, const int max) { st_tree_t *sttmp; /* sanity check */ if (min > max) { upslogx(LOG_ERR, "%s: min is superior to max! (%i, %i)", __func__, min, max); return 0; } /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { upslogx(LOG_ERR, "%s: base variable (%s) " "does not exist", __func__, var); return 0; /* failed */ } st_tree_node_refresh_timestamp(sttmp); return st_tree_range_add(&sttmp->range_list, min, max); } int state_setaux(st_tree_t *root, const char *var, const char *auxs) { st_tree_t *sttmp; long aux; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { upslogx(LOG_ERR, "%s: base variable (%s) " "does not exist", __func__, var); return -1; /* failed */ } st_tree_node_refresh_timestamp(sttmp); aux = strtol(auxs, (char **) NULL, 10); /* silently ignore matches */ if (sttmp->aux == aux) { return 0; } sttmp->aux = aux; return 1; } const char *state_getinfo(st_tree_t *root, const char *var) { st_tree_t *sttmp; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { return NULL; } return sttmp->val; } int state_getflags(st_tree_t *root, const char *var) { st_tree_t *sttmp; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { return -1; } return sttmp->flags; } long state_getaux(st_tree_t *root, const char *var) { st_tree_t *sttmp; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { return -1; } return sttmp->aux; } const enum_t *state_getenumlist(st_tree_t *root, const char *var) { st_tree_t *sttmp; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { return NULL; } return sttmp->enum_list; } const range_t *state_getrangelist(st_tree_t *root, const char *var) { st_tree_t *sttmp; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { return NULL; } return sttmp->range_list; } void state_setflags(st_tree_t *root, const char *var, size_t numflags, char **flag) { size_t i; st_tree_t *sttmp; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { upslogx(LOG_ERR, "%s: base variable (%s) " "does not exist", __func__, var); return; } st_tree_node_refresh_timestamp(sttmp); sttmp->flags = 0; for (i = 0; i < numflags; i++) { if (!strcasecmp(flag[i], "RW")) { sttmp->flags |= ST_FLAG_RW; continue; } if (!strcasecmp(flag[i], "STRING")) { sttmp->flags |= ST_FLAG_STRING; continue; } if (!strcasecmp(flag[i], "NUMBER")) { sttmp->flags |= ST_FLAG_NUMBER; continue; } upsdebugx(2, "%s: Unrecognized flag [%s]", __func__, flag[i]); } } int state_addcmd(cmdlist_t **list, const char *cmd) { cmdlist_t *item; while (*list) { if (strcasecmp((*list)->name, cmd) > 0) { /* insertion point reached */ break; } if (strcasecmp((*list)->name, cmd) < 0) { list = &(*list)->next; continue; } return 0; /* duplicate */ } item = xcalloc(1, sizeof(*item)); item->name = xstrdup(cmd); item->next = *list; /* now we're done creating it, insert it in the list */ *list = item; return 1; /* added */ } void state_infofree(st_tree_t *node) { if (!node) { return; } state_infofree(node->left); state_infofree(node->right); st_tree_node_free(node); } void state_cmdfree(cmdlist_t *list) { if (!list) { return; } state_cmdfree(list->next); free(list->name); free(list); } int state_delcmd(cmdlist_t **list, const char *cmd) { while (*list) { cmdlist_t *item = *list; if (strcasecmp(item->name, cmd) > 0) { /* not found */ break; } if (strcasecmp(item->name, cmd) < 0) { list = &item->next; continue; } /* we found it! */ *list = item->next; free(item->name); free(item); return 1; /* deleted */ } return 0; /* not found */ } static int st_tree_del_enum(enum_t **list, const char *val) { while (*list) { enum_t *item = *list; /* if this is not the right value, go on to the next */ if (strcasecmp(item->val, val)) { list = &item->next; continue; } /* we found it! */ *list = item->next; free(item->val); free(item); return 1; /* deleted */ } return 0; /* not found */ } int state_delenum(st_tree_t *root, const char *var, const char *val) { st_tree_t *sttmp; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { return 0; } st_tree_node_refresh_timestamp(sttmp); return st_tree_del_enum(&sttmp->enum_list, val); } static int st_tree_del_range(range_t **list, const int min, const int max) { while (*list) { range_t *item = *list; /* if this is not the right value, go on to the next */ if (((*list)->min != min) && ((*list)->max != max)) { list = &item->next; continue; } /* we found it! */ *list = item->next; free(item); return 1; /* deleted */ } return 0; /* not found */ } int state_delrange(st_tree_t *root, const char *var, const int min, const int max) { st_tree_t *sttmp; /* find the tree node for var */ sttmp = state_tree_find(root, var); if (!sttmp) { return 0; } st_tree_node_refresh_timestamp(sttmp); return st_tree_del_range(&sttmp->range_list, min, max); } st_tree_t *state_tree_find(st_tree_t *node, const char *var) { while (node) { if (strcasecmp(node->var, var) > 0) { node = node->left; continue; } if (strcasecmp(node->var, var) < 0) { node = node->right; continue; } break; /* found */ } return node; } nut-2.8.3/common/strnlen.c0000644000200500020050000000330414777534445012404 00000000000000/*- * Copyright (c) 2009 David Schultz * 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. */ /* // Includes amended for NUT cross-platform purposes #include __FBSDID("$FreeBSD: src/lib/libc/string/strnlen.c,v 1.1 2009/02/28 06:00:58 das Exp $"); */ #include #include size_t strnlen(const char *s, size_t maxlen) { size_t len; for (len = 0; len < maxlen; len++, s++) { if (!*s) break; } return (len); } nut-2.8.3/common/nutipc.cpp0000644000200500020050000001557614777767434012605 00000000000000/* nutipc.cpp - NUT IPC Copyright (C) 2012 Eaton Author: Vaclav Krpec Copyright (C) 2024-2025 NUT Community Author: Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* For C++ code below, we do not actually use the fallback time methods * (on mingw mostly), but in C++ context they happen to conflict with * time.h or ctime headers, while native-C does not. Just disable the * fallback localtime_r(), gmtime_r() etc. if/when NUT common.h gets * included by the header chain: */ #ifndef HAVE_GMTIME_R # define HAVE_GMTIME_R 111 #endif #ifndef HAVE_LOCALTIME_R # define HAVE_LOCALTIME_R 111 #endif #include "common.h" #include "nutipc.hpp" #include "nutstream.hpp" #include namespace nut { /* Trivial implementations out of class declaration to avoid * error: 'ClassName' has no out-of-line virtual method definitions; its vtable * will be emitted in every translation unit [-Werror,-Wweak-vtables] */ Process::Main::~Main() {} Signal::Handler::~Handler() {} pid_t Process::getPID() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { return getpid(); } pid_t Process::getPPID() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { #ifdef WIN32 /* FIXME: Detect HAVE_GETPPID in configure; throw exceptions here?.. * NOTE: Does not seem to be currently used in nutconf codebase. */ /* NUT_WIN32_INCOMPLETE(); */ return -1; #else /* !WIN32 */ return getppid(); #endif /* !WIN32 */ } /** * \brief Command line segmentation * * The function parses the \c command and chops off (and return) * the first command line word (i.e. does segmentation based * on white spaces, unless quoted). * White spaces are removed from the returned words. * * \param[in,out] command Command line * * \return Command line word */ static std::string getCmdLineWord(std::string & command) { size_t len = 0; // Remove initial whitespace while (len < command.size()) { if (' ' != command[len] && '\t' != command[len]) break; ++len; } command.erase(0, len); // Seek word end bool bslsh = false; char quote = 0; for (len = 0; len < command.size(); ++len) { char ch = command[len]; // White space (may be inside quotes) if (' ' == ch || '\t' == ch) { if (!quote) break; } // Backspace (second one cancels the first) else if ('\\' == ch) { bslsh = bslsh ? false : true; } // Double quote (may be escaped or nested) else if ('"' == ch) { if (!bslsh) { if (!quote) quote = '"'; // Final double quote else if ('"' == quote) quote = 0; } } // Single quote (can't be escaped) else if ('\'' == ch) { if (!quote) quote = '\''; else if ('\'' == quote) quote = 0; } // Cancel backslash if ('\\' != ch) bslsh = false; } // Extract the word std::string word = command.substr(0, len); command.erase(0, len); return word; } Process::Executor::Executor(const std::string & command) { std::string cmd(command); m_bin = getCmdLineWord(cmd); for (;;) { std::string arg = getCmdLineWord(cmd); if (arg.empty()) break; m_args.push_back(arg); } } int Process::Executor::operator () () #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { const char ** args_c_str = new const char *[m_args.size() + 2]; const char * bin_c_str = m_bin.c_str(); args_c_str[0] = bin_c_str; Arguments::const_iterator arg = m_args.begin(); size_t i = 1; for (; arg != m_args.end(); ++arg, ++i) { args_c_str[i] = (*arg).c_str(); } args_c_str[i] = nullptr; int status = ::execvp(bin_c_str, const_cast(args_c_str)); // Upon successful execution, the execvp function never returns // (since the process context is replaced, completely) delete[] args_c_str; std::stringstream e; e << "Failed to execute binary " << m_bin << ": " << status; throw std::runtime_error(e.str()); } int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { char * cmd_bytes = reinterpret_cast(cmd); do { ssize_t written = ::write(fh, cmd_bytes, cmd_size); if (written < 0) return errno; cmd_bytes += written; cmd_size -= static_cast(written); } while (cmd_size); return 0; } int Signal::send(Signal::enum_t signame, pid_t pid) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { int sig = static_cast(signame); #ifdef WIN32 /* FIXME: Implement (for NUT processes) via pipes? * See e.g. upsdrvctl implementation. */ std::stringstream e; e << "Can't send signal " << sig << " to PID " << pid << ": not implemented on this platform yet"; /* NUT_WIN32_INCOMPLETE(); */ throw std::logic_error(e.str()); #else /* !WIN32 */ int status = ::kill(pid, sig); if (0 == status) return 0; if (EINVAL != errno) return errno; std::stringstream e; e << "Can't send invalid signal " << sig; throw std::logic_error(e.str()); #endif /* !WIN32 */ } int Signal::send(Signal::enum_t signame, const std::string & pid_file) { NutFile file(pid_file, NutFile::READ_ONLY); std::string pid_str; NutStream::status_t read_st = file.getString(pid_str); if (NutStream::NUTS_OK != read_st) { std::stringstream e; e << "Failed to read PID from " << pid_file << ": " << read_st; throw std::runtime_error(e.str()); } std::stringstream pid_conv(pid_str); pid_t pid; if (!(pid_conv >> pid)) { std::stringstream e; e << "Failed to convert contents of " << pid_file << " to PID"; throw std::runtime_error(e.str()); } return send(signame, pid); } int NutSignal::send(NutSignal::enum_t signame, const std::string & process) { std::string pid_file; // FIXME: What about ALTPIDPATH (for non-root daemons) // and shouldn't we also consider it (e.g. try/catch)? /* FIXME NUT_WIN32_INCOMPLETE : Actually modern Windows supports both * slashes, but revise this code so we do not mix them (maybe enforce a * specific one - e.g. some other code does replace / with \ in common.c) */ pid_file += rootpidpath(); pid_file += '/'; pid_file += process; pid_file += ".pid"; return Signal::send(signame, pid_file); } } // end of namespace nut nut-2.8.3/common/strsep.c0000644000200500020050000000074714777534445012247 00000000000000#include /* Simple implem courtesy of https://stackoverflow.com/a/58244503 * Note: like the (BSD) standard implem, this changes the original stringp! * Result is undefined (segfault here) if stringp==NULL * (it is supposed to be address of string after all) */ char *strsep(char **stringp, const char *delim) { char *rv = *stringp; if (rv) { *stringp += strcspn(*stringp, delim); if (**stringp) *(*stringp)++ = '\0'; else *stringp = NULL; } return rv; } nut-2.8.3/common/Makefile.in0000644000200500020050000025164215001555010012576 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: common VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ # We define the recipe below in any case, but only activate it by default # if the build configuration tells us to: # We want it built and delivered (standalone or with tool) @WITH_DEV_LIBNUTCONF_TRUE@am__append_1 = libnutconf.la # We only want the tool, make a private build @WITH_DEV_LIBNUTCONF_FALSE@@WITH_NUTCONF_TRUE@am__append_2 = libnutconf.la @BUILDING_IN_TREE_TRUE@am__append_3 = common.c @BUILDING_IN_TREE_TRUE@am__append_4 = common.c @BUILDING_IN_TREE_TRUE@am__append_5 = common.c @BUILDING_IN_TREE_FALSE@am__append_6 = $(top_builddir)/common/common.c @HAVE_STRPTIME_TRUE@am__append_7 = strptime.c @HAVE_STRPTIME_FALSE@am__append_8 = strptime.c @HAVE_STRPTIME_FALSE@am__append_9 = strptime.c @HAVE_STRPTIME_FALSE@am__append_10 = strptime.c @HAVE_STRNLEN_TRUE@am__append_11 = strnlen.c @HAVE_STRNLEN_FALSE@am__append_12 = strnlen.c @HAVE_STRNLEN_FALSE@am__append_13 = strnlen.c @HAVE_STRNLEN_FALSE@am__append_14 = strnlen.c @HAVE_STRSEP_TRUE@am__append_15 = strsep.c @HAVE_STRSEP_FALSE@am__append_16 = strsep.c @HAVE_STRSEP_FALSE@am__append_17 = strsep.c @HAVE_STRSEP_FALSE@am__append_18 = strsep.c @WANT_TIMEGM_FALLBACK_TRUE@am__append_19 = timegm_fallback.c @WANT_TIMEGM_FALLBACK_TRUE@am__append_20 = timegm_fallback.c @WANT_TIMEGM_FALLBACK_TRUE@am__append_21 = timegm_fallback.c @WANT_TIMEGM_FALLBACK_FALSE@am__append_22 = timegm_fallback.c @HAVE_WINDOWS_TRUE@am__append_23 = libnutwincompat.la @HAVE_WINDOWS_TRUE@am__append_24 = wincompat.c $(top_srcdir)/include/wincompat.h @HAVE_WINDOWS_TRUE@am__append_25 = wincompat.c $(top_srcdir)/include/wincompat.h @HAVE_WINDOWS_TRUE@@WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@am__append_26 = -no-undefined @WITH_LIBNUTCONF_FALSE@am__append_27 = nutconf.cpp nutstream.cpp nutwriter.cpp nutipc.cpp @HAVE_LIBREGEX_TRUE@am__append_28 = $(LIBREGEX_CFLAGS) @HAVE_LIBREGEX_TRUE@am__append_29 = $(LIBREGEX_LIBS) @HAVE_LIBREGEX_TRUE@am__append_30 = $(LIBREGEX_CFLAGS) @HAVE_LIBREGEX_TRUE@am__append_31 = $(LIBREGEX_LIBS) @HAVE_LIBREGEX_TRUE@am__append_32 = $(LIBREGEX_CFLAGS) @HAVE_LIBREGEX_TRUE@am__append_33 = $(LIBREGEX_LIBS) # Did the user request, and build env support, tighter integration with # libsystemd methods such as sd_notify()? @WITH_LIBSYSTEMD_TRUE@am__append_34 = $(LIBSYSTEMD_CFLAGS) @WITH_LIBSYSTEMD_TRUE@am__append_35 = $(LIBSYSTEMD_LIBS) # A typical client should not need this, # but just in case (and to simplify linking)... # libcommonclient_la_CFLAGS += $(LIBSYSTEMD_CFLAGS) # libcommonclient_la_LIBADD += $(LIBSYSTEMD_LIBS) @WITH_LIBSYSTEMD_TRUE@am__append_36 = -DWITHOUT_LIBSYSTEMD=1 subdir = common ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = @HAVE_LIBREGEX_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) @WITH_LIBSYSTEMD_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) libcommon_la_DEPENDENCIES = libparseconf.la @LTLIBOBJS@ \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) am__libcommon_la_SOURCES_DIST = state.c str.c upsconf.c common.c \ strptime.c strnlen.c strsep.c timegm_fallback.c wincompat.c \ $(top_srcdir)/include/wincompat.h @BUILDING_IN_TREE_TRUE@am__objects_1 = libcommon_la-common.lo @HAVE_STRPTIME_FALSE@am__objects_2 = libcommon_la-strptime.lo @HAVE_STRNLEN_FALSE@am__objects_3 = libcommon_la-strnlen.lo @HAVE_STRSEP_FALSE@am__objects_4 = libcommon_la-strsep.lo @WANT_TIMEGM_FALLBACK_TRUE@am__objects_5 = \ @WANT_TIMEGM_FALLBACK_TRUE@ libcommon_la-timegm_fallback.lo @HAVE_WINDOWS_TRUE@am__objects_6 = libcommon_la-wincompat.lo am_libcommon_la_OBJECTS = libcommon_la-state.lo libcommon_la-str.lo \ libcommon_la-upsconf.lo $(am__objects_1) $(am__objects_2) \ $(am__objects_3) $(am__objects_4) $(am__objects_5) \ $(am__objects_6) @BUILDING_IN_TREE_FALSE@nodist_libcommon_la_OBJECTS = \ @BUILDING_IN_TREE_FALSE@ libcommon_la-common.lo libcommon_la_OBJECTS = $(am_libcommon_la_OBJECTS) \ $(nodist_libcommon_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libcommon_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libcommon_la_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ libcommonclient_la_DEPENDENCIES = libparseconf.la @LTLIBOBJS@ \ $(am__DEPENDENCIES_2) am__libcommonclient_la_SOURCES_DIST = state.c str.c common.c \ strptime.c strnlen.c strsep.c timegm_fallback.c wincompat.c \ $(top_srcdir)/include/wincompat.h @BUILDING_IN_TREE_TRUE@am__objects_7 = libcommonclient_la-common.lo @HAVE_STRPTIME_FALSE@am__objects_8 = libcommonclient_la-strptime.lo @HAVE_STRNLEN_FALSE@am__objects_9 = libcommonclient_la-strnlen.lo @HAVE_STRSEP_FALSE@am__objects_10 = libcommonclient_la-strsep.lo @WANT_TIMEGM_FALLBACK_TRUE@am__objects_11 = libcommonclient_la-timegm_fallback.lo @HAVE_WINDOWS_TRUE@am__objects_12 = libcommonclient_la-wincompat.lo am_libcommonclient_la_OBJECTS = libcommonclient_la-state.lo \ libcommonclient_la-str.lo $(am__objects_7) $(am__objects_8) \ $(am__objects_9) $(am__objects_10) $(am__objects_11) \ $(am__objects_12) @BUILDING_IN_TREE_FALSE@nodist_libcommonclient_la_OBJECTS = \ @BUILDING_IN_TREE_FALSE@ libcommonclient_la-common.lo libcommonclient_la_OBJECTS = $(am_libcommonclient_la_OBJECTS) \ $(nodist_libcommonclient_la_OBJECTS) libcommonclient_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libcommonclient_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ libcommonstr_la_DEPENDENCIES = @LTLIBOBJS@ $(am__DEPENDENCIES_2) am__libcommonstr_la_SOURCES_DIST = str.c common.c strptime.c strnlen.c \ strsep.c timegm_fallback.c @BUILDING_IN_TREE_TRUE@am__objects_13 = libcommonstr_la-common.lo @HAVE_STRPTIME_FALSE@am__objects_14 = libcommonstr_la-strptime.lo @HAVE_STRNLEN_FALSE@am__objects_15 = libcommonstr_la-strnlen.lo @HAVE_STRSEP_FALSE@am__objects_16 = libcommonstr_la-strsep.lo @WANT_TIMEGM_FALLBACK_TRUE@am__objects_17 = \ @WANT_TIMEGM_FALLBACK_TRUE@ libcommonstr_la-timegm_fallback.lo am_libcommonstr_la_OBJECTS = libcommonstr_la-str.lo $(am__objects_13) \ $(am__objects_14) $(am__objects_15) $(am__objects_16) \ $(am__objects_17) @BUILDING_IN_TREE_FALSE@nodist_libcommonstr_la_OBJECTS = \ @BUILDING_IN_TREE_FALSE@ libcommonstr_la-common.lo libcommonstr_la_OBJECTS = $(am_libcommonstr_la_OBJECTS) \ $(nodist_libcommonstr_la_OBJECTS) libcommonstr_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libcommonstr_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ @WITH_LIBNUTCONF_TRUE@libnutconf_la_DEPENDENCIES = libcommonclient.la am__libnutconf_la_SOURCES_DIST = nutconf.cpp nutstream.cpp \ nutwriter.cpp nutipc.cpp ../include/nutconf.hpp \ ../include/nutipc.hpp ../include/nutstream.hpp \ ../include/nutwriter.hpp @WITH_LIBNUTCONF_TRUE@am_libnutconf_la_OBJECTS = \ @WITH_LIBNUTCONF_TRUE@ libnutconf_la-nutconf.lo \ @WITH_LIBNUTCONF_TRUE@ libnutconf_la-nutstream.lo \ @WITH_LIBNUTCONF_TRUE@ libnutconf_la-nutwriter.lo \ @WITH_LIBNUTCONF_TRUE@ libnutconf_la-nutipc.lo libnutconf_la_OBJECTS = $(am_libnutconf_la_OBJECTS) libnutconf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) $(libnutconf_la_LDFLAGS) \ $(LDFLAGS) -o $@ @WITH_DEV_LIBNUTCONF_FALSE@@WITH_NUTCONF_TRUE@am_libnutconf_la_rpath = @WITH_DEV_LIBNUTCONF_TRUE@am_libnutconf_la_rpath = -rpath $(libdir) libnutwincompat_la_DEPENDENCIES = am__libnutwincompat_la_SOURCES_DIST = wincompat.c \ $(top_srcdir)/include/wincompat.h @HAVE_WINDOWS_TRUE@am_libnutwincompat_la_OBJECTS = \ @HAVE_WINDOWS_TRUE@ libnutwincompat_la-wincompat.lo libnutwincompat_la_OBJECTS = $(am_libnutwincompat_la_OBJECTS) libnutwincompat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libnutwincompat_la_CFLAGS) $(CFLAGS) \ $(libnutwincompat_la_LDFLAGS) $(LDFLAGS) -o $@ @HAVE_WINDOWS_TRUE@am_libnutwincompat_la_rpath = libparseconf_la_LIBADD = am_libparseconf_la_OBJECTS = parseconf.lo libparseconf_la_OBJECTS = $(am_libparseconf_la_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(DEPDIR)/atexit.Plo $(DEPDIR)/setenv.Plo \ $(DEPDIR)/snprintf.Plo $(DEPDIR)/strerror.Plo \ $(DEPDIR)/unsetenv.Plo ./$(DEPDIR)/libcommon_la-common.Plo \ ./$(DEPDIR)/libcommon_la-state.Plo \ ./$(DEPDIR)/libcommon_la-str.Plo \ ./$(DEPDIR)/libcommon_la-strnlen.Plo \ ./$(DEPDIR)/libcommon_la-strptime.Plo \ ./$(DEPDIR)/libcommon_la-strsep.Plo \ ./$(DEPDIR)/libcommon_la-timegm_fallback.Plo \ ./$(DEPDIR)/libcommon_la-upsconf.Plo \ ./$(DEPDIR)/libcommon_la-wincompat.Plo \ ./$(DEPDIR)/libcommonclient_la-common.Plo \ ./$(DEPDIR)/libcommonclient_la-state.Plo \ ./$(DEPDIR)/libcommonclient_la-str.Plo \ ./$(DEPDIR)/libcommonclient_la-strnlen.Plo \ ./$(DEPDIR)/libcommonclient_la-strptime.Plo \ ./$(DEPDIR)/libcommonclient_la-strsep.Plo \ ./$(DEPDIR)/libcommonclient_la-timegm_fallback.Plo \ ./$(DEPDIR)/libcommonclient_la-wincompat.Plo \ ./$(DEPDIR)/libcommonstr_la-common.Plo \ ./$(DEPDIR)/libcommonstr_la-str.Plo \ ./$(DEPDIR)/libcommonstr_la-strnlen.Plo \ ./$(DEPDIR)/libcommonstr_la-strptime.Plo \ ./$(DEPDIR)/libcommonstr_la-strsep.Plo \ ./$(DEPDIR)/libcommonstr_la-timegm_fallback.Plo \ ./$(DEPDIR)/libnutconf_la-nutconf.Plo \ ./$(DEPDIR)/libnutconf_la-nutipc.Plo \ ./$(DEPDIR)/libnutconf_la-nutstream.Plo \ ./$(DEPDIR)/libnutconf_la-nutwriter.Plo \ ./$(DEPDIR)/libnutwincompat_la-wincompat.Plo \ ./$(DEPDIR)/parseconf.Plo am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(libcommon_la_SOURCES) $(nodist_libcommon_la_SOURCES) \ $(libcommonclient_la_SOURCES) \ $(nodist_libcommonclient_la_SOURCES) \ $(libcommonstr_la_SOURCES) $(nodist_libcommonstr_la_SOURCES) \ $(libnutconf_la_SOURCES) $(libnutwincompat_la_SOURCES) \ $(libparseconf_la_SOURCES) DIST_SOURCES = $(am__libcommon_la_SOURCES_DIST) \ $(am__libcommonclient_la_SOURCES_DIST) \ $(am__libcommonstr_la_SOURCES_DIST) \ $(am__libnutconf_la_SOURCES_DIST) \ $(am__libnutwincompat_la_SOURCES_DIST) \ $(libparseconf_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp atexit.c \ setenv.c snprintf.c strerror.c unsetenv.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ AM_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include AM_CXXFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include AM_LDFLAGS = -no-undefined EXTRA_DIST = $(am__append_7) $(am__append_11) $(am__append_15) \ $(am__append_22) $(am__append_27) CLEANFILES = $(am__append_6) # several other Makefiles include the two helpers common.c str.c (and # perhaps some other string-related code), so make them a library too; # note that LTLIBOBJS pulls in snprintf.c contents too. noinst_LTLIBRARIES = libparseconf.la libcommon.la libcommonclient.la \ $(am__append_2) libcommonstr.la $(am__append_23) lib_LTLIBRARIES = $(am__append_1) # else do not build at all, e.g. do not have C++ support libparseconf_la_SOURCES = parseconf.c # FIXME: If we maintain some of those helper libs as subsets of the others # (strictly), maybe build the lowest common denominator only and link the # bigger scopes with it (rinse and repeat)? libcommon_la_SOURCES = state.c str.c upsconf.c $(am__append_3) \ $(am__append_8) $(am__append_12) $(am__append_16) \ $(am__append_19) $(am__append_24) libcommonclient_la_SOURCES = state.c str.c $(am__append_5) \ $(am__append_10) $(am__append_14) $(am__append_18) \ $(am__append_21) $(am__append_25) libcommonstr_la_SOURCES = str.c $(am__append_4) $(am__append_9) \ $(am__append_13) $(am__append_17) $(am__append_20) libcommonstr_la_CFLAGS = $(AM_CFLAGS) -DWITHOUT_LIBSYSTEMD=1 \ $(am__append_30) libcommonstr_la_LIBADD = @LTLIBOBJS@ @BSDKVMPROCLIBS@ $(am__append_31) @BUILDING_IN_TREE_FALSE@nodist_libcommon_la_SOURCES = common.c @BUILDING_IN_TREE_FALSE@nodist_libcommonstr_la_SOURCES = common.c @BUILDING_IN_TREE_FALSE@nodist_libcommonclient_la_SOURCES = common.c @BUILDING_IN_TREE_FALSE@BUILT_SOURCES = common.c @HAVE_WINDOWS_TRUE@libnutwincompat_la_SOURCES = wincompat.c $(top_srcdir)/include/wincompat.h @HAVE_WINDOWS_TRUE@libnutwincompat_la_LDFLAGS = @HAVE_WINDOWS_TRUE@libnutwincompat_la_LIBADD = @HAVE_WINDOWS_TRUE@libnutwincompat_la_CFLAGS = $(AM_CFLAGS) -DHAVE_SETENV=1 # ensure inclusion of local implementation of missing systems functions # using LTLIBOBJS. Refer to configure.in/.ac -> AC_REPLACE_FUNCS libcommon_la_LIBADD = libparseconf.la @LTLIBOBJS@ @NETLIBS@ \ @BSDKVMPROCLIBS@ $(am__append_29) $(am__append_35) libcommonclient_la_LIBADD = libparseconf.la @LTLIBOBJS@ @NETLIBS@ \ @BSDKVMPROCLIBS@ $(am__append_33) libcommon_la_CFLAGS = $(AM_CFLAGS) $(am__append_28) $(am__append_34) libcommonclient_la_CFLAGS = $(AM_CFLAGS) $(am__append_32) \ $(am__append_36) @WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@libnutconf_la_LDFLAGS = \ @WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@ -version-info \ @WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@ 0:1:0 \ @WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@ $(am__append_26) @WITH_LIBNUTCONF_TRUE@libnutconf_la_CXXFLAGS = $(AM_CXXFLAGS) @WITH_LIBNUTCONF_TRUE@libnutconf_la_LIBADD = @NETLIBS@ libcommonclient.la @WITH_LIBNUTCONF_TRUE@libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp nutwriter.cpp nutipc.cpp \ @WITH_LIBNUTCONF_TRUE@ ../include/nutconf.hpp ../include/nutipc.hpp \ @WITH_LIBNUTCONF_TRUE@ ../include/nutstream.hpp ../include/nutwriter.hpp MAINTAINERCLEANFILES = Makefile.in .dirstamp all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .cpp .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu common/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu common/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libcommon.la: $(libcommon_la_OBJECTS) $(libcommon_la_DEPENDENCIES) $(EXTRA_libcommon_la_DEPENDENCIES) $(AM_V_CCLD)$(libcommon_la_LINK) $(libcommon_la_OBJECTS) $(libcommon_la_LIBADD) $(LIBS) libcommonclient.la: $(libcommonclient_la_OBJECTS) $(libcommonclient_la_DEPENDENCIES) $(EXTRA_libcommonclient_la_DEPENDENCIES) $(AM_V_CCLD)$(libcommonclient_la_LINK) $(libcommonclient_la_OBJECTS) $(libcommonclient_la_LIBADD) $(LIBS) libcommonstr.la: $(libcommonstr_la_OBJECTS) $(libcommonstr_la_DEPENDENCIES) $(EXTRA_libcommonstr_la_DEPENDENCIES) $(AM_V_CCLD)$(libcommonstr_la_LINK) $(libcommonstr_la_OBJECTS) $(libcommonstr_la_LIBADD) $(LIBS) libnutconf.la: $(libnutconf_la_OBJECTS) $(libnutconf_la_DEPENDENCIES) $(EXTRA_libnutconf_la_DEPENDENCIES) $(AM_V_CXXLD)$(libnutconf_la_LINK) $(am_libnutconf_la_rpath) $(libnutconf_la_OBJECTS) $(libnutconf_la_LIBADD) $(LIBS) libnutwincompat.la: $(libnutwincompat_la_OBJECTS) $(libnutwincompat_la_DEPENDENCIES) $(EXTRA_libnutwincompat_la_DEPENDENCIES) $(AM_V_CCLD)$(libnutwincompat_la_LINK) $(am_libnutwincompat_la_rpath) $(libnutwincompat_la_OBJECTS) $(libnutwincompat_la_LIBADD) $(LIBS) libparseconf.la: $(libparseconf_la_OBJECTS) $(libparseconf_la_DEPENDENCIES) $(EXTRA_libparseconf_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libparseconf_la_OBJECTS) $(libparseconf_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/atexit.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/setenv.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/snprintf.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strerror.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/unsetenv.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-common.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-state.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-str.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-strnlen.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-strptime.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-strsep.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-timegm_fallback.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-upsconf.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommon_la-wincompat.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonclient_la-common.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonclient_la-state.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonclient_la-str.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonclient_la-strnlen.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonclient_la-strptime.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonclient_la-strsep.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonclient_la-timegm_fallback.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonclient_la-wincompat.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonstr_la-common.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonstr_la-str.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonstr_la-strnlen.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonstr_la-strptime.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonstr_la-strsep.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcommonstr_la-timegm_fallback.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutconf_la-nutconf.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutconf_la-nutipc.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutconf_la-nutstream.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutconf_la-nutwriter.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnutwincompat_la-wincompat.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parseconf.Plo@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libcommon_la-state.lo: state.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-state.lo -MD -MP -MF $(DEPDIR)/libcommon_la-state.Tpo -c -o libcommon_la-state.lo `test -f 'state.c' || echo '$(srcdir)/'`state.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-state.Tpo $(DEPDIR)/libcommon_la-state.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='state.c' object='libcommon_la-state.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-state.lo `test -f 'state.c' || echo '$(srcdir)/'`state.c libcommon_la-str.lo: str.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-str.lo -MD -MP -MF $(DEPDIR)/libcommon_la-str.Tpo -c -o libcommon_la-str.lo `test -f 'str.c' || echo '$(srcdir)/'`str.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-str.Tpo $(DEPDIR)/libcommon_la-str.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='str.c' object='libcommon_la-str.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-str.lo `test -f 'str.c' || echo '$(srcdir)/'`str.c libcommon_la-upsconf.lo: upsconf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-upsconf.lo -MD -MP -MF $(DEPDIR)/libcommon_la-upsconf.Tpo -c -o libcommon_la-upsconf.lo `test -f 'upsconf.c' || echo '$(srcdir)/'`upsconf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-upsconf.Tpo $(DEPDIR)/libcommon_la-upsconf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='upsconf.c' object='libcommon_la-upsconf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-upsconf.lo `test -f 'upsconf.c' || echo '$(srcdir)/'`upsconf.c libcommon_la-common.lo: common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-common.lo -MD -MP -MF $(DEPDIR)/libcommon_la-common.Tpo -c -o libcommon_la-common.lo `test -f 'common.c' || echo '$(srcdir)/'`common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-common.Tpo $(DEPDIR)/libcommon_la-common.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common.c' object='libcommon_la-common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-common.lo `test -f 'common.c' || echo '$(srcdir)/'`common.c libcommon_la-strptime.lo: strptime.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-strptime.lo -MD -MP -MF $(DEPDIR)/libcommon_la-strptime.Tpo -c -o libcommon_la-strptime.lo `test -f 'strptime.c' || echo '$(srcdir)/'`strptime.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-strptime.Tpo $(DEPDIR)/libcommon_la-strptime.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strptime.c' object='libcommon_la-strptime.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-strptime.lo `test -f 'strptime.c' || echo '$(srcdir)/'`strptime.c libcommon_la-strnlen.lo: strnlen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-strnlen.lo -MD -MP -MF $(DEPDIR)/libcommon_la-strnlen.Tpo -c -o libcommon_la-strnlen.lo `test -f 'strnlen.c' || echo '$(srcdir)/'`strnlen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-strnlen.Tpo $(DEPDIR)/libcommon_la-strnlen.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strnlen.c' object='libcommon_la-strnlen.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-strnlen.lo `test -f 'strnlen.c' || echo '$(srcdir)/'`strnlen.c libcommon_la-strsep.lo: strsep.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-strsep.lo -MD -MP -MF $(DEPDIR)/libcommon_la-strsep.Tpo -c -o libcommon_la-strsep.lo `test -f 'strsep.c' || echo '$(srcdir)/'`strsep.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-strsep.Tpo $(DEPDIR)/libcommon_la-strsep.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strsep.c' object='libcommon_la-strsep.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-strsep.lo `test -f 'strsep.c' || echo '$(srcdir)/'`strsep.c libcommon_la-timegm_fallback.lo: timegm_fallback.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-timegm_fallback.lo -MD -MP -MF $(DEPDIR)/libcommon_la-timegm_fallback.Tpo -c -o libcommon_la-timegm_fallback.lo `test -f 'timegm_fallback.c' || echo '$(srcdir)/'`timegm_fallback.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-timegm_fallback.Tpo $(DEPDIR)/libcommon_la-timegm_fallback.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='timegm_fallback.c' object='libcommon_la-timegm_fallback.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-timegm_fallback.lo `test -f 'timegm_fallback.c' || echo '$(srcdir)/'`timegm_fallback.c libcommon_la-wincompat.lo: wincompat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -MT libcommon_la-wincompat.lo -MD -MP -MF $(DEPDIR)/libcommon_la-wincompat.Tpo -c -o libcommon_la-wincompat.lo `test -f 'wincompat.c' || echo '$(srcdir)/'`wincompat.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommon_la-wincompat.Tpo $(DEPDIR)/libcommon_la-wincompat.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wincompat.c' object='libcommon_la-wincompat.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommon_la_CFLAGS) $(CFLAGS) -c -o libcommon_la-wincompat.lo `test -f 'wincompat.c' || echo '$(srcdir)/'`wincompat.c libcommonclient_la-state.lo: state.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -MT libcommonclient_la-state.lo -MD -MP -MF $(DEPDIR)/libcommonclient_la-state.Tpo -c -o libcommonclient_la-state.lo `test -f 'state.c' || echo '$(srcdir)/'`state.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonclient_la-state.Tpo $(DEPDIR)/libcommonclient_la-state.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='state.c' object='libcommonclient_la-state.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -c -o libcommonclient_la-state.lo `test -f 'state.c' || echo '$(srcdir)/'`state.c libcommonclient_la-str.lo: str.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -MT libcommonclient_la-str.lo -MD -MP -MF $(DEPDIR)/libcommonclient_la-str.Tpo -c -o libcommonclient_la-str.lo `test -f 'str.c' || echo '$(srcdir)/'`str.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonclient_la-str.Tpo $(DEPDIR)/libcommonclient_la-str.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='str.c' object='libcommonclient_la-str.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -c -o libcommonclient_la-str.lo `test -f 'str.c' || echo '$(srcdir)/'`str.c libcommonclient_la-common.lo: common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -MT libcommonclient_la-common.lo -MD -MP -MF $(DEPDIR)/libcommonclient_la-common.Tpo -c -o libcommonclient_la-common.lo `test -f 'common.c' || echo '$(srcdir)/'`common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonclient_la-common.Tpo $(DEPDIR)/libcommonclient_la-common.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common.c' object='libcommonclient_la-common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -c -o libcommonclient_la-common.lo `test -f 'common.c' || echo '$(srcdir)/'`common.c libcommonclient_la-strptime.lo: strptime.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -MT libcommonclient_la-strptime.lo -MD -MP -MF $(DEPDIR)/libcommonclient_la-strptime.Tpo -c -o libcommonclient_la-strptime.lo `test -f 'strptime.c' || echo '$(srcdir)/'`strptime.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonclient_la-strptime.Tpo $(DEPDIR)/libcommonclient_la-strptime.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strptime.c' object='libcommonclient_la-strptime.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -c -o libcommonclient_la-strptime.lo `test -f 'strptime.c' || echo '$(srcdir)/'`strptime.c libcommonclient_la-strnlen.lo: strnlen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -MT libcommonclient_la-strnlen.lo -MD -MP -MF $(DEPDIR)/libcommonclient_la-strnlen.Tpo -c -o libcommonclient_la-strnlen.lo `test -f 'strnlen.c' || echo '$(srcdir)/'`strnlen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonclient_la-strnlen.Tpo $(DEPDIR)/libcommonclient_la-strnlen.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strnlen.c' object='libcommonclient_la-strnlen.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -c -o libcommonclient_la-strnlen.lo `test -f 'strnlen.c' || echo '$(srcdir)/'`strnlen.c libcommonclient_la-strsep.lo: strsep.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -MT libcommonclient_la-strsep.lo -MD -MP -MF $(DEPDIR)/libcommonclient_la-strsep.Tpo -c -o libcommonclient_la-strsep.lo `test -f 'strsep.c' || echo '$(srcdir)/'`strsep.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonclient_la-strsep.Tpo $(DEPDIR)/libcommonclient_la-strsep.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strsep.c' object='libcommonclient_la-strsep.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -c -o libcommonclient_la-strsep.lo `test -f 'strsep.c' || echo '$(srcdir)/'`strsep.c libcommonclient_la-timegm_fallback.lo: timegm_fallback.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -MT libcommonclient_la-timegm_fallback.lo -MD -MP -MF $(DEPDIR)/libcommonclient_la-timegm_fallback.Tpo -c -o libcommonclient_la-timegm_fallback.lo `test -f 'timegm_fallback.c' || echo '$(srcdir)/'`timegm_fallback.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonclient_la-timegm_fallback.Tpo $(DEPDIR)/libcommonclient_la-timegm_fallback.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='timegm_fallback.c' object='libcommonclient_la-timegm_fallback.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -c -o libcommonclient_la-timegm_fallback.lo `test -f 'timegm_fallback.c' || echo '$(srcdir)/'`timegm_fallback.c libcommonclient_la-wincompat.lo: wincompat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -MT libcommonclient_la-wincompat.lo -MD -MP -MF $(DEPDIR)/libcommonclient_la-wincompat.Tpo -c -o libcommonclient_la-wincompat.lo `test -f 'wincompat.c' || echo '$(srcdir)/'`wincompat.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonclient_la-wincompat.Tpo $(DEPDIR)/libcommonclient_la-wincompat.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wincompat.c' object='libcommonclient_la-wincompat.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonclient_la_CFLAGS) $(CFLAGS) -c -o libcommonclient_la-wincompat.lo `test -f 'wincompat.c' || echo '$(srcdir)/'`wincompat.c libcommonstr_la-str.lo: str.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -MT libcommonstr_la-str.lo -MD -MP -MF $(DEPDIR)/libcommonstr_la-str.Tpo -c -o libcommonstr_la-str.lo `test -f 'str.c' || echo '$(srcdir)/'`str.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonstr_la-str.Tpo $(DEPDIR)/libcommonstr_la-str.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='str.c' object='libcommonstr_la-str.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -c -o libcommonstr_la-str.lo `test -f 'str.c' || echo '$(srcdir)/'`str.c libcommonstr_la-common.lo: common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -MT libcommonstr_la-common.lo -MD -MP -MF $(DEPDIR)/libcommonstr_la-common.Tpo -c -o libcommonstr_la-common.lo `test -f 'common.c' || echo '$(srcdir)/'`common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonstr_la-common.Tpo $(DEPDIR)/libcommonstr_la-common.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common.c' object='libcommonstr_la-common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -c -o libcommonstr_la-common.lo `test -f 'common.c' || echo '$(srcdir)/'`common.c libcommonstr_la-strptime.lo: strptime.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -MT libcommonstr_la-strptime.lo -MD -MP -MF $(DEPDIR)/libcommonstr_la-strptime.Tpo -c -o libcommonstr_la-strptime.lo `test -f 'strptime.c' || echo '$(srcdir)/'`strptime.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonstr_la-strptime.Tpo $(DEPDIR)/libcommonstr_la-strptime.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strptime.c' object='libcommonstr_la-strptime.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -c -o libcommonstr_la-strptime.lo `test -f 'strptime.c' || echo '$(srcdir)/'`strptime.c libcommonstr_la-strnlen.lo: strnlen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -MT libcommonstr_la-strnlen.lo -MD -MP -MF $(DEPDIR)/libcommonstr_la-strnlen.Tpo -c -o libcommonstr_la-strnlen.lo `test -f 'strnlen.c' || echo '$(srcdir)/'`strnlen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonstr_la-strnlen.Tpo $(DEPDIR)/libcommonstr_la-strnlen.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strnlen.c' object='libcommonstr_la-strnlen.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -c -o libcommonstr_la-strnlen.lo `test -f 'strnlen.c' || echo '$(srcdir)/'`strnlen.c libcommonstr_la-strsep.lo: strsep.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -MT libcommonstr_la-strsep.lo -MD -MP -MF $(DEPDIR)/libcommonstr_la-strsep.Tpo -c -o libcommonstr_la-strsep.lo `test -f 'strsep.c' || echo '$(srcdir)/'`strsep.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonstr_la-strsep.Tpo $(DEPDIR)/libcommonstr_la-strsep.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strsep.c' object='libcommonstr_la-strsep.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -c -o libcommonstr_la-strsep.lo `test -f 'strsep.c' || echo '$(srcdir)/'`strsep.c libcommonstr_la-timegm_fallback.lo: timegm_fallback.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -MT libcommonstr_la-timegm_fallback.lo -MD -MP -MF $(DEPDIR)/libcommonstr_la-timegm_fallback.Tpo -c -o libcommonstr_la-timegm_fallback.lo `test -f 'timegm_fallback.c' || echo '$(srcdir)/'`timegm_fallback.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcommonstr_la-timegm_fallback.Tpo $(DEPDIR)/libcommonstr_la-timegm_fallback.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='timegm_fallback.c' object='libcommonstr_la-timegm_fallback.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libcommonstr_la_CFLAGS) $(CFLAGS) -c -o libcommonstr_la-timegm_fallback.lo `test -f 'timegm_fallback.c' || echo '$(srcdir)/'`timegm_fallback.c libnutwincompat_la-wincompat.lo: wincompat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutwincompat_la_CFLAGS) $(CFLAGS) -MT libnutwincompat_la-wincompat.lo -MD -MP -MF $(DEPDIR)/libnutwincompat_la-wincompat.Tpo -c -o libnutwincompat_la-wincompat.lo `test -f 'wincompat.c' || echo '$(srcdir)/'`wincompat.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnutwincompat_la-wincompat.Tpo $(DEPDIR)/libnutwincompat_la-wincompat.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wincompat.c' object='libnutwincompat_la-wincompat.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutwincompat_la_CFLAGS) $(CFLAGS) -c -o libnutwincompat_la-wincompat.lo `test -f 'wincompat.c' || echo '$(srcdir)/'`wincompat.c .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< libnutconf_la-nutconf.lo: nutconf.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) -MT libnutconf_la-nutconf.lo -MD -MP -MF $(DEPDIR)/libnutconf_la-nutconf.Tpo -c -o libnutconf_la-nutconf.lo `test -f 'nutconf.cpp' || echo '$(srcdir)/'`nutconf.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnutconf_la-nutconf.Tpo $(DEPDIR)/libnutconf_la-nutconf.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutconf.cpp' object='libnutconf_la-nutconf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) -c -o libnutconf_la-nutconf.lo `test -f 'nutconf.cpp' || echo '$(srcdir)/'`nutconf.cpp libnutconf_la-nutstream.lo: nutstream.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) -MT libnutconf_la-nutstream.lo -MD -MP -MF $(DEPDIR)/libnutconf_la-nutstream.Tpo -c -o libnutconf_la-nutstream.lo `test -f 'nutstream.cpp' || echo '$(srcdir)/'`nutstream.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnutconf_la-nutstream.Tpo $(DEPDIR)/libnutconf_la-nutstream.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutstream.cpp' object='libnutconf_la-nutstream.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) -c -o libnutconf_la-nutstream.lo `test -f 'nutstream.cpp' || echo '$(srcdir)/'`nutstream.cpp libnutconf_la-nutwriter.lo: nutwriter.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) -MT libnutconf_la-nutwriter.lo -MD -MP -MF $(DEPDIR)/libnutconf_la-nutwriter.Tpo -c -o libnutconf_la-nutwriter.lo `test -f 'nutwriter.cpp' || echo '$(srcdir)/'`nutwriter.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnutconf_la-nutwriter.Tpo $(DEPDIR)/libnutconf_la-nutwriter.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutwriter.cpp' object='libnutconf_la-nutwriter.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) -c -o libnutconf_la-nutwriter.lo `test -f 'nutwriter.cpp' || echo '$(srcdir)/'`nutwriter.cpp libnutconf_la-nutipc.lo: nutipc.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) -MT libnutconf_la-nutipc.lo -MD -MP -MF $(DEPDIR)/libnutconf_la-nutipc.Tpo -c -o libnutconf_la-nutipc.lo `test -f 'nutipc.cpp' || echo '$(srcdir)/'`nutipc.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnutconf_la-nutipc.Tpo $(DEPDIR)/libnutconf_la-nutipc.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='nutipc.cpp' object='libnutconf_la-nutipc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnutconf_la_CXXFLAGS) $(CXXFLAGS) -c -o libnutconf_la-nutipc.lo `test -f 'nutipc.cpp' || echo '$(srcdir)/'`nutipc.cpp mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -f $(DEPDIR)/atexit.Plo -rm -f $(DEPDIR)/setenv.Plo -rm -f $(DEPDIR)/snprintf.Plo -rm -f $(DEPDIR)/strerror.Plo -rm -f $(DEPDIR)/unsetenv.Plo -rm -f ./$(DEPDIR)/libcommon_la-common.Plo -rm -f ./$(DEPDIR)/libcommon_la-state.Plo -rm -f ./$(DEPDIR)/libcommon_la-str.Plo -rm -f ./$(DEPDIR)/libcommon_la-strnlen.Plo -rm -f ./$(DEPDIR)/libcommon_la-strptime.Plo -rm -f ./$(DEPDIR)/libcommon_la-strsep.Plo -rm -f ./$(DEPDIR)/libcommon_la-timegm_fallback.Plo -rm -f ./$(DEPDIR)/libcommon_la-upsconf.Plo -rm -f ./$(DEPDIR)/libcommon_la-wincompat.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-common.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-state.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-str.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-strnlen.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-strptime.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-strsep.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-timegm_fallback.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-wincompat.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-common.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-str.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-strnlen.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-strptime.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-strsep.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-timegm_fallback.Plo -rm -f ./$(DEPDIR)/libnutconf_la-nutconf.Plo -rm -f ./$(DEPDIR)/libnutconf_la-nutipc.Plo -rm -f ./$(DEPDIR)/libnutconf_la-nutstream.Plo -rm -f ./$(DEPDIR)/libnutconf_la-nutwriter.Plo -rm -f ./$(DEPDIR)/libnutwincompat_la-wincompat.Plo -rm -f ./$(DEPDIR)/parseconf.Plo -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(DEPDIR)/atexit.Plo -rm -f $(DEPDIR)/setenv.Plo -rm -f $(DEPDIR)/snprintf.Plo -rm -f $(DEPDIR)/strerror.Plo -rm -f $(DEPDIR)/unsetenv.Plo -rm -f ./$(DEPDIR)/libcommon_la-common.Plo -rm -f ./$(DEPDIR)/libcommon_la-state.Plo -rm -f ./$(DEPDIR)/libcommon_la-str.Plo -rm -f ./$(DEPDIR)/libcommon_la-strnlen.Plo -rm -f ./$(DEPDIR)/libcommon_la-strptime.Plo -rm -f ./$(DEPDIR)/libcommon_la-strsep.Plo -rm -f ./$(DEPDIR)/libcommon_la-timegm_fallback.Plo -rm -f ./$(DEPDIR)/libcommon_la-upsconf.Plo -rm -f ./$(DEPDIR)/libcommon_la-wincompat.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-common.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-state.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-str.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-strnlen.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-strptime.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-strsep.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-timegm_fallback.Plo -rm -f ./$(DEPDIR)/libcommonclient_la-wincompat.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-common.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-str.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-strnlen.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-strptime.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-strsep.Plo -rm -f ./$(DEPDIR)/libcommonstr_la-timegm_fallback.Plo -rm -f ./$(DEPDIR)/libnutconf_la-nutconf.Plo -rm -f ./$(DEPDIR)/libnutconf_la-nutipc.Plo -rm -f ./$(DEPDIR)/libnutconf_la-nutstream.Plo -rm -f ./$(DEPDIR)/libnutconf_la-nutwriter.Plo -rm -f ./$(DEPDIR)/libnutwincompat_la-wincompat.Plo -rm -f ./$(DEPDIR)/parseconf.Plo -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: all check install install-am install-exec install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES .PRECIOUS: Makefile # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ # do not hard depend on '../include/nut_version.h', since it blocks # 'dist', and is only required for actual build, in which case # BUILT_SOURCES (in ../include) will ensure nut_version.h will # be built before anything else... but do depend on its build area: # No need for symlink hack @BUILDING_IN_TREE_TRUE@ common.c: $(top_builddir)/include/nut_version.h # Surprisingly, for some "make" implementations this dependency means # that the "common.c" required for builds below will be seeked in the # current directory. So for out-of-tree builds like distcheck, we have # to symlink the "real" source to build area. And then when we handle # subsequent dependencies, we already have a filename that "make" now # discovers and is confused about: @BUILDING_IN_TREE_FALSE@ common.c: $(top_builddir)/include/nut_version.h $(srcdir)/common.c @BUILDING_IN_TREE_FALSE@ @if [ x"$(abs_top_srcdir)" = x"$(abs_top_builddir)" ] || test -s "$@" ; then \ @BUILDING_IN_TREE_FALSE@ exit 0 ; \ @BUILDING_IN_TREE_FALSE@ else \ @BUILDING_IN_TREE_FALSE@ echo " LN $(top_srcdir)/common/common.c => $@ (relative to `pwd`)" ; \ @BUILDING_IN_TREE_FALSE@ ln -s -f "$(top_srcdir)/common/common.c" "$@" ; \ @BUILDING_IN_TREE_FALSE@ fi $(top_builddir)/include/nut_version.h: +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) @HAVE_STRPTIME_FALSE@ # fall back to NetBSD implem @HAVE_STRNLEN_FALSE@ # fall back to FreeBSD implem @HAVE_STRSEP_FALSE@ # fall back to simple implem @WANT_TIMEGM_FALLBACK_TRUE@ # fall back to simple implem @HAVE_WINDOWS_TRUE@ # Assume setenv() provided by OS or nut_setenv() provided by @HAVE_WINDOWS_TRUE@ # another NUT library and linked to the final NUT program/lib @HAVE_WINDOWS_TRUE@ # (anyhow, avoid a link-time conflict with two definitions): @WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@ # libnutconf version information and build @WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@ # currently considered a highly experimental and so unstable API at least @WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@ # (at least, headers contain a lot of data/code, not sure they should) @HAVE_WINDOWS_TRUE@@WITH_DEV_LIBNUTCONF_TRUE@@WITH_LIBNUTCONF_TRUE@ # Many versions of MingW seem to fail to build non-static DLL without this @WITH_LIBNUTCONF_TRUE@ # NOTE: No @LTLIBOBJS@ here, because libcommonclient.la includes them (if any) # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! clean-local: if test -L $(builddir)/common.c || test -h $(builddir)/common.c ; then rm -f $(builddir)/common.c ; fi # $(AM_V_at)rm -rf $(builddir)/.deps # Helper for only the enabled libs to get built: all-libs-local: $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) $(EXTRA_LTLIBRARIES) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/common/nutwriter.cpp0000644000200500020050000007147315001552635013314 00000000000000/* nutwriter.cpp - NUT writer Copyright (C) 2012 Eaton Author: Vaclav Krpec Copyright (C) 2024-2025 NUT Community Author: Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nutwriter.hpp" #include #include #include #include #include #include #include /** * \brief NUT configuration directive generator * * The macro is used to simplify generation of * NUT config. directives. * * IMPORTANT NOTE: * In case of writing error, the macro causes immediate * return from the calling function (propagating the writing status). * * \param name Directive name * \param arg_t Directive argument implementation type * \param arg Directive argument * \param quote_arg Boolean flag; check to quote the argument */ #define CONFIG_DIRECTIVEX(name, arg_t, arg, quote_arg) \ do { \ if ((arg).set()) { \ const arg_t & arg_val = (arg); \ std::stringstream ss; \ ss << name << ' '; \ if (quote_arg) \ ss << '"'; \ ss << arg_val; \ if (quote_arg) \ ss << '"'; \ status_t status = writeDirective(ss.str()); \ if (NUTW_OK != status) \ return status; \ } \ } while (0) /** * \brief Shell (envvar) configuration directive generator * * The macro is used to simplify generation of * nut.conf file directives. * * IMPORTANT NOTE: * In case of writing error, the macro causes immediate * return from the calling function (propagating the writing status). * * \param name Directive name * \param arg_t Directive argument implementation type * \param arg Directive argument * \param quote_arg Boolean flag; check to quote the argument */ // NOTE: Due to this being a macro applied to any argument type, // implementation for e.g. bool handling jumps through hoops like // stringification and back. FIXME: working optimization welcome. #define SHELL_CONFIG_DIRECTIVEX(name, arg_t, arg, quote_arg) \ do { \ if ((arg).set()) { \ const arg_t & arg_val = (arg); \ std::stringstream ss; \ ss << name << '='; \ if (quote_arg) \ ss << '\''; \ if (typeid(arg_val) == typeid(bool&)) { \ std::stringstream ssb; \ ssb << arg_val; \ std::string sb = ssb.str(); \ if ("1" == sb) { ss << "true"; } \ else if ("0" == sb) { ss << "false"; } \ else { ss << arg_val; } \ } else \ ss << arg_val; \ if (quote_arg) \ ss << '\''; \ status_t status = writeDirective(ss.str()); \ if (NUTW_OK != status) \ return status; \ } \ } while (0) namespace nut { /* Trivial implementations out of class declaration to avoid * error: 'ClassName' has no out-of-line virtual method definitions; its vtable * will be emitted in every translation unit [-Werror,-Wweak-vtables] */ NutConfigWriter::~NutConfigWriter() {} // generic interface/base class // Flat-config classes: NutConfConfigWriter::~NutConfConfigWriter() {} // nut.conf, shell format UpsmonConfigWriter::~UpsmonConfigWriter() {} // upsmon.conf UpsdConfigWriter::~UpsdConfigWriter() {} // upsd.conf // Structured-config classes R/W is handled via GenericConfiguration: // UpsConfiguration: ups.conf // UpsdUsersConfiguration: upsd.users // Not handled currently: // xxx: upssched.conf // xxx: upsset.conf // xxx: hosts.conf // End-of-Line separators (arch. dependent) /** UNIX style EoL */ static const std::string LF("\n"); // TODO: Make a compile-time selection #if (0) // M$ Windows EoL static const std::string CRLF("\r\n"); // Apple MAC EoL static const std::string CR("\r"); #endif // end of #if (0) const std::string & NutWriter::eol(LF); const std::string GenericConfigWriter::s_default_section_entry_indent("\t"); const std::string GenericConfigWriter::s_default_section_entry_separator(" = "); /** * \brief NSS certificate identity serializer * * \param ident Certificate identity object * * \return Serialized certificate identity */ static std::string serializeCertIdent(const nut::CertIdent & ident) { std::stringstream directive; const std::string & val1 = (ident.certName), val2 = (ident.certDbPass); directive << "CERTIDENT \"" << val1 << "\" \"" << val2 << "\""; return directive.str(); } /** * \brief NSS certificate-protected host info serializer * * \param certHost Certificate-protected host info object * * \return Serialized certificate-protected host info */ static std::string serializeCertHost(const nut::CertHost & certHost) { std::stringstream directive; const std::string & val1 = (certHost.host), val2 = (certHost.certName); directive << "CERTHOST \"" << val1 << "\" \"" << val2 << "\""; // Spec says to write these as 0/1 integers nut::BoolInt bi; int i; // NOTE: After copy-assignments below (which inherit original strictness), // need to add relaxed mode for 0/1 as false/true handling: //bi.bool01 = true; // Avoid static analysis concerns that the internal _value // "may be used uninitialized in this function" (ETOOSMART): bi = false; // Assumed to be set() - exception otherwise bi = certHost.certVerify; bi.bool01 = true; i = bi; directive << " " << i; bi = certHost.forceSsl; bi.bool01 = true; i = bi; directive << " " << i; return directive.str(); } NutWriter::status_t NutWriter::writeEachLine(const std::string & str, const std::string & pref) { for (size_t pos = 0; pos < str.size(); ) { // Prefix every line status_t status = write(pref); if (NUTW_OK != status) return status; // Write up to the next EoL (or till the end) size_t eol_pos = str.find(eol, pos); if (str.npos == eol_pos) return write(str.substr(pos) + eol); eol_pos += eol.size(); status = write(str.substr(pos, eol_pos)); if (NUTW_OK != status) return status; // Update position pos = eol_pos; } return NUTW_OK; } NutWriter::status_t SectionlessConfigWriter::writeDirective(const std::string & str) { return write(str + eol); } NutWriter::status_t SectionlessConfigWriter::writeComment(const std::string & str) { return writeEachLine(str, "# "); } NutWriter::status_t SectionlessConfigWriter::writeSectionName(const std::string & name) { std::string e("INTERNAL ERROR: Attempt to write section name "); e += name + " to a section-less configuration file"; throw std::logic_error(e); } NutWriter::status_t NutConfConfigWriter::writeConfig(const NutConfiguration & config) { // Mode // TBD: How should I serialize an unknown mode? if (config.mode.set()) { status_t status; std::string mode_str; NutConfiguration::NutMode mode = config.mode; switch (mode) { case NutConfiguration::MODE_UNKNOWN: // BEWARE! Intentional fall-through to MODE_NONE branch case NutConfiguration::MODE_NONE: mode_str = "none"; break; case NutConfiguration::MODE_STANDALONE: mode_str = "standalone"; break; case NutConfiguration::MODE_NETSERVER: mode_str = "netserver"; break; case NutConfiguration::MODE_NETCLIENT: mode_str = "netclient"; break; case NutConfiguration::MODE_CONTROLLED: mode_str = "controlled"; break; case NutConfiguration::MODE_MANUAL: mode_str = "manual"; break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif default: /* Must not occur. */ break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } status = writeDirective("MODE=" + mode_str); if (NUTW_OK != status) return status; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" #endif SHELL_CONFIG_DIRECTIVEX("ALLOW_NO_DEVICE", bool, config.allowNoDevice, false); SHELL_CONFIG_DIRECTIVEX("ALLOW_NOT_ALL_LISTENERS", bool, config.allowNotAllListeners, false); SHELL_CONFIG_DIRECTIVEX("UPSD_OPTIONS", std::string, config.upsdOptions, true); SHELL_CONFIG_DIRECTIVEX("UPSMON_OPTIONS", std::string, config.upsmonOptions, true); SHELL_CONFIG_DIRECTIVEX("POWEROFF_WAIT", unsigned int, config.poweroffWait, false); SHELL_CONFIG_DIRECTIVEX("POWEROFF_QUIET", bool, config.poweroffQuiet, false); SHELL_CONFIG_DIRECTIVEX("NUT_DEBUG_LEVEL", int, config.debugLevel, false); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop #endif return NUTW_OK; } /** Notify types & flags strings */ struct NotifyFlagsStrings { // TBD: Shouldn't this mapping be shared with the parser? // This is an obvious redundancy... /** Notify type strings list */ typedef const char * TypeStrings[UpsmonConfiguration::NOTIFY_TYPE_MAX]; /** Notify flag strings map */ typedef std::map FlagStrings; /** Notify type strings */ static const TypeStrings type_str; /** Notify flag strings */ static const FlagStrings flag_str; /** * \brief Initialize notify flag strings * * \return Notify flag strings map */ static FlagStrings initFlagStrings() { FlagStrings str; str[UpsmonConfiguration::NOTIFY_IGNORE] = "IGNORE"; str[UpsmonConfiguration::NOTIFY_SYSLOG] = "SYSLOG"; str[UpsmonConfiguration::NOTIFY_WALL] = "WALL"; str[UpsmonConfiguration::NOTIFY_EXEC] = "EXEC"; return str; } }; // end of struct NotifyFlagsStrings const NotifyFlagsStrings::TypeStrings NotifyFlagsStrings::type_str = { "ONLINE", // NOTIFY_ONLINE "ONBATT", // NOTIFY_ONBATT "LOWBATT", // NOTIFY_LOWBATT "FSD\t", // NOTIFY_FSD (including padding) "COMMOK", // NOTIFY_COMMOK "COMMBAD", // NOTIFY_COMMBAD "SHUTDOWN", // NOTIFY_SHUTDOWN "REPLBATT", // NOTIFY_REPLBATT "NOCOMM", // NOTIFY_NOCOMM "NOPARENT", // NOTIFY_NOPARENT "CAL\t", // NOTIFY_CAL (including padding) "NOTCAL", // NOTIFY_NOTCAL "OFF\t", // NOTIFY_OFF (including padding) "NOTOFF", // NOTIFY_NOTOFF "BYPASS", // NOTIFY_BYPASS "NOTBYPASS", // NOTIFY_NOTBYPASS "ECO\t", // NOTIFY_ECO (including padding); NOTE: inverter mode, not ups state, for notifications "NOTECO", // NOTIFY_NOTECO "ALARM", // NOTIFY_ALARM "NOTALARM", // NOTIFY_NOTALARM "OVER", // NOTIFY_OVER "NOTOVER", // NOTIFY_NOTOVER "TRIM", // NOTIFY_TRIM "NOTTRIM", // NOTIFY_NOTTRIM "BOOST", // NOTIFY_BOOST "NOTBOOST", // NOTIFY_NOTBOOST "OTHER", // NOTIFY_OTHER "NOTOTHER", // NOTIFY_NOTOTHER "SUSPEND_STARTING", // NOTIFY_SUSPEND_STARTING "SUSPEND_FINISHED", // NOTIFY_SUSPEND_FINISHED }; const NotifyFlagsStrings::FlagStrings NotifyFlagsStrings::flag_str = NotifyFlagsStrings::initFlagStrings(); /** * \brief upsmon notify flags serializer * * \param type Notification type * \param flags Notification flags * * \return NOTIFYFLAG directive string */ static std::string serializeNotifyFlags(UpsmonConfiguration::NotifyType type, unsigned int flags) { static const NotifyFlagsStrings::FlagStrings::const_iterator ignore_str_iter = NotifyFlagsStrings::flag_str.find(UpsmonConfiguration::NOTIFY_IGNORE); static const std::string ignore_str(ignore_str_iter->second); assert(type < UpsmonConfiguration::NOTIFY_TYPE_MAX); std::string directive("NOTIFYFLAG "); directive += NotifyFlagsStrings::type_str[type]; char separator = '\t'; // The IGNORE flag is actually no-flag case if (UpsmonConfiguration::NOTIFY_IGNORE == flags) { directive += separator; directive += ignore_str; return directive; } NotifyFlagsStrings::FlagStrings::const_iterator fl_iter = NotifyFlagsStrings::flag_str.begin(); for (; fl_iter != NotifyFlagsStrings::flag_str.end(); ++fl_iter) { if (fl_iter->first & flags) { directive += separator; directive += fl_iter->second; separator = '+'; } } return directive; } /** * \brief upsmon notify messages serializer * * \param type Notification type * \param msg Notification message * * \return NOTIFYMSG directive string */ static std::string serializeNotifyMessage(UpsmonConfiguration::NotifyType type, const std::string & msg) { assert(type < UpsmonConfiguration::NOTIFY_TYPE_MAX); std::string directive("NOTIFYMSG "); directive += NotifyFlagsStrings::type_str[type]; directive += '\t'; directive += '"' + msg + '"'; return directive; } /** * \brief Get notify type successor * * TBD: Should be in nutconf.hpp * * \param type Notify type * * \return Notify type successor */ inline static UpsmonConfiguration::NotifyType nextNotifyType(UpsmonConfiguration::NotifyType type) { assert(type < UpsmonConfiguration::NOTIFY_TYPE_MAX); int type_ord = static_cast(type); return static_cast(type_ord + 1); } /** * \brief Notify type pre-increment * * TBD: Should be in nutconf.hpp * * \param[in,out] type Notify type * * \return \c type successor */ inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::NotifyType & type) { return type = nextNotifyType(type); } /** * \brief Notify type post-increment * * TBD: Should be in nutconf.hpp * * \param[in,out] type Notify type * * \return \c type */ /* // CURRENTLY UNUSED inline static UpsmonConfiguration::NotifyType operator ++(UpsmonConfiguration::NotifyType & type, int) { UpsmonConfiguration::NotifyType type_copy = type; type = nextNotifyType(type); return type_copy; } */ /** * \brief UPS monitor definition serializer * * \param monitor Monitor * * \return Monitor config. directive */ static std::string serializeMonitor(const UpsmonConfiguration::Monitor & monitor) { std::stringstream directive; directive << "MONITOR "; // System directive << monitor.upsname << '@' << monitor.hostname; if (monitor.port) directive << ':' << monitor.port; directive << ' '; // Power value directive << monitor.powerValue << ' '; // Username & password directive << monitor.username << ' ' << monitor.password << ' '; // Primary/secondary (legacy master/slave) directive << (monitor.isPrimary ? "primary" : "secondary"); /* NUT v2.7.4 and older: directive << (monitor.isPrimary ? "master" : "slave");*/ return directive.str(); } NutWriter::status_t UpsmonConfigWriter::writeConfig(const UpsmonConfiguration & config) { /** * \brief upsmon directive generator * * The macro is locally used to simplify generation of * upsmon config. directives (except those with enumerated * arguments). * * NOTE that the macro may cause return from the function * (upon writing error). * See \ref CONFIG_DIRECTIVEX for more information. * * \param name Directive name * \param arg_t Directive argument implementation type * \param arg Directive argument * \param quote_arg Boolean flag; check to quote the argument */ # define UPSMON_DIRECTIVEX(name, arg_t, arg, quote_arg) \ CONFIG_DIRECTIVEX(name, arg_t, arg, quote_arg) /* The "false" arg in macro below evaluates to `if (false) ...` after * pre-processing, and causes warnings about unreachable code */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" #endif UPSMON_DIRECTIVEX("DEBUG_MIN", int, config.debugMin, false); UPSMON_DIRECTIVEX("RUN_AS_USER", std::string, config.runAsUser, true); UPSMON_DIRECTIVEX("SHUTDOWNCMD", std::string, config.shutdownCmd, true); UPSMON_DIRECTIVEX("NOTIFYCMD", std::string, config.notifyCmd, true); UPSMON_DIRECTIVEX("POWERDOWNFLAG", std::string, config.powerDownFlag, true); UPSMON_DIRECTIVEX("MINSUPPLIES", unsigned int, config.minSupplies, false); UPSMON_DIRECTIVEX("POLLFREQ", unsigned int, config.pollFreq, false); UPSMON_DIRECTIVEX("POLLFREQALERT", unsigned int, config.pollFreqAlert, false); UPSMON_DIRECTIVEX("POLLFAIL_LOG_THROTTLE_MAX", int, config.pollFailLogThrottleMax, false); UPSMON_DIRECTIVEX("OFFDURATION", int, config.offDuration, false); UPSMON_DIRECTIVEX("OBLBDURATION", int, config.oblbDuration, false); UPSMON_DIRECTIVEX("OVERDURATION", int, config.overDuration, false); UPSMON_DIRECTIVEX("SHUTDOWNEXIT", nut::BoolInt, config.shutdownExit, false); UPSMON_DIRECTIVEX("CERTPATH", std::string, config.certPath, true); // Spec says to write these as 0/1 integers // and the macro requires Settable<> // Mumbo-jumbo below for guaranteed casting to int nut::BoolInt bi, bi2; Settable bis; int i; // NOTE: After copy-assignments below (which inherit original strictness), // need to add relaxed mode for 0/1 as false/true handling: // bi.bool01 = true; bi2.bool01 = false; // strict mode for 0/1 as int handling // Avoid static analysis concerns that the internal _value // "may be used uninitialized in this function" (ETOOSMART): bi = false; bi2 = false; if (config.certVerify.set()) { bi = config.certVerify; bi.bool01 = true; i = bi; bi2 = i; bis = bi2; UPSMON_DIRECTIVEX("CERTVERIFY", nut::BoolInt, bis, false); } if (config.forceSsl.set()) { bi = config.forceSsl; bi.bool01 = true; i = bi; bi2 = i; bis = bi2; UPSMON_DIRECTIVEX("FORCESSL", nut::BoolInt, bis, false); } if (config.alarmCritical.set()) { bi = config.alarmCritical; bi.bool01 = true; i = bi; bi2 = i; bis = bi2; UPSMON_DIRECTIVEX("ALARMCRITICAL", nut::BoolInt, bis, false); } UPSMON_DIRECTIVEX("HOSTSYNC", unsigned int, config.hostSync, false); UPSMON_DIRECTIVEX("DEADTIME", unsigned int, config.deadTime, false); UPSMON_DIRECTIVEX("RBWARNTIME", unsigned int, config.rbWarnTime, false); UPSMON_DIRECTIVEX("NOCOMMWARNTIME", unsigned int, config.noCommWarnTime, false); UPSMON_DIRECTIVEX("FINALDELAY", unsigned int, config.finalDelay, false); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop #endif # undef UPSMON_DIRECTIVEX // Certificate identity if (config.certIdent.set()) { std::string directive = serializeCertIdent(config.certIdent); status_t status = writeDirective(directive); if (NUTW_OK != status) return status; } // Remote host(s) protected by specific certificates on their listeners std::list::const_iterator la_iter = config.certHosts.begin(); for (; la_iter != config.certHosts.end(); ++la_iter) { std::string directive = serializeCertHost(*la_iter); status_t status = writeDirective(directive); if (NUTW_OK != status) return status; } UpsmonConfiguration::NotifyType type; // Notify flags type = UpsmonConfiguration::NOTIFY_ONLINE; for (; type < UpsmonConfiguration::NOTIFY_TYPE_MAX; ++type) { if (config.notifyFlags[type].set()) { std::string directive = serializeNotifyFlags(type, config.notifyFlags[type]); status_t status = writeDirective(directive); if (NUTW_OK != status) return status; } } // Notify messages type = UpsmonConfiguration::NOTIFY_ONLINE; for (; type < UpsmonConfiguration::NOTIFY_TYPE_MAX; ++type) { if (config.notifyMessages[type].set()) { std::string directive = serializeNotifyMessage(type, config.notifyMessages[type]); status_t status = writeDirective(directive); if (NUTW_OK != status) return status; } } // Monitors std::list::const_iterator mon_iter = config.monitors.begin(); for (; mon_iter != config.monitors.end(); ++mon_iter) { std::string directive = serializeMonitor(*mon_iter); status_t status = writeDirective(directive); if (NUTW_OK != status) return status; } return NUTW_OK; } /** * \brief upsd listen address serializer * * \param address Listen address * * \return Serialized listen address */ static std::string serializeUpsdListenAddress(const UpsdConfiguration::Listen & address) { std::stringstream directive; directive << "LISTEN " << address.address; if (address.port.set()) directive << ' ' << static_cast(address.port); return directive.str(); } NutWriter::status_t UpsdConfigWriter::writeConfig(const UpsdConfiguration & config) { /** * \brief upsd directive generator * * The macro is locally used to simplify generation of * upsd config. directives (except the listen addresses). * * NOTE that the macro may cause return from the function * (upon writing error). * See \ref CONFIG_DIRECTIVEX for more information. * * \param name Directive name * \param arg_t Directive argument implementation type * \param arg Directive argument */ # define UPSD_DIRECTIVEX(name, arg_t, arg) \ CONFIG_DIRECTIVEX(name, arg_t, arg, false) /* The "false" arg in macro below evaluates to `if (false) ...` after * pre-processing, and causes warnings about unreachable code */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" #endif UPSD_DIRECTIVEX("DEBUG_MIN", int, config.debugMin); UPSD_DIRECTIVEX("MAXAGE", unsigned int, config.maxAge); UPSD_DIRECTIVEX("MAXCONN", unsigned int, config.maxConn); UPSD_DIRECTIVEX("TRACKINGDELAY", unsigned int, config.trackingDelay); UPSD_DIRECTIVEX("ALLOW_NO_DEVICE", bool, config.allowNoDevice); UPSD_DIRECTIVEX("ALLOW_NOT_ALL_LISTENERS", bool, config.allowNotAllListeners); UPSD_DIRECTIVEX("DISABLE_WEAK_SSL", bool, config.disableWeakSsl); CONFIG_DIRECTIVEX("STATEPATH", std::string, config.statePath, true); CONFIG_DIRECTIVEX("CERTFILE", std::string, config.certFile, true); CONFIG_DIRECTIVEX("CERTPATH", std::string, config.certPath, true); UPSD_DIRECTIVEX("CERTREQUEST", unsigned int, config.certRequestLevel); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) # pragma GCC diagnostic pop #endif # undef UPSD_DIRECTIVEX // Certificate identity if (config.certIdent.set()) { std::string directive = serializeCertIdent(config.certIdent); status_t status = writeDirective(directive); if (NUTW_OK != status) return status; } // Listen addresses std::list::const_iterator la_iter = config.listens.begin(); for (; la_iter != config.listens.end(); ++la_iter) { std::string directive = serializeUpsdListenAddress(*la_iter); status_t status = writeDirective(directive); if (NUTW_OK != status) return status; } return NUTW_OK; } NutWriter::status_t DefaultConfigWriter::writeComment(const std::string & str) { return writeEachLine(str, "# "); } NutWriter::status_t DefaultConfigWriter::writeSectionName(const std::string & name) { std::string section_line("["); section_line += name + "]" + eol; return write(section_line); } NutWriter::status_t DefaultConfigWriter::writeDirective(const std::string & str) { return write(str + eol); } /** * \brief Value quoting and escaping * * The function checks whether the value string contains * any spaces and/or '=' characters. * If so, the result is double-quoted and all inner double * quotes shall be escaped using backslash. * * \param val Value string * * \return Value string ready for serialization */ static std::string encodeValue(const std::string & val) { // Check the string for spaces and '=' bool quote = false; for (size_t i = 0; i < val.size() && !quote; ++i) { char ch = val[i]; quote = ' ' == ch || '=' == ch || ':' == ch; } if (!quote) return val; // Quote value and escape inner quotes std::string qval; qval += '"'; for (size_t i = 0; i < val.size(); ++i) { char ch = val[i]; if ('"' == ch) qval += '\\'; qval += ch; } qval += '"'; return qval; } NutWriter::status_t GenericConfigWriter::writeSectionEntry( const GenericConfigSectionEntry & entry, const std::string & indent, const std::string & kv_sep) { ConfigParamList::const_iterator value_iter = entry.values.begin(); for (; value_iter != entry.values.end(); ++value_iter) { std::string value = encodeValue(*value_iter); status_t status = writeDirective(indent + entry.name + kv_sep + value); if (NUTW_OK != status) return status; } return NUTW_OK; } NutWriter::status_t GenericConfigWriter::writeSection(const GenericConfigSection & section) { status_t status; // Note that global scope definitions are in section // with an empty name // The section name won't be written and the assignments // won't be indented std::string indent; if (!section.name.empty()) { status = writeSectionName(section.name); if (NUTW_OK != status) return status; indent += "\t"; } // Write section name/value pairs GenericConfigSection::EntryMap::const_iterator entry_iter = section.entries.begin(); for (; entry_iter != section.entries.end(); ++entry_iter) { status = writeSectionEntry(entry_iter->second, indent); if (NUTW_OK != status) return status; } return NUTW_OK; } NutWriter::status_t GenericConfigWriter::writeConfig(const GenericConfiguration & config) { // Write sections // Note that lexicographic ordering places the global // (i.e. empty-name) section as the first one GenericConfiguration::SectionMap::const_iterator section_iter = config.sections.begin(); for (; section_iter != config.sections.end(); ++section_iter) { status_t status = writeSection(section_iter->second); if (NUTW_OK != status) return status; // TBD: Write one empty line as section separator status = write(eol); if (NUTW_OK != status) return status; } return NUTW_OK; } NutWriter::status_t UpsdUsersConfigWriter::writeSection(const GenericConfigSection & section) { static const std::string upsmon_entry_separator(" "); status_t status; // upsmon section requires special handling because of the upsmon (master|slave) directive if ("upsmon" != section.name) return GenericConfigWriter::writeSection(section); status = writeSectionName(section.name); if (NUTW_OK != status) return status; // Write section name/value pairs GenericConfigSection::EntryMap::const_iterator entry_iter = section.entries.begin(); for (; entry_iter != section.entries.end(); ++entry_iter) { // Special case of upsmon parameter if ("upsmon" == entry_iter->second.name) { status = writeSectionEntry(entry_iter->second, s_default_section_entry_indent, upsmon_entry_separator); } // Standard entry serialization else { status = writeSectionEntry(entry_iter->second); } if (NUTW_OK != status) return status; } return NUTW_OK; } } // end of namespace nut nut-2.8.3/common/Makefile.am0000644000200500020050000001722015001552635012567 00000000000000# Network UPS Tools: common # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ AM_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include AM_CXXFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include AM_LDFLAGS = -no-undefined EXTRA_DIST = CLEANFILES = noinst_LTLIBRARIES = libparseconf.la libcommon.la libcommonclient.la lib_LTLIBRARIES = # We define the recipe below in any case, but only activate it by default # if the build configuration tells us to: if WITH_DEV_LIBNUTCONF # We want it built and delivered (standalone or with tool) lib_LTLIBRARIES += libnutconf.la else !WITH_DEV_LIBNUTCONF if WITH_NUTCONF # We only want the tool, make a private build noinst_LTLIBRARIES += libnutconf.la # else do not build at all, e.g. do not have C++ support endif WITH_NUTCONF endif !WITH_DEV_LIBNUTCONF libparseconf_la_SOURCES = parseconf.c # do not hard depend on '../include/nut_version.h', since it blocks # 'dist', and is only required for actual build, in which case # BUILT_SOURCES (in ../include) will ensure nut_version.h will # be built before anything else... but do depend on its build area: if BUILDING_IN_TREE # No need for symlink hack common.c: $(top_builddir)/include/nut_version.h else !BUILDING_IN_TREE # Surprisingly, for some "make" implementations this dependency means # that the "common.c" required for builds below will be seeked in the # current directory. So for out-of-tree builds like distcheck, we have # to symlink the "real" source to build area. And then when we handle # subsequent dependencies, we already have a filename that "make" now # discovers and is confused about: common.c: $(top_builddir)/include/nut_version.h $(srcdir)/common.c @if [ x"$(abs_top_srcdir)" = x"$(abs_top_builddir)" ] || test -s "$@" ; then \ exit 0 ; \ else \ echo " LN $(top_srcdir)/common/common.c => $@ (relative to `pwd`)" ; \ ln -s -f "$(top_srcdir)/common/common.c" "$@" ; \ fi endif !BUILDING_IN_TREE $(top_builddir)/include/nut_version.h: +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # FIXME: If we maintain some of those helper libs as subsets of the others # (strictly), maybe build the lowest common denominator only and link the # bigger scopes with it (rinse and repeat)? libcommon_la_SOURCES = state.c str.c upsconf.c libcommonclient_la_SOURCES = state.c str.c # several other Makefiles include the two helpers common.c str.c (and # perhaps some other string-related code), so make them a library too; # note that LTLIBOBJS pulls in snprintf.c contents too. noinst_LTLIBRARIES += libcommonstr.la libcommonstr_la_SOURCES = str.c libcommonstr_la_CFLAGS = $(AM_CFLAGS) -DWITHOUT_LIBSYSTEMD=1 libcommonstr_la_LIBADD = @LTLIBOBJS@ @BSDKVMPROCLIBS@ if BUILDING_IN_TREE libcommon_la_SOURCES += common.c libcommonstr_la_SOURCES += common.c libcommonclient_la_SOURCES += common.c else !BUILDING_IN_TREE nodist_libcommon_la_SOURCES = common.c nodist_libcommonstr_la_SOURCES = common.c nodist_libcommonclient_la_SOURCES = common.c CLEANFILES += $(top_builddir)/common/common.c BUILT_SOURCES = common.c endif !BUILDING_IN_TREE if HAVE_STRPTIME EXTRA_DIST += strptime.c else !HAVE_STRPTIME # fall back to NetBSD implem libcommon_la_SOURCES += strptime.c libcommonstr_la_SOURCES += strptime.c libcommonclient_la_SOURCES += strptime.c endif !HAVE_STRPTIME if HAVE_STRNLEN EXTRA_DIST += strnlen.c else !HAVE_STRNLEN # fall back to FreeBSD implem libcommon_la_SOURCES += strnlen.c libcommonstr_la_SOURCES += strnlen.c libcommonclient_la_SOURCES += strnlen.c endif !HAVE_STRNLEN if HAVE_STRSEP EXTRA_DIST += strsep.c else !HAVE_STRSEP # fall back to simple implem libcommon_la_SOURCES += strsep.c libcommonstr_la_SOURCES += strsep.c libcommonclient_la_SOURCES += strsep.c endif !HAVE_STRSEP if WANT_TIMEGM_FALLBACK # fall back to simple implem libcommon_la_SOURCES += timegm_fallback.c libcommonstr_la_SOURCES += timegm_fallback.c libcommonclient_la_SOURCES += timegm_fallback.c else !WANT_TIMEGM_FALLBACK EXTRA_DIST += timegm_fallback.c endif !WANT_TIMEGM_FALLBACK if HAVE_WINDOWS libnutwincompat_la_SOURCES = wincompat.c $(top_srcdir)/include/wincompat.h libnutwincompat_la_LDFLAGS = libnutwincompat_la_LIBADD = # Assume setenv() provided by OS or nut_setenv() provided by # another NUT library and linked to the final NUT program/lib # (anyhow, avoid a link-time conflict with two definitions): libnutwincompat_la_CFLAGS = $(AM_CFLAGS) -DHAVE_SETENV=1 noinst_LTLIBRARIES += libnutwincompat.la libcommon_la_SOURCES += wincompat.c $(top_srcdir)/include/wincompat.h libcommonclient_la_SOURCES += wincompat.c $(top_srcdir)/include/wincompat.h endif HAVE_WINDOWS # ensure inclusion of local implementation of missing systems functions # using LTLIBOBJS. Refer to configure.in/.ac -> AC_REPLACE_FUNCS libcommon_la_LIBADD = libparseconf.la @LTLIBOBJS@ @NETLIBS@ @BSDKVMPROCLIBS@ libcommonclient_la_LIBADD = libparseconf.la @LTLIBOBJS@ @NETLIBS@ @BSDKVMPROCLIBS@ libcommon_la_CFLAGS = $(AM_CFLAGS) libcommonclient_la_CFLAGS = $(AM_CFLAGS) if WITH_LIBNUTCONF if WITH_DEV_LIBNUTCONF # libnutconf version information and build # currently considered a highly experimental and so unstable API at least # (at least, headers contain a lot of data/code, not sure they should) libnutconf_la_LDFLAGS = -version-info 0:1:0 if HAVE_WINDOWS # Many versions of MingW seem to fail to build non-static DLL without this libnutconf_la_LDFLAGS += -no-undefined endif HAVE_WINDOWS endif WITH_DEV_LIBNUTCONF libnutconf_la_CXXFLAGS = $(AM_CXXFLAGS) # NOTE: No @LTLIBOBJS@ here, because libcommonclient.la includes them (if any) libnutconf_la_LIBADD = @NETLIBS@ libcommonclient.la libnutconf_la_SOURCES = nutconf.cpp nutstream.cpp nutwriter.cpp nutipc.cpp \ ../include/nutconf.hpp ../include/nutipc.hpp \ ../include/nutstream.hpp ../include/nutwriter.hpp else !WITH_LIBNUTCONF EXTRA_DIST += nutconf.cpp nutstream.cpp nutwriter.cpp nutipc.cpp endif !WITH_LIBNUTCONF if HAVE_LIBREGEX libcommon_la_CFLAGS += $(LIBREGEX_CFLAGS) libcommon_la_LIBADD += $(LIBREGEX_LIBS) libcommonstr_la_CFLAGS += $(LIBREGEX_CFLAGS) libcommonstr_la_LIBADD += $(LIBREGEX_LIBS) libcommonclient_la_CFLAGS += $(LIBREGEX_CFLAGS) libcommonclient_la_LIBADD += $(LIBREGEX_LIBS) endif HAVE_LIBREGEX # Did the user request, and build env support, tighter integration with # libsystemd methods such as sd_notify()? if WITH_LIBSYSTEMD libcommon_la_CFLAGS += $(LIBSYSTEMD_CFLAGS) libcommon_la_LIBADD += $(LIBSYSTEMD_LIBS) # A typical client should not need this, # but just in case (and to simplify linking)... # libcommonclient_la_CFLAGS += $(LIBSYSTEMD_CFLAGS) # libcommonclient_la_LIBADD += $(LIBSYSTEMD_LIBS) libcommonclient_la_CFLAGS += -DWITHOUT_LIBSYSTEMD=1 endif WITH_LIBSYSTEMD MAINTAINERCLEANFILES = Makefile.in .dirstamp # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! clean-local: if test -L $(builddir)/common.c || test -h $(builddir)/common.c ; then rm -f $(builddir)/common.c ; fi # $(AM_V_at)rm -rf $(builddir)/.deps # Helper for only the enabled libs to get built: all-libs-local: $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) $(EXTRA_LTLIBRARIES) nut-2.8.3/common/common.c0000644000200500020050000040203515001552635012171 00000000000000/* common.c - common useful functions Copyright (C) 2000 Russell Kroll Copyright (C) 2021-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "timehead.h" #include #ifndef WIN32 # include # include # include # include # include #else /* WIN32 */ # include "wincompat.h" # include # include #endif /* WIN32 */ #ifdef HAVE_UNISTD_H # include /* readlink */ #endif #include #if !HAVE_DECL_REALPATH # include #endif #if (defined WITH_LIBSYSTEMD_INHIBITOR) && (defined WITH_LIBSYSTEMD && WITH_LIBSYSTEMD) && (defined WITH_LIBSYSTEMD_INHIBITOR && WITH_LIBSYSTEMD_INHIBITOR) && !(defined(WITHOUT_LIBSYSTEMD) && (WITHOUT_LIBSYSTEMD)) # ifdef HAVE_SYSTEMD_SD_BUS_H # include # endif /* Code below is inspired by https://systemd.io/INHIBITOR_LOCKS/ docs, and * https://github.com/systemd/systemd/issues/34004 discussion which pointed * to https://github.com/systemd/systemd/blob/main/src/login/inhibit.c tool * and https://github.com/systemd/systemd/blob/main/src/basic/errno-util.h etc. * and https://www.freedesktop.org/software/systemd/man/latest/sd_bus_call_method.html */ static int RET_NERRNO(int ret) { if (ret < 0) { if (errno > 0) return -EINVAL; return -errno; } return ret; } /* FIXME: Pedantically speaking, the attribute is assumed supported by GCC * and CLANG; practically - not sure if we have platforms with sufficiently * new libsystemd (its headers and example code also use this) and older or * different compilers. This can be addressed a bit more clumsily directly, * but we only want to do so if needed in real life. */ #define _cleanup_(f) __attribute__((cleanup(f))) /* The "bus_login_mgr" definition per * https://github.com/systemd/systemd/blob/4cf7a676af9a79ff418227d8ff488dfca6f243ab/src/shared/bus-locator.c#L24 */ #define SDBUS_DEST "org.freedesktop.login1" #define SDBUS_PATH "/org/freedesktop/login1" #define SDBUS_IFACE "org.freedesktop.login1.Manager" static /*_cleanup_(sd_bus_flush_close_unrefp)*/ sd_bus *systemd_bus = NULL; static int isSupported_Inhibit = -1, isSupported_Inhibit_errno = 0; static int isSupported_PreparingForSleep = -1, isSupported_PreparingForSleep_errno = 0; static void close_sdbus_once(void) { /* Per https://manpages.debian.org/testing/libsystemd-dev/sd_bus_flush_close_unrefp.3.en.html * these end-of-life methods do not tell us if we succeeded or failed * closing the bus connection in any manner, so we here also do not. */ if (!systemd_bus) { errno = 0; return; } upsdebugx(1, "%s: trying", __func__); errno = 0; sd_bus_flush_close_unrefp(&systemd_bus); systemd_bus = NULL; } static int open_sdbus_once(const char *caller) { static int openedOnce = 0, faultReported = 0; int r = 1; errno = 0; if (systemd_bus) return r; # if defined HAVE_SD_BUS_OPEN_SYSTEM_WITH_DESCRIPTION && HAVE_SD_BUS_OPEN_SYSTEM_WITH_DESCRIPTION r = sd_bus_open_system_with_description(&systemd_bus, "Bus connection for Network UPS Tools sleep/suspend/hibernate handling"); # else r = sd_bus_open_system(&systemd_bus); # endif if (r < 0 || !systemd_bus) { if (r >= 0) { if (!faultReported) upsdebugx(1, "%s: Failed to acquire bus for %s(): " "got null pointer and %d exit-code; setting EINVAL", __func__, NUT_STRARG(caller), r); r = -EINVAL; } else { if (!faultReported) upsdebugx(1, "%s: Failed to acquire bus for %s() (%d): %s", __func__, NUT_STRARG(caller), r, strerror(-r)); } faultReported = 1; } else { upsdebugx(1, "%s: succeeded for %s", __func__, NUT_STRARG(caller)); faultReported = 0; } if (systemd_bus && !openedOnce) { openedOnce = 1; atexit(close_sdbus_once); } if (systemd_bus) { # if !(defined HAVE_SD_BUS_OPEN_SYSTEM_WITH_DESCRIPTION && HAVE_SD_BUS_OPEN_SYSTEM_WITH_DESCRIPTION) # if defined HAVE_SD_BUS_SET_DESCRIPTION && HAVE_SD_BUS_SET_DESCRIPTION if (sd_bus_set_description(systemd_bus, "Bus connection for Network UPS Tools sleep/suspend/hibernate handling") < 0) upsdebugx(1, "%s: failed to sd_bus_set_description(), oh well", __func__); # endif # endif /* second arg for (bool)arg_ask_password - 0 for the non-interactive daemon */ sd_bus_set_allow_interactive_authorization(systemd_bus, 0); } return r; } static int would_reopen_sdbus(int r) { if (r >= 0) return 0; switch (-r) { /* Rule out issues that would not clear themselves (e.g. not stale connections) */ case ENOENT: case EPERM: case EACCES: return 0; default: break; } return 1; } static int reopen_sdbus_once(int r, const char *caller, const char *purpose) { if (r >= 0) return r; switch (-r) { /* Rule out issues that would not clear themselves (e.g. not stale connections) */ case ENOENT: case EPERM: case EACCES: break; /* An "Invalid request descriptor" might fit this bill */ default: upsdebugx(1, "%s for %s() for %s failed (%d) once, will retry D-Bus connection: %s", __func__, caller, purpose, r, strerror(-r)); close_sdbus_once(); r = open_sdbus_once(caller); if (r < 0) { /* Errors, if any, reported above */ return r; } break; } return r; } int isInhibitSupported(void) { return isSupported_Inhibit; } int isPreparingForSleepSupported(void) { return isSupported_PreparingForSleep; } TYPE_FD Inhibit(const char *arg_what, const char *arg_who, const char *arg_why, const char *arg_mode) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; TYPE_FD fd = ERROR_FD; if (isSupported_Inhibit == 0) { /* Already determined that we can not use it, e.g. due to perms */ errno = isSupported_Inhibit_errno; return -errno; } /* Not found in public headers: bool arg_ask_password = true; (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); */ r = open_sdbus_once(__func__); if (r < 0) { /* Errors, if any, reported above */ return r; } r = sd_bus_call_method(systemd_bus, SDBUS_DEST, SDBUS_PATH, SDBUS_IFACE, "Inhibit", &error, &reply, "ssss", arg_what, arg_who, arg_why, arg_mode); if (r < 0) { if (would_reopen_sdbus(r)) { if ((r = reopen_sdbus_once(r, __func__, "sd_bus_call_method()")) < 0) return r; r = sd_bus_call_method(systemd_bus, SDBUS_DEST, SDBUS_PATH, SDBUS_IFACE, "Inhibit", &error, &reply, "ssss", arg_what, arg_who, arg_why, arg_mode); } else { /* Permissions for the privileged operation... did it ever succeed? */ if (isSupported_Inhibit < 0) { upsdebugx(1, "%s: %s() failed seemingly due to permissions, marking %s as not supported", __func__, "sd_bus_call_method", "Inhibit"); isSupported_Inhibit = 0; isSupported_Inhibit_errno = r; } } if (r < 0) { upsdebugx(1, "%s: %s() failed (%d): %s", __func__, "sd_bus_call_method", r, strerror(-r)); if (error.message && *(error.message)) upsdebugx(2, "%s: details from libsystemd: %s", __func__, error.message); return r; } else { upsdebugx(1, "%s: reconnection to D-Bus helped with %s()", __func__, "sd_bus_call_method"); } } r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_UNIX_FD, &fd); if (r < 0) { upsdebugx(1, "%s: %s() failed (%d): %s", __func__, "sd_bus_message_read_basic", r, strerror(-r)); if (isSupported_Inhibit < 0 && !would_reopen_sdbus(r)) { upsdebugx(1, "%s: %s() failed seemingly due to permissions, marking %s as not supported", __func__, "sd_bus_message_read_basic", "Inhibit"); isSupported_Inhibit = 0; isSupported_Inhibit_errno = r; } return r; } /* Data query succeeded, so it is supported */ isSupported_Inhibit = 1; /* NOTE: F_DUPFD_CLOEXEC is in POSIX.1-2008 (Linux 2.6.24); seek out * an alternative sequence of options if needed on older systems */ r = RET_NERRNO(fcntl(fd, F_DUPFD_CLOEXEC, 3)); if (r < 0) { upsdebugx(1, "%s: fcntl() failed (%d): %s", __func__, r, strerror(-r)); return fd; } return r; } void Uninhibit(TYPE_FD *fd_ptr) { if (!fd_ptr) return; if (INVALID_FD(*fd_ptr)) return; /* Closing the socket allows systemd to proceed (we un-inhibit our lock on system * life-cycle handling). After waking up, we should Inhibit() anew, if needed. */ close(*fd_ptr); *fd_ptr = ERROR_FD; } int isPreparingForSleep(void) { static int32_t prev = -1; int32_t val = 0; /* 4-byte int expected for SD_BUS_TYPE_BOOLEAN aka 'b' */ int r; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (isSupported_PreparingForSleep == 0) { /* Already determined that we can not use it, e.g. due to perms */ errno = isSupported_PreparingForSleep_errno; upsdebug_with_errno(8, "%s: isSupported_PreparingForSleep=%d", __func__, isSupported_PreparingForSleep); return -errno; } r = open_sdbus_once(__func__); if (r < 0) { /* Errors, if any, reported above */ return r; } /* @org.freedesktop.DBus.Property.EmitsChangedSignal("false") * readonly b PreparingForSleep = ...; * https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html * https://www.freedesktop.org/software/systemd/man/latest/sd_bus_set_property.html * https://www.freedesktop.org/software/systemd/man/latest/sd_bus_message_append.html (data types) */ r = sd_bus_get_property_trivial(systemd_bus, SDBUS_DEST, SDBUS_PATH, SDBUS_IFACE, "PreparingForSleep", &error, SD_BUS_TYPE_BOOLEAN, &val); if (r < 0) { if (would_reopen_sdbus(r)) { if ((r = reopen_sdbus_once(r, __func__, "sd_bus_get_property_trivial()")) < 0) return r; r = sd_bus_get_property_trivial(systemd_bus, SDBUS_DEST, SDBUS_PATH, SDBUS_IFACE, "PreparingForSleep", &error, 'b', &val); } else { if (isSupported_PreparingForSleep < 0) { upsdebugx(1, "%s: %s() failed seemingly due to permissions, marking %s as not supported", __func__, "sd_bus_get_property_trivial", "PreparingForSleep"); isSupported_PreparingForSleep = 0; isSupported_PreparingForSleep_errno = r; } } if (r < 0) { upsdebugx(1, "%s: %s() failed (%d): %s", __func__, "sd_bus_get_property_trivial", r, strerror(-r)); if (error.message && *(error.message)) upsdebugx(2, "%s: details from libsystemd: %s", __func__, error.message); return r; } else { upsdebugx(1, "%s: reconnection to D-Bus helped with %s()", __func__, "sd_bus_get_property_trivial"); } } /* Data query succeeded, so it is supported */ isSupported_PreparingForSleep = 1; if (val == prev) { /* Unchanged */ upsdebugx(8, "%s: state unchanged", __func__); return -1; } /* First run and not immediately going to sleep, assume unchanged (no-op for upsmon et al) */ if (prev < 0 && !val) { prev = val; upsdebugx(8, "%s: state unchanged (assumed): first run and not immediately going to sleep", __func__); return -1; } /* 0 or 1 */ upsdebugx(8, "%s: state changed): %" PRIi32 " -> %" PRIi32, __func__, prev, val); prev = val; return val; } #else /* not WITH_LIBSYSTEMD_INHIBITOR */ int isInhibitSupported(void) { return 0; } int isPreparingForSleepSupported(void) { return 0; } TYPE_FD Inhibit(const char *arg_what, const char *arg_who, const char *arg_why, const char *arg_mode) { static int reported = 0; NUT_UNUSED_VARIABLE(arg_what); NUT_UNUSED_VARIABLE(arg_who); NUT_UNUSED_VARIABLE(arg_why); NUT_UNUSED_VARIABLE(arg_mode); if (!reported) { upsdebugx(6, "%s: Not implemented on this platform", __func__); reported = 1; } return ERROR_FD; } int isPreparingForSleep(void) { static int reported = 0; if (!reported) { upsdebugx(6, "%s: Not implemented on this platform", __func__); reported = 1; } return -1; } void Uninhibit(TYPE_FD *fd_ptr) { static int reported = 0; NUT_UNUSED_VARIABLE(fd_ptr); if (!reported) { upsdebugx(6, "%s: Not implemented on this platform", __func__); reported = 1; } } #endif /* not WITH_LIBSYSTEMD_INHIBITOR */ #ifdef WITH_LIBSYSTEMD # include /* upsnotify() debug-logs its reports; a watchdog ping is something we * try to send often so report it just once (whether enabled or not) */ static int upsnotify_reported_watchdog_systemd = 0; /* Similarly for only reporting once if the notification subsystem is disabled */ static int upsnotify_reported_disabled_systemd = 0; # ifndef DEBUG_SYSTEMD_WATCHDOG /* Define this to 1 for lots of spam at debug level 6, and ignoring WATCHDOG_PID * so trying to post reports anyway if WATCHDOG_USEC is valid */ # define DEBUG_SYSTEMD_WATCHDOG 0 # endif /* DEBUG_SYSTEMD_WATCHDOG */ #endif /* WITH_LIBSYSTEMD */ /* Similarly for only reporting once if the notification subsystem is not built-in */ static int upsnotify_reported_disabled_notech = 0; static int upsnotify_report_verbosity = -1; /* the reason we define UPS_VERSION as a static string, rather than a macro, is to make dependency tracking easier (only common.o depends on nut_version.h), and also to prevent all sources from having to be recompiled each time the version changes (they only need to be re-linked). */ #include "nut_version.h" const char *UPS_VERSION = NUT_VERSION_MACRO; #include /* Know which bitness we were built for, * to adjust the search paths for get_libname() */ #include "nut_stdint.h" #if defined(UINTPTR_MAX) && (UINTPTR_MAX + 0) == 0xffffffffffffffffULL # define BUILD_64 1 #else # ifdef BUILD_64 # undef BUILD_64 # endif #endif /* https://stackoverflow.com/a/12844426/4715872 */ #include #include #include #if defined(HAVE_LIB_BSD_KVM_PROC) && HAVE_LIB_BSD_KVM_PROC # include # include # include #endif #if defined(HAVE_LIB_ILLUMOS_PROC) && HAVE_LIB_ILLUMOS_PROC # include #endif pid_t get_max_pid_t(void) { #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif if (sizeof(pid_t) == sizeof(short)) return (pid_t)SHRT_MAX; if (sizeof(pid_t) == sizeof(int)) return (pid_t)INT_MAX; if (sizeof(pid_t) == sizeof(long)) return (pid_t)LONG_MAX; #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined _STDC_C99) || (defined __C99FEATURES__) /* C99+ build mode */ # if defined(LLONG_MAX) /* since C99 */ if (sizeof(pid_t) == sizeof(long long)) return (pid_t)LLONG_MAX; # endif #endif abort(); #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif } /* Normally sendsignalfn(), sendsignalpid() and related methods call * upslogx() to report issues such as failed fopen() of PID file, * failed parse of its contents, inability to send a signal (absent * process or some other issue like permissions). * Some of these low-level reports look noisy and scary to users, * others are a bit confusing ("PID file not found... is it bad or * good, what do I do with that knowledge?") so several consuming * programs actually parse the returned codes to formulate their * own messages like "No earlier instance of this daemon was found * running" and users benefit even less from low-level reports. * This variable and its values are a bit of internal detail between * certain NUT programs to hush the low-level reports when they are * not being otherwise debugged (e.g. nut_debug_level < 1). * Default value allows all those messages to appear. */ int nut_sendsignal_debug_level = NUT_SENDSIGNAL_DEBUG_LEVEL_DEFAULT; int nut_debug_level = 0; int nut_log_level = 0; static int upslog_flags = UPSLOG_STDERR; static struct timeval upslog_start = { 0, 0 }; static void xbit_set(int *val, int flag) { *val |= flag; } static void xbit_clear(int *val, int flag) { *val ^= (*val & flag); } static int xbit_test(int val, int flag) { return ((val & flag) == flag); } int syslog_is_disabled(void) { static int value = -1; if (value < 0) { char *s = getenv("NUT_DEBUG_SYSLOG"); /* Not set or not disabled by the setting: default is enabled (inversed per method name) */ value = 0; if (s) { if (!strcmp(s, "stderr")) { value = 1; } else if (!strcmp(s, "none") || !strcmp(s, "false")) { value = 2; } else if (!strcmp(s, "syslog") || !strcmp(s, "true") || !strcmp(s, "default")) { /* Just reserve a value to quietly do the default */ value = 0; } else { upsdebugx(0, "%s: unknown NUT_DEBUG_SYSLOG='%s' value, ignored (assuming enabled)", __func__, s); } } } return value; } int banner_is_disabled(void) { static int value = -1; if (value < 0) { char *s = getenv("NUT_QUIET_INIT_BANNER"); /* Envvar present and empty or true-ish means NUT tool name+version * banners disabled by the setting: default is enabled (inversed per * method name) */ value = 0; if (s) { if (*s == '\0' || !strcasecmp(s, "true") || strcmp(s, "1")) { value = 1; } } } return value; } const char *describe_NUT_VERSION_once(void) { static char buf[LARGEBUF]; static const char *printed = NULL; if (printed) return printed; memset(buf, 0, sizeof(buf)); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif /* NOTE: Some compilers deduce that macro-based decisions about * NUT_VERSION_IS_RELEASE make one of codepaths unreachable in * a particular build. So we pragmatically handwave this away. */ if (1 < snprintf(buf, sizeof(buf), "%s %s%s%s", NUT_VERSION_MACRO, NUT_VERSION_IS_RELEASE ? "release" : (NUT_VERSION_IS_PRERELEASE ? "(pre-release iteration of " : "(development iteration after "), NUT_VERSION_IS_RELEASE ? "" : NUT_VERSION_SEMVER_MACRO, NUT_VERSION_IS_RELEASE ? "" : ")" )) { printed = buf; } else { upslogx(LOG_WARNING, "%s: failed to report detailed NUT version", __func__); printed = UPS_VERSION; } #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif return printed; } int print_banner_once(const char *prog, int even_if_disabled) { static int printed = 0; static int ret = -1; if (printed) return ret; if (!banner_is_disabled() || even_if_disabled) { ret = printf("Network UPS Tools %s %s%s\n", prog, describe_NUT_VERSION_once(), even_if_disabled == 2 ? "\n" : ""); fflush(stdout); if (ret > 0) printed = 1; } return ret; } const char *suggest_doc_links(const char *progname, const char *progconf) { static char buf[LARGEBUF]; buf[0] = '\0'; if (progname) { char *s = NULL, *buf2 = xstrdup(xbasename(progname)); size_t i; for (i = 0; buf2[i]; i++) { buf2[i] = tolower((unsigned char)(buf2[i])); } if ((s = strstr(buf2, ".exe")) && strcmp(buf2, "nut.exe")) *s = '\0'; snprintf(buf, sizeof(buf), "For more information please "); #if defined(WITH_DOCS) && WITH_DOCS /* FIXME: Currently all NUT tools and drivers are in same * man page section for "System Management Programs". * If this ever changes (e.g. clients like `upsc` can be * a "User Program" just as well), we may need an extra method argument here. */ snprintfcat(buf, sizeof(buf), "Read The Fine Manual ('man %s %s') and/or ", MAN_SECTION_CMD_SYS, buf2); #endif snprintfcat(buf, sizeof(buf), "see\n\t%s/docs/man/%s.html\n", NUT_WEBSITE_BASE, buf2); free(buf2); } if (progconf) snprintfcat(buf, sizeof(buf), "%s check documentation and samples of %s\n", progname ? "Also" : "Please", progconf); return buf; } /* enable writing upslog_with_errno() and upslogx() type messages to the syslog */ void syslogbit_set(void) { if (!syslog_is_disabled()) xbit_set(&upslog_flags, UPSLOG_SYSLOG); } /* get the syslog ready for us */ void open_syslog(const char *progname) { #ifndef WIN32 int opt; if (syslog_is_disabled()) return; opt = LOG_PID; /* we need this to grab /dev/log before chroot */ # ifdef LOG_NDELAY opt |= LOG_NDELAY; # endif /* LOG_NDELAY */ openlog(progname, opt, LOG_FACILITY); switch (nut_log_level) { #if HAVE_SETLOGMASK && HAVE_DECL_LOG_UPTO case 7: setlogmask(LOG_UPTO(LOG_EMERG)); /* system is unusable */ break; case 6: setlogmask(LOG_UPTO(LOG_ALERT)); /* action must be taken immediately */ break; case 5: setlogmask(LOG_UPTO(LOG_CRIT)); /* critical conditions */ break; case 4: setlogmask(LOG_UPTO(LOG_ERR)); /* error conditions */ break; case 3: setlogmask(LOG_UPTO(LOG_WARNING)); /* warning conditions */ break; case 2: setlogmask(LOG_UPTO(LOG_NOTICE)); /* normal but significant condition */ break; case 1: setlogmask(LOG_UPTO(LOG_INFO)); /* informational */ break; case 0: setlogmask(LOG_UPTO(LOG_DEBUG)); /* debug-level messages */ break; default: fatalx(EXIT_FAILURE, "Invalid log level threshold"); # else case 0: break; default: upslogx(LOG_INFO, "Changing log level threshold not possible"); break; # endif /* HAVE_SETLOGMASK && HAVE_DECL_LOG_UPTO */ } #else /* WIN32 */ EventLogName = progname; #endif /* WIN32 */ } /* close ttys and become a daemon */ void background(void) { /* Normally we enable SYSLOG and disable STDERR, * unless NUT_DEBUG_SYSLOG envvar interferes as * interpreted in syslog_is_disabled() method: */ int syslog_disabled = syslog_is_disabled(), stderr_disabled = (syslog_disabled == 0 || syslog_disabled == 2); #ifndef WIN32 int pid; if ((pid = fork()) < 0) fatal_with_errno(EXIT_FAILURE, "Unable to enter background"); #endif /* !WIN32 */ if (!syslog_disabled) /* not disabled: NUT_DEBUG_SYSLOG is unset or invalid */ xbit_set(&upslog_flags, UPSLOG_SYSLOG); if (stderr_disabled) /* NUT_DEBUG_SYSLOG="none" or unset/invalid */ xbit_clear(&upslog_flags, UPSLOG_STDERR); #ifndef WIN32 if (pid != 0) { /* parent */ /* these are typically fds 0-2: */ close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); _exit(EXIT_SUCCESS); } /* child */ /* make fds 0-2 (typically) point somewhere defined */ # ifdef HAVE_DUP2 /* system can close (if needed) and (re-)open a specific FD number */ if (1) { /* scoping */ TYPE_FD devnull = open("/dev/null", O_RDWR); if (devnull < 0) fatal_with_errno(EXIT_FAILURE, "open /dev/null"); if (dup2(devnull, STDIN_FILENO) != STDIN_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDIN"); if (dup2(devnull, STDOUT_FILENO) != STDOUT_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDOUT"); if (stderr_disabled) { if (dup2(devnull, STDERR_FILENO) != STDERR_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDERR"); } close(devnull); } # else # ifdef HAVE_DUP /* opportunistically duplicate to the "lowest-available" FD number */ close(STDIN_FILENO); if (open("/dev/null", O_RDWR) != STDIN_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDIN"); close(STDOUT_FILENO); if (dup(STDIN_FILENO) != STDOUT_FILENO) fatal_with_errno(EXIT_FAILURE, "dup /dev/null as STDOUT"); if (stderr_disabled) { close(STDERR_FILENO); if (dup(STDIN_FILENO) != STDERR_FILENO) fatal_with_errno(EXIT_FAILURE, "dup /dev/null as STDERR"); } # else close(STDIN_FILENO); if (open("/dev/null", O_RDWR) != STDIN_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDIN"); close(STDOUT_FILENO); if (open("/dev/null", O_RDWR) != STDOUT_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDOUT"); if (stderr_disabled) { close(STDERR_FILENO); if (open("/dev/null", O_RDWR) != STDERR_FILENO) fatal_with_errno(EXIT_FAILURE, "re-open /dev/null as STDERR"); } # endif # endif # ifdef HAVE_SETSID setsid(); /* make a new session to dodge signals */ # endif #else /* WIN32 */ NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE(); #endif /* WIN32 */ upslogx(LOG_INFO, "Startup successful"); } /* do this here to keep pwd/grp stuff out of the main files */ struct passwd *get_user_pwent(const char *name) { #ifndef WIN32 struct passwd *r; errno = 0; if ((r = getpwnam(name))) return r; /* POSIX does not specify that "user not found" is an error, so some implementations of getpwnam() do not set errno when this happens. */ if (errno == 0) fatalx(EXIT_FAILURE, "OS user %s not found", name); else fatal_with_errno(EXIT_FAILURE, "getpwnam(%s)", name); #else /* WIN32 */ NUT_UNUSED_VARIABLE(name); /* NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE(); */ #endif /* WIN32 */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN) ) #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN #pragma GCC diagnostic ignored "-Wunreachable-code-return" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" # ifdef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN # pragma clang diagnostic ignored "-Wunreachable-code-return" # endif #endif /* Oh joy, adding unreachable "return" to make one compiler happy, * and pragmas around to make other compilers happy, all at once! */ return NULL; #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) || (defined HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN) ) #pragma GCC diagnostic pop #endif } /* change to the user defined in the struct */ void become_user(struct passwd *pw) { #ifndef WIN32 /* if we can't switch users, then don't even try */ intmax_t initial_uid = getuid(); intmax_t initial_euid = geteuid(); if (!pw) { upsdebugx(1, "Can not become_user(), skipped"); return; } if ((initial_euid != 0) && (initial_uid != 0)) { intmax_t initial_gid = getgid(); if (initial_euid == (intmax_t)pw->pw_uid || initial_uid == (intmax_t)pw->pw_uid ) { upsdebugx(1, "No need to become_user(%s): " "already UID=%jd GID=%jd", pw->pw_name, initial_uid, initial_gid); } else { upsdebugx(1, "Can not become_user(%s): " "not root initially, " "remaining UID=%jd GID=%jd", pw->pw_name, initial_uid, initial_gid); } return; } if (initial_uid == 0) if (seteuid(0)) fatal_with_errno(EXIT_FAILURE, "getuid gave 0, but seteuid(0) failed"); if (initgroups(pw->pw_name, pw->pw_gid) == -1) fatal_with_errno(EXIT_FAILURE, "initgroups"); if (setgid(pw->pw_gid) == -1) fatal_with_errno(EXIT_FAILURE, "setgid"); if (setuid(pw->pw_uid) == -1) fatal_with_errno(EXIT_FAILURE, "setuid"); upsdebugx(1, "Succeeded to become_user(%s): now UID=%jd GID=%jd", pw->pw_name, (intmax_t)getuid(), (intmax_t)getgid()); #else /* WIN32 */ /* NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE(); */ upsdebugx(1, "Can not become_user(%s): not implemented on this platform", pw ? pw->pw_name : ""); #endif /* WIN32 */ } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic push #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtype-limits" #endif #if (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* drop down into a directory and throw away pointers to the old path */ void chroot_start(const char *path) { if (chdir(path)) fatal_with_errno(EXIT_FAILURE, "chdir(%s)", path); #ifndef WIN32 if (chroot(path)) fatal_with_errno(EXIT_FAILURE, "chroot(%s)", path); #else /* WIN32 */ /* NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE(); */ upsdebugx(1, "Can not chroot into %s: not implemented on this platform", path); #endif /* WIN32 */ if (chdir("/")) fatal_with_errno(EXIT_FAILURE, "chdir(/)"); #ifndef WIN32 upsdebugx(1, "chrooted into %s", path); #endif /* !WIN32 */ } char * getprocname(pid_t pid) { /* Try to identify process (program) name for the given PID, * return NULL if we can not for any reason (does not run, * no rights, do not know how to get it on current OS, etc.) * If the returned value is not NULL, caller should free() it. * Some implementation pieces borrowed from * https://man7.org/linux/man-pages/man2/readlink.2.html and * https://github.com/openbsd/src/blob/master/bin/ps/ps.c * NOTE: Very much platform-dependent! */ char *procname = NULL; size_t procnamelen = 0; char pathname[NUT_PATH_MAX + 1]; struct stat st; #ifdef WIN32 /* Try Windows API calls, then fall through to /proc emulation in MinGW/MSYS2 * https://stackoverflow.com/questions/1591342/c-how-to-determine-if-a-windows-process-is-running * http://cppip.blogspot.com/2013/01/check-if-process-is-running.html */ upsdebugx(5, "%s: begin to query WIN32 process info", __func__); HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)pid); if (process) { DWORD ret = GetModuleFileNameExA( process, /* hProcess */ NULL, /* hModule */ (LPSTR)pathname, (DWORD)(sizeof(pathname)) ); CloseHandle(process); pathname[sizeof(pathname) - 1] = '\0'; if (ret) { /* length of the string copied to the buffer */ procnamelen = strlen(pathname); upsdebugx(3, "%s: try to parse the name from WIN32 process info", __func__); if (ret != procnamelen) { upsdebugx(3, "%s: length mismatch getting WIN32 process info: %" PRIuMAX " vs. " PRIuSIZE, __func__, (uintmax_t)ret, procnamelen); } if ((procname = (char*)calloc(procnamelen + 1, sizeof(char)))) { if (snprintf(procname, procnamelen + 1, "%s", pathname) < 1) { upsdebug_with_errno(3, "%s: failed to snprintf procname: WIN32-like", __func__); } else { goto finish; } } else { upsdebug_with_errno(3, "%s: failed to allocate the procname " "string to store token from WIN32 size %" PRIuSIZE, __func__, procnamelen); } /* Fall through to try /proc etc. if available */ } else { LPVOID WinBuf; DWORD WinErr = GetLastError(); FormatMessage( FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, WinErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &WinBuf, 0, NULL ); upsdebugx(3, "%s: failed to get WIN32 process info: %s", __func__, (char *)WinBuf); LocalFree(WinBuf); } } #endif /* WIN32 */ if (stat("/proc", &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR)) { upsdebugx(3, "%s: /proc is an accessible directory, investigating", __func__); #if (defined HAVE_READLINK) && HAVE_READLINK /* Linux-like */ if (snprintf(pathname, sizeof(pathname), "/proc/%" PRIuMAX "/exe", (uintmax_t)pid) < 10) { upsdebug_with_errno(3, "%s: failed to snprintf pathname: Linux-like", __func__); goto finish; } if (lstat(pathname, &st) == 0) { goto process_stat_symlink; } /* FreeBSD-like */ if (snprintf(pathname, sizeof(pathname), "/proc/%" PRIuMAX "/file", (uintmax_t)pid) < 10) { upsdebug_with_errno(3, "%s: failed to snprintf pathname: FreeBSD-like", __func__); goto finish; } if (lstat(pathname, &st) == 0) { goto process_stat_symlink; } goto process_parse_file; process_stat_symlink: upsdebugx(3, "%s: located symlink for PID %" PRIuMAX " at: %s", __func__, (uintmax_t)pid, pathname); /* Some magic symlinks under (for example) /proc and /sys * report 'st_size' as zero. In that case, take PATH_MAX * or equivalent as a "good enough" estimate. */ if (st.st_size) { /* Add one for ending '\0' */ procnamelen = st.st_size + 1; } else { procnamelen = sizeof(pathname); } /* Not xcalloc() here, not too fatal if we fail */ procname = (char*)calloc(procnamelen, sizeof(char)); if (procname) { int nbytes = readlink(pathname, procname, procnamelen); if (nbytes < 0) { upsdebug_with_errno(1, "%s: failed to readlink() from %s", __func__, pathname); free(procname); procname = NULL; goto process_parse_file; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif if ((unsigned int)nbytes > SIZE_MAX || procnamelen <= (size_t)nbytes) { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE) ) # pragma GCC diagnostic pop #endif upsdebugx(1, "%s: failed to readlink() from %s: may have been truncated", __func__, pathname); free(procname); procname = NULL; goto process_parse_file; } /* Got a useful reply */ procname[nbytes] = '\0'; goto finish; } else { upsdebug_with_errno(3, "%s: failed to allocate the procname string " "to readlink() size %" PRIuSIZE, __func__, procnamelen); goto finish; } #else upsdebugx(3, "%s: this platform does not have readlink(), skipping this method", __func__); goto process_parse_file; #endif /* HAVE_READLINK */ process_parse_file: upsdebugx(5, "%s: try to parse some files under /proc", __func__); /* Check /proc/NNN/cmdline (may start with a '-' to ignore, for * a title string like "-bash" where programs edit their argv[0] * (Linux-like OSes at least). Inspired by * https://gist.github.com/evanslai/30c6d588a80222f665f10b4577dadd61 */ if (snprintf(pathname, sizeof(pathname), "/proc/%" PRIuMAX "/cmdline", (uintmax_t)pid) < 10) { upsdebug_with_errno(3, "%s: failed to snprintf pathname: Linux-like", __func__); goto finish; } if (stat(pathname, &st) == 0) { FILE* fp = fopen(pathname, "r"); if (fp) { char buf[sizeof(pathname)]; if (fgets(buf, sizeof(buf), fp) != NULL) { /* check the first token in the file, the program name */ char* first = strtok(buf, " "); fclose(fp); if (first) { if (*first == '-') first++; /* Not xcalloc() here, not too fatal if we fail */ if ((procnamelen = strlen(first))) { upsdebugx(3, "%s: try to parse some files under /proc: processing %s", __func__, pathname); if ((procname = (char*)calloc(procnamelen + 1, sizeof(char)))) { if (snprintf(procname, procnamelen + 1, "%s", first) < 1) { upsdebug_with_errno(3, "%s: failed to snprintf procname: Linux-like", __func__); } } else { upsdebug_with_errno(3, "%s: failed to allocate the procname " "string to store token from 'cmdline' size %" PRIuSIZE, __func__, procnamelen); } goto finish; } } } else { fclose(fp); } } } /* Check /proc/NNN/stat (second token, in parentheses, may be truncated) * see e.g. https://stackoverflow.com/a/12675103/4715872 */ if (snprintf(pathname, sizeof(pathname), "/proc/%" PRIuMAX "/stat", (uintmax_t)pid) < 10) { upsdebug_with_errno(3, "%s: failed to snprintf pathname: Linux-like", __func__); goto finish; } if (stat(pathname, &st) == 0) { FILE* fp = fopen(pathname, "r"); if (fp) { long spid; char sstate; char buf[sizeof(pathname)]; memset (buf, 0, sizeof(buf)); if ( (fscanf(fp, "%ld (%[^)]) %c", &spid, buf, &sstate)) == 3 ) { /* Some names can be pretty titles like "init(Ubuntu)" * or "Relay(223)". Or truncated like "docker-desktop-". * Tokenize by "(" " " and extract the first token to * address the former "problem", not too much we can * do about the latter except for keeping NUT program * names concise. */ char* first = strtok(buf, "( "); fclose(fp); if (first) { /* Not xcalloc() here, not too fatal if we fail */ if ((procnamelen = strlen(first))) { upsdebugx(3, "%s: try to parse some files under /proc: processing %s " "(WARNING: may be truncated)", __func__, pathname); if ((procname = (char*)calloc(procnamelen + 1, sizeof(char)))) { if (snprintf(procname, procnamelen + 1, "%s", first) < 1) { upsdebug_with_errno(3, "%s: failed to snprintf procname: Linux-like", __func__); } } else { upsdebug_with_errno(3, "%s: failed to allocate the procname " "string to store token from 'stat' size %" PRIuSIZE, __func__, procnamelen); } goto finish; } } } else { fclose(fp); } } } #if defined(HAVE_LIB_ILLUMOS_PROC) && HAVE_LIB_ILLUMOS_PROC /* Solaris/illumos: parse binary structure at /proc/NNN/psinfo */ if (snprintf(pathname, sizeof(pathname), "/proc/%" PRIuMAX "/psinfo", (uintmax_t)pid) < 10) { upsdebug_with_errno(3, "%s: failed to snprintf pathname: Solaris/illumos-like", __func__); goto finish; } if (stat(pathname, &st) == 0) { FILE* fp = fopen(pathname, "r"); if (!fp) { upsdebug_with_errno(3, "%s: try to parse '%s':" "fopen() returned NULL", __func__, pathname); } else { psinfo_t info; /* process information from /proc */ size_t r; memset (&info, 0, sizeof(info)); r = fread((char *)&info, sizeof (info), 1, fp); if (r != 1) { upsdebug_with_errno(3, "%s: try to parse '%s': " "unexpected read size: got %" PRIuSIZE " record(s) from file of size %" PRIuMAX " vs. 1 piece of %" PRIuSIZE " struct size", __func__, pathname, r, (uintmax_t)st.st_size, sizeof (info)); fclose(fp); } else { fclose(fp); /* Not xcalloc() here, not too fatal if we fail */ if ((procnamelen = strlen(info.pr_fname))) { upsdebugx(3, "%s: try to parse some files under /proc: processing %s", __func__, pathname); if ((procname = (char*)calloc(procnamelen + 1, sizeof(char)))) { if (snprintf(procname, procnamelen + 1, "%s", info.pr_fname) < 1) { upsdebug_with_errno(3, "%s: failed to snprintf pathname: Solaris/illumos-like", __func__); } } else { upsdebug_with_errno(3, "%s: failed to allocate the procname " "string to store token from 'psinfo' size %" PRIuSIZE, __func__, procnamelen); } goto finish; } } } } #endif } else { upsdebug_with_errno(3, "%s: /proc is not a directory or not accessible", __func__); } #if defined(HAVE_LIB_BSD_KVM_PROC) && HAVE_LIB_BSD_KVM_PROC /* OpenBSD, maybe other BSD: no /proc; use API call, see ps.c link above and * https://kaashif.co.uk/2015/06/18/how-to-get-a-list-of-processes-on-openbsd-in-c/ */ if (!procname) { char errbuf[_POSIX2_LINE_MAX]; kvm_t *kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); upsdebugx(3, "%s: try to parse BSD KVM process info snapsnot", __func__); if (!kd) { upsdebugx(3, "%s: try to parse BSD KVM process info snapsnot: " "kvm_openfiles() returned NULL", __func__); } else { int nentries = 0; struct kinfo_proc *kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(*kp), &nentries); if (!kp) { upsdebugx(3, "%s: try to parse BSD KVM process info snapsnot: " "kvm_getprocs() returned NULL", __func__); } else { int i; if (nentries != 1) upsdebugx(3, "%s: expected to get 1 reply from BSD kvm_getprocs but got %d", __func__, nentries); for (i = 0; i < nentries; i++) { upsdebugx(5, "%s: processing reply #%d from BSD" " kvm_getprocs: pid=%" PRIuMAX " name='%s'", __func__, i, (uintmax_t)kp[i].p_pid, kp[i].p_comm); if ((uintmax_t)(kp[i].p_pid) == (uintmax_t)pid) { /* Not xcalloc() here, not too fatal if we fail */ if ((procnamelen = strlen(kp[i].p_comm))) { if ((procname = (char*)calloc(procnamelen + 1, sizeof(char)))) { if (snprintf(procname, procnamelen + 1, "%s", kp[i].p_comm) < 1) { upsdebug_with_errno(3, "%s: failed to snprintf procname: BSD-like", __func__); } } else { upsdebug_with_errno(3, "%s: failed to allocate the procname " "string to store token from BSD KVM process info " "snapsnot size %" PRIuSIZE, __func__, procnamelen); } goto finish; } } } } } } #endif /* HAVE_LIB_BSD_KVM_PROC */ goto finish; finish: if (procname) { procnamelen = strlen(procname); if (procnamelen == 0) { free(procname); procname = NULL; } else { upsdebugx(1, "%s: determined process name for PID %" PRIuMAX ": %s", __func__, (uintmax_t)pid, procname); } } if (!procname) { upsdebugx(1, "%s: failed to determine process name for PID %" PRIuMAX, __func__, (uintmax_t)pid); } return procname; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && (!defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif size_t parseprogbasename(char *buf, size_t buflen, const char *progname, size_t *pprogbasenamelen, size_t *pprogbasenamedot) { size_t i, progbasenamelen = 0, progbasenamedot = 0; if (pprogbasenamelen) *pprogbasenamelen = 0; if (pprogbasenamedot) *pprogbasenamedot = 0; if (!buf || !progname || !buflen || progname[0] == '\0') return 0; for (i = 0; i < buflen && progname[i] != '\0'; i++) { if (progname[i] == '/' #ifdef WIN32 || progname[i] == '\\' #endif /* WIN32 */ ) { progbasenamelen = 0; progbasenamedot = 0; continue; } if (progname[i] == '.') progbasenamedot = progbasenamelen; buf[progbasenamelen++] = progname[i]; } buf[progbasenamelen] = '\0'; buf[buflen - 1] = '\0'; if (pprogbasenamelen) *pprogbasenamelen = progbasenamelen; if (pprogbasenamedot) *pprogbasenamedot = progbasenamedot; return progbasenamelen; } int checkprocname_ignored(const char *caller) { char *s = NULL; if ((s = getenv("NUT_IGNORE_CHECKPROCNAME"))) { /* FIXME: Make server/conf.c::parse_boolean() reusable */ if ( (!strcasecmp(s, "true")) || (!strcasecmp(s, "on")) || (!strcasecmp(s, "yes")) || (!strcasecmp(s, "1"))) { upsdebugx(1, "%s for %s: skipping because caller set NUT_IGNORE_CHECKPROCNAME", __func__, NUT_STRARG(caller)); return 1; } } return 0; } int compareprocname(pid_t pid, const char *procname, const char *progname) { /* Given the binary path name of (presumably) a running process, * check if it matches the assumed name of the current program. * The "pid" value is used in log reporting. * Returns: * -3 Skipped because NUT_IGNORE_CHECKPROCNAME is set * -2 Could not parse a program name (ok to proceed, * risky - but matches legacy behavior) * -1 Could not identify a program name (ok to proceed, * risky - but matches legacy behavior) * 0 Process name identified, does not seem to match * 1+ Process name identified, and seems to match with * varying precision * Generally speaking, if (compareprocname(...)) then ok to proceed */ int ret = -127; size_t procbasenamelen = 0, progbasenamelen = 0; /* Track where the last dot is in the basename; 0 means none */ size_t procbasenamedot = 0, progbasenamedot = 0; char procbasename[NUT_PATH_MAX + 1], progbasename[NUT_PATH_MAX + 1]; if (checkprocname_ignored(__func__)) { ret = -3; goto finish; } if (!procname || !progname) { ret = -1; goto finish; } /* First quickly try for an exact hit (possible dir names included) */ if (!strcmp(procname, progname)) { ret = 1; goto finish; } /* Parse the basenames apart */ if (!parseprogbasename(progbasename, sizeof(progbasename), progname, &progbasenamelen, &progbasenamedot) || !parseprogbasename(procbasename, sizeof(procbasename), procname, &procbasenamelen, &procbasenamedot) ) { ret = -2; goto finish; } /* First quickly try for an exact hit of base names */ if (progbasenamelen == procbasenamelen && progbasenamedot == procbasenamedot && !strcmp(procbasename, progbasename)) { ret = 2; goto finish; } /* Check for executable program filename extensions and/or case-insensitive * matching on some platforms */ #ifdef WIN32 if (!strcasecmp(procname, progname)) { ret = 3; goto finish; } if (!strcasecmp(procbasename, progbasename)) { ret = 4; goto finish; } if (progbasenamedot == procbasenamedot || !progbasenamedot || !procbasenamedot) { /* Same base name before ext, maybe different casing or absence of ext in one of them */ size_t dot = progbasenamedot ? progbasenamedot : procbasenamedot; if (!strncasecmp(progbasename, procbasename, dot - 1) && ( (progbasenamedot && !strcasecmp(progbasename + progbasenamedot, ".exe")) || (procbasenamedot && !strcasecmp(procbasename + procbasenamedot, ".exe")) ) ) { ret = 5; goto finish; } } #endif /* WIN32 */ /* TOTHINK: Developer builds wrapped with libtool may be prefixed * by "lt-" in the filename. Should we re-enter (or wrap around) * this search with a set of variants with/without the prefix on * both sides?.. */ /* Nothing above has matched */ ret = 0; finish: switch (ret) { case 5: upsdebugx(1, "%s: case-insensitive base name hit with " "an executable program extension involved for " "PID %" PRIuMAX " of '%s'=>'%s' and checked " "'%s'=>'%s'", __func__, (uintmax_t)pid, procname, procbasename, progname, progbasename); break; case 4: upsdebugx(1, "%s: case-insensitive base name hit for PID %" PRIuMAX " of '%s'=>'%s' and checked '%s'=>'%s'", __func__, (uintmax_t)pid, procname, procbasename, progname, progbasename); break; case 3: upsdebugx(1, "%s: case-insensitive full name hit for PID %" PRIuMAX " of '%s' and checked '%s'", __func__, (uintmax_t)pid, procname, progname); break; case 2: upsdebugx(1, "%s: case-sensitive base name hit for PID %" PRIuMAX " of '%s'=>'%s' and checked '%s'=>'%s'", __func__, (uintmax_t)pid, procname, procbasename, progname, progbasename); break; case 1: upsdebugx(1, "%s: exact case-sensitive full name hit for PID %" PRIuMAX " of '%s' and checked '%s'", __func__, (uintmax_t)pid, procname, progname); break; case 0: upsdebugx(1, "%s: did not find any match of program names " "for PID %" PRIuMAX " of '%s'=>'%s' and checked " "'%s'=>'%s'", __func__, (uintmax_t)pid, procname, procbasename, progname, progbasename); break; case -1: /* failed to getprocname(), logged above in it */ break; case -2: upsdebugx(1, "%s: failed to parse base names of the programs", __func__); break; case -3: /* skipped due to envvar, logged above */ break; default: upsdebugx(1, "%s: unexpected result looking for process name " "of PID %" PRIuMAX ": %d", __func__, (uintmax_t)pid, ret); ret = -127; break; } return ret; } int checkprocname(pid_t pid, const char *progname) { /* If we can determine the binary path name of the specified "pid", * check if it matches the assumed name of the current program. * Returns: same as compareprocname() * Generally speaking, if (checkprocname(...)) then ok to proceed */ char *procname = NULL; int ret = 0; /* Quick skip before drilling into getprocname() */ if (checkprocname_ignored(__func__)) { ret = -3; goto finish; } if (!progname) { ret = -1; goto finish; } procname = getprocname(pid); if (!procname) { ret = -1; goto finish; } ret = compareprocname(pid, procname, progname); finish: if (procname) free(procname); return ret; } #ifdef WIN32 /* In WIN32 all non binaries files (namely configuration and PID files) are retrieved relative to the path of the binary itself. So this function fill "dest" with the full path to "relative_path" depending on the .exe path */ char * getfullpath(char * relative_path) { char buf[NUT_PATH_MAX + 1]; if ( GetModuleFileName(NULL, buf, sizeof(buf)) == 0 ) { return NULL; } /* remove trailing executable name and its preceeding slash */ char * last_slash = strrchr(buf, '\\'); *last_slash = '\0'; if( relative_path ) { strncat(buf, relative_path, sizeof(buf) - 1); } return(xstrdup(buf)); } #endif /* WIN32 */ /* drop off a pidfile for this process */ void writepid(const char *name) { #ifndef WIN32 char fn[NUT_PATH_MAX + 1]; FILE *pidf; mode_t mask; /* use full path if present, else build filename in PIDPATH */ if (*name == '/') snprintf(fn, sizeof(fn), "%s", name); else snprintf(fn, sizeof(fn), "%s/%s.pid", rootpidpath(), name); mask = umask(022); pidf = fopen(fn, "w"); if (pidf) { intmax_t pid = (intmax_t)getpid(); upsdebugx(1, "Saving PID %" PRIdMAX " into %s", pid, fn); fprintf(pidf, "%" PRIdMAX "\n", pid); fclose(pidf); } else { upslog_with_errno(LOG_NOTICE, "writepid: fopen %s", fn); } umask(mask); #else /* WIN32 */ NUT_UNUSED_VARIABLE(name); NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE(); #endif /* WIN32 */ } /* send sig to pid, returns -1 for error, or * zero for a successfully sent signal */ int sendsignalpid(pid_t pid, int sig, const char *progname, int check_current_progname) { #ifndef WIN32 int ret, cpn1 = -10, cpn2 = -10; char *current_progname = NULL, *procname = NULL; /* TOTHINK: What about containers where a NUT daemon *is* the only process * and is the PID=1 of the container (recycle if dead)? */ if (pid < 2 || pid > get_max_pid_t()) { if (nut_debug_level > 0 || nut_sendsignal_debug_level > 0) upslogx(LOG_NOTICE, "Ignoring invalid pid number %" PRIdMAX, (intmax_t) pid); return -1; } ret = 0; if (!checkprocname_ignored(__func__)) procname = getprocname(pid); if (procname && progname) { /* Check against some expected (often built-in) name */ if (!(cpn1 = compareprocname(pid, procname, progname))) { /* Did not match expected (often built-in) name */ ret = -1; } else { if (cpn1 > 0) { /* Matched expected name, ok to proceed */ ret = 1; } /* ...else could not determine name of PID; think later */ } } /* if (cpn1 == -3) => NUT_IGNORE_CHECKPROCNAME=true */ /* if (cpn1 == -1) => could not determine name of PID... retry just in case? */ if (procname && ret <= 0 && check_current_progname && cpn1 != -3) { /* NOTE: This could be optimized a bit by pre-finding the procname * of "pid" and re-using it, but this is not a hot enough code path * to bother much. */ current_progname = getprocname(getpid()); if (current_progname && (cpn2 = compareprocname(pid, procname, current_progname))) { if (cpn2 > 0) { /* Matched current process as asked, ok to proceed */ ret = 2; } /* ...else could not determine name of PID; think later */ } else { if (current_progname) { /* Did not match current process name */ ret = -2; } /* else just did not determine current process * name, so did not actually check either * // ret = -3; */ } } /* if ret == 0, ok to proceed - not asked for any sanity checks; * if ret > 0, ok to proceed - we had some definitive match above; * if ret < 0, NOT OK to proceed - we had some definitive fault above */ if (ret < 0) { upsdebugx(1, "%s: ran at least one check, and all such checks " "found a process name for PID %" PRIuMAX " and " "failed to match: " "found procname='%s', " "expected progname='%s' (res=%d%s), " "current progname='%s' (res=%d%s)", __func__, (uintmax_t)pid, NUT_STRARG(procname), NUT_STRARG(progname), cpn1, (cpn1 == -10 ? ": did not check" : ""), NUT_STRARG(current_progname), cpn2, (cpn2 == -10 ? ": did not check" : "")); if (nut_debug_level > 0 || nut_sendsignal_debug_level > 1) { switch (ret) { case -1: upslogx(LOG_ERR, "Tried to signal PID %" PRIuMAX " which exists but is not of" " expected program '%s'; not asked" " to cross-check current PID's name", (uintmax_t)pid, progname); break; /* Maybe we tried both data sources, maybe just current_progname */ case -2: /*case -3:*/ if (progname && current_progname) { /* Tried both, downgraded verdict further */ upslogx(LOG_ERR, "Tried to signal PID %" PRIuMAX " which exists but is not of expected" " program '%s' nor current '%s'", (uintmax_t)pid, progname, current_progname); } else if (current_progname) { /* Not asked for progname==NULL */ upslogx(LOG_ERR, "Tried to signal PID %" PRIuMAX " which exists but is not of" " current program '%s'", (uintmax_t)pid, current_progname); } else if (progname) { upslogx(LOG_ERR, "Tried to signal PID %" PRIuMAX " which exists but is not of" " expected program '%s'; could not" " cross-check current PID's name", (uintmax_t)pid, progname); } else { /* Both NULL; one not asked, another not detected; * should not actually get here (wannabe `ret==-3`) */ upslogx(LOG_ERR, "Tried to signal PID %" PRIuMAX " but could not cross-check current PID's" " name: did not expect to get here", (uintmax_t)pid); } break; default: break; } } if (current_progname) { free(current_progname); current_progname = NULL; } if (procname) { free(procname); procname = NULL; } /* Logged or not, sanity-check was requested and failed */ return -1; } if (current_progname) { free(current_progname); current_progname = NULL; } if (procname) { free(procname); procname = NULL; } /* see if this is going to work first - does the process exist, * and do we have permissions to signal it? */ ret = kill(pid, 0); if (ret < 0) { if (nut_debug_level > 0 || nut_sendsignal_debug_level >= NUT_SENDSIGNAL_DEBUG_LEVEL_KILL_SIG0PING) perror("kill"); return -1; } if (sig != 0) { /* now actually send it */ ret = kill(pid, sig); if (ret < 0) { if (nut_debug_level > 0 || nut_sendsignal_debug_level > 1) perror("kill"); return -1; } } return 0; #else /* WIN32 */ NUT_UNUSED_VARIABLE(pid); NUT_UNUSED_VARIABLE(sig); NUT_UNUSED_VARIABLE(progname); NUT_UNUSED_VARIABLE(check_current_progname); /* Windows builds use named pipes, not signals per se */ NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE(); upslogx(LOG_ERR, "%s: not implemented for Win32 and " "should not have been called directly!", __func__); return -1; #endif /* WIN32 */ } /* parses string buffer into a pid_t if it passes * a few sanity checks; returns -1 on error */ pid_t parsepid(const char *buf) { pid_t pid = -1; intmax_t _pid; errno = 0; if (!buf) { upsdebugx(6, "%s: called with NULL input", __func__); errno = EINVAL; return pid; } /* assuming 10 digits for a long */ _pid = strtol(buf, (char **)NULL, 10); if (_pid <= get_max_pid_t()) { pid = (pid_t)_pid; } else { errno = ERANGE; if (nut_debug_level > 0 || nut_sendsignal_debug_level > 0) upslogx(LOG_NOTICE, "Received a pid number too big for a pid_t: %" PRIdMAX, _pid); } return pid; } /* open pidfn, get the pid; * returns negative codes for errors, or * zero for a successfully discovered value */ pid_t parsepidfile(const char *pidfn) { char buf[SMALLBUF]; FILE *pidf; pid_t pid = -1; pidf = fopen(pidfn, "r"); if (!pidf) { /* This one happens quite often when a daemon starts * for the first time and no opponent PID file exists, * so the cut-off verbosity is higher. */ if (nut_debug_level > 0 || nut_sendsignal_debug_level >= NUT_SENDSIGNAL_DEBUG_LEVEL_FOPEN_PIDFILE) upslog_with_errno(LOG_NOTICE, "fopen %s", pidfn); return -3; } if (fgets(buf, sizeof(buf), pidf) == NULL) { if (nut_debug_level > 0 || nut_sendsignal_debug_level > 2) upslogx(LOG_NOTICE, "Failed to read pid from %s", pidfn); fclose(pidf); return -2; } /* TOTHINK: Original sendsignalfn code (which this * was extracted from) only closed pidf before * exiting the method, on error or "normally". * Why not here? Do we want an (exclusive?) hold * on it while being active in the method? */ /* this method actively reports errors, if any */ pid = parsepid(buf); fclose(pidf); return pid; } /* open pidfn, get the pid, then send it sig * returns negative codes for errors, or * zero for a successfully sent signal */ #ifndef WIN32 int sendsignalfn(const char *pidfn, int sig, const char *progname, int check_current_progname) { int ret = -1; pid_t pid = parsepidfile(pidfn); if (pid >= 0) { /* this method actively reports errors, if any */ ret = sendsignalpid(pid, sig, progname, check_current_progname); } return ret; } #else /* => WIN32 */ int sendsignalfn(const char *pidfn, const char * sig, const char *progname_ignored, int check_current_progname_ignored) { BOOL ret; NUT_UNUSED_VARIABLE(progname_ignored); NUT_UNUSED_VARIABLE(check_current_progname_ignored); ret = send_to_named_pipe(pidfn, sig); if (ret != 0) { return -1; } return 0; } #endif /* WIN32 */ int snprintfcat(char *dst, size_t size, const char *fmt, ...) { va_list ap; size_t len = strlen(dst); int ret; size--; if (len > size) { /* Do not truncate existing string */ errno = ERANGE; return -1; } va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* Note: this code intentionally uses a caller-provided format string */ ret = vsnprintf(dst + len, size - len, fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); dst[size] = '\0'; /* Note: there is a standards loophole here: strlen() must return size_t * and printf() family returns a signed int with negatives for errors. * In theory it can overflow a 64-vs-32 bit range, or signed-vs-unsigned. * In practice we hope to not have gigabytes-long config strings. */ if (ret < 0) { return ret; } #ifdef INT_MAX if ( ( (unsigned long long)len + (unsigned long long)ret ) >= (unsigned long long)INT_MAX ) { errno = ERANGE; return -1; } #endif return (int)len + ret; } /***************************************************************************** * String methods for space-separated token lists, used originally in dstate * *****************************************************************************/ /* Return non-zero if "string" contains "token" (case-sensitive), * either surrounded by space character(s) or start/end of "string", * or 0 if that token is not there, or if either string is NULL or empty. */ int str_contains_token(const char *string, const char *token) { char *s = NULL; size_t offset = 0, toklen = 0; if (!token || !*token || !string || !*string) return 0; s = strstr(string, token); toklen = strlen(token); repeat: /* not found or hit end of line */ if (!s || !*s) return 0; offset = s - string; #ifdef DEBUG upsdebugx(3, "%s: '%s' in '%s': offset=%" PRIuSIZE" toklen=%" PRIuSIZE" s[toklen]='0x%2X'\n", __func__, token, string, offset, toklen, s[toklen]); #endif if (offset == 0 || string[offset - 1] == ' ') { /* We have hit the start of token */ if (s[toklen] == '\0' || s[toklen] == ' ') { /* And we have hit the end of token */ return 1; } } /* token was a substring of some other token */ s = strstr(s + 1, token); goto repeat; } /* Add "token" to end of string "tgt", if it is not yet there * (prefix it with a space character if "tgt" is not empty). * Return 0 if already there, 1 if token was added successfully, * -1 if we needed to add it but it did not fit under the tgtsize limit, * -2 if either string was NULL or "token" was empty. * NOTE: If token contains space(s) inside, recurse to treat it * as several tokens to add independently. * Optionally calls "callback_always" (if not NULL) after checking * for spaces (and maybe recursing) and before checking if the token * is already there, and/or "callback_unique" (if not NULL) after * checking for uniqueness and going to add a newly seen token. * If such callback returns 0, abort the addition of token. */ int str_add_unique_token(char *tgt, size_t tgtsize, const char *token, int (*callback_always)(char *, size_t, const char *), int (*callback_unique)(char *, size_t, const char *) ) { size_t toklen = 0, tgtlen = 0; #ifdef DEBUG upsdebugx(3, "%s: '%s'\n", __func__, token); #endif if (!tgt || !token || !*token) return -2; if (strstr(token, " ")) { /* Recurse adding each sub-token one by one (avoid duplicates) * We frown upon adding "A FEW TOKENS" at once, but in e.g. * code with mapping tables this is not easily avoidable... */ char *tmp = xstrdup(token), *p = tmp, *s = tmp; int retval = -2, ret = 0; while (*p) { if (*p == ' ') { *p = '\0'; if (s != p) { /* Only recurse to set non-trivial tokens */ ret = str_add_unique_token(tgt, tgtsize, s, callback_always, callback_unique); /* Only remember this ret if we are just * starting, or it is a failure, or * if we never failed and keep up the * successful streak */ if ( (retval == -2) || (ret < 0) || (retval >= 0 && ret >= retval) ) retval = ret; } p++; s = p; /* Start of new word... or a consecutive space to ignore on next cycle */ } else { p++; } } if (s != p) { /* Last valid token did end with (*p=='\0') */ ret = str_add_unique_token(tgt, tgtsize, s, callback_always, callback_unique); if ( (retval == -2) || (ret < 0) || (retval >= 0 && ret >= retval) ) retval = ret; } free(tmp); /* Return 0 if all tokens were already there, * or 1 if all tokens were successfully added * (and there was at least one non-trivial token) */ return retval; } if (callback_always) { int cbret = callback_always(tgt, tgtsize, token); if (!cbret) { upsdebugx(2, "%s: skip token '%s': due to callback_always()", __func__, token); return -3; } } if (str_contains_token(tgt, token)) { upsdebugx(2, "%s: skip token '%s': was already set", __func__, token); return 0; } if (callback_unique) { int cbret = callback_unique(tgt, tgtsize, token); if (!cbret) { upsdebugx(2, "%s: skip token '%s': due to callback_unique()", __func__, token); return -3; } } /* separate with a space if multiple elements are present */ toklen = strlen(token); tgtlen = strlen(tgt); if (tgtsize < (tgtlen + (tgtlen > 0 ? 1 : 0) + toklen + 1)) { upsdebugx(1, "%s: skip token '%s': too long for target string", __func__, token); return -1; } if (snprintfcat(tgt, tgtsize, "%s%s", (tgtlen > 0) ? " " : "", token) < 0) { upsdebugx(1, "%s: error adding token '%s': snprintfcat() failed", __func__, token); return -1; } /* Added successfully */ return 1; } /* lazy way to send a signal if the program uses the PIDPATH */ #ifndef WIN32 int sendsignal(const char *progname, int sig, int check_current_progname) { char fn[NUT_PATH_MAX + 1]; snprintf(fn, sizeof(fn), "%s/%s.pid", rootpidpath(), progname); return sendsignalfn(fn, sig, progname, check_current_progname); } #else /* WIN32 */ int sendsignal(const char *progname, const char * sig, int check_current_progname) { /* progname is used as the pipe name for WIN32 * check_current_progname is de-facto ignored */ return sendsignalfn(progname, sig, NULL, check_current_progname); } #endif /* WIN32 */ const char *xbasename(const char *file) { #ifndef WIN32 const char *p = strrchr(file, '/'); #else /* WIN32 */ const char *p = strrchr(file, '\\'); const char *r = strrchr(file, '/'); /* if not found, try '/' */ if( r > p ) { p = r; } #endif /* WIN32 */ if (p == NULL) return file; return p + 1; } /* Based on https://www.gnu.org/software/libc/manual/html_node/Calculating-Elapsed-Time.html * modified for a syntax similar to difftime() */ double difftimeval(struct timeval x, struct timeval y) { struct timeval result; double d; /* Code below assumes that tv_sec is signed (time_t), * but tv_usec is not necessarily */ /* Perform the carry for the later subtraction by updating y. */ if (x.tv_usec < y.tv_usec) { intmax_t numsec = (y.tv_usec - x.tv_usec) / 1000000 + 1; y.tv_usec -= 1000000 * numsec; y.tv_sec += numsec; } if (x.tv_usec - y.tv_usec > 1000000) { intmax_t numsec = (x.tv_usec - y.tv_usec) / 1000000; y.tv_usec += 1000000 * numsec; y.tv_sec -= numsec; } /* Compute the time remaining to wait. * tv_usec is certainly positive. */ result.tv_sec = x.tv_sec - y.tv_sec; result.tv_usec = x.tv_usec - y.tv_usec; d = 0.000001 * (double)(result.tv_usec) + (double)(result.tv_sec); return d; } #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC /* From https://github.com/systemd/systemd/blob/main/src/basic/time-util.c * and https://github.com/systemd/systemd/blob/main/src/basic/time-util.h */ typedef uint64_t usec_t; typedef uint64_t nsec_t; #define PRI_NSEC PRIu64 #define PRI_USEC PRIu64 #define USEC_INFINITY ((usec_t) UINT64_MAX) #define NSEC_INFINITY ((nsec_t) UINT64_MAX) #define MSEC_PER_SEC 1000ULL #define USEC_PER_SEC ((usec_t) 1000000ULL) #define USEC_PER_MSEC ((usec_t) 1000ULL) #define NSEC_PER_SEC ((nsec_t) 1000000000ULL) #define NSEC_PER_MSEC ((nsec_t) 1000000ULL) #define NSEC_PER_USEC ((nsec_t) 1000ULL) # if defined(WITH_LIBSYSTEMD) && (WITH_LIBSYSTEMD) && !(defined(WITHOUT_LIBSYSTEMD) && (WITHOUT_LIBSYSTEMD)) && defined(HAVE_SD_NOTIFY) && (HAVE_SD_NOTIFY) /* Limited to upsnotify() use-cases below, currently */ static usec_t timespec_load(const struct timespec *ts) { assert(ts); if (ts->tv_sec < 0 || ts->tv_nsec < 0) return USEC_INFINITY; if ((usec_t) ts->tv_sec > (UINT64_MAX - ((uint64_t)(ts->tv_nsec) / NSEC_PER_USEC)) / USEC_PER_SEC) return USEC_INFINITY; return (usec_t) ts->tv_sec * USEC_PER_SEC + (usec_t) ts->tv_nsec / NSEC_PER_USEC; } /* Not used, currently -- maybe later */ /* static nsec_t timespec_load_nsec(const struct timespec *ts) { assert(ts); if (ts->tv_sec < 0 || ts->tv_nsec < 0) return NSEC_INFINITY; if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC) return NSEC_INFINITY; return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec; } */ # endif /* WITH_LIBSYSTEMD && HAVE_SD_NOTIFY && !WITHOUT_LIBSYSTEMD */ double difftimespec(struct timespec x, struct timespec y) { struct timespec result; double d; /* Code below assumes that tv_sec is signed (time_t), * but tv_nsec is not necessarily */ /* Perform the carry for the later subtraction by updating y. */ if (x.tv_nsec < y.tv_nsec) { intmax_t numsec = (y.tv_nsec - x.tv_nsec) / 1000000000L + 1; y.tv_nsec -= 1000000000L * numsec; y.tv_sec += numsec; } if (x.tv_nsec - y.tv_nsec > 1000000) { intmax_t numsec = (x.tv_nsec - y.tv_nsec) / 1000000000L; y.tv_nsec += 1000000000L * numsec; y.tv_sec -= numsec; } /* Compute the time remaining to wait. * tv_nsec is certainly positive. */ result.tv_sec = x.tv_sec - y.tv_sec; result.tv_nsec = x.tv_nsec - y.tv_nsec; d = 0.000000001 * (double)(result.tv_nsec) + (double)(result.tv_sec); return d; } #endif /* HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC */ /* Help avoid cryptic "upsnotify: notify about state 4 with libsystemd:" * (with only numeric codes) below */ const char *str_upsnotify_state(upsnotify_state_t state) { switch (state) { case NOTIFY_STATE_READY: return "NOTIFY_STATE_READY"; case NOTIFY_STATE_READY_WITH_PID: return "NOTIFY_STATE_READY_WITH_PID"; case NOTIFY_STATE_RELOADING: return "NOTIFY_STATE_RELOADING"; case NOTIFY_STATE_STOPPING: return "NOTIFY_STATE_STOPPING"; case NOTIFY_STATE_STATUS: /* Send a text message per "fmt" below */ return "NOTIFY_STATE_STATUS"; case NOTIFY_STATE_WATCHDOG: /* Ping the framework that we are still alive */ return "NOTIFY_STATE_WATCHDOG"; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif default: /* Must not occur. */ return "NOTIFY_STATE_UNDEFINED"; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } } static void upsnotify_suggest_NUT_QUIET_INIT_UPSNOTIFY_once(void) { static int reported = 0; if (reported) return; reported = 1; if (getenv("NUT_QUIET_INIT_UPSNOTIFY")) return; upsdebugx(1, "On systems without service units, " "consider `export NUT_QUIET_INIT_UPSNOTIFY=true`"); } /* Send (daemon) state-change notifications to an * external service management framework such as systemd */ int upsnotify(upsnotify_state_t state, const char *fmt, ...) { int ret = -127; va_list va; char buf[LARGEBUF]; char msgbuf[LARGEBUF]; size_t msglen = 0; #if defined(WITH_LIBSYSTEMD) && (WITH_LIBSYSTEMD) && !(defined(WITHOUT_LIBSYSTEMD) && (WITHOUT_LIBSYSTEMD)) # ifdef HAVE_SD_NOTIFY # if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC /* In current systemd, this is only used for RELOADING/READY after * a reload action for Type=notify-reload; for more details see * https://github.com/systemd/systemd/blob/main/src/core/service.c#L2618 */ struct timespec monoclock_ts; int got_monoclock = clock_gettime(CLOCK_MONOTONIC, &monoclock_ts); # endif /* HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC */ # endif /* HAVE_SD_NOTIFY */ #endif /* WITH_LIBSYSTEMD */ /* Were we asked to be quiet on the console? */ if (upsnotify_report_verbosity < 0) { char *quiet_init = getenv("NUT_QUIET_INIT_UPSNOTIFY"); if (quiet_init == NULL) { /* No envvar, default is to inform once on the console */ upsnotify_report_verbosity = 0; } else { /* Envvar is set, does it tell us to be quiet? * NOTE: Empty also means "yes" */ if (*quiet_init == '\0' || (strcasecmp(quiet_init, "true") && strcasecmp(quiet_init, "yes") && strcasecmp(quiet_init, "on") && strcasecmp(quiet_init, "1") ) ) { upsdebugx(1, "NUT_QUIET_INIT_UPSNOTIFY='%s' value " "was not recognized, ignored", quiet_init); upsnotify_report_verbosity = 0; } else { /* Avoid the verbose message below * (only seen with non-zero debug) */ upsnotify_report_verbosity = 1; } } } /* Prepare the message (if any) as a string */ msgbuf[0] = '\0'; if (fmt) { va_start(va, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif /* generic message... */ ret = vsnprintf(msgbuf, sizeof(msgbuf), fmt, va); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(va); if ((ret < 0) || (ret >= (int) sizeof(msgbuf))) { if (syslog_is_disabled()) { fprintf(stderr, "%s (%s:%d): vsnprintf needed more than %" PRIuSIZE " bytes: %d", __func__, __FILE__, __LINE__, sizeof(msgbuf), ret); } else { syslog(LOG_WARNING, "%s (%s:%d): vsnprintf needed more than %" PRIuSIZE " bytes: %d", __func__, __FILE__, __LINE__, sizeof(msgbuf), ret); } } else { msglen = strlen(msgbuf); } /* Reset for actual notification processing below */ ret = -127; } #if defined(WITH_LIBSYSTEMD) && (WITH_LIBSYSTEMD) # if defined(WITHOUT_LIBSYSTEMD) && (WITHOUT_LIBSYSTEMD) NUT_UNUSED_VARIABLE(buf); NUT_UNUSED_VARIABLE(msglen); if (!upsnotify_reported_disabled_systemd) { upsdebugx(upsnotify_report_verbosity, "%s: notify about state %s with libsystemd: " "skipped for libcommonclient build, " "will not spam more about it", __func__, str_upsnotify_state(state)); upsnotify_suggest_NUT_QUIET_INIT_UPSNOTIFY_once(); } upsnotify_reported_disabled_systemd = 1; # else /* not WITHOUT_LIBSYSTEMD */ if (!getenv("NOTIFY_SOCKET")) { if (!upsnotify_reported_disabled_systemd) { upsdebugx(upsnotify_report_verbosity, "%s: notify about state %s with libsystemd: " "was requested, but not running as a service " "unit now, will not spam more about it", __func__, str_upsnotify_state(state)); upsnotify_suggest_NUT_QUIET_INIT_UPSNOTIFY_once(); } upsnotify_reported_disabled_systemd = 1; } else { # ifdef HAVE_SD_NOTIFY char monoclock_str[SMALLBUF]; monoclock_str[0] = '\0'; # if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC if (got_monoclock == 0) { usec_t monots = timespec_load(&monoclock_ts); ret = snprintf(monoclock_str + 1, sizeof(monoclock_str) - 1, "MONOTONIC_USEC=%" PRI_USEC, monots); if ((ret < 0) || (ret >= (int) sizeof(monoclock_str) - 1)) { if (syslog_is_disabled()) { fprintf(stderr, "%s (%s:%d): snprintf needed more than %" PRIuSIZE " bytes: %d", __func__, __FILE__, __LINE__, sizeof(monoclock_str), ret); } else { syslog(LOG_WARNING, "%s (%s:%d): snprintf needed more than %" PRIuSIZE " bytes: %d", __func__, __FILE__, __LINE__, sizeof(monoclock_str), ret); } msglen = 0; } else { monoclock_str[0] = '\n'; } } # endif /* HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC */ # if ! DEBUG_SYSTEMD_WATCHDOG if (state != NOTIFY_STATE_WATCHDOG || !upsnotify_reported_watchdog_systemd) # endif upsdebugx(6, "%s: notify about state %s with " "libsystemd: use sd_notify()", __func__, str_upsnotify_state(state)); /* https://www.freedesktop.org/software/systemd/man/sd_notify.html */ if (msglen) { ret = snprintf(buf, sizeof(buf), "STATUS=%s", msgbuf); if ((ret < 0) || (ret >= (int) sizeof(buf))) { if (syslog_is_disabled()) { fprintf(stderr, "%s (%s:%d): snprintf needed more than %" PRIuSIZE " bytes: %d", __func__, __FILE__, __LINE__, sizeof(buf), ret); } else { syslog(LOG_WARNING, "%s (%s:%d): snprintf needed more than %" PRIuSIZE " bytes: %d", __func__, __FILE__, __LINE__, sizeof(buf), ret); } msglen = 0; } else { msglen = (size_t)ret; } } switch (state) { case NOTIFY_STATE_READY: ret = snprintf(buf + msglen, sizeof(buf) - msglen, "%sREADY=1%s", msglen ? "\n" : "", monoclock_str); break; case NOTIFY_STATE_READY_WITH_PID: if (1) { /* scoping */ char pidbuf[SMALLBUF]; if (snprintf(pidbuf, sizeof(pidbuf), "%lu", (unsigned long) getpid())) { ret = snprintf(buf + msglen, sizeof(buf) - msglen, "%sREADY=1\n" "MAINPID=%s%s", msglen ? "\n" : "", pidbuf, monoclock_str); upsdebugx(6, "%s: notifying systemd about MAINPID=%s", __func__, pidbuf); /* https://github.com/systemd/systemd/issues/25961 * Reset the WATCHDOG_PID so we know this is the * process we want to post pings from! */ unsetenv("WATCHDOG_PID"); setenv("WATCHDOG_PID", pidbuf, 1); } else { upsdebugx(6, "%s: NOT notifying systemd about MAINPID, " "got an error stringifying it; processing as " "plain NOTIFY_STATE_READY", __func__); ret = snprintf(buf + msglen, sizeof(buf) - msglen, "%sREADY=1%s", msglen ? "\n" : "", monoclock_str); /* TODO: Maybe revise/drop this tweak if * loggers other than systemd are used: */ state = NOTIFY_STATE_READY; } } break; case NOTIFY_STATE_RELOADING: ret = snprintf(buf + msglen, sizeof(buf) - msglen, "%s%s%s", msglen ? "\n" : "", "RELOADING=1", monoclock_str); break; case NOTIFY_STATE_STOPPING: ret = snprintf(buf + msglen, sizeof(buf) - msglen, "%s%s", msglen ? "\n" : "", "STOPPING=1"); break; case NOTIFY_STATE_STATUS: /* Only send a text message per "fmt" */ if (!msglen) { upsdebugx(6, "%s: failed to notify about status: none provided", __func__); ret = -1; } else { ret = (int)msglen; } break; case NOTIFY_STATE_WATCHDOG: /* Ping the framework that we are still alive */ if (1) { /* scoping */ int postit = 0; # ifdef HAVE_SD_WATCHDOG_ENABLED uint64_t to = 0; postit = sd_watchdog_enabled(0, &to); if (postit < 0) { # if ! DEBUG_SYSTEMD_WATCHDOG if (!upsnotify_reported_watchdog_systemd) # endif upsdebugx(6, "%s: sd_enabled_watchdog query failed: %s", __func__, strerror(postit)); } else { # if ! DEBUG_SYSTEMD_WATCHDOG if (!upsnotify_reported_watchdog_systemd || postit > 0) # else if (postit > 0) # endif upsdebugx(6, "%s: sd_enabled_watchdog query returned: %d " "(%" PRIu64 "msec remain)", __func__, postit, to); } # endif /* HAVE_SD_WATCHDOG_ENABLED */ if (postit < 1) { char *s = getenv("WATCHDOG_USEC"); # if ! DEBUG_SYSTEMD_WATCHDOG if (!upsnotify_reported_watchdog_systemd) # endif upsdebugx(6, "%s: WATCHDOG_USEC=%s", __func__, s); if (s && *s) { long l = strtol(s, (char **)NULL, 10); if (l > 0) { pid_t wdpid = parsepid(getenv("WATCHDOG_PID")); if (wdpid == (pid_t)-1 || wdpid == getpid()) { # if ! DEBUG_SYSTEMD_WATCHDOG if (!upsnotify_reported_watchdog_systemd) # endif upsdebugx(6, "%s: can post: WATCHDOG_PID=%li", __func__, (long)wdpid); postit = 1; } else { # if ! DEBUG_SYSTEMD_WATCHDOG if (!upsnotify_reported_watchdog_systemd) # endif upsdebugx(6, "%s: watchdog is configured, " "but not for this process: " "WATCHDOG_PID=%li", __func__, (long)wdpid); # if DEBUG_SYSTEMD_WATCHDOG /* Just try to post - at worst, systemd * NotifyAccess will prohibit the message. * The envvar simply helps child processes * know they should not spam the watchdog * handler (usually only MAINPID should): * https://github.com/systemd/systemd/issues/25961#issuecomment-1373947907 */ postit = 1; # else postit = 0; # endif } } } } if (postit > 0) { ret = snprintf(buf + msglen, sizeof(buf) - msglen, "%s%s", msglen ? "\n" : "", "WATCHDOG=1"); } else if (postit == 0) { # if ! DEBUG_SYSTEMD_WATCHDOG if (!upsnotify_reported_watchdog_systemd) # endif upsdebugx(6, "%s: failed to tickle the watchdog: not enabled for this unit", __func__); ret = -126; } } break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: if (!msglen) { upsdebugx(6, "%s: unknown state and no status message provided", __func__); ret = -1; } else { upsdebugx(6, "%s: unknown state but have a status message provided", __func__); ret = (int)msglen; } #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } if ((ret < 0) || (ret >= (int) sizeof(buf))) { /* Refusal to send the watchdog ping is not an error to report */ if ( !(ret == -126 && (state == NOTIFY_STATE_WATCHDOG)) ) { if (syslog_is_disabled()) { fprintf(stderr, "%s (%s:%d): snprintf needed more than %" PRIuSIZE " bytes: %d", __func__, __FILE__, __LINE__, sizeof(buf), ret); } else { syslog(LOG_WARNING, "%s (%s:%d): snprintf needed more than %" PRIuSIZE " bytes: %d", __func__, __FILE__, __LINE__, sizeof(buf), ret); } } ret = -1; } else { upsdebugx(6, "%s: posting sd_notify: %s", __func__, buf); msglen = (size_t)ret; ret = sd_notify(0, buf); if (ret > 0 && state == NOTIFY_STATE_READY_WITH_PID) { /* Usually we begin the main loop just after this * and post a watchdog message but systemd did not * yet prepare to handle us */ upsdebugx(6, "%s: wait for NOTIFY_STATE_READY_WITH_PID to be handled by systemd", __func__); # ifdef HAVE_SD_NOTIFY_BARRIER sd_notify_barrier(0, UINT64_MAX); # else usleep(3 * 1000000); # endif } } # else /* not HAVE_SD_NOTIFY: */ /* FIXME: Try to fork and call systemd-notify helper program */ upsdebugx(6, "%s: notify about state %s with " "libsystemd: lacking sd_notify()", __func__, str_upsnotify_state(state)); ret = -127; # endif /* HAVE_SD_NOTIFY */ } # endif /* if not WITHOUT_LIBSYSTEMD (explicit avoid) */ #else /* not WITH_LIBSYSTEMD */ NUT_UNUSED_VARIABLE(buf); NUT_UNUSED_VARIABLE(msglen); #endif /* WITH_LIBSYSTEMD */ if (ret < 0 #if defined(WITH_LIBSYSTEMD) && (WITH_LIBSYSTEMD) && !(defined(WITHOUT_LIBSYSTEMD) && (WITHOUT_LIBSYSTEMD)) && (defined(HAVE_SD_NOTIFY) && HAVE_SD_NOTIFY) # if ! DEBUG_SYSTEMD_WATCHDOG && (!upsnotify_reported_watchdog_systemd || (state != NOTIFY_STATE_WATCHDOG)) # endif #endif ) { if (ret == -127) { if (!upsnotify_reported_disabled_notech) { int verbosity = upsnotify_report_verbosity; if (state == NOTIFY_STATE_STOPPING && upsnotify_report_verbosity == 0) { /* By default, do not spam even this if our * first-most message to be suppressed is * already about stopping (e.g. a failed * driver) unless explicitly requested to. */ char *s = getenv("NUT_QUIET_INIT_UPSNOTIFY"); /* FIXME: Make an INVERTED server/conf.c::parse_boolean() reusable */ if (s && *s && ( (!strcasecmp(s, "false")) || (!strcasecmp(s, "off")) || (!strcasecmp(s, "no")) || (!strcasecmp(s, "0"))) ) { upsdebugx(1, "Caller WANTS to see all these messages: NUT_QUIET_INIT_UPSNOTIFY=%s", NUT_STRARG(s)); } else { /* Hide this one by default */ verbosity = 1; } } upsdebugx(verbosity, "%s: failed to notify about state %s: " "no notification tech defined, " "will not spam more about it", __func__, str_upsnotify_state(state)); } upsnotify_reported_disabled_notech = 1; upsnotify_suggest_NUT_QUIET_INIT_UPSNOTIFY_once(); } else { upsdebugx(6, "%s: failed to notify about state %s", __func__, str_upsnotify_state(state)); } } #if defined(WITH_LIBSYSTEMD) && (WITH_LIBSYSTEMD) # if ! DEBUG_SYSTEMD_WATCHDOG if (state == NOTIFY_STATE_WATCHDOG && !upsnotify_reported_watchdog_systemd) { upsdebugx(upsnotify_report_verbosity, "%s: logged the systemd watchdog situation once, " "will not spam more about it", __func__); upsnotify_reported_watchdog_systemd = 1; upsnotify_suggest_NUT_QUIET_INIT_UPSNOTIFY_once(); } # endif #endif return ret; } void nut_report_config_flags(void) { /* Roughly similar to upslogx() but without the buffer-size limits and * timestamp/debug-level prefixes. Only printed if debug (any) is on. * Depending on amount of configuration tunables involved by a particular * build of NUT, the string can be quite long (over 1KB). */ #if 0 const char *acinit_ver = NULL; #endif /* Pass these as variables to avoid warning about never reaching one * of compiled codepaths: */ const char *compiler_ver = CC_VERSION; const char *config_flags = CONFIG_FLAGS; struct timeval now; if (nut_debug_level < 1) return; #if 0 /* Only report git revision if NUT_VERSION_MACRO in nut_version.h aka * UPS_VERSION here is remarkably different from PACKAGE_VERSION from * configure.ac AC_INIT() -- which may be e.g. "2.8.0.1" although some * distros, especially embedders, tend to place their product IDs here). * The macro may be that fixed version or refer to git source revision, * as decided when generating nut_version.h (and if it was re-generated * in case of rebuilds while developers are locally iterating -- this * may be disabled for faster local iterations at a cost of a little lie). */ if (PACKAGE_VERSION && UPS_VERSION && (strlen(UPS_VERSION) < 12 || !strstr(UPS_VERSION, PACKAGE_VERSION)) ) { /* If UPS_VERSION is too short (so likely a static string * from configure.ac AC_INIT() -- although some distros, * especially embedders, tend to place their product IDs here), * or if PACKAGE_VERSION *is NOT* a substring of it: */ acinit_ver = PACKAGE_VERSION; /* // Triplet that was printed below: (acinit_ver ? " (release/snapshot of " : ""), (acinit_ver ? acinit_ver : ""), (acinit_ver ? ")" : ""), */ } #endif /* NOTE: If changing wording here, keep in sync with configure.ac logic * looking for CONFIG_FLAGS_DEPLOYED via "configured with flags:" string! */ gettimeofday(&now, NULL); if (upslog_start.tv_sec == 0) { upslog_start = now; } if (upslog_start.tv_usec > now.tv_usec) { now.tv_usec += 1000000; now.tv_sec -= 1; } if (xbit_test(upslog_flags, UPSLOG_STDERR)) { fprintf(stderr, "%4.0f.%06ld\t[D1] Network UPS Tools version %s%s%s%s %s%s\n", difftime(now.tv_sec, upslog_start.tv_sec), (long)(now.tv_usec - upslog_start.tv_usec), describe_NUT_VERSION_once(), (compiler_ver && *compiler_ver != '\0' ? " built with " : ""), (compiler_ver && *compiler_ver != '\0' ? compiler_ver : ""), (compiler_ver && *compiler_ver != '\0' ? " and" : ""), (config_flags && *config_flags != '\0' ? "configured with flags: " : "configured all by default guesswork"), (config_flags && *config_flags != '\0' ? config_flags : "") ); #ifdef WIN32 fflush(stderr); #endif /* WIN32 */ } /* NOTE: May be ignored or truncated by receiver if that syslog server * (and/or OS sender) does not accept messages of such length */ if (xbit_test(upslog_flags, UPSLOG_SYSLOG)) { syslog(LOG_DEBUG, "Network UPS Tools version %s%s%s%s %s%s", describe_NUT_VERSION_once(), (compiler_ver && *compiler_ver != '\0' ? " built with " : ""), (compiler_ver && *compiler_ver != '\0' ? compiler_ver : ""), (compiler_ver && *compiler_ver != '\0' ? " and" : ""), (config_flags && *config_flags != '\0' ? "configured with flags: " : "configured all by default guesswork"), (config_flags && *config_flags != '\0' ? config_flags : "") ); } } static void vupslog(int priority, const char *fmt, va_list va, int use_strerror) { int ret, errno_orig = errno; size_t bufsize = LARGEBUF; char *buf = xcalloc(bufsize, sizeof(char)); /* Be pedantic about our limitations */ bufsize *= sizeof(char); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wformat-nonliteral" #pragma clang diagnostic ignored "-Wformat-security" #endif /* Note: errors here can reset errno, * so errno_orig is stashed beforehand */ do { ret = vsnprintf(buf, bufsize, fmt, va); if ((ret < 0) || ((uintmax_t)ret >= (uintmax_t)bufsize)) { /* Try to adjust bufsize until we can print the * whole message. Note that standards only require * up to 4095 bytes to be manageable in printf-like * methods: * The number of characters that can be produced * by any single conversion shall be at least 4095. * C17dr § 7.21.6.1 15 * In general, vsnprintf() is not specified to set * errno on any condition (or to not implement a * larger limit). Select implementations may do so * though. * Based on https://stackoverflow.com/a/72981237/4715872 */ if (bufsize < SIZE_MAX/2) { size_t newbufsize = bufsize*2; if (ret > 0) { /* Be generous, we snprintfcat() some * suffixes, prefix a timestamp, etc. */ if (((uintmax_t)ret) > (SIZE_MAX - LARGEBUF)) { goto vupslog_too_long; } newbufsize = (size_t)ret + LARGEBUF; } /* else: errno, e.g. ERANGE printing: * "...(34 => Result too large)" */ if (nut_debug_level > 0) { fprintf(stderr, "WARNING: vupslog: " "vsnprintf needed more than %" PRIuSIZE " bytes: %d (%d => %s)," " extending to %" PRIuSIZE "\n", bufsize, ret, errno, strerror(errno), newbufsize); } bufsize = newbufsize; buf = xrealloc(buf, bufsize); continue; } } else { /* All fits well now; majority of use-cases should * have nailed this on first try (envvar prints of * longer fully-qualified PATHs, compilation settings * reports etc. may need more). Even a LARGEBUF may * still overflow some older syslog buffers and would * be truncated there. At least stderr would see as * complete a picture as we can give it. */ break; } /* Arbitrary limit, gotta stop somewhere */ if (bufsize > LARGEBUF * 64) { vupslog_too_long: if (syslog_is_disabled()) { fprintf(stderr, "vupslog: vsnprintf needed " "more than %" PRIuSIZE " bytes; logged " "output can be truncated", bufsize); } else { syslog(LOG_WARNING, "vupslog: vsnprintf needed " "more than %" PRIuSIZE " bytes; logged " "output can be truncated", bufsize); } break; } } while(1); #ifdef __clang__ #pragma clang diagnostic pop #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif if (use_strerror) { #ifdef WIN32 LPVOID WinBuf; DWORD WinErr = GetLastError(); #endif /* WIN32 */ snprintfcat(buf, bufsize, ": %s", strerror(errno_orig)); #ifdef WIN32 FormatMessage( FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, WinErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &WinBuf, 0, NULL ); snprintfcat(buf, bufsize, " [%s]", (char *)WinBuf); LocalFree(WinBuf); #endif /* WIN32 */ } /* Note: nowadays debug level can be changed during run-time, * so mark the starting point whenever we first try to log */ if (upslog_start.tv_sec == 0) { struct timeval now; gettimeofday(&now, NULL); upslog_start = now; } if (xbit_test(upslog_flags, UPSLOG_STDERR)) { if (nut_debug_level > 0) { struct timeval now; gettimeofday(&now, NULL); if (upslog_start.tv_usec > now.tv_usec) { now.tv_usec += 1000000; now.tv_sec -= 1; } /* Print all in one shot, to better avoid * mixed lines in parallel threads */ fprintf(stderr, "%4.0f.%06ld\t%s\n", difftime(now.tv_sec, upslog_start.tv_sec), (long)(now.tv_usec - upslog_start.tv_usec), buf); } else { fprintf(stderr, "%s\n", buf); } #ifdef WIN32 fflush(stderr); #endif /* WIN32 */ } if (xbit_test(upslog_flags, UPSLOG_SYSLOG)) syslog(priority, "%s", buf); free(buf); } /* Return the default path for the directory containing configuration files */ const char * confpath(void) { static const char *path = NULL; /* Cached by earlier calls? */ if (path) return path; path = getenv("NUT_CONFPATH"); #ifdef WIN32 if (path == NULL) { /* fall back to built-in pathname relative to binary/workdir */ path = getfullpath(PATH_ETC); } #endif /* WIN32 */ /* We assume, here and elsewhere, that * at least CONFPATH is always defined */ if (path == NULL || *path == '\0') path = CONFPATH; return path; } /* Return the default path for the directory containing state files */ const char * dflt_statepath(void) { static const char *path = NULL; /* Cached by earlier calls? */ if (path) return path; path = getenv("NUT_STATEPATH"); #ifdef WIN32 if (path == NULL) { /* fall back to built-in pathname relative to binary/workdir */ path = getfullpath(PATH_VAR_RUN); } #endif /* WIN32 */ /* We assume, here and elsewhere, that * at least STATEPATH is always defined */ if (path == NULL || *path == '\0') path = STATEPATH; return path; } /* Return the alternate path for pid files, for processes running as non-root * Per documentation and configure script, the fallback value is the * state-file path as the daemon and drivers can write there too. * Note that this differs from PIDPATH that higher-privileged daemons, such * as upsmon, tend to use. */ const char * altpidpath(void) { static const char *path = NULL; /* Cached by earlier calls? */ if (path) return path; path = getenv("NUT_ALTPIDPATH"); if ( (path == NULL) || (*path == '\0') ) { path = getenv("NUT_STATEPATH"); #ifdef WIN32 if (path == NULL) { /* fall back to built-in pathname relative to binary/workdir */ path = getfullpath(PATH_VAR_RUN); } #endif /* WIN32 */ } if ( (path != NULL) && (*path != '\0') ) return path; #ifdef ALTPIDPATH path = ALTPIDPATH; #else /* With WIN32 in the loop, this may be more than a fallback to STATEPATH: */ path = dflt_statepath(); #endif return path; } /* Return the main path for pid files, for processes running as root, such * as upsmon. Typically this is the built-in PIDPATH (from configure script) * but certain use-cases such as the test suite can override it with the * NUT_PIDPATH environment variable. */ const char * rootpidpath(void) { static const char *path = NULL; /* Cached by earlier calls? */ if (path) return path; path = getenv("NUT_PIDPATH"); #ifdef WIN32 if (path == NULL) { /* fall back to built-in pathname relative to binary/workdir */ path = getfullpath(PATH_ETC); } #endif /* WIN32 */ /* We assume, here and elsewhere, that * at least PIDPATH is always defined */ if (path == NULL || *path == '\0') path = PIDPATH; return path; } /* Die with a standard message if socket filename is too long */ void check_unix_socket_filename(const char *fn) { size_t len = strlen(fn); size_t max = NUT_PATH_MAX; /* no +1 here */ #ifndef WIN32 struct sockaddr_un ssaddr; max = sizeof(ssaddr.sun_path); #endif /* WIN32 */ if (len < max) return; /* Avoid useless truncated pathnames that * other driver instances would conflict * with, and upsd can not discover. * Note this is quite short on many OSes * varying 104-108 bytes (UNIX_PATH_MAX) * as opposed to PATH_MAX or MAXPATHLEN * typically of a kilobyte range. * We define NUT_PATH_MAX as the greatest * value of them all. */ fatalx(EXIT_FAILURE, "Can't create a unix domain socket: pathname '%s' " "is too long (%" PRIuSIZE ") for 'struct sockaddr_un->sun_path' " "on this system (%" PRIuSIZE ")", fn, len, max); } /* logs the formatted string to any configured logging devices + the output of strerror(errno) */ void upslog_with_errno(int priority, const char *fmt, ...) { va_list va; va_start(va, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vupslog(priority, fmt, va, 1); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(va); } /* logs the formatted string to any configured logging devices */ void upslogx(int priority, const char *fmt, ...) { va_list va; va_start(va, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vupslog(priority, fmt, va, 0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(va); } void s_upsdebug_with_errno(int level, const char *fmt, ...) { va_list va; char fmt2[LARGEBUF]; static int NUT_DEBUG_PID = -1; /* Note: Thanks to macro wrapping, we do not quite need this * test now, but we still need the "level" value to report * below - when it is not zero. */ if (nut_debug_level < level) return; /* For debugging output, we want to prepend the debug level so the user can * e.g. lower the level (less -D's on command line) to retain just the amount * of logging info he needs to see at the moment. Using '-DDDDD' all the time * is too brutal and needed high-level overview can be lost. This [D#] prefix * can help limit this debug stream quicker, than experimentally picking ;) */ if (level > 0) { int ret; if (NUT_DEBUG_PID < 0) { NUT_DEBUG_PID = (getenv("NUT_DEBUG_PID") != NULL); } if (NUT_DEBUG_PID) { /* Note that we re-request PID every time as it can * change during the run-time (forking etc.) */ ret = snprintf(fmt2, sizeof(fmt2), "[D%d:%" PRIiMAX "] %s", level, (intmax_t)getpid(), fmt); } else { ret = snprintf(fmt2, sizeof(fmt2), "[D%d] %s", level, fmt); } if ((ret < 0) || (ret >= (int) sizeof(fmt2))) { if (syslog_is_disabled()) { fprintf(stderr, "upsdebug_with_errno: snprintf needed more than %d bytes", LARGEBUF); } else { syslog(LOG_WARNING, "upsdebug_with_errno: snprintf needed more than %d bytes", LARGEBUF); } } else { fmt = (const char *)fmt2; } } va_start(va, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vupslog(LOG_DEBUG, fmt, va, 1); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(va); } void s_upsdebugx(int level, const char *fmt, ...) { va_list va; char fmt2[LARGEBUF]; static int NUT_DEBUG_PID = -1; if (nut_debug_level < level) return; /* See comments above in upsdebug_with_errno() - they apply here too. */ if (level > 0) { int ret; if (NUT_DEBUG_PID < 0) { NUT_DEBUG_PID = (getenv("NUT_DEBUG_PID") != NULL); } if (NUT_DEBUG_PID) { /* Note that we re-request PID every time as it can * change during the run-time (forking etc.) */ ret = snprintf(fmt2, sizeof(fmt2), "[D%d:%" PRIiMAX "] %s", level, (intmax_t)getpid(), fmt); } else { ret = snprintf(fmt2, sizeof(fmt2), "[D%d] %s", level, fmt); } if ((ret < 0) || (ret >= (int) sizeof(fmt2))) { if (syslog_is_disabled()) { fprintf(stderr, "upsdebugx: snprintf needed more than %d bytes", LARGEBUF); } else { syslog(LOG_WARNING, "upsdebugx: snprintf needed more than %d bytes", LARGEBUF); } } else { fmt = (const char *)fmt2; } } va_start(va, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vupslog(LOG_DEBUG, fmt, va, 0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(va); } /* dump message msg and len bytes from buf to upsdebugx(level) in hexadecimal. (This function replaces Philippe Marzouk's original dump_hex() function) */ void s_upsdebug_hex(int level, const char *msg, const void *buf, size_t len) { char line[100]; int n; /* number of characters currently in line */ size_t i; /* number of bytes output from buffer */ n = snprintf(line, sizeof(line), "%s: (%" PRIuSIZE " bytes) =>", msg, len); if (n < 0) goto failed; for (i = 0; i < len; i++) { if (n > 72) { upsdebugx(level, "%s", line); line[0] = 0; } n = snprintfcat(line, sizeof(line), n ? " %02x" : "%02x", ((const unsigned char *)buf)[i]); if (n < 0) goto failed; } s_upsdebugx(level, "%s", line); return; failed: s_upsdebugx(level, "%s", "Failed to print a hex dump for debug"); } /* taken from www.asciitable.com */ static const char* ascii_symb[] = { "NUL", /* 0x00 */ "SOH", /* 0x01 */ "STX", /* 0x02 */ "ETX", /* 0x03 */ "EOT", /* 0x04 */ "ENQ", /* 0x05 */ "ACK", /* 0x06 */ "BEL", /* 0x07 */ "BS", /* 0x08 */ "TAB", /* 0x09 */ "LF", /* 0x0A */ "VT", /* 0x0B */ "FF", /* 0x0C */ "CR", /* 0x0D */ "SO", /* 0x0E */ "SI", /* 0x0F */ "DLE", /* 0x10 */ "DC1", /* 0x11 */ "DC2", /* 0x12 */ "DC3", /* 0x13 */ "DC4", /* 0x14 */ "NAK", /* 0x15 */ "SYN", /* 0x16 */ "ETB", /* 0x17 */ "CAN", /* 0x18 */ "EM", /* 0x19 */ "SUB", /* 0x1A */ "ESC", /* 0x1B */ "FS", /* 0x1C */ "GS", /* 0x1D */ "RS", /* 0x1E */ "US" /* 0x1F */ }; /* dump message msg and len bytes from buf to upsdebugx(level) in ascii. */ void s_upsdebug_ascii(int level, const char *msg, const void *buf, size_t len) { char line[256]; int n; /* number of characters currently in line */ size_t i; /* number of bytes output from buffer */ unsigned char ch; if (nut_debug_level < level) return; /* save cpu cycles */ n = snprintf(line, sizeof(line), "%s", msg); if (n < 0) goto failed; for (i=0; i= 0x80) n = snprintfcat(line, sizeof(line), "%02Xh ", ch); else n = snprintfcat(line, sizeof(line), "'%c' ", ch); if (n < 0) goto failed; } s_upsdebugx(level, "%s", line); return; failed: s_upsdebugx(level, "%s", "Failed to print an ASCII data dump for debug"); } static void vfatal(const char *fmt, va_list va, int use_strerror) { /* Normally we enable SYSLOG and disable STDERR, * unless NUT_DEBUG_SYSLOG envvar interferes as * interpreted in syslog_is_disabled() method: */ int syslog_disabled = syslog_is_disabled(), stderr_disabled = (syslog_disabled == 0 || syslog_disabled == 2); if (xbit_test(upslog_flags, UPSLOG_STDERR_ON_FATAL)) xbit_set(&upslog_flags, UPSLOG_STDERR); if (xbit_test(upslog_flags, UPSLOG_SYSLOG_ON_FATAL)) { if (syslog_disabled) { /* FIXME: Corner case... env asked for stderr * instead of syslog - should we care about * UPSLOG_STDERR_ON_FATAL being not set? */ if (!stderr_disabled) xbit_set(&upslog_flags, UPSLOG_STDERR); } else { xbit_set(&upslog_flags, UPSLOG_SYSLOG); } } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vupslog(LOG_ERR, fmt, va, use_strerror); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } void fatal_with_errno(int status, const char *fmt, ...) { va_list va; va_start(va, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vfatal(fmt, va, (errno > 0) ? 1 : 0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(va); exit(status); } void fatalx(int status, const char *fmt, ...) { va_list va; va_start(va, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vfatal(fmt, va, 0); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(va); exit(status); } static const char *oom_msg = "Out of memory"; void *xmalloc(size_t size) { void *p = malloc(size); if (p == NULL) fatal_with_errno(EXIT_FAILURE, "%s", oom_msg); #ifdef WIN32 /* FIXME: This is what (x)calloc() is for! */ memset(p, 0, size); #endif /* WIN32 */ return p; } void *xcalloc(size_t number, size_t size) { void *p = calloc(number, size); if (p == NULL) fatal_with_errno(EXIT_FAILURE, "%s", oom_msg); #ifdef WIN32 /* FIXME: calloc() above should have initialized this already! */ memset(p, 0, size * number); #endif /* WIN32 */ return p; } void *xrealloc(void *ptr, size_t size) { void *p = realloc(ptr, size); if (p == NULL) fatal_with_errno(EXIT_FAILURE, "%s", oom_msg); return p; } char *xstrdup(const char *string) { char *p; if (string == NULL) { upsdebugx(1, "%s: got null input", __func__); return NULL; } p = strdup(string); if (p == NULL) fatal_with_errno(EXIT_FAILURE, "%s", oom_msg); return p; } /* Read up to buflen bytes from fd and return the number of bytes read. If no data is available within d_sec + d_usec, return 0. On error, a value < 0 is returned (errno indicates error). */ #ifndef WIN32 ssize_t select_read(const int fd, void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec) { int ret; fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = d_sec; tv.tv_usec = d_usec; ret = select(fd + 1, &fds, NULL, NULL, &tv); if (ret < 1) { return ret; } return read(fd, buf, buflen); } #else /* WIN32 */ ssize_t select_read(serial_handler_t *fd, void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec) { /* This function is only called by serial drivers right now */ /* TODO: Assert below that resulting values fit in ssize_t range */ /* DWORD bytes_read; */ int res; DWORD timeout; COMMTIMEOUTS TOut; timeout = (d_sec*1000) + ((d_usec+999)/1000); GetCommTimeouts(fd->handle,&TOut); TOut.ReadIntervalTimeout = MAXDWORD; TOut.ReadTotalTimeoutMultiplier = 0; TOut.ReadTotalTimeoutConstant = timeout; SetCommTimeouts(fd->handle,&TOut); res = w32_serial_read(fd,buf,buflen,timeout); return res; } #endif /* WIN32 */ /* Write up to buflen bytes to fd and return the number of bytes written. If no data is available within d_sec + d_usec, return 0. On error, a value < 0 is returned (errno indicates error). */ #ifndef WIN32 ssize_t select_write(const int fd, const void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec) { int ret; fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = d_sec; tv.tv_usec = d_usec; ret = select(fd + 1, NULL, &fds, NULL, &tv); if (ret < 1) { return ret; } return write(fd, buf, buflen); } #else /* WIN32 */ /* Note: currently not implemented de-facto for Win32 */ ssize_t select_write(serial_handler_t *fd, const void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec) { NUT_UNUSED_VARIABLE(fd); NUT_UNUSED_VARIABLE(buf); NUT_UNUSED_VARIABLE(buflen); NUT_UNUSED_VARIABLE(d_sec); NUT_UNUSED_VARIABLE(d_usec); NUT_WIN32_INCOMPLETE_LOGWARN(); /* upsdebugx(1, "WARNING: method %s() is not implemented yet for WIN32", __func__); */ return 0; } #endif /* WIN32 */ /* FIXME: would be good to get more from /etc/ld.so.conf[.d] and/or * LD_LIBRARY_PATH and a smarter dependency on build bitness; also * note that different OSes can have their pathnames set up differently * with regard to default/preferred bitness (maybe a "32" in the name * should also be searched explicitly - again, IFF our build is 32-bit). * * General premise for this solution is that some parts of NUT (e.g. the * nut-scanner tool, or DMF feature code) must be pre-built and distributed * in binary packages, but only at run-time it gets to know which third-party * libraries it should use for particular operations. This differs from e.g. * distribution packages which group NUT driver binaries explicitly dynamically * linked against certain OS-provided libraries for accessing this or that * communications media and/or vendor protocol. */ static const char * search_paths_builtin[] = { /* Use the library path (and bitness) provided during ./configure first */ LIBDIR, "/usr"LIBDIR, /* Note: this can lead to bogus strings like */ "/usr/local"LIBDIR, /* "/usr/usr/lib" which would be ignored quickly */ /* TOTHINK: Should AUTOTOOLS_* specs also be highly preferred? * Currently they are listed after the "legacy" hard-coded paths... */ #ifdef MULTIARCH_TARGET_ALIAS # ifdef BUILD_64 "/usr/lib/64/" MULTIARCH_TARGET_ALIAS, "/usr/lib64/" MULTIARCH_TARGET_ALIAS, "/lib/64/" MULTIARCH_TARGET_ALIAS, "/lib64/" MULTIARCH_TARGET_ALIAS, # endif /* MULTIARCH_TARGET_ALIAS && BUILD_64 */ "/usr/lib/" MULTIARCH_TARGET_ALIAS, "/lib/" MULTIARCH_TARGET_ALIAS, #endif /* MULTIARCH_TARGET_ALIAS */ #ifdef BUILD_64 /* Fall back to explicit preference of 64-bit paths as named on some OSes */ "/usr/lib/64", "/usr/lib64", #endif "/usr/lib", #ifdef BUILD_64 "/lib/64", "/lib64", #endif "/lib", #ifdef BUILD_64 "/usr/local/lib/64", "/usr/local/lib64", #endif "/usr/local/lib", #ifdef AUTOTOOLS_TARGET_SHORT_ALIAS "/usr/lib/" AUTOTOOLS_TARGET_SHORT_ALIAS, "/usr/lib/gcc/" AUTOTOOLS_TARGET_SHORT_ALIAS, #else # ifdef AUTOTOOLS_HOST_SHORT_ALIAS "/usr/lib/" AUTOTOOLS_HOST_SHORT_ALIAS, "/usr/lib/gcc/" AUTOTOOLS_HOST_SHORT_ALIAS, # else # ifdef AUTOTOOLS_BUILD_SHORT_ALIAS "/usr/lib/" AUTOTOOLS_BUILD_SHORT_ALIAS, "/usr/lib/gcc/" AUTOTOOLS_BUILD_SHORT_ALIAS, # endif # endif #endif #ifdef AUTOTOOLS_TARGET_ALIAS "/usr/lib/" AUTOTOOLS_TARGET_ALIAS, "/usr/lib/gcc/" AUTOTOOLS_TARGET_ALIAS, #else # ifdef AUTOTOOLS_HOST_ALIAS "/usr/lib/" AUTOTOOLS_HOST_ALIAS, "/usr/lib/gcc/" AUTOTOOLS_HOST_ALIAS, # else # ifdef AUTOTOOLS_BUILD_ALIAS "/usr/lib/" AUTOTOOLS_BUILD_ALIAS, "/usr/lib/gcc/" AUTOTOOLS_BUILD_ALIAS, # endif # endif #endif #ifdef WIN32 /* TODO: Track the binary program name (many platform-specific solutions, * or custom one to stash argv[0] in select programs, and derive its * dirname (with realpath and apparent path) as well as "../lib". * Perhaps a decent fallback idea for all platforms, not just WIN32. */ ".", #endif /* WIN32 */ NULL }; static const char ** search_paths = search_paths_builtin; /* free this when a NUT program ends (common library is unloaded) * IFF it is not the built-in version. */ static void nut_free_search_paths(void) { if (search_paths == NULL) { search_paths = search_paths_builtin; return; } if (search_paths != search_paths_builtin) { size_t i; for (i = 0; search_paths[i] != NULL; i++) { free((char *)search_paths[i]); } free(search_paths); search_paths = search_paths_builtin; } } void nut_prepare_search_paths(void) { /* Produce the search_paths[] with minimal confusion allowing * for faster walks and fewer logs in NUT applications: * * only existing paths * * discard lower-priority duplicates if a path is already listed * * NOTE: Currently this only trims info from search_paths_builtin[] * but might later supplant iterations in the get_libname(), * get_libname_in_pathset() and upsdebugx_report_search_paths() * methods. Surely would make their code easier, but at a cost of * probably losing detailed logging of where something came from... */ static int atexit_hooked = 0; size_t count_builtin = 0, count_filtered = 0, i, j, index = 0; const char ** filtered_search_paths; DIR *dp; /* As a starting point, allow at least as many items as before */ /* TODO: somehow extend (xrealloc?) if we mix other paths later */ for (i = 0; search_paths_builtin[i] != NULL; i++) {} count_builtin = i + 1; /* +1 for the NULL */ /* Bytes inside should all be zeroed... */ filtered_search_paths = xcalloc(count_builtin, sizeof(const char *)); /* FIXME: here "count_builtin" means size of filtered_search_paths[] * and may later be more, if we would consider other data sources */ for (i = 0; search_paths_builtin[i] != NULL && count_filtered < count_builtin; i++) { int dupe = 0; const char *dirname = search_paths_builtin[i]; if ((dp = opendir(dirname)) == NULL) { upsdebugx(5, "%s: SKIP " "unreachable directory #%" PRIuSIZE " : %s", __func__, index++, dirname); continue; } index++; #if HAVE_DECL_REALPATH /* allocates the buffer we free() later */ dirname = (const char *)realpath(dirname, NULL); #endif /* Revise for duplicates */ /* Note: (count_filtered == 0) means first existing dir seen, no hassle */ for (j = 0; j < count_filtered; j++) { if (!strcmp(filtered_search_paths[j], dirname)) { #if HAVE_DECL_REALPATH if (strcmp(search_paths_builtin[i], dirname)) { /* They differ, highlight it */ upsdebugx(5, "%s: SKIP " "duplicate directory #%" PRIuSIZE " : %s (%s)", __func__, index, dirname, search_paths_builtin[i]); } else #endif upsdebugx(5, "%s: SKIP " "duplicate directory #%" PRIuSIZE " : %s", __func__, index, dirname); dupe = 1; #if HAVE_DECL_REALPATH free((char *)dirname); /* Have some valid value, for kicks (likely * to be ignored in the code path below) */ dirname = search_paths_builtin[i]; #endif break; } } if (!dupe) { upsdebugx(5, "%s: ADD[#%" PRIuSIZE "] " "existing unique directory: %s", __func__, count_filtered, dirname); #if !HAVE_DECL_REALPATH /* Make a copy of table entry, else we have * a dynamic result of realpath() made above. */ dirname = (const char *)xstrdup(dirname); #endif filtered_search_paths[count_filtered++] = dirname; } /* else: dirname was freed above (for realpath) * or is a reference to the table entry; no need * to free() it either way */ closedir(dp); } /* If we mangled this before, forget the old result: */ nut_free_search_paths(); /* Better safe than sorry: */ filtered_search_paths[count_filtered] = NULL; search_paths = filtered_search_paths; if (!atexit_hooked) { atexit(nut_free_search_paths); atexit_hooked = 1; } } void upsdebugx_report_search_paths(int level, int report_search_paths_builtin) { size_t index; char *s, *varname; const char ** reported_search_paths = ( report_search_paths_builtin ? search_paths_builtin : search_paths); if (nut_debug_level < level) return; upsdebugx(level, "Run-time loadable library search paths used by this build of NUT:"); /* NOTE: Reporting order follows get_libname(), and * while some values are individual paths, others can * be "pathsets" (e.g. coming envvars) with certain * platform-dependent separator characters. */ #ifdef BUILD_64 varname = "LD_LIBRARY_PATH_64"; #else varname = "LD_LIBRARY_PATH_32"; #endif if (((s = getenv(varname)) != NULL) && strlen(s) > 0) { upsdebugx(level, "\tVia %s:\t%s", varname, s); } varname = "LD_LIBRARY_PATH"; if (((s = getenv(varname)) != NULL) && strlen(s) > 0) { upsdebugx(level, "\tVia %s:\t%s", varname, s); } for (index = 0; reported_search_paths[index] != NULL; index++) { if (index == 0) { upsdebugx(level, "\tNOTE: Reporting %s built-in paths:", (report_search_paths_builtin ? "raw" : "filtered (existing unique)")); } upsdebugx(level, "\tBuilt-in:\t%s", reported_search_paths[index]); } #ifdef WIN32 if (((s = getfullpath(NULL)) != NULL) && strlen(s) > 0) { upsdebugx(level, "\tWindows near EXE:\t%s", s); } # ifdef PATH_LIB if (((s = getfullpath(PATH_LIB)) != NULL) && strlen(s) > 0) { upsdebugx(level, "\tWindows PATH_LIB (%s):\t%s", PATH_LIB, s); } # endif if (((s = getfullpath("/../lib")) != NULL) && strlen(s) > 0) { upsdebugx(level, "\tWindows \"lib\" dir near EXE:\t%s", s); } varname = "PATH"; if (((s = getenv(varname)) != NULL) && strlen(s) > 0) { upsdebugx(level, "\tWindows via %s:\t%s", varname, s); } #endif /* WIN32 */ } static char * get_libname_in_dir(const char* base_libname, size_t base_libname_length, const char* dirname, int index) { /* Implementation detail for get_libname() below. * Returns pointer to allocated copy of the buffer * (caller must free later) if dir has lib, * or NULL otherwise. * base_libname_length is optimization to not recalculate length in a loop. * index is for search_paths[] table looping; use negative to not log dir number */ DIR *dp; struct dirent *dirp; char *libname_path = NULL, *libname_alias = NULL; char current_test_path[NUT_PATH_MAX + 1]; upsdebugx(3, "%s('%s', %" PRIuSIZE ", '%s', %i): Entering method...", __func__, base_libname, base_libname_length, dirname, index); memset(current_test_path, 0, sizeof(current_test_path)); if ((dp = opendir(dirname)) == NULL) { if (index >= 0) { upsdebugx(5, "%s: NOT looking for lib %s in " "unreachable directory #%d : %s", __func__, base_libname, index, dirname); } else { upsdebugx(5, "%s: NOT looking for lib %s in " "unreachable directory : %s", __func__, base_libname, dirname); } return NULL; } if (index >= 0) { upsdebugx(4, "%s: Looking for lib %s in directory #%d : %s", __func__, base_libname, index, dirname); } else { upsdebugx(4, "%s: Looking for lib %s in directory : %s", __func__, base_libname, dirname); } /* TODO: Try a quick stat() first? */ while ((dirp = readdir(dp)) != NULL) { #if !HAVE_DECL_REALPATH struct stat st; #endif int compres; upsdebugx(5, "%s: Comparing lib %s with dirpath entry %s", __func__, base_libname, dirp->d_name); compres = strncmp(dirp->d_name, base_libname, base_libname_length); if (compres == 0) { /* avoid "*.dll.a", ".so.1.2.3" etc. */ if (dirp->d_name[base_libname_length] != '\0') { if (!libname_alias) { libname_alias = xstrdup(dirp->d_name); } continue; } snprintf(current_test_path, sizeof(current_test_path), "%s/%s", dirname, dirp->d_name); #if HAVE_DECL_REALPATH libname_path = realpath(current_test_path, NULL); #else /* Just check if candidate name is (points to?) valid file */ libname_path = NULL; if (stat(current_test_path, &st) == 0) { if (st.st_size > 0) { libname_path = xstrdup(current_test_path); } } # ifdef WIN32 if (!libname_path) { char *p; for (p = current_test_path; *p != '\0' && (p - current_test_path) < LARGEBUF; p++) { if (*p == '/') *p = '\\'; } upsdebugx(4, "%s: WIN32: re-checking with %s", __func__, current_test_path); if (stat(current_test_path, &st) == 0) { if (st.st_size > 0) { libname_path = xstrdup(current_test_path); } } } if (!libname_path && strcmp(dirname, ".") == 0 && current_test_path[0] == '.' && current_test_path[1] == '\\' && current_test_path[2] != '\0') { /* Seems mingw stat() only works for files in current dir, * so for others a chdir() is needed (and memorizing the * original dir, and no threading at this moment, to be safe!) * https://stackoverflow.com/a/66096983/4715872 */ upsdebugx(4, "%s: WIN32: re-checking with %s", __func__, current_test_path + 2); if (stat(current_test_path + 2, &st) == 0) { if (st.st_size > 0) { libname_path = xstrdup(current_test_path + 2); } } } # endif /* WIN32 */ #endif /* HAVE_DECL_REALPATH */ upsdebugx(2, "Candidate path for lib %s is %s (realpath %s)", base_libname, current_test_path, NUT_STRARG(libname_path)); if (libname_path != NULL) break; } } /* while iterating dir */ closedir(dp); if (libname_alias) { if (!libname_path) { upsdebugx(1, "Got no strong candidate path for lib %s in %s" ", but saw seemingly related names (are you missing" " a symbolic link, perhaps?) e.g.: %s", base_libname, dirname, libname_alias); } free(libname_alias); } return libname_path; } static char * get_libname_in_pathset(const char* base_libname, size_t base_libname_length, char* pathset, int *counter) { /* Note: this method iterates specified pathset, * so it increments the counter by reference. * A copy of original pathset is used, because * strtok() tends to modify its input! */ char *libname_path = NULL; char *onedir = NULL; char* pathset_tmp; upsdebugx(3, "%s('%s', %" PRIuSIZE ", '%s', %i): Entering method...", __func__, base_libname, base_libname_length, NUT_STRARG(pathset), counter ? *counter : -1); if (!pathset || *pathset == '\0') return NULL; /* First call to tokenization passes the string, others pass NULL */ pathset_tmp = xstrdup(pathset); upsdebugx(4, "%s: Looking for lib %s in a colon-separated path set", __func__, base_libname); while (NULL != (onedir = strtok( (onedir ? NULL : pathset_tmp), ":" ))) { libname_path = get_libname_in_dir(base_libname, base_libname_length, onedir, (*counter)++); if (libname_path != NULL) break; } free(pathset_tmp); #ifdef WIN32 /* Note: with mingw, the ":" separator above might have been resolvable */ pathset_tmp = xstrdup(pathset); if (!libname_path) { onedir = NULL; /* probably is NULL already, but better ensure this */ upsdebugx(4, "%s: WIN32: Looking for lib %s in a semicolon-separated path set", __func__, base_libname); while (NULL != (onedir = strtok( (onedir ? NULL : pathset_tmp), ";" ))) { libname_path = get_libname_in_dir(base_libname, base_libname_length, onedir, (*counter)++); if (libname_path != NULL) break; } } free(pathset_tmp); #endif /* WIN32 */ return libname_path; } char * get_libname(const char* base_libname) { /* NOTE: Keep changes to practical search order * synced to upsdebugx_report_search_paths() */ int index = 0, counter = 0; char *libname_path = NULL; size_t base_libname_length = strlen(base_libname); struct stat st; upsdebugx(3, "%s('%s'): Entering method...", __func__, base_libname); /* First, check for an exact hit by absolute/relative path * if `base_libname` includes path separator character(s) */ if (xbasename(base_libname) != base_libname) { upsdebugx(4, "%s: Looking for lib %s by exact hit...", __func__, base_libname); #if HAVE_DECL_REALPATH /* allocates the buffer we free() later */ libname_path = realpath(base_libname, NULL); if (libname_path != NULL) { if (stat(libname_path, &st) == 0) { if (st.st_size > 0) { upsdebugx(2, "Looking for lib %s, found by exact hit", base_libname); goto found; } } /* else: does not actually exist */ free(libname_path); libname_path = NULL; } #endif /* HAVE_DECL_REALPATH */ /* Just check if candidate name is (points to?) valid file */ if (stat(base_libname, &st) == 0) { if (st.st_size > 0) { libname_path = xstrdup(base_libname); upsdebugx(2, "Looking for lib %s, found by exact hit", base_libname); goto found; } } } /* Normally these envvars should not be set, but if the user insists, * we should prefer the override... */ #ifdef BUILD_64 upsdebugx(4, "%s: Looking for lib %s by path-set LD_LIBRARY_PATH_64...", __func__, base_libname); libname_path = get_libname_in_pathset(base_libname, base_libname_length, getenv("LD_LIBRARY_PATH_64"), &counter); if (libname_path != NULL) { upsdebugx(2, "Looking for lib %s, found in LD_LIBRARY_PATH_64", base_libname); goto found; } #else upsdebugx(4, "%s: Looking for lib %s by path-set LD_LIBRARY_PATH_32...", __func__, base_libname); libname_path = get_libname_in_pathset(base_libname, base_libname_length, getenv("LD_LIBRARY_PATH_32"), &counter); if (libname_path != NULL) { upsdebugx(2, "Looking for lib %s, found in LD_LIBRARY_PATH_32", base_libname); goto found; } #endif upsdebugx(4, "%s: Looking for lib %s by path-set LD_LIBRARY_PATH...", __func__, base_libname); libname_path = get_libname_in_pathset(base_libname, base_libname_length, getenv("LD_LIBRARY_PATH"), &counter); if (libname_path != NULL) { upsdebugx(2, "Looking for lib %s, found in LD_LIBRARY_PATH", base_libname); goto found; } upsdebugx(4, "%s: Looking for lib %s by search_paths[]...", __func__, base_libname); for (index = 0 ; (search_paths[index] != NULL) && (libname_path == NULL) ; index++) { libname_path = get_libname_in_dir(base_libname, base_libname_length, search_paths[index], counter++); if (libname_path != NULL) break; } #ifdef WIN32 /* TODO: Need a reliable cross-platform way to get the full path * of current executable -- possibly stash it when starting NUT * programs... consider some way for `nut-scanner` too */ if (!libname_path) { /* First check near the EXE (if executing it from another * working directory) */ upsdebugx(4, "%s: WIN32: Looking for lib %s near EXE...", __func__, base_libname); libname_path = get_libname_in_dir(base_libname, base_libname_length, getfullpath(NULL), counter++); } # ifdef PATH_LIB if (!libname_path) { upsdebugx(4, "%s: WIN32: Looking for lib %s via PATH_LIB...", __func__, base_libname); libname_path = get_libname_in_dir(base_libname, base_libname_length, getfullpath(PATH_LIB), counter++); } # endif if (!libname_path) { /* Resolve "lib" dir near the one with current executable ("bin" or "sbin") */ upsdebugx(4, "%s: WIN32: Looking for lib %s in a 'lib' dir near EXE...", __func__, base_libname); libname_path = get_libname_in_dir(base_libname, base_libname_length, getfullpath("/../lib"), counter++); } #endif /* WIN32 so far */ #ifdef WIN32 /* Windows-specific: DLLs can be provided by common "PATH" envvar, * at lowest search priority though (after EXE dir, system, etc.) */ if (!libname_path) { upsdebugx(4, "%s: WIN32: Looking for lib %s in PATH", __func__, base_libname); libname_path = get_libname_in_pathset(base_libname, base_libname_length, getenv("PATH"), &counter); } #endif /* WIN32 */ found: upsdebugx(1, "Looking for lib %s, found %s", base_libname, NUT_STRARG(libname_path)); return libname_path; } /* TODO: Extend for TYPE_FD and WIN32 eventually? */ void set_close_on_exec(int fd) { /* prevent fd leaking to child processes */ #ifndef FD_CLOEXEC /* Find a way, if possible at all old platforms */ NUT_UNUSED_VARIABLE(fd); #else # ifdef WIN32 /* Find a way, if possible at all (WIN32: get INT fd from the HANDLE?) */ NUT_UNUSED_VARIABLE(fd); NUT_WIN32_INCOMPLETE(); # else /* !WIN32 */ fcntl(fd, F_SETFD, FD_CLOEXEC); # endif /* !WIN32 */ #endif } /**** REGEX helper methods ****/ int strcmp_null(const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) { return 0; } if (s1 == NULL) { return -1; } if (s2 == NULL) { return 1; } return strcmp(s1, s2); } #if (defined HAVE_LIBREGEX && HAVE_LIBREGEX) int compile_regex(regex_t **compiled, const char *regex, const int cflags) { int r; regex_t *preg; if (regex == NULL) { *compiled = NULL; return 0; } preg = malloc(sizeof(*preg)); if (!preg) { return -1; } r = regcomp(preg, regex, cflags); if (r) { free(preg); return -2; } *compiled = preg; return 0; } int match_regex(const regex_t *preg, const char *str) { int r; size_t len = 0; char *string; regmatch_t match; if (!preg) { return 1; } if (!str) { string = xstrdup(""); } else { /* skip leading whitespace */ for (len = 0; len < strlen(str); len++) { if (!strchr(" \t\n", str[len])) { break; } } string = xstrdup(str+len); /* skip trailing whitespace */ for (len = strlen(string); len > 0; len--) { if (!strchr(" \t\n", string[len-1])) { break; } } string[len] = '\0'; } /* test the regular expression */ r = regexec(preg, string, 1, &match, 0); free(string); if (r) { return 0; } /* check that the match is the entire string */ if ((match.rm_so != 0) || (match.rm_eo != (int)len)) { return 0; } return 1; } int match_regex_hex(const regex_t *preg, const int n) { char buf[10]; snprintf(buf, sizeof(buf), "%04x", (unsigned int)n); return match_regex(preg, buf); } #endif /* HAVE_LIBREGEX */ nut-2.8.3/common/strerror.c0000644000200500020050000002732514777534445012612 00000000000000/* strerror() Mark Powell */ /* Simple implementation derived from libiberty */ #include "config.h" #ifndef HAVE_STRERROR #include #ifdef HAVE_STDIO_H # include /* for snprintf() */ #else # include "proto.h" #endif char *strerror(int errnum) { static char buf[32]; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK #pragma GCC diagnostic ignored "-Wunreachable-code-break" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic ignored "-Wunreachable-code" #endif switch (errnum) { #if defined (EPERM) case EPERM: return "Not owner"; #endif #if defined (ENOENT) case ENOENT: return "No such file or directory"; #endif #if defined (ESRCH) case ESRCH: return "No such process"; #endif #if defined (EINTR) case EINTR: return "Interrupted system call"; #endif #if defined (EIO) case EIO: return "I/O error"; #endif #if defined (ENXIO) case ENXIO: return "No such device or address"; #endif #if defined (E2BIG) return "Arg list too long"; #endif #if defined (ENOEXEC) case ENOEXEC: return "Exec format error"; #endif #if defined (EBADF) case EBADF: return "Bad file number"; #endif #if defined (ECHILD) case ECHILD: return "No child processes"; #endif #if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */ case EWOULDBLOCK: return "Operation would block"; #endif #if defined (EAGAIN) #if defined (EWOULDBLOCK) && EAGAIN != EWOULDBLOCK case EAGAIN: return "No more processes"; #endif #endif #if defined (ENOMEM) case ENOMEM: return "Not enough space"; #endif #if defined (EACCES) case EACCES: return "Permission denied"; #endif #if defined (EFAULT) case EFAULT: return "Bad address"; #endif #if defined (ENOTBLK) case ENOTBLK: return "Block device required"; #endif #if defined (EBUSY) case EBUSY: return "Device busy"; #endif #if defined (EEXIST) case EEXIST: return "File exists"; #endif #if defined (EXDEV) case EXDEV: return "Cross-device link"; #endif #if defined (ENODEV) case ENODEV: return "No such device"; #endif #if defined (ENOTDIR) case ENOTDIR: return "Not a directory"; #endif #if defined (EISDIR) case EISDIR: return "Is a directory"; #endif #if defined (EINVAL) case EINVAL: return "Invalid argument"; #endif #if defined (ENFILE) case ENFILE: return "File table overflow"; #endif #if defined (EMFILE) case EMFILE: return "Too many open files"; #endif #if defined (ENOTTY) case ENOTTY: return "Not a typewriter"; #endif #if defined (ETXTBSY) case ETXTBSY: return "Text file busy"; #endif #if defined (EFBIG) case EFBIG: return "File too large"; #endif #if defined (ENOSPC) case ENOSPC: return "No space left on device"; #endif #if defined (ESPIPE) case ESPIPE: return "Illegal seek"; #endif #if defined (EROFS) case EROFS: return "Read-only file system"; #endif #if defined (EMLINK) case EMLINK: return "Too many links"; #endif #if defined (EPIPE) case EPIPE: return "Broken pipe"; #endif #if defined (EDOM) case EDOM: return "Math argument out of domain of func"; #endif #if defined (ERANGE) case ERANGE: return "Math result not representable"; #endif #if defined (ENOMSG) case ENOMSG: return "No message of desired type"; #endif #if defined (EIDRM) case EIDRM: return "Identifier removed"; #endif #if defined (ECHRNG) case ECHRNG: return "Channel number out of range"; #endif #if defined (EL2NSYNC) return "Level 2 not synchronized"; #endif #if defined (EL3HLT) return "Level 3 halted"; #endif #if defined (EL3RST) return "Level 3 reset"; #endif #if defined (ELNRNG) case ELNRNG: return "Link number out of range"; #endif #if defined (EUNATCH) case EUNATCH: return "Protocol driver not attached"; #endif #if defined (ENOCSI) case ENOCSI: return "No CSI structure available"; #endif #if defined (EL2HLT) return "Level 2 halted"; #endif #if defined (EDEADLK) case EDEADLK: return "Deadlock condition"; #endif #if defined (ENOLCK) case ENOLCK: return "No record locks available"; #endif #if defined (EBADE) case EBADE: return "Invalid exchange"; #endif #if defined (EBADR) case EBADR: return "Invalid request descriptor"; #endif #if defined (EXFULL) case EXFULL: return "Exchange full"; #endif #if defined (ENOANO) case ENOANO: return "No anode"; #endif #if defined (EBADRQC) case EBADRQC: return "Invalid request code"; #endif #if defined (EBADSLT) case EBADSLT: return "Invalid slot"; #endif #if defined (EDEADLOCK) # if (!defined(EDEADLK)) || EDEADLK != EDEADLOCK case EDEADLOCK: return "File locking deadlock error"; # endif #endif #if defined (EBFONT) case EBFONT: return "Bad font file format"; #endif #if defined (ENOSTR) case ENOSTR: return "Device not a stream"; #endif #if defined (ENODATA) case ENODATA: return "No data available"; #endif #if defined (ETIME) case ETIME: return "Timer expired"; #endif #if defined (ENOSR) case ENOSR: return "Out of streams resources"; #endif #if defined (ENONET) case ENONET: return "Machine is not on the network"; #endif #if defined (ENOPKG) case ENOPKG: return "Package not installed"; #endif #if defined (EREMOTE) case EREMOTE: return "Object is remote"; #endif #if defined (ENOLINK) case ENOLINK: return "Link has been severed"; #endif #if defined (EADV) case EADV: return "Advertise error"; #endif #if defined (ESRMNT) case ESRMNT: return "Srmount error"; #endif #if defined (ECOMM) case ECOMM: return "Communication error on send"; #endif #if defined (EPROTO) case EPROTO: return "Protocol error"; #endif #if defined (EMULTIHOP) case EMULTIHOP: return "Multihop attempted"; #endif #if defined (EDOTDOT) case EDOTDOT: return "RFS specific error"; #endif #if defined (EBADMSG) case EBADMSG: return "Not a data message"; #endif #if defined (ENAMETOOLONG) case ENAMETOOLONG: return "File name too long"; #endif #if defined (EOVERFLOW) case EOVERFLOW: return "Value too large for defined data type"; #endif #if defined (ENOTUNIQ) case ENOTUNIQ: return "Name not unique on network"; #endif #if defined (EBADFD) case EBADFD: return "File descriptor in bad state"; #endif #if defined (EREMCHG) case EREMCHG: return "Remote address changed"; #endif #if defined (ELIBACC) case ELIBACC: return "Can not access a needed shared library"; #endif #if defined (ELIBBAD) case ELIBBAD: return "Accessing a corrupted shared library"; #endif #if defined (ELIBSCN) case ELIBSCN: return ".lib section in a.out corrupted"; #endif #if defined (ELIBMAX) case ELIBMAX: return "Attempting to link in too many shared libraries"; #endif #if defined (ELIBEXEC) case ELIBEXEC: return "Cannot exec a shared library directly"; #endif #if defined (EILSEQ) case EILSEQ: return "Illegal byte sequence"; #endif #if defined (ENOSYS) case ENOSYS: return "Operation not applicable"; #endif #if defined (ELOOP) case ELOOP: return "Too many symbolic links encountered"; #endif #if defined (ERESTART) case ERESTART: return "Interrupted system call should be restarted"; #endif #if defined (ESTRPIPE) case ESTRPIPE: return "Streams pipe error"; #endif #if defined (ENOTEMPTY) case ENOTEMPTY: return "Directory not empty"; #endif #if defined (EUSERS) case EUSERS: return "Too many users"; #endif #if defined (ENOTSOCK) case ENOTSOCK: return "Socket operation on non-socket"; #endif #if defined (EDESTADDRREQ) case EDESTADDRREQ: return "Destination address required"; #endif #if defined (EMSGSIZE) case EMSGSIZE: return "Message too long"; #endif #if defined (EPROTOTYPE) case EPROTOTYPE: return "Protocol wrong type for socket"; #endif #if defined (ENOPROTOOPT) case ENOPROTOOPT: return "Protocol not available"; #endif #if defined (EPROTONOSUPPORT) case EPROTONOSUPPORT: return "Protocol not supported"; #endif #if defined (ESOCKTNOSUPPORT) case ESOCKTNOSUPPORT: return "Socket type not supported"; #endif #if defined (EOPNOTSUPP) case EOPNOTSUPP: return "Operation not supported on transport endpoint"; #endif #if defined (EPFNOSUPPORT) case EPFNOSUPPORT: return "Protocol family not supported"; #endif #if defined (EAFNOSUPPORT) case EAFNOSUPPORT: return "Address family not supported by protocol"; #endif #if defined (EADDRINUSE) case EADDRINUSE: return "Address already in use"; #endif #if defined (EADDRNOTAVAIL) case EADDRNOTAVAIL: return "Cannot assign requested address"; #endif #if defined (ENETDOWN) case ENETDOWN: return "Network is down"; #endif #if defined (ENETUNREACH) case ENETUNREACH: return "Network is unreachable"; #endif #if defined (ENETRESET) case ENETRESET: return "Network dropped connection because of reset"; #endif #if defined (ECONNABORTED) case ECONNABORTED: return "Software caused connection abort"; #endif #if defined (ECONNRESET) case ECONNRESET: return "Connection reset by peer"; #endif #if defined (ENOBUFS) case ENOBUFS: return "No buffer space available"; #endif #if defined (EISCONN) case EISCONN: return "Transport endpoint is already connected"; #endif #if defined (ENOTCONN) case ENOTCONN: return "Transport endpoint is not connected"; #endif #if defined (ESHUTDOWN) case ESHUTDOWN: return "Cannot send after transport endpoint shutdown"; #endif #if defined (ETOOMANYREFS) case ETOOMANYREFS: return "Too many references: cannot splice"; #endif #if defined (ETIMEDOUT) case ETIMEDOUT: return "Connection timed out"; #endif #if defined (ECONNREFUSED) case ECONNREFUSED: return "Connection refused"; #endif #if defined (EHOSTDOWN) case EHOSTDOWN: return "Host is down"; #endif #if defined (EHOSTUNREACH) case EHOSTUNREACH: return "No route to host"; #endif #if defined (EALREADY) case EALREADY: return "Operation already in progress"; #endif #if defined (EINPROGRESS) case EINPROGRESS: return "Operation now in progress"; #endif #if defined (ESTALE) case ESTALE: return "Stale NFS file handle"; #endif #if defined (EUCLEAN) case EUCLEAN: return "Structure needs cleaning"; #endif #if defined (ENOTNAM) case ENOTNAM: return "Not a XENIX named type file"; #endif #if defined (ENAVAIL) case ENAVAIL: return "No XENIX semaphores available"; #endif #if defined (EISNAM) case EISNAM: return "Is a named type file"; #endif #if defined (EREMOTEIO) case EREMOTEIO: return "Remote I/O error"; #endif } /* Fallback: just print the error number */ snprintf(buf, sizeof(buf), "Error %d", errnum); return buf; #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE #pragma GCC diagnostic pop #endif } #endif /* HAVE_STRERROR */ nut-2.8.3/common/atexit.c0000644000200500020050000000075514777534445012224 00000000000000/* atexit() Mark Powell */ /* Implemented in terms of on_exit() for old BSD-style systems, like SunOS4 */ #include "config.h" #ifndef HAVE_ATEXIT #include #include "common.h" int atexit(fn) void (*fn)(); { #ifdef HAVE_ON_EXIT return on_exit(fn, 0); #else NUT_UNUSED_VARIABLE(fn); /* Choose some errno thats likely to exist on lots of systems */ errno = EPERM; return (-1); #endif /* HAVE_ON_EXIT */ } #endif /* HAVE_ATEXIT */ nut-2.8.3/common/snprintf.c0000644000200500020050000005700314777534445012567 00000000000000/* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point... * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nast effects. * * More Recently: * Brandon Long 9/15/96 for mutt 0.43 * This was ugly. It is still ugly. I opted out of floating point * numbers, but the formatter understands just about everything * from the normal C string format, at least as far as I can tell from * the Solaris 2.5 printf(3S) man page. * * Brandon Long 10/22/97 for mutt 0.87.1 * Ok, added some minimal floating point support, which means this * probably requires libm on most operating systems. Don't yet * support the exponent (e,E) and sigfig (g,G). Also, fmtint() * was pretty badly broken, it just wasn't being exercised in ways * which showed it, so that's been fixed. Also, formated the code * to mutt conventions, and removed dead code left over from the * original. Also, there is now a builtin-test, just compile with: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm * and run snprintf for results. * * Thomas Roessler 01/27/98 for mutt 0.89i * The PGP code was using unsigned hexadecimal formats. * Unfortunately, unsigned formats simply didn't work. * * Michael Elkins 03/05/98 for mutt 0.90.8 * The original code assumed that both snprintf() and vsnprintf() were * missing. Some systems only have snprintf() but not vsnprintf(), so * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. * * Andrew Tridgell (tridge@samba.org) Oct 1998 * fixed handling of %.0f * added test for HAVE_LONG_DOUBLE * **************************************************************/ #include "config.h" #include #include #include #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) /* Define this as a fall through, HAVE_STDARG_H is probably already set */ #ifndef HAVE_VARARGS_H #define HAVE_VARARGS_H #endif /* varargs declarations: */ #if defined(HAVE_STDARG_H) # include # define HAVE_STDARGS /* let's hope that works everywhere (mj) */ # define VA_LOCAL_DECL va_list ap # define VA_START(f) va_start(ap, f) # define VA_SHIFT(v,t) ; /* no-op for ANSI */ # define VA_END va_end(ap) #else # if defined(HAVE_VARARGS_H) # include # undef HAVE_STDARGS # define VA_LOCAL_DECL va_list ap # define VA_START(f) va_start(ap) /* f is ignored! */ # define VA_SHIFT(v,t) v = va_arg(ap,t) # define VA_END va_end(ap) # else /*XX ** NO VARARGS ** XX*/ # endif #endif #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double #else #define LDOUBLE double #endif #ifdef HAVE_LONG_LONG_INT #define LLONG long long #else #define LLONG long #endif /*int snprintf (char *str, size_t count, const char *fmt, ...);*/ /*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args); static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max); static void fmtint (char *buffer, size_t *currlen, size_t maxlen, long value, int base, int min, int max, int flags); static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags); static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c ); /* * dopr(): poor man's version of doprintf */ /* format read states */ #define DP_S_DEFAULT 0 #define DP_S_FLAGS 1 #define DP_S_MIN 2 #define DP_S_DOT 3 #define DP_S_MAX 4 #define DP_S_MOD 5 #define DP_S_CONV 6 #define DP_S_DONE 7 /* format flags - Bits */ #define DP_F_MINUS (1 << 0) #define DP_F_PLUS (1 << 1) #define DP_F_SPACE (1 << 2) #define DP_F_NUM (1 << 3) #define DP_F_ZERO (1 << 4) #define DP_F_UP (1 << 5) #define DP_F_UNSIGNED (1 << 6) /* Conversion Flags */ #define DP_C_SHORT 1 /* Note: Originally DP_C_SHORT converted to "short int" types, but modernish * (C99+ or even earlier) standards require that the minimal type passed * through variadic args '...' is an int, and smaller types are padded up * to it - so value shifts in memory and erroneous access crashes can occur * if smaller data is accessed blindly. Code below has been fixed to not pass * "short int" anymore - it just casts the int to desired smaller type (and * so drops the padding bits). */ #define DP_C_LONG 2 #define DP_C_LDOUBLE 3 #define DP_C_LLONG 4 #ifdef C89PLUS #undef C89PLUS #endif #if defined(__STDC__) || defined(__STDC_VERSION__) /* C89+ and C90+ code respectively */ #define C89PLUS 1 #endif #define char_to_int(p) ((p)- '0') #define MAX(p,q) (((p) >= (q)) ? (p) : (q)) static void dopr (char *buffer, size_t maxlen, const char *format, va_list args) { char ch; LLONG value; LDOUBLE fvalue; char *strvalue; int min; int max; int state; int flags; int cflags; size_t currlen; state = DP_S_DEFAULT; currlen = flags = cflags = min = 0; max = -1; ch = *format++; while (state != DP_S_DONE) { if ((ch == '\0') || (currlen >= maxlen)) state = DP_S_DONE; switch(state) { case DP_S_DEFAULT: if (ch == '%') state = DP_S_FLAGS; else dopr_outch (buffer, &currlen, maxlen, ch); ch = *format++; break; case DP_S_FLAGS: switch (ch) { case '-': flags |= DP_F_MINUS; ch = *format++; break; case '+': flags |= DP_F_PLUS; ch = *format++; break; case ' ': flags |= DP_F_SPACE; ch = *format++; break; case '#': flags |= DP_F_NUM; ch = *format++; break; case '0': flags |= DP_F_ZERO; ch = *format++; break; default: state = DP_S_MIN; break; } break; case DP_S_MIN: if (isdigit((unsigned char)ch)) { min = 10*min + char_to_int (ch); ch = *format++; } else if (ch == '*') { min = va_arg (args, int); ch = *format++; state = DP_S_DOT; } else state = DP_S_DOT; break; case DP_S_DOT: if (ch == '.') { state = DP_S_MAX; ch = *format++; } else state = DP_S_MOD; break; case DP_S_MAX: if (isdigit((unsigned char)ch)) { if (max < 0) max = 0; max = 10*max + char_to_int (ch); ch = *format++; } else if (ch == '*') { max = va_arg (args, int); ch = *format++; state = DP_S_MOD; } else state = DP_S_MOD; break; case DP_S_MOD: switch (ch) { case 'h': cflags = DP_C_SHORT; ch = *format++; break; case 'l': cflags = DP_C_LONG; ch = *format++; if (ch == 'l') { /* It's a long long */ cflags = DP_C_LLONG; ch = *format++; } break; case 'L': cflags = DP_C_LDOUBLE; ch = *format++; break; default: break; } state = DP_S_CONV; break; case DP_S_CONV: switch (ch) { case 'd': case 'i': if (cflags == DP_C_SHORT) #ifdef C89PLUS value = (short int)va_arg (args, int); #else value = va_arg (args, short int); #endif else if (cflags == DP_C_LONG) value = va_arg (args, long int); else if (cflags == DP_C_LLONG) value = va_arg (args, LLONG); else value = va_arg (args, int); fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'o': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) #ifdef C89PLUS value = (unsigned short int)va_arg (args, unsigned int); #else value = va_arg (args, unsigned short int); #endif else if (cflags == DP_C_LONG) value = (long)va_arg (args, unsigned long int); else if (cflags == DP_C_LLONG) value = (long)va_arg (args, unsigned LLONG); else value = (long)va_arg (args, unsigned int); fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); break; case 'u': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) #ifdef C89PLUS value = (unsigned short int)va_arg (args, unsigned int); #else value = va_arg (args, unsigned short int); #endif else if (cflags == DP_C_LONG) value = (long)va_arg (args, unsigned long int); else if (cflags == DP_C_LLONG) value = (LLONG)va_arg (args, unsigned LLONG); else value = (long)va_arg (args, unsigned int); fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'X': flags |= DP_F_UP; goto fallthrough_case_x; case 'x': fallthrough_case_x: flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) #ifdef C89PLUS value = (unsigned short int)va_arg (args, unsigned int); #else value = va_arg (args, unsigned short int); #endif else if (cflags == DP_C_LONG) value = (long)va_arg (args, unsigned long int); else if (cflags == DP_C_LLONG) value = (LLONG)va_arg (args, unsigned LLONG); else value = (long)va_arg (args, unsigned int); fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); break; case 'f': if (cflags == DP_C_LDOUBLE) fvalue = va_arg (args, LDOUBLE); else fvalue = va_arg (args, double); /* um, floating point? */ fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'E': flags |= DP_F_UP; goto fallthrough_case_e; case 'e': fallthrough_case_e: if (cflags == DP_C_LDOUBLE) fvalue = va_arg (args, LDOUBLE); else fvalue = va_arg (args, double); break; case 'G': flags |= DP_F_UP; goto fallthrough_case_g; case 'g': fallthrough_case_g: if (cflags == DP_C_LDOUBLE) fvalue = va_arg (args, LDOUBLE); else fvalue = va_arg (args, double); break; case 'c': dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); break; case 's': strvalue = va_arg (args, char *); if (max < 0) max = maxlen; /* ie, no max */ fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); break; case 'p': strvalue = va_arg (args, void *); /* FIXME: in 64-bit (and Windows-targeted) builds this code yields: * warning: cast from pointer to integer of different size * so probably prints a truncated pointer value. Should check * if sizeof(void*) == sizeof(long) and output e.g. two pieces * (lower and upper long for bytes of the pointer). */ fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); break; case 'n': if (cflags == DP_C_SHORT) { short int *num; num = va_arg (args, short int *); *num = currlen; } else if (cflags == DP_C_LONG) { long int *num; num = va_arg (args, long int *); *num = (long int)currlen; } else if (cflags == DP_C_LLONG) { LLONG *num; num = va_arg (args, LLONG *); *num = (LLONG)currlen; } else { int *num; num = va_arg (args, int *); *num = currlen; } break; case '%': dopr_outch (buffer, &currlen, maxlen, ch); break; case 'w': /* not supported yet, treat as next char */ ch = *format++; break; default: /* Unknown, skip */ break; } ch = *format++; state = DP_S_DEFAULT; flags = cflags = min = 0; max = -1; break; case DP_S_DONE: break; default: /* hmm? */ break; /* some picky compilers need this */ } } if (currlen < maxlen - 1) buffer[currlen] = '\0'; else buffer[maxlen - 1] = '\0'; } static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max) { int padlen, strln; /* amount to pad */ int cnt = 0; if (value == 0) { value = ""; } for (strln = 0; value[strln]; ++strln); /* strlen */ padlen = min - strln; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justify */ while ((padlen > 0) && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, ' '); --padlen; ++cnt; } while (*value && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, *value++); ++cnt; } while ((padlen < 0) && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; ++cnt; } } /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ static void fmtint (char *buffer, size_t *currlen, size_t maxlen, long value, int base, int min, int max, int flags) { int signvalue = 0; unsigned long uvalue; char convert[20]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ int caps = 0; if (max < 0) max = 0; uvalue = value; if(!(flags & DP_F_UNSIGNED)) { if( value < 0 ) { signvalue = '-'; uvalue = -value; } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ signvalue = '+'; else if (flags & DP_F_SPACE) signvalue = ' '; } if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ do { convert[place++] = (caps? "0123456789ABCDEF":"0123456789abcdef") [uvalue % (unsigned)base ]; uvalue = (uvalue / (unsigned)base ); } while(uvalue && (place < 20)); if (place == 20) place--; convert[place] = 0; zpadlen = max - place; spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); if (zpadlen < 0) zpadlen = 0; if (spadlen < 0) spadlen = 0; if (flags & DP_F_ZERO) { zpadlen = MAX(zpadlen, spadlen); spadlen = 0; } if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */ #ifdef DEBUG_SNPRINTF printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", zpadlen, spadlen, min, max, place); #endif /* Spaces */ while (spadlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --spadlen; } /* Sign */ if (signvalue) dopr_outch (buffer, currlen, maxlen, signvalue); /* Zeros */ if (zpadlen > 0) { while (zpadlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --zpadlen; } } /* Digits */ while (place > 0) dopr_outch (buffer, currlen, maxlen, convert[--place]); /* Left Justified spaces */ while (spadlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++spadlen; } } #ifndef HAVE_ABS_VAL static LDOUBLE abs_val (LDOUBLE value) { LDOUBLE result = value; if (value < 0) result = -value; return result; } #endif #ifndef WIN32 # ifndef HAVE_FCVT /* The two routines that may get defined below are only used if we also don't * have a fcvt() in the system. Defining and not using the routines may be a * warning (fatal with -Werror), so we hide them here. * FIXME: They are blindly expected (assumed?) to be available on Windows, * maybe better trust configure script macros on this? */ # if ! HAVE_DECL_POW10 static LDOUBLE pow10 (int exp) { LDOUBLE result = 1; while (exp) { result *= 10; exp--; } return result; } # endif /* HAVE_DECL_POW10 */ # if ! HAVE_DECL_ROUND static long round (LDOUBLE value) { long intpart; intpart = (long)value; value = value - intpart; if (value >= 0.5) intpart++; return intpart; } # endif /* HAVE_DECL_ROUND */ # endif /* HAVE_FCVT */ #endif /* WIN32 */ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags) { int signvalue = 0; LDOUBLE ufvalue; #ifndef HAVE_FCVT char iconvert[20]; char fconvert[20]; #else char iconvert[311]; char fconvert[311]; char *result; int dec_pt, sig; int r_length; # ifdef HAVE_FCVTL extern char *fcvtl(long double value, int ndigit, int *decpt, int *sign); # else extern char *fcvt(double value, int ndigit, int *decpt, int *sign); # endif #endif int iplace = 0; int fplace = 0; int padlen = 0; /* amount to pad */ int zpadlen = 0; #ifndef HAVE_FCVT int caps = 0; long intpart; long fracpart; #endif /* * AIX manpage says the default is 0, but Solaris says the default * is 6, and sprintf on AIX defaults to 6 */ if (max < 0) max = 6; ufvalue = abs_val (fvalue); if (fvalue < 0) signvalue = '-'; else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ signvalue = '+'; else if (flags & DP_F_SPACE) signvalue = ' '; #if 0 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ #endif #ifndef HAVE_FCVT intpart = (long)ufvalue; /* * Sorry, we only support 9 digits past the decimal because of our * conversion method */ if (max > 9) max = 9; /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 */ fracpart = round ((pow10 (max)) * (ufvalue - intpart)); if (fracpart >= pow10 (max)) { intpart++; fracpart -= pow10 (max); } #ifdef DEBUG_SNPRINTF printf("fmtfp: %g %d.%d min=%d max=%d\n", (double)fvalue, intpart, fracpart, min, max); #endif /* Convert integer part */ do { iconvert[iplace++] = (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10]; intpart = (intpart / 10); } while(intpart && (iplace < 20)); if (iplace == 20) iplace--; iconvert[iplace] = 0; /* Convert fractional part */ do { fconvert[fplace++] = (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10]; fracpart = (fracpart / 10); } while(fracpart && (fplace < 20)); if (fplace == 20) fplace--; fconvert[fplace] = 0; #else /* use fcvt() */ if (max > 310) max = 310; # ifdef HAVE_FCVTL result = fcvtl(ufvalue, max, &dec_pt, &sig); # else result = fcvt(ufvalue, max, &dec_pt, &sig); # endif r_length = strlen(result); /* * Fix broken fcvt implementation returns.. */ if (r_length == 0) { result[0] = '0'; result[1] = '\0'; r_length = 1; } if ( r_length < dec_pt ) dec_pt = r_length; if (dec_pt <= 0) { iplace = 1; iconvert[0] = '0'; iconvert[1] = '\0'; fplace = 0; while(r_length) fconvert[fplace++] = result[--r_length]; while ((dec_pt < 0) && (fplace < max)) { fconvert[fplace++] = '0'; dec_pt++; } } else { int c; iplace=0; for(c=dec_pt; c; iconvert[iplace++] = result[--c]) ; iconvert[iplace] = '\0'; result += dec_pt; fplace = 0; for(c=(r_length-dec_pt); c; fconvert[fplace++] = result[--c]) ; } #endif /* fcvt */ /* -1 for decimal point, another -1 if we are printing a sign */ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); zpadlen = max - fplace; if (zpadlen < 0) zpadlen = 0; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justifty */ if ((flags & DP_F_ZERO) && (padlen > 0)) { if (signvalue) { dopr_outch (buffer, currlen, maxlen, signvalue); --padlen; signvalue = 0; } while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --padlen; } } while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --padlen; } if (signvalue) dopr_outch (buffer, currlen, maxlen, signvalue); while (iplace > 0) dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); #ifdef DEBUG_SNPRINTF printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); #endif /* * Decimal point. This should probably use locale to find the correct * char to print out. */ if (max > 0) { dopr_outch (buffer, currlen, maxlen, '.'); while (fplace > 0) dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); } while (zpadlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --zpadlen; } while (padlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; } } static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) { if (*currlen < maxlen) buffer[(*currlen)++] = c; } #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ #ifndef HAVE_VSNPRINTF int vsnprintf (char *str, size_t count, const char *fmt, va_list args) { str[0] = 0; dopr(str, count, fmt, args); return(strlen(str)); } #endif /* !HAVE_VSNPRINTF */ #ifndef HAVE_SNPRINTF /* VARARGS3 */ #ifdef HAVE_STDARGS int snprintf (char *str,size_t count,const char *fmt,...) #else int snprintf (va_alist) va_dcl #endif { #ifndef HAVE_STDARGS char *str; size_t count; char *fmt; #endif VA_LOCAL_DECL; VA_START (fmt); VA_SHIFT (str, char *); VA_SHIFT (count, size_t ); VA_SHIFT (fmt, char *); (void) vsnprintf(str, count, fmt, ap); VA_END; return(strlen(str)); } #else /* keep compilers happy about empty files */ void dummy_snprintf(void) {} #endif /* !HAVE_SNPRINTF */ #ifdef TEST_SNPRINTF #ifndef LONG_STRING #define LONG_STRING 1024 #endif int main (void) { char buf1[LONG_STRING]; char buf2[LONG_STRING]; char *fp_fmt[] = { "%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f", "%+22.9f", "%+4.9f", "%01.3f", "%4f", "%3.1f", "%3.2f", "%.0f", "%.1f", NULL }; double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, 0.9996, 1.996, 4.136, 6442452944.1234, 0}; char *int_fmt[] = { "%-1.5d", "%1.5d", "%123.9d", "%5.5d", "%10.5d", "% 10.5d", "%+22.33d", "%01.3d", "%4d", NULL }; long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; int x, y; int fail = 0; int num = 0; printf ("Testing snprintf format codes against system sprintf...\n"); for (x = 0; fp_fmt[x] != NULL ; x++) for (y = 0; fp_nums[y] != 0 ; y++) { snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]); sprintf (buf2, fp_fmt[x], fp_nums[y]); if (strcmp (buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", fp_fmt[x], buf1, buf2); fail++; } num++; } for (x = 0; int_fmt[x] != NULL ; x++) for (y = 0; int_nums[y] != 0 ; y++) { snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]); sprintf (buf2, int_fmt[x], int_nums[y]); if (strcmp (buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", int_fmt[x], buf1, buf2); fail++; } num++; } printf ("%d tests failed out of %d.\n", fail, num); } #endif /* SNPRINTF_TEST */ nut-2.8.3/common/unsetenv.c0000644000200500020050000000044514777767434012577 00000000000000/* unsetenv.c Jim Klimov */ #include "config.h" /* must be first */ #ifndef HAVE_UNSETENV #include #include #include "common.h" #include "proto.h" int nut_unsetenv(const char *name) { return setenv(name, "", 1); } #endif /* !HAVE_UNSETENV */ nut-2.8.3/common/wincompat.c0000644000200500020050000011301414777767434012726 00000000000000/* 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. */ #ifdef WIN32 #include "config.h" /* should be first */ #include "wincompat.h" #include "nut_stdint.h" #if ! HAVE_INET_PTON # include # include # if HAVE_WINSOCK2_H # include # endif # if HAVE_WS2TCPIP_H # include # endif #endif #if (0) extern int errno; #endif const char * EventLogName = NULL; struct passwd wincompat_passwd; char wincompat_user_name[SMALLBUF]; char wincompat_password[SMALLBUF]; uid_t getuid(void) { DWORD size = sizeof(wincompat_user_name); if( !GetUserName(wincompat_user_name,&size) ) { return NULL; } return wincompat_user_name; } struct passwd *getpwuid(uid_t uid) { wincompat_passwd.pw_name = uid; wincompat_passwd.pw_uid = 0; return &wincompat_passwd; } char *getpass( const char *prompt) { HANDLE hStdin; DWORD mode; hStdin = GetStdHandle(STD_INPUT_HANDLE); if(hStdin == INVALID_HANDLE_VALUE) { return NULL; } printf("%s",prompt); GetConsoleMode( hStdin, &mode ); mode &= ~ENABLE_ECHO_INPUT; SetConsoleMode( hStdin , mode); if (fgets(wincompat_password, sizeof(wincompat_password), stdin) == NULL) { upsdebug_with_errno(LOG_INFO, "%s", __func__); return NULL; } /* deal with that pesky newline */ if (strlen(wincompat_password) > 1) { wincompat_password[strlen(wincompat_password) - 1] = '\0'; }; hStdin = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode( hStdin, &mode ); mode |= ENABLE_ECHO_INPUT; SetConsoleMode( hStdin , mode); return wincompat_password; } #ifndef HAVE_USLEEP /* Verbatim from http://cygwin.com/cgi-bin/cvsweb.cgi/~checkout~/src/winsup/mingw/mingwex/usleep.c?rev=1.2&cvsroot=src */ /* int __cdecl usleep(unsigned int useconds) */ int __cdecl usleep(useconds_t useconds) { if(useconds == 0) return 0; if(useconds >= 1000000) return EINVAL; Sleep((useconds + 999) / 1000); return 0; } #endif /* !HAVE_USLEEP */ char * strtok_r(char *str, const char *delim, char **saveptr) { char *token_start, *token_end; /* Subsequent call ? */ token_start = str ? str : *saveptr; /* Skip delim characters */ token_start += strspn(token_start, delim); if (*token_start == '\0') { /* No more token */ *saveptr = ""; return NULL; } /* Skip NO delim characters */ token_end = token_start + strcspn(token_start, delim); /* Prepare token to be a null terminated string */ if (*token_end != '\0') *token_end++ = '\0'; *saveptr = token_end; return token_start; } int sktconnect(int fh, struct sockaddr * name, int len) { int ret = connect(fh,name,len); errno = WSAGetLastError(); return ret; } int sktread(int fh, char *buf, int size) { int ret = recv(fh,buf,size,0); errno = WSAGetLastError(); return ret; } int sktwrite(int fh, char *buf, int size) { int ret = send(fh,buf,size,0); errno = WSAGetLastError(); return ret; } int sktclose(int fh) { int ret = closesocket((SOCKET)fh); errno = WSAGetLastError(); return ret; } #if ! HAVE_INET_NTOP # if (0) /* Some old winapi? or just sloppy original commits? */ const char* inet_ntop(int af, const void* src, char* dst, int cnt) # else const char* inet_ntop(int af, const void* src, char* dst, size_t cnt) # endif { /* Instead of WSAAddressToString() consider getnameinfo() if this would in fact * return decorated addresses (brackets, ports...) as discussed below: * https://users.ipv6.narkive.com/RXpR5aML/windows-and-inet-ntop-vs-wsaaddresstostring * https://docs.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getnameinfo * https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaaddresstostringa */ switch (af) { case AF_INET: { struct sockaddr_in srcaddr; memset(&srcaddr, 0, sizeof(struct sockaddr_in)); memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr)); srcaddr.sin_family = af; if (WSAAddressToString((struct sockaddr*) &srcaddr, sizeof(struct sockaddr_in), 0, dst, (LPDWORD) &cnt) != 0) { WSAGetLastError(); return NULL; } } break; case AF_INET6: /* NOTE: Since WinXP SP1, with IPv6 installed on the system */ { struct sockaddr_in6 srcaddr; memset(&srcaddr, 0, sizeof(struct sockaddr_in6)); memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr)); srcaddr.sin6_family = af; if (WSAAddressToString((struct sockaddr*) &srcaddr, sizeof(struct sockaddr_in6), 0, dst, (LPDWORD) &cnt) != 0) { WSAGetLastError(); return NULL; } } break; default: errno = EAFNOSUPPORT; return NULL; } /* switch */ return dst; } #endif /* HAVE_INET_NTOP */ #if ! HAVE_INET_PTON /* Fallback implementation of inet_pton() for systems that lack it, * such as older versions of Windows (including MinGW builds that do * not specifically target _WIN32_WINNT or newer). * * Based on code attributed to Paul Vixie, 1996, * sourced from https://stackoverflow.com/a/15370175/4715872 */ #define NS_INADDRSZ sizeof(struct in_addr) /* 4 */ #define NS_IN6ADDRSZ sizeof(struct in6_addr) /* 16 */ #define NS_INT16SZ sizeof(uint16_t) /* 2 */ static int inet_pton4(const char *src, void *dst) { uint8_t tmp[NS_INADDRSZ], *tp; /* for struct in_addr *dst */ int saw_digit = 0; int octets = 0; int ch; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { if (ch >= '0' && ch <= '9') { uint32_t n = *tp * 10 + (ch - '0'); if (saw_digit && *tp == 0) return 0; if (n > 255) return 0; *tp = n; 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; } static int inet_pton6(const char *src, void *dst) { static const char xdigits[] = "0123456789abcdef"; uint8_t tmp[NS_IN6ADDRSZ]; /* for struct in6_addr *dst */ uint8_t *tp = (uint8_t*) memset(tmp, '\0', NS_IN6ADDRSZ); uint8_t *endp = tp + NS_IN6ADDRSZ; uint8_t *colonp = NULL; const char *curtok = NULL; int saw_xdigit = 0; uint32_t val = 0; int ch; /* Leading :: requires some special handling. */ if (*src == ':') { if (*++src != ':') return 0; } curtok = src; while ((ch = tolower(*src++)) != '\0') { const char *pch = strchr(xdigits, 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; } else if (*src == '\0') { return 0; } if (tp + NS_INT16SZ > endp) return 0; *tp++ = (uint8_t) (val >> 8) & 0xff; *tp++ = (uint8_t) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4(curtok, (char*) 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++ = (uint8_t) (val >> 8) & 0xff; *tp++ = (uint8_t) 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; if (tp == endp) return 0; 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; } int inet_pton(int af, const char *src, void *dst) { switch (af) { case AF_INET: return inet_pton4(src, dst); case AF_INET6: return inet_pton6(src, dst); default: return -1; } } #endif /* ! HAVE_INET_PTON */ /* "system" call seems to handle path with blank name incorrectly */ int win_system(const char * command) { BOOL res; STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si,0,sizeof(si)); si.cb = sizeof(si); memset(&pi,0,sizeof(pi)); res = CreateProcess(NULL,(char *)command,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi); if( res != 0 ) { return 0; } return -1; } /* the " character is forbiden in Windows files , so we filter this character in data file paths to be coherent with command line which require " to distinguish the command from its parameter. This avoid complicated explanation in the documentation */ char * filter_path(const char * source) { char * res; unsigned int i,j; if( source == NULL ) { return NULL; } res = xmalloc(strlen(source)+1); for(i=0,j=0;i<=strlen(source);i++) { if(source[i] != '"') { res[j] = source[i]; j++; } } return res; } /* syslog sends a message through a pipe to the wininit service. Which is in charge of adding an event in the Windows event logger. The message is made of 4 bytes containing the priority followed by an array of chars containing the message to display (no terminal 0 required here) */ void syslog(int priority, const char *fmt, ...) { char pipe_name[] = "\\\\.\\pipe\\"EVENTLOG_PIPE_NAME; char buf1[LARGEBUF+sizeof(DWORD)]; char buf2[LARGEBUF]; va_list ap; HANDLE pipe; DWORD bytesWritten = 0; if( EventLogName == NULL ) { return; } /* Format message */ va_start(ap,fmt); vsnprintf(buf1, sizeof(buf1), fmt, ap); va_end(ap); /* Add progname to the formated message */ snprintf(buf2, sizeof(buf2), "%s - %s", EventLogName, buf1); /* Create the frame */ /* first 4 bytes are priority */ memcpy(buf1,&priority,sizeof(DWORD)); /* then comes the message */ memcpy(buf1+sizeof(DWORD),buf2,sizeof(buf2)); pipe = CreateFile( pipe_name, /* pipe name */ GENERIC_WRITE, 0, /* no sharing */ NULL, /* default security attributes FIXME */ OPEN_EXISTING, /* opens existing pipe */ FILE_FLAG_OVERLAPPED, /* enable async IO */ NULL); /* no template file */ if (pipe == INVALID_HANDLE_VALUE) { return; } WriteFile (pipe,buf1,strlen(buf2)+sizeof(DWORD),&bytesWritten,NULL); /* testing result is useless. If we have an error and try to report it, this will probably lead to a call to this function and an infinite loop */ CloseHandle(pipe); } /* Signal emulation via NamedPipe */ static HANDLE pipe_connection_handle; OVERLAPPED pipe_connection_overlapped; pipe_conn_t *pipe_connhead = NULL; static const char *named_pipe_name=NULL; void pipe_create(const char * pipe_name) { BOOL ret; char pipe_full_name[NUT_PATH_MAX + 1]; /* save pipe name for further use in pipe_connect */ if (pipe_name == NULL) { if (named_pipe_name == NULL) { return; } } else { named_pipe_name = pipe_name; } snprintf(pipe_full_name, sizeof(pipe_full_name), "\\\\.\\pipe\\%s", named_pipe_name); if( pipe_connection_overlapped.hEvent != 0 ) { CloseHandle(pipe_connection_overlapped.hEvent); } memset(&pipe_connection_overlapped,0,sizeof(pipe_connection_overlapped)); pipe_connection_handle = CreateNamedPipe( pipe_full_name, PIPE_ACCESS_INBOUND | /* to server only */ FILE_FLAG_OVERLAPPED, /* async IO */ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, /* max. instances */ LARGEBUF, /* output buffer size */ LARGEBUF, /* input buffer size */ 0, /* client time-out */ NULL); /* FIXME: default security attribute */ if (pipe_connection_handle == INVALID_HANDLE_VALUE) { upslogx(LOG_ERR, "Error creating named pipe"); fatal_with_errno(EXIT_FAILURE, "Can't create a state socket (windows named pipe)"); } /* Prepare an async wait on a connection on the pipe */ pipe_connection_overlapped.hEvent = CreateEvent(NULL, /*Security*/ FALSE, /* auto-reset*/ FALSE, /* inital state = non signaled*/ NULL /* no name*/); if(pipe_connection_overlapped.hEvent == NULL ) { upslogx(LOG_ERR, "Error creating event"); fatal_with_errno(EXIT_FAILURE, "Can't create event"); } /* Wait for a connection */ ret = ConnectNamedPipe(pipe_connection_handle,&pipe_connection_overlapped); if(ret == 0 && GetLastError() != ERROR_IO_PENDING ) { upslogx(LOG_ERR,"ConnectNamedPipe error"); } } void pipe_connect() { /* We have detected a connection on the opened pipe. So we start by saving its handle and create a new pipe for future connections */ pipe_conn_t *conn; conn = xcalloc(1,sizeof(*conn)); conn->handle = pipe_connection_handle; /* restart a new listening pipe */ pipe_create(NULL); /* A new pipe waiting for new client connection has been created. We could manage the current connection now */ /* Start a read operation on the newly connected pipe so we could wait on the event associated to this IO */ memset(&conn->overlapped,0,sizeof(conn->overlapped)); memset(conn->buf,0,sizeof(conn->buf)); conn->overlapped.hEvent = CreateEvent(NULL, /*Security*/ FALSE, /* auto-reset*/ FALSE, /* inital state = non signaled*/ NULL /* no name*/); if(conn->overlapped.hEvent == NULL ) { upslogx(LOG_ERR,"Can't create event for reading event log"); return; } ReadFile (conn->handle, conn->buf, sizeof(conn->buf)-1, /* -1 to be sure to have a trailling 0 */ NULL, &(conn->overlapped)); if (pipe_connhead) { conn->next = pipe_connhead; pipe_connhead->prev = conn; } pipe_connhead = conn; } void pipe_disconnect(pipe_conn_t *conn) { if( conn->overlapped.hEvent != INVALID_HANDLE_VALUE) { CloseHandle(conn->overlapped.hEvent); conn->overlapped.hEvent = INVALID_HANDLE_VALUE; } if( conn->handle != INVALID_HANDLE_VALUE) { if ( DisconnectNamedPipe(conn->handle) == 0 ) { upslogx(LOG_ERR, "DisconnectNamedPipe error : %d", (int)GetLastError()); } CloseHandle(conn->handle); conn->handle = INVALID_HANDLE_VALUE; } if (conn->prev) { conn->prev->next = conn->next; } else { pipe_connhead = conn->next; } if (conn->next) { conn->next->prev = conn->prev; } else { /* conntail = conn->prev; */ } free(conn); } int pipe_ready(pipe_conn_t *conn) { DWORD bytesRead; BOOL res; res = GetOverlappedResult(conn->handle, &conn->overlapped, &bytesRead, FALSE); if( res == 0 ) { upslogx(LOG_ERR, "Pipe read error"); pipe_disconnect(conn); return 0; } return 1; } /* return 1 on error, 0 if OK */ int send_to_named_pipe(const char * pipe_name, const char * data) { HANDLE pipe; BOOL result = FALSE; DWORD bytesWritten = 0; char buf[SMALLBUF]; snprintf(buf, sizeof(buf), "\\\\.\\pipe\\%s", pipe_name); pipe = CreateFile( buf, GENERIC_WRITE, 0, /* no sharing */ NULL, /* default security attributes FIXME */ OPEN_EXISTING, /* opens existing pipe */ FILE_FLAG_OVERLAPPED, /* enable async IO */ NULL); /* no template file */ if (pipe == INVALID_HANDLE_VALUE) { return 1; } result = WriteFile (pipe,data,strlen(data)+1,&bytesWritten,NULL); if (result == 0 || bytesWritten != strlen(data)+1 ) { CloseHandle(pipe); return 1; } CloseHandle(pipe); return 0; } int w32_setcomm ( serial_handler_t * h, int * flags ) { int ret = 0; if( *flags & TIOCM_DTR ) { if( !EscapeCommFunction(h->handle,SETDTR) ) { errno = EIO; ret = -1; } } else { if( !EscapeCommFunction(h->handle,CLRDTR) ) { errno = EIO; ret = -1; } } if( *flags & TIOCM_RTS ) { if( !EscapeCommFunction(h->handle,SETRTS) ) { errno = EIO; ret = -1; } } else { if( !EscapeCommFunction(h->handle,CLRRTS) ) { errno = EIO; ret = -1; } } return ret; } int w32_getcomm ( serial_handler_t * h, int * flags ) { BOOL ret_val; DWORD f; ret_val = GetCommModemStatus(h->handle, &f); if (ret_val == 0) { errno = EIO; return -1; } *flags = f; return 0; } /* Serial port wrapper inspired by : http://serial-programming-in-win32-os.blogspot.com/2008/07/convert-linux-code-to-windows-serial.html */ void overlapped_setup (serial_handler_t * sh) { memset (&sh->io_status, 0, sizeof (sh->io_status)); sh->io_status.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); sh->overlapped_armed = 0; } int w32_serial_read (serial_handler_t * sh, void *ptr, size_t ulen, DWORD timeout) { int tot; DWORD num; HANDLE w4; DWORD minchars = sh->vmin_ ? sh->vmin_ : ulen; errno = 0; w4 = sh->io_status.hEvent; upsdebugx(4, "w32_serial_read : ulen %" PRIuSIZE ", vmin_ %d, vtime_ %d, hEvent %p", ulen, sh->vmin_, sh->vtime_, sh->io_status.hEvent); if (!sh->overlapped_armed) { SetCommMask (sh->handle, EV_RXCHAR); ResetEvent (sh->io_status.hEvent); } for (num = 0, tot = 0; ulen; ulen -= num, ptr = (char *)ptr + num) { DWORD ev; COMSTAT st; DWORD inq = 1; num = 0; if (!sh->vtime_ && !sh->vmin_) { inq = ulen; } else if (sh->vtime_) { /* non-interruptible -- have to use kernel timeouts also note that this is not strictly correct. if vmin > ulen then things won't work right. sh->overlapped_armed = -1; */ inq = ulen; } if (!ClearCommError (sh->handle, &ev, &st)) { goto err; } else if (ev) { upsdebugx(4, "w32_serial_read : error detected %x", (int)ev); } else if (st.cbInQue) { inq = st.cbInQue; } else if (!sh->overlapped_armed) { if ((size_t)tot >= minchars) { break; } else if (WaitCommEvent (sh->handle, &ev, &sh->io_status)) { /* WaitCommEvent succeeded */ if (!ev) { continue; } } else if (GetLastError () != ERROR_IO_PENDING) { goto err; } else { sh->overlapped_armed = 1; switch (WaitForSingleObject (w4, timeout)) { case WAIT_OBJECT_0: if (!GetOverlappedResult (sh->handle, &sh->io_status, &num, FALSE)) { goto err; } upsdebugx(4, "w32_serial_read : characters are available on input buffer"); break; case WAIT_TIMEOUT: if(!tot) { CancelIo(sh->handle); sh->overlapped_armed = 0; ResetEvent (sh->io_status.hEvent); upsdebugx(4, "w32_serial_read : timeout %d ms elapsed", (int)timeout); SetLastError(WAIT_TIMEOUT); errno = 0; return 0; } default: goto err; } } } sh->overlapped_armed = 0; ResetEvent (sh->io_status.hEvent); if (inq > ulen) { inq = ulen; } upsdebugx(4, "w32_serial_read : Reading %d characters", (int)inq); if (ReadFile (sh->handle, ptr, min (inq, ulen), &num, &sh->io_status)) { /* Got something */; } else if (GetLastError () != ERROR_IO_PENDING) { goto err; } else if (!GetOverlappedResult (sh->handle, &sh->io_status, &num, TRUE)) { goto err; } tot += num; upsdebugx(4, "w32_serial_read : total characters read = %d", tot); if (sh->vtime_ || !sh->vmin_ || !num) { break; } continue; err: PurgeComm (sh->handle, PURGE_RXABORT); upsdebugx(4, "w32_serial_read : err %d", (int)GetLastError()); if (GetLastError () == ERROR_OPERATION_ABORTED) { num = 0; } else { errno = EIO; tot = -1; break; } } return tot; } /* Cover function to WriteFile to provide Posix interface and semantics (as much as possible). */ int w32_serial_write (serial_handler_t * sh, const void *ptr, size_t len) { DWORD bytes_written; OVERLAPPED write_status; errno = 0; memset (&write_status, 0, sizeof (write_status)); write_status.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); for (;;) { if (WriteFile (sh->handle, ptr, len, &bytes_written, &write_status)) break; switch (GetLastError ()) { case ERROR_OPERATION_ABORTED: continue; case ERROR_IO_PENDING: break; default: goto err; } if (!GetOverlappedResult (sh->handle, &write_status, &bytes_written, TRUE)) goto err; break; } CloseHandle(write_status.hEvent); return bytes_written; err: CloseHandle(write_status.hEvent); errno = EIO; return -1; } serial_handler_t * w32_serial_open (const char *name, int flags) { /* flags are currently ignored, it's here just to have the same interface as POSIX open */ NUT_UNUSED_VARIABLE(flags); COMMTIMEOUTS to; errno = 0; upslogx(LOG_INFO, "w32_serial_open (%s)", name); serial_handler_t * sh; sh = xmalloc(sizeof(serial_handler_t)); memset(sh,0,sizeof(serial_handler_t)); sh->handle = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); if(sh->handle == INVALID_HANDLE_VALUE) { upslogx(LOG_ERR, "could not open %s", name); errno = EPERM; return NULL; } SetCommMask (sh->handle, EV_RXCHAR); overlapped_setup (sh); memset (&to, 0, sizeof (to)); SetCommTimeouts (sh->handle, &to); /* Reset serial port to known state of 9600-8-1-no flow control on open for better behavior under Win 95. */ DCB state; GetCommState (sh->handle, &state); upslogx (LOG_INFO, "setting initial state on %s", name); state.BaudRate = CBR_9600; state.ByteSize = 8; state.StopBits = ONESTOPBIT; state.Parity = NOPARITY; /* FIXME: correct default? */ state.fBinary = TRUE; /* binary xfer */ state.EofChar = 0; /* no end-of-data in binary mode */ state.fNull = FALSE; /* don't discard nulls in binary mode */ state.fParity = FALSE; /* ignore parity errors */ state.fErrorChar = FALSE; state.fTXContinueOnXoff = TRUE; /* separate TX and RX flow control */ state.fOutX = FALSE; /* disable transmission flow control */ state.fInX = FALSE; /* disable reception flow control */ state.XonChar = 0x11; state.XoffChar = 0x13; state.fOutxDsrFlow = FALSE; /* disable DSR flow control */ state.fRtsControl = RTS_CONTROL_ENABLE; /* ignore lead control except DTR */ state.fOutxCtsFlow = FALSE; /* disable output flow control */ state.fDtrControl = DTR_CONTROL_ENABLE; /* assert DTR */ state.fDsrSensitivity = FALSE; /* don't assert DSR */ state.fAbortOnError = TRUE; if (!SetCommState (sh->handle, &state)) { upslogx (LOG_ERR, "couldn't set initial state for %s", name); } SetCommMask (sh->handle, EV_RXCHAR); upslogx (LOG_INFO, "%p = w32_serial_open (%s)", sh->handle, name); return sh; } int w32_serial_close (serial_handler_t * sh) { if( sh->io_status.hEvent != INVALID_HANDLE_VALUE ) { CloseHandle (sh->io_status.hEvent); } if( sh->handle != INVALID_HANDLE_VALUE ) { CloseHandle (sh->handle); } free(sh); errno = 0; return 0; } /* tcsendbreak: POSIX 7.2.2.1 */ /* Break for 250-500 milliseconds if duration == 0 */ /* Otherwise, units for duration are undefined */ int tcsendbreak (serial_handler_t * sh, int duration) { unsigned int sleeptime = 300000; errno = 0; if (duration > 0) sleeptime *= duration; if (SetCommBreak (sh->handle) == 0) { errno = EIO; return -1; } /* FIXME: need to send zero bits during duration */ usleep (sleeptime); if (ClearCommBreak (sh->handle) == 0) { errno = EIO; return -1; } upslogx(LOG_DEBUG, "0 = tcsendbreak (%d)", duration); return 0; } /* tcdrain: POSIX 7.2.2.1 */ int tcdrain (serial_handler_t * sh) { errno = 0; if (FlushFileBuffers (sh->handle) == 0) { errno = EIO; return -1; } return 0; } /* tcflow: POSIX 7.2.2.1 */ int tcflow (serial_handler_t * sh, int action) { DWORD win32action = 0; DCB dcb; char xchar; errno = 0; upslogx(LOG_DEBUG, "action %d", action); switch (action) { case TCOOFF: win32action = SETXOFF; break; case TCOON: win32action = SETXON; break; case TCION: case TCIOFF: if (GetCommState (sh->handle, &dcb) == 0) return -1; if (action == TCION) xchar = (dcb.XonChar ? dcb.XonChar : 0x11); else xchar = (dcb.XoffChar ? dcb.XoffChar : 0x13); if (TransmitCommChar (sh->handle, xchar) == 0) return -1; return 0; break; default: return -1; break; } if (EscapeCommFunction (sh->handle, win32action) == 0) { errno = EIO; return -1; } return 0; } /* tcflush: POSIX 7.2.2.1 */ int tcflush (serial_handler_t * sh, int queue) { int max; errno = 0; if (queue == TCOFLUSH || queue == TCIOFLUSH) PurgeComm (sh->handle, PURGE_TXABORT | PURGE_TXCLEAR); if ((queue == TCIFLUSH) | (queue == TCIOFLUSH)) /* Input flushing by polling until nothing turns up (we stop after 1000 chars anyway) */ for (max = 1000; max > 0; max--) { DWORD ev; COMSTAT st; if (!PurgeComm (sh->handle, PURGE_RXABORT | PURGE_RXCLEAR)) break; Sleep (100); if (!ClearCommError (sh->handle, &ev, &st) || !st.cbInQue) break; } return 0; } /* tcsetattr: POSIX 7.2.1.1 */ int tcsetattr (serial_handler_t * sh, int action, const struct termios *t) { /* Possible actions: TCSANOW: immediately change attributes. TCSADRAIN: flush output, then change attributes. TCSAFLUSH: flush output and discard input, then change attributes. */ BOOL dropDTR = FALSE; COMMTIMEOUTS to; DCB ostate, state; unsigned int ovtime = sh->vtime_, ovmin = sh->vmin_; errno = 0; upslogx(LOG_DEBUG, "action %d", action); if ((action == TCSADRAIN) || (action == TCSAFLUSH)) { FlushFileBuffers (sh->handle); upslogx(LOG_DEBUG, "flushed file buffers"); } if (action == TCSAFLUSH) PurgeComm (sh->handle, (PURGE_RXABORT | PURGE_RXCLEAR)); /* get default/last comm state */ if (!GetCommState (sh->handle, &ostate)) { errno = EIO; return -1; } state = ostate; /* -------------- Set baud rate ------------------ */ /* FIXME: WIN32 also has 14400, 56000, 128000, and 256000. Unix also has 230400. */ switch (t->c_ospeed) { case B0: /* drop DTR */ dropDTR = TRUE; state.BaudRate = 0; break; case B110: state.BaudRate = CBR_110; break; case B300: state.BaudRate = CBR_300; break; case B600: state.BaudRate = CBR_600; break; case B1200: state.BaudRate = CBR_1200; break; case B2400: state.BaudRate = CBR_2400; break; case B4800: state.BaudRate = CBR_4800; break; case B9600: state.BaudRate = CBR_9600; break; case B19200: state.BaudRate = CBR_19200; break; case B38400: state.BaudRate = CBR_38400; break; case B57600: state.BaudRate = CBR_57600; break; case B115200: state.BaudRate = CBR_115200; break; default: /* Unsupported baud rate! */ upslogx(LOG_ERR, "Invalid t->c_ospeed %d", t->c_ospeed); errno = EINVAL; return -1; } /* -------------- Set byte size ------------------ */ switch (t->c_cflag & CSIZE) { case CS5: state.ByteSize = 5; break; case CS6: state.ByteSize = 6; break; case CS7: state.ByteSize = 7; break; case CS8: state.ByteSize = 8; break; default: /* Unsupported byte size! */ upslogx(LOG_ERR, "Invalid t->c_cflag byte size %d", t->c_cflag & CSIZE); errno = EINVAL; return -1; } /* -------------- Set stop bits ------------------ */ if (t->c_cflag & CSTOPB) state.StopBits = TWOSTOPBITS; else state.StopBits = ONESTOPBIT; /* -------------- Set parity ------------------ */ if (t->c_cflag & PARENB) state.Parity = (t->c_cflag & PARODD) ? ODDPARITY : EVENPARITY; else state.Parity = NOPARITY; state.fBinary = TRUE; /* Binary transfer */ state.EofChar = 0; /* No end-of-data in binary mode */ state.fNull = FALSE; /* Don't discard nulls in binary mode */ /* -------------- Parity errors ------------------ */ /* fParity combines the function of INPCK and NOT IGNPAR */ if ((t->c_iflag & INPCK) && !(t->c_iflag & IGNPAR)) state.fParity = TRUE; /* detect parity errors */ else state.fParity = FALSE; /* ignore parity errors */ /* Only present in Win32, Unix has no equivalent */ state.fErrorChar = FALSE; state.ErrorChar = 0; /* -------------- Set software flow control ------------------ */ /* Set fTXContinueOnXoff to FALSE. This prevents the triggering of a premature XON when the remote device interprets a received character as XON (same as IXANY on the remote side). Otherwise, a TRUE value separates the TX and RX functions. */ state.fTXContinueOnXoff = TRUE; /* separate TX and RX flow control */ /* Transmission flow control */ if (t->c_iflag & IXON) state.fOutX = TRUE; /* enable */ else state.fOutX = FALSE; /* disable */ /* Reception flow control */ if (t->c_iflag & IXOFF) state.fInX = TRUE; /* enable */ else state.fInX = FALSE; /* disable */ /* XoffLim and XonLim are left at default values */ state.XonChar = (t->c_cc[VSTART] ? t->c_cc[VSTART] : 0x11); state.XoffChar = (t->c_cc[VSTOP] ? t->c_cc[VSTOP] : 0x13); /* -------------- Set hardware flow control ------------------ */ /* Disable DSR flow control */ state.fOutxDsrFlow = FALSE; /* Some old flavors of Unix automatically enabled hardware flow control when software flow control was not enabled. Since newer Unices tend to require explicit setting of hardware flow-control, this is what we do. */ /* RTS/CTS flow control */ if (t->c_cflag & CRTSCTS) { /* enable */ state.fOutxCtsFlow = TRUE; state.fRtsControl = RTS_CONTROL_HANDSHAKE; } else { /* disable */ state.fRtsControl = RTS_CONTROL_ENABLE; state.fOutxCtsFlow = FALSE; } /* if (t->c_cflag & CRTSXOFF) state.fRtsControl = RTS_CONTROL_HANDSHAKE; */ /* -------------- DTR ------------------ */ /* Assert DTR on device open */ state.fDtrControl = DTR_CONTROL_ENABLE; /* -------------- DSR ------------------ */ /* Assert DSR at the device? */ if (t->c_cflag & CLOCAL) state.fDsrSensitivity = FALSE; /* no */ else state.fDsrSensitivity = TRUE; /* yes */ /* -------------- Error handling ------------------ */ /* Since read/write operations terminate upon error, we will use ClearCommError() to resume. */ state.fAbortOnError = TRUE; /* -------------- Set state and exit ------------------ */ if (memcmp (&ostate, &state, sizeof (state)) != 0) SetCommState (sh->handle, &state); sh->r_binary = ((t->c_iflag & IGNCR) ? 0 : 1); sh->w_binary = ((t->c_oflag & ONLCR) ? 0 : 1); if (dropDTR == TRUE) EscapeCommFunction (sh->handle, CLRDTR); else { /* FIXME: Sometimes when CLRDTR is set, setting state.fDtrControl = DTR_CONTROL_ENABLE will fail. This is a problem since a program might want to change some parameters while DTR is still down. */ EscapeCommFunction (sh->handle, SETDTR); } /* The following documentation on was taken from "Linux Serial Programming HOWTO". It explains how MIN (t->c_cc[VMIN] || vmin_) and TIME (t->c_cc[VTIME] || vtime_) is to be used. In non-canonical input processing mode, input is not assembled into lines and input processing (erase, kill, delete, etc.) does not occur. Two parameters control the behavior of this mode: c_cc[VTIME] sets the character timer, and c_cc[VMIN] sets the minimum number of characters to receive before satisfying the read. If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before the read is satisfied. As TIME is zero, the timer is not used. If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be satisfied if a single character is read, or TIME is exceeded (t = TIME *0.1 s). If TIME is exceeded, no character will be returned. If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read will be satisfied if MIN characters are received, or the time between two characters exceeds TIME. The timer is restarted every time a character is received and only becomes active after the first character has been received. If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of characters currently available, or the number of characters requested will be returned. According to Antonino (see contributions), you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get the same result. */ if (t->c_lflag & ICANON) { sh->vmin_ = MAXDWORD; sh->vtime_ = 0; } else { sh->vtime_ = t->c_cc[VTIME] * 100; sh->vmin_ = t->c_cc[VMIN]; } upslogx(LOG_DEBUG, "vtime %d, vmin %d\n", sh->vtime_, sh->vmin_); if (ovmin == sh->vmin_ && ovtime == sh->vtime_) { errno = EINVAL; return 0; } memset (&to, 0, sizeof (to)); if ((sh->vmin_ > 0) && (sh->vtime_ == 0)) { /* Returns immediately with whatever is in buffer on a ReadFile(); or blocks if nothing found. We will keep calling ReadFile(); until vmin_ characters are read */ to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; to.ReadTotalTimeoutConstant = MAXDWORD - 1; } else if ((sh->vmin_ == 0) && (sh->vtime_ > 0)) { /* set timeoout constant appropriately and we will only try to read one character in ReadFile() */ to.ReadTotalTimeoutConstant = sh->vtime_; to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; } else if ((sh->vmin_ > 0) && (sh->vtime_ > 0)) { /* time applies to the interval time for this case */ to.ReadIntervalTimeout = sh->vtime_; } else if ((sh->vmin_ == 0) && (sh->vtime_ == 0)) { /* returns immediately with whatever is in buffer as per Time-Outs docs in Win32 SDK API docs */ to.ReadIntervalTimeout = MAXDWORD; } upslogx(LOG_DEBUG, "ReadTotalTimeoutConstant %d, " "ReadIntervalTimeout %d, " "ReadTotalTimeoutMultiplier %d", (int)to.ReadTotalTimeoutConstant, (int)to.ReadIntervalTimeout, (int)to.ReadTotalTimeoutMultiplier); int res = SetCommTimeouts(sh->handle, &to); if (!res) { upslogx(LOG_ERR, "SetCommTimeout failed"); errno = EIO; return -1; } return 0; } /* tcgetattr: POSIX 7.2.1.1 */ int tcgetattr (serial_handler_t * sh, struct termios *t) { DCB state; errno = 0; /* Get current Win32 comm state */ if (GetCommState (sh->handle, &state) == 0) { errno = EIO; return -1; } /* for safety */ memset (t, 0, sizeof (*t)); /* -------------- Baud rate ------------------ */ switch (state.BaudRate) { case 0: /* FIXME: need to drop DTR */ t->c_cflag = t->c_ospeed = t->c_ispeed = B0; break; case CBR_110: t->c_cflag = t->c_ospeed = t->c_ispeed = B110; break; case CBR_300: t->c_cflag = t->c_ospeed = t->c_ispeed = B300; break; case CBR_600: t->c_cflag = t->c_ospeed = t->c_ispeed = B600; break; case CBR_1200: t->c_cflag = t->c_ospeed = t->c_ispeed = B1200; break; case CBR_2400: t->c_cflag = t->c_ospeed = t->c_ispeed = B2400; break; case CBR_4800: t->c_cflag = t->c_ospeed = t->c_ispeed = B4800; break; case CBR_9600: t->c_cflag = t->c_ospeed = t->c_ispeed = B9600; break; case CBR_19200: t->c_cflag = t->c_ospeed = t->c_ispeed = B19200; break; case CBR_38400: t->c_cflag = t->c_ospeed = t->c_ispeed = B38400; break; case CBR_57600: t->c_cflag = t->c_ospeed = t->c_ispeed = B57600; break; case CBR_115200: t->c_cflag = t->c_ospeed = t->c_ispeed = B115200; break; default: /* Unsupported baud rate! */ upslogx(LOG_ERR, "Invalid baud rate %d", (int)state.BaudRate); errno = EINVAL; return -1; } /* -------------- Byte size ------------------ */ switch (state.ByteSize) { case 5: t->c_cflag |= CS5; break; case 6: t->c_cflag |= CS6; break; case 7: t->c_cflag |= CS7; break; case 8: t->c_cflag |= CS8; break; default: /* Unsupported byte size! */ upslogx(LOG_ERR, "Invalid byte size %d", state.ByteSize); errno = EINVAL; return -1; } /* -------------- Stop bits ------------------ */ if (state.StopBits == TWOSTOPBITS) t->c_cflag |= CSTOPB; /* -------------- Parity ------------------ */ if (state.Parity == ODDPARITY) t->c_cflag |= (PARENB | PARODD); if (state.Parity == EVENPARITY) t->c_cflag |= PARENB; /* -------------- Parity errors ------------------ */ /* fParity combines the function of INPCK and NOT IGNPAR */ if (state.fParity == TRUE) t->c_iflag |= INPCK; else t->c_iflag |= IGNPAR; /* not necessarily! */ /* -------------- Software flow control ------------------ */ /* transmission flow control */ if (state.fOutX) t->c_iflag |= IXON; /* reception flow control */ if (state.fInX) t->c_iflag |= IXOFF; t->c_cc[VSTART] = (state.XonChar ? state.XonChar : 0x11); t->c_cc[VSTOP] = (state.XoffChar ? state.XoffChar : 0x13); /* -------------- Hardware flow control ------------------ */ /* Some old flavors of Unix automatically enabled hardware flow control when software flow control was not enabled. Since newer Unices tend to require explicit setting of hardware flow-control, this is what we do. */ /* Input flow-control */ if ((state.fRtsControl == RTS_CONTROL_HANDSHAKE) && (state.fOutxCtsFlow == TRUE)) t->c_cflag |= CRTSCTS; /* if (state.fRtsControl == RTS_CONTROL_HANDSHAKE) t->c_cflag |= CRTSXOFF; */ /* -------------- CLOCAL --------------- */ /* DSR is only lead toggled only by CLOCAL. Check it to see if CLOCAL was called. */ /* FIXME: If tcsetattr() hasn't been called previously, this may give a false CLOCAL. */ if (state.fDsrSensitivity == FALSE) t->c_cflag |= CLOCAL; /* FIXME: need to handle IGNCR */ #if 0 if (!sh->r_binary ()) t->c_iflag |= IGNCR; #endif if (!sh->w_binary) t->c_oflag |= ONLCR; upslogx (LOG_DEBUG, "vmin_ %d, vtime_ %d", sh->vmin_, sh->vtime_); if (sh->vmin_ == MAXDWORD) { t->c_lflag |= ICANON; t->c_cc[VTIME] = t->c_cc[VMIN] = 0; } else { t->c_cc[VTIME] = sh->vtime_ / 100; t->c_cc[VMIN] = sh->vmin_; } return 0; } /* FIXME no difference between ispeed and ospeed */ void cfsetispeed(struct termios * t, speed_t speed) { t->c_ispeed = t->c_ospeed = speed; } void cfsetospeed(struct termios * t, speed_t speed) { t->c_ispeed = t->c_ospeed = speed; } speed_t cfgetispeed(const struct termios *t) { return t->c_ispeed; } speed_t cfgetospeed(const struct termios *t) { return t->c_ospeed; } #else /* !WIN32 */ /* Just avoid: ISO C forbids an empty translation unit [-Werror=pedantic] */ int main (int argc, char ** argv); #endif /* !WIN32 */ nut-2.8.3/common/upsconf.c0000644000200500020050000000537314777767434012412 00000000000000/* upsconf.c - code for handling ups.conf ini-style parsing Copyright (C) 2001 Russell Kroll This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* must be the first header */ #include #include #include #include #include "upsconf.h" #include "common.h" #include "parseconf.h" static char *ups_section; /* handle arguments separated by parseconf */ static void conf_args(size_t numargs, char **arg) { if (numargs < 1) return; /* look for section headers - [upsname] */ if ((arg[0][0] == '[') && (arg[0][strlen(arg[0])-1] == ']')) { free(ups_section); arg[0][strlen(arg[0])-1] = '\0'; ups_section = xstrdup(&arg[0][1]); return; } /* handle 'foo' (flag) */ if (numargs == 1) { do_upsconf_args(ups_section, arg[0], NULL); return; } if (numargs < 3) return; /* handle 'foo = bar', 'foo=bar', 'foo =bar' or 'foo= bar' forms */ if (!strcmp(arg[1], "=")) { do_upsconf_args(ups_section, arg[0], arg[2]); return; } } /* called for fatal errors in parseconf like malloc failures */ static void upsconf_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf(ups.conf): %s", errmsg); } /* open the ups.conf, parse it, and call back do_upsconf_args() * returns -1 (or aborts the program) in case of errors; * returns 1 if processing finished successfully * See also reload_flag support in main.c for live-reload feature */ int read_upsconf(int fatal_errors) { char fn[NUT_PATH_MAX + 1]; PCONF_CTX_t ctx; ups_section = NULL; snprintf(fn, sizeof(fn), "%s/ups.conf", confpath()); pconf_init(&ctx, upsconf_err); if (!pconf_file_begin(&ctx, fn)) { if (fatal_errors) { fatalx(EXIT_FAILURE, "Can't open %s: %s", fn, ctx.errmsg); } else { upslogx(LOG_WARNING, "Can't open %s: %s", fn, ctx.errmsg); return -1; } } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } conf_args(ctx.numargs, ctx.arglist); } pconf_finish(&ctx); free(ups_section); return 1; /* Handled OK */ } nut-2.8.3/common/str.c0000644000200500020050000002451114777767434011540 00000000000000/* str.c - Common string-related functions * * Copyright (C) * 2000 Russell Kroll * 2015 Daniele Pezzini * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "config.h" /* must be first */ #include #include #include #ifdef HAVE_STRING_H #include /* for strdup() and many others */ #endif #ifdef HAVE_STRINGS_H #include /* for strncasecmp() and strcasecmp() */ #endif #include "nut_stdint.h" #include "str.h" char *str_trim(char *string, const char character) { return str_rtrim(str_ltrim(string, character), character); } char *str_trim_m(char *string, const char *characters) { return str_rtrim_m(str_ltrim_m(string, characters), characters); } char *str_ltrim(char *string, const char character) { char characters[2] = { character, '\0' }; return str_ltrim_m(string, characters); } char *str_ltrim_m(char *string, const char *characters) { if ( string == NULL || *string == '\0' || characters == NULL || *characters == '\0' ) return string; while ( *string != '\0' && strchr(characters, *string) != NULL ) memmove(string, string + 1, strlen(string)); return string; } char *str_rtrim(char *string, const char character) { char characters[2] = { character, '\0' }; return str_rtrim_m(string, characters); } char *str_rtrim_m(char *string, const char *characters) { char *ptr; if ( string == NULL || *string == '\0' || characters == NULL || *characters == '\0' ) return string; ptr = &string[strlen(string) - 1]; while ( ptr >= string && strchr(characters, *ptr) != NULL ) *ptr-- = '\0'; return string; } char *str_trim_space(char *string) { return str_rtrim_space(str_ltrim_space(string)); } char *str_ltrim_space(char *string) { if ( string == NULL || *string == '\0' ) return string; while ( *string != '\0' && isspace((size_t)*string) ) memmove(string, string + 1, strlen(string)); return string; } char *str_rtrim_space(char *string) { char *ptr; if ( string == NULL || *string == '\0' ) return string; ptr = &string[strlen(string) - 1]; while ( ptr >= string && isspace((size_t)*ptr) ) *ptr-- = '\0'; return string; } int str_is_short(const char *string, const int base) { short number; return str_to_short(string, &number, base); } int str_is_short_strict(const char *string, const int base) { short number; return str_to_short_strict(string, &number, base); } int str_is_ushort(const char *string, const int base) { unsigned short number; return str_to_ushort(string, &number, base); } int str_is_ushort_strict(const char *string, const int base) { unsigned short number; return str_to_ushort_strict(string, &number, base); } int str_is_int(const char *string, const int base) { int number; return str_to_int(string, &number, base); } int str_is_int_strict(const char *string, const int base) { int number; return str_to_int_strict(string, &number, base); } int str_is_uint(const char *string, const int base) { unsigned int number; return str_to_uint(string, &number, base); } int str_is_uint_strict(const char *string, const int base) { unsigned int number; return str_to_uint_strict(string, &number, base); } int str_is_long(const char *string, const int base) { long number; return str_to_long(string, &number, base); } int str_is_long_strict(const char *string, const int base) { long number; return str_to_long_strict(string, &number, base); } int str_is_ulong(const char *string, const int base) { unsigned long number; return str_to_ulong(string, &number, base); } int str_is_ulong_strict(const char *string, const int base) { unsigned long number; return str_to_ulong_strict(string, &number, base); } int str_is_double(const char *string, const int base) { double number; return str_to_double(string, &number, base); } int str_is_double_strict(const char *string, const int base) { double number; return str_to_double_strict(string, &number, base); } int str_to_short(const char *string, short *number, const int base) { long num; *number = 0; if (!str_to_long(string, &num, base)) return 0; if ( num < SHRT_MIN || num > SHRT_MAX ) { errno = ERANGE; return 0; } *number = (short)num; return 1; } int str_to_short_strict(const char *string, short *number, const int base) { long num; *number = 0; if (!str_to_long_strict(string, &num, base)) return 0; if ( num < SHRT_MIN || num > SHRT_MAX ) { errno = ERANGE; return 0; } *number = (short)num; return 1; } int str_to_ushort(const char *string, unsigned short *number, const int base) { unsigned long num; *number = 0; if (!str_to_ulong(string, &num, base)) return 0; if (num > USHRT_MAX) { errno = ERANGE; return 0; } *number = (unsigned short)num; return 1; } int str_to_ushort_strict(const char *string, unsigned short *number, const int base) { unsigned long num; *number = 0; if (!str_to_ulong_strict(string, &num, base)) return 0; if (num > USHRT_MAX) { errno = ERANGE; return 0; } *number = (unsigned short)num; return 1; } int str_to_int(const char *string, int *number, const int base) { long num; /* long >= int, make sure we fit well */ *number = 0; if (!str_to_long(string, &num, base)) return 0; if ( num < INT_MIN || num > INT_MAX ) { errno = ERANGE; return 0; } *number = (int)num; return 1; } int str_to_int_strict(const char *string, int *number, const int base) { long num; /* long >= int, make sure we fit well */ *number = 0; if (!str_to_long_strict(string, &num, base)) return 0; if ( num < INT_MIN || num > INT_MAX ) { errno = ERANGE; return 0; } *number = (int)num; return 1; } int str_to_uint(const char *string, unsigned int *number, const int base) { unsigned long num; /* long >= int, make sure we fit well */ *number = 0; if (!str_to_ulong(string, &num, base)) return 0; if (num > UINT_MAX) { errno = ERANGE; return 0; } *number = (unsigned int)num; return 1; } int str_to_uint_strict(const char *string, unsigned int *number, const int base) { unsigned long num; /* long >= int, make sure we fit well */ *number = 0; if (!str_to_ulong_strict(string, &num, base)) return 0; if (num > UINT_MAX) { errno = ERANGE; return 0; } *number = (unsigned int)num; return 1; } int str_to_long(const char *string, long *number, const int base) { char *str; *number = 0; if ( string == NULL || *string == '\0' ) { errno = EINVAL; return 0; } str = strdup(string); if (str == NULL) return 0; str_trim_space(str); if (!str_to_long_strict(str, number, base)) { free(str); return 0; } free(str); return 1; } int str_to_long_strict(const char *string, long *number, const int base) { char *ptr = NULL; *number = 0; if ( string == NULL || *string == '\0' || isspace((size_t)*string) ) { errno = EINVAL; return 0; } errno = 0; *number = strtol(string, &ptr, base); if ( errno == EINVAL || *ptr != '\0' ) { *number = 0; errno = EINVAL; return 0; } if (errno == ERANGE) { *number = 0; return 0; } return 1; } int str_to_ulong(const char *string, unsigned long *number, const int base) { char *str; *number = 0; if ( string == NULL || *string == '\0' ) { errno = EINVAL; return 0; } str = strdup(string); if (str == NULL) return 0; str_trim_space(str); if (!str_to_ulong_strict(str, number, base)) { free(str); return 0; } free(str); return 1; } int str_to_ulong_strict(const char *string, unsigned long *number, const int base) { char *ptr = NULL; *number = 0; if ( string == NULL || *string == '\0' || *string == '+' || *string == '-' || isspace((size_t)*string) ) { errno = EINVAL; return 0; } errno = 0; *number = strtoul(string, &ptr, base); if ( errno == EINVAL || *ptr != '\0' ) { *number = 0; errno = EINVAL; return 0; } if (errno == ERANGE) { *number = 0; return 0; } return 1; } int str_to_double(const char *string, double *number, const int base) { char *str; *number = 0; if ( string == NULL || *string == '\0' ) { errno = EINVAL; return 0; } str = strdup(string); if (str == NULL) return 0; str_trim_space(str); if (!str_to_double_strict(str, number, base)) { free(str); return 0; } free(str); return 1; } int str_to_double_strict(const char *string, double *number, const int base) { char *ptr = NULL; *number = 0; if ( string == NULL || *string == '\0' || isspace((size_t)*string) ) { errno = EINVAL; return 0; } switch (base) { case 0: break; case 10: if (strlen(string) != strspn(string, "-+.0123456789Ee")) { errno = EINVAL; return 0; } break; case 16: if (strlen(string) != strspn(string, "-+.0123456789ABCDEFabcdefXxPp")) { errno = EINVAL; return 0; } break; default: errno = EINVAL; return 0; } errno = 0; *number = strtod(string, &ptr); if ( errno == EINVAL || *ptr != '\0' ) { *number = 0; errno = EINVAL; return 0; } if (errno == ERANGE) { *number = 0; return 0; } return 1; } int str_ends_with(const char *s, const char *suff) { size_t slen; size_t sufflen; if (!s) return 0; /* null string does not end with anything */ if (!suff) return 1; /* null suffix tails anything */ slen = strlen(s); sufflen = strlen(suff); return (slen >= sufflen) && (!memcmp(s + slen - sufflen, suff, sufflen)); } #ifndef HAVE_STRTOF # include # include float strtof(const char *nptr, char **endptr) { double d; int i; if (!nptr || !*nptr) { errno = EINVAL; return 0; } /* FIXME: LC_NUMERIC=C for dot floats */ i = sscanf(nptr, "%f", &d); if (i < 1) { errno = EINVAL; return 0; } if (endptr) { *endptr = (char*)nptr + i; } return (float)d; } #endif nut-2.8.3/common/strptime.c0000644000200500020050000003336014777534445012573 00000000000000/* $NetBSD: strptime.c,v 1.36 2012/03/13 21:13:48 christos Exp $ */ /* Fetched into NUT codebase from MSYS2 packaging of MINGW: * https://raw.githubusercontent.com/msys2/MINGW-packages/master/mingw-w64-libkml/strptime.c */ /*- * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. * All rights reserved. * * This code was contributed to The NetBSD Foundation by Klaus Klein. * Heavily optimised by David Laight * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ /* Use NUT build configuration */ #include "config.h" /* #include #if defined(LIBC_SCCS) && !defined(lint) __RCSID("$NetBSD: strptime.c,v 1.36 2012/03/13 21:13:48 christos Exp $"); #endif #include "namespace.h" #include */ #include #include #include #include #if defined HAVE_STDINT_H # include #else # include "nut_stdint.h" #endif /* #include #include "private.h" #ifdef __weak_alias __weak_alias(strptime,_strptime) #endif */ typedef unsigned char u_char; typedef unsigned int uint; typedef unsigned __int64 uint64_t; #define _ctloc(x) (_CurrentTimeLocale->x) /* * We do not implement alternate representations. However, we always * check whether a given modifier is allowed for a certain conversion. */ #define ALT_E 0x01 #define ALT_O 0x02 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; } static int TM_YEAR_BASE = 1900; static char gmt[] = { "GMT" }; static char utc[] = { "UTC" }; /* RFC-822/RFC-2822 */ static const char * const nast[5] = { "EST", "CST", "MST", "PST", "\0\0\0" }; static const char * const nadt[5] = { "EDT", "CDT", "MDT", "PDT", "\0\0\0" }; static const char * const am_pm[2] = { "am", "pm" }; static const char * const day[7] = { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" }; static const char * const abday[7] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; static const char * const mon[12] = { "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" }; static const char * const abmon[12] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; static const u_char *conv_num(const unsigned char *, int *, uint, uint); static const u_char *find_string(const u_char *, int *, const char * const *, const char * const *, int); /* #ifndef MO_MINGW32 static int strncasecmp(const char *a, const char *b, size_t c) { return _strnicmp(a, b, c); } #endif */ char * strptime(const char *buf, const char *fmt, struct tm *tm) { unsigned char c; const unsigned char *bp, *ep; int alt_format, i, split_year = 0, neg = 0, offs; const char *new_fmt; bp = (const u_char *)buf; while (bp != NULL && (c = *fmt++) != '\0') { /* Clear `alternate' modifier prior to new conversion. */ alt_format = 0; i = 0; /* Eat up white-space. */ if (isspace(c)) { while (isspace(*bp)) bp++; continue; } if (c != '%') goto literal; again: switch (c = *fmt++) { case '%': /* "%%" is converted to "%". */ literal: if (c != *bp++) return NULL; LEGAL_ALT(0); continue; /* * "Alternative" modifiers. Just set the appropriate flag * and start over again. */ case 'E': /* "%E?" alternative conversion modifier. */ LEGAL_ALT(0); alt_format |= ALT_E; goto again; case 'O': /* "%O?" alternative conversion modifier. */ LEGAL_ALT(0); alt_format |= ALT_O; goto again; /* * "Complex" conversion rules, implemented through recursion. */ /* // we do not need 'c': case 'c': Date and time, using the locale's format. new_fmt = _ctloc(d_t_fmt); goto recurse; */ case 'D': /* The date as "%m/%d/%y". */ new_fmt = "%m/%d/%y"; LEGAL_ALT(0); goto recurse; case 'F': /* The date as "%Y-%m-%d". */ new_fmt = "%Y-%m-%d"; LEGAL_ALT(0); goto recurse; case 'R': /* The time as "%H:%M". */ new_fmt = "%H:%M"; LEGAL_ALT(0); goto recurse; case 'r': /* The time in 12-hour clock representation. */ new_fmt = "%I:%M:S %p";/*_ctloc(t_fmt_ampm); */ LEGAL_ALT(0); goto recurse; case 'T': /* The time as "%H:%M:%S". */ new_fmt = "%H:%M:%S"; LEGAL_ALT(0); goto recurse; /* // we don't use 'X' case 'X': The time, using the locale's format. new_fmt =_ctloc(t_fmt); goto recurse; */ /* // we do not need 'x' case 'x': The date, using the locale's format. new_fmt =_ctloc(d_fmt); */ recurse: bp = (const u_char *)strptime((const char *)bp, new_fmt, tm); LEGAL_ALT(ALT_E); continue; /* * "Elementary" conversion rules. */ case 'A': /* The day of week, using the locale's form. */ case 'a': bp = find_string(bp, &tm->tm_wday, day, abday, 7); LEGAL_ALT(0); continue; case 'B': /* The month, using the locale's form. */ case 'b': case 'h': bp = find_string(bp, &tm->tm_mon, mon, abmon, 12); LEGAL_ALT(0); continue; case 'C': /* The century number. */ i = 20; bp = conv_num(bp, &i, 0, 99); i = i * 100 - TM_YEAR_BASE; if (split_year) i += tm->tm_year % 100; split_year = 1; tm->tm_year = i; LEGAL_ALT(ALT_E); continue; case 'd': /* The day of month. */ case 'e': bp = conv_num(bp, &tm->tm_mday, 1, 31); LEGAL_ALT(ALT_O); continue; case 'k': /* The hour (24-hour clock representation). */ LEGAL_ALT(0); /* FALLTHROUGH */ case 'H': bp = conv_num(bp, &tm->tm_hour, 0, 23); LEGAL_ALT(ALT_O); continue; case 'l': /* The hour (12-hour clock representation). */ LEGAL_ALT(0); /* FALLTHROUGH */ case 'I': bp = conv_num(bp, &tm->tm_hour, 1, 12); if (tm->tm_hour == 12) tm->tm_hour = 0; LEGAL_ALT(ALT_O); continue; case 'j': /* The day of year. */ i = 1; bp = conv_num(bp, &i, 1, 366); tm->tm_yday = i - 1; LEGAL_ALT(0); continue; case 'M': /* The minute. */ bp = conv_num(bp, &tm->tm_min, 0, 59); LEGAL_ALT(ALT_O); continue; case 'm': /* The month. */ i = 1; bp = conv_num(bp, &i, 1, 12); tm->tm_mon = i - 1; LEGAL_ALT(ALT_O); continue; case 'p': /* The locale's equivalent of AM/PM. */ bp = find_string(bp, &i, am_pm, NULL, 2); if (tm->tm_hour > 11) return NULL; tm->tm_hour += i * 12; LEGAL_ALT(0); continue; case 'S': /* The seconds. */ bp = conv_num(bp, &tm->tm_sec, 0, 61); LEGAL_ALT(ALT_O); continue; #ifndef TIME_MAX #define TIME_MAX INT64_MAX #endif case 's': /* seconds since the epoch */ { time_t sse = 0; uint64_t rulim = TIME_MAX; if (*bp < '0' || *bp > '9') { bp = NULL; continue; } do { sse *= 10; sse += *bp++ - '0'; rulim /= 10; } while (((uint64_t)sse * 10 <= TIME_MAX) && rulim && *bp >= '0' && *bp <= '9'); if (sse < 0 || (uint64_t)sse > TIME_MAX) { bp = NULL; continue; } tm = localtime(&sse); if (tm == NULL) bp = NULL; } continue; case 'U': /* The week of year, beginning on sunday. */ case 'W': /* The week of year, beginning on monday. */ /* * XXX This is bogus, as we can not assume any valid * information present in the tm structure at this * point to calculate a real value, so just check the * range for now. */ bp = conv_num(bp, &i, 0, 53); LEGAL_ALT(ALT_O); continue; case 'w': /* The day of week, beginning on sunday. */ bp = conv_num(bp, &tm->tm_wday, 0, 6); LEGAL_ALT(ALT_O); continue; case 'u': /* The day of week, monday = 1. */ bp = conv_num(bp, &i, 1, 7); tm->tm_wday = i % 7; LEGAL_ALT(ALT_O); continue; case 'g': /* The year corresponding to the ISO week * number but without the century. */ bp = conv_num(bp, &i, 0, 99); continue; case 'G': /* The year corresponding to the ISO week * number with century. */ do { bp++; } while (isdigit(*bp)); continue; case 'V': /* The ISO 8601:1988 week number as decimal */ bp = conv_num(bp, &i, 0, 53); continue; case 'Y': /* The year. */ i = TM_YEAR_BASE; /* just for data sanity... */ bp = conv_num(bp, &i, 0, 9999); tm->tm_year = i - TM_YEAR_BASE; LEGAL_ALT(ALT_E); continue; case 'y': /* The year within 100 years of the epoch. */ /* LEGAL_ALT(ALT_E | ALT_O); */ bp = conv_num(bp, &i, 0, 99); if (split_year) /* preserve century */ i += (tm->tm_year / 100) * 100; else { split_year = 1; if (i <= 68) i = i + 2000 - TM_YEAR_BASE; else i = i + 1900 - TM_YEAR_BASE; } tm->tm_year = i; continue; case 'Z': _tzset(); if (strncasecmp((const char *)bp, gmt, 3) == 0 || strncasecmp((const char *)bp, utc, 3) == 0 ) { tm->tm_isdst = 0; #ifdef TM_GMTOFF tm->TM_GMTOFF = 0; #endif #ifdef TM_ZONE tm->TM_ZONE = gmt; #endif bp += 3; } else { ep = find_string(bp, &i, (const char * const *)tzname, NULL, 2); if (ep != NULL) { tm->tm_isdst = i; #ifdef TM_GMTOFF tm->TM_GMTOFF = -(timezone); #endif #ifdef TM_ZONE tm->TM_ZONE = tzname[i]; #endif } bp = ep; } continue; case 'z': /* * We recognize all ISO 8601 formats: * Z = Zulu time/UTC * [+-]hhmm * [+-]hh:mm * [+-]hh * We recognize all RFC-822/RFC-2822 formats: * UT|GMT * North American : UTC offsets * E[DS]T = Eastern : -4 | -5 * C[DS]T = Central : -5 | -6 * M[DS]T = Mountain: -6 | -7 * P[DS]T = Pacific : -7 | -8 * Military * [A-IL-M] = -1 ... -9 (J not used) * [N-Y] = +1 ... +12 */ while (isspace(*bp)) bp++; switch (*bp++) { case 'G': if (*bp++ != 'M') return NULL; /*FALLTHROUGH*/ case 'U': if (*bp++ != 'T') return NULL; /*FALLTHROUGH*/ case 'Z': tm->tm_isdst = 0; #ifdef TM_GMTOFF tm->TM_GMTOFF = 0; #endif #ifdef TM_ZONE tm->TM_ZONE = utc; #endif continue; case '+': neg = 0; break; case '-': neg = 1; break; default: --bp; ep = find_string(bp, &i, nast, NULL, 4); if (ep != NULL) { #ifdef TM_GMTOFF tm->TM_GMTOFF = -5 - i; #endif #ifdef TM_ZONE tm->TM_ZONE = __UNCONST(nast[i]); #endif bp = ep; continue; } ep = find_string(bp, &i, nadt, NULL, 4); if (ep != NULL) { tm->tm_isdst = 1; #ifdef TM_GMTOFF tm->TM_GMTOFF = -4 - i; #endif #ifdef TM_ZONE tm->TM_ZONE = __UNCONST(nadt[i]); #endif bp = ep; continue; } if ((*bp >= 'A' && *bp <= 'I') || (*bp >= 'L' && *bp <= 'Y') ) { #ifdef TM_GMTOFF /* Argh! No 'J'! */ if (*bp >= 'A' && *bp <= 'I') tm->TM_GMTOFF = ('A' - 1) - (int)*bp; else if (*bp >= 'L' && *bp <= 'M') tm->TM_GMTOFF = 'A' - (int)*bp; else if (*bp >= 'N' && *bp <= 'Y') tm->TM_GMTOFF = (int)*bp - 'M'; #endif #ifdef TM_ZONE tm->TM_ZONE = NULL; /* XXX */ #endif bp++; continue; } return NULL; } offs = 0; for (i = 0; i < 4; ) { if (isdigit(*bp)) { offs = offs * 10 + (*bp++ - '0'); i++; continue; } if (i == 2 && *bp == ':') { bp++; continue; } break; } switch (i) { case 2: offs *= 100; break; case 4: i = offs % 100; if (i >= 60) return NULL; /* Convert minutes into decimal */ offs = (offs / 100) * 100 + (i * 50) / 30; break; default: return NULL; } if (neg) offs = -offs; tm->tm_isdst = 0; /* XXX */ #ifdef TM_GMTOFF tm->TM_GMTOFF = offs; #endif #ifdef TM_ZONE tm->TM_ZONE = NULL; /* XXX */ #endif continue; /* * Miscellaneous conversions. */ case 'n': /* Any kind of white-space. */ case 't': while (isspace(*bp)) bp++; LEGAL_ALT(0); continue; default: /* Unknown/unsupported conversion. */ return NULL; } } return (char *)(bp); } static const u_char * conv_num(const unsigned char *buf, int *dest, uint llim, uint ulim) { uint result = 0; unsigned char ch; /* The limit also determines the number of valid digits. */ uint rulim = ulim; ch = *buf; if (ch < '0' || ch > '9') return NULL; do { result *= 10; result += ch - '0'; rulim /= 10; ch = *++buf; } while ((result * 10 <= ulim) && rulim && ch >= '0' && ch <= '9'); if (result < llim || result > ulim) return NULL; *dest = result; return buf; } static const u_char * find_string(const u_char *bp, int *tgt, const char * const *n1, const char * const *n2, int c) { int i; size_t len; /* check full name - then abbreviated ones */ for (; n1 != NULL; n1 = n2, n2 = NULL) { for (i = 0; i < c; i++, n1++) { len = strlen(*n1); if (strncasecmp(*n1, (const char *)bp, len) == 0) { *tgt = i; return bp + len; } } } /* Nothing matched */ return NULL; } nut-2.8.3/common/nutstream.cpp0000644000200500020050000010173314777767434013314 00000000000000/* nutstream.cpp - NUT stream Copyright (C) 2012 Eaton Author: Vaclav Krpec Copyright (C) 2024-2025 NUT Community Author: Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nutstream.hpp" #include #include #include #include #include #include extern "C" { /* For C++ code below, we do not actually use the fallback time methods * (on mingw mostly), but in C++ context they happen to conflict with * time.h or ctime headers, while native-C does not. Just disable the * fallback localtime_r(), gmtime_r() etc. if/when NUT timehead.h gets * included by the header chain from common.h: */ #ifndef HAVE_GMTIME_R # define HAVE_GMTIME_R 111 #endif #ifndef HAVE_LOCALTIME_R # define HAVE_LOCALTIME_R 111 #endif #include "common.h" #include #include #include #include /* Windows/Linux Socket compatibility layer, lifted from nutclient.cpp * (note we do not use wincompat.h here as it slightly conflicts, with * extern vs. static etc.) */ /* Thanks to Benjamin Roux (http://broux.developpez.com/articles/c/sockets/) */ #ifdef WIN32 # define SOCK_OPT_CAST(x) reinterpret_cast(x) /* equivalent of W32_NETWORK_CALL_OVERRIDE * invoked by wincompat.h in upsclient.c: */ static inline int sktconnect(int fh, struct sockaddr * name, int len) { int ret = connect(fh,name,len); errno = WSAGetLastError(); return ret; } static inline int sktread(int fh, void *buf, int size) { int ret = recv(fh,(char*)buf,size,0); errno = WSAGetLastError(); return ret; } static inline int sktwrite(int fh, const void*buf, int size) { int ret = send(fh,(char*)buf,size,0); errno = WSAGetLastError(); return ret; } static inline int sktclose(int fh) { int ret = closesocket((SOCKET)fh); errno = WSAGetLastError(); return ret; } #else /* not WIN32 */ # include # include # include # include # include # include /* gethostbyname */ # include # ifndef INVALID_SOCKET # define INVALID_SOCKET -1 # endif # ifndef SOCKET_ERROR # define SOCKET_ERROR -1 # endif # ifndef closesocket # define closesocket(s) close(s) # endif # define SOCK_OPT_CAST(x) reinterpret_cast(x) typedef int SOCKET; typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr SOCKADDR; typedef struct in_addr IN_ADDR; # define sktconnect(h,n,l) ::connect(h,n,l) # define sktread(h,b,s) ::read(h,b,s) # define sktwrite(h,b,s) ::write(h,b,s) # define sktclose(h) ::close(h) /* WA for Solaris/i386 bug: non-blocking connect sets errno to ENOENT */ # if (defined NUT_PLATFORM_SOLARIS) # define SOLARIS_i386_NBCONNECT_ENOENT(status) ( (!strcmp("i386", CPU_TYPE)) ? (ENOENT == (status)) : 0 ) # else # define SOLARIS_i386_NBCONNECT_ENOENT(status) (0) # endif /* end of Solaris/i386 WA for non-blocking connect */ /* WA for AIX bug: non-blocking connect sets errno to 0 */ # if (defined NUT_PLATFORM_AIX) # define AIX_NBCONNECT_0(status) (0 == (status)) # else # define AIX_NBCONNECT_0(status) (0) # endif /* end of AIX WA for non-blocking connect */ #endif /* WIN32 */ /* End of Windows/Linux Socket compatibility layer */ } namespace nut { /* Trivial implementation out of class declaration to avoid * error: 'ClassName' has no out-of-line virtual method definitions; its vtable * will be emitted in every translation unit [-Werror,-Wweak-vtables] */ NutStream::~NutStream() {} NutStream::status_t NutMemory::getChar(char & ch) { if (m_pos == m_impl.size()) return NUTS_EOF; if (m_pos > m_impl.size()) return NUTS_ERROR; ch = m_impl.at(m_pos); return NUTS_OK; } void NutMemory::readChar() { if (m_pos < m_impl.size()) ++m_pos; } NutStream::status_t NutMemory::getString(std::string & str) { str = m_impl.substr(m_pos); m_pos = m_impl.size(); return NUTS_OK; } NutStream::status_t NutMemory::putChar(char ch) { m_impl += ch; return NUTS_OK; } NutStream::status_t NutMemory::putString(const std::string & str) { m_impl += str; return NUTS_OK; } NutStream::status_t NutMemory::putData(const std::string & data) { return putString(data); } /* Here we align with OS envvars like TMPDIR or TEMPDIR, * consider portability to Windows, or use of tmpfs like * /dev/shm or (/var)/run on some platforms - e.g. NUT * STATEPATH, (ALT)PIDPATH or similar locations desired * by packager who knows their system. */ static bool checkExistsWritableDir(const char *s) { DIR *pd; #ifdef DEBUG std::cerr << "checkExistsWritableDir(" << (s ? s : "") << "): "; #endif if (!s || *s == '\0') { #ifdef DEBUG std::cerr << "null or empty string" << std::endl; #endif return false; } if (!(pd = opendir(s))) { #ifdef DEBUG std::cerr << "not a dir" << std::endl; #endif return false; } closedir(pd); /* POSIX: If the requested access is permitted, access() succeeds * and shall return 0; otherwise, -1 shall be returned and errno * shall be set to indicate the error. */ if (access(s, X_OK)) { #ifdef DEBUG std::cerr << "not traversable" << std::endl; #endif return false; } if (access(s, W_OK)) { #ifdef DEBUG std::cerr << "not writeable" << std::endl; #endif return false; } #ifdef DEBUG std::cerr << "is ok" << std::endl; #endif return true; } static const char* getTmpDirPath() { const char *s; #ifdef WIN32 /* Suggestions from https://sourceforge.net/p/mingw/bugs/666/ */ static char pathbuf[NUT_PATH_MAX + 1]; int i; #endif /* WIN32 */ if (checkExistsWritableDir(s = ::altpidpath())) return s; /* NOTE: For C++17 or newer we might also call * https://en.cppreference.com/w/cpp/filesystem/temp_directory_path */ #ifdef WIN32 i = GetTempPathA(sizeof(pathbuf), pathbuf); if ((i > 0) && (i < NUT_PATH_MAX) && checkExistsWritableDir(pathbuf)) return (const char *)pathbuf; #endif /* WIN32 */ if (checkExistsWritableDir(s = ::getenv("TMPDIR"))) return s; if (checkExistsWritableDir(s = ::getenv("TEMPDIR"))) return s; if (checkExistsWritableDir(s = ::getenv("TEMP"))) return s; if (checkExistsWritableDir(s = ::getenv("TMP"))) return s; /* Some OS-dependent locations */ #ifdef WIN32 if (checkExistsWritableDir(s = "C:\\Temp")) return s; if (checkExistsWritableDir(s = "C:\\Windows\\Temp")) return s; if (checkExistsWritableDir(s = "/c/Temp")) return s; if (checkExistsWritableDir(s = "/c/Windows/Temp")) return s; #else /* !WIN32 */ if (checkExistsWritableDir(s = "/dev/shm")) return s; if (checkExistsWritableDir(s = "/run")) return s; if (checkExistsWritableDir(s = "/var/run")) return s; #endif /* !WIN32 */ /* May be applicable to WIN32 depending on emulation environment/mapping */ if (checkExistsWritableDir(s = "/tmp")) return s; if (checkExistsWritableDir(s = "/var/tmp")) return s; /* Maybe ok, for tests at least: a current working directory */ if (checkExistsWritableDir(s = ".")) return s; return "/tmp"; } /* Pedantic builds complain about the static variable below... * It is assumed safe to ignore since it is a std::string with * no complex teardown at program exit. */ #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) #pragma GCC diagnostic push # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS # pragma GCC diagnostic ignored "-Wglobal-constructors" # endif # ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS # pragma GCC diagnostic ignored "-Wexit-time-destructors" # endif #endif const std::string NutFile::m_tmp_dir(getTmpDirPath()); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) #pragma GCC diagnostic pop #endif NutFile::NutFile(anonymous_t): m_name(""), m_impl(nullptr), m_current_ch('\0'), m_current_ch_valid(false) { #ifdef WIN32 /* Suggestions from https://sourceforge.net/p/mingw/bugs/666/ because * msvcrt tmpfile() uses C: root dir and lacks permissions to actually * use it, and mingw tends to call that OS method so far */ char filename[NUT_PATH_MAX + 1]; memset(filename, 0, sizeof(filename)); GetTempFileNameA(m_tmp_dir.c_str(), "nuttemp", 0, filename); /* if (verbose) std::cerr << "TMP FILE: " << filename << std::endl; */ std::string mode_str = std::string(strAccessMode(READ_WRITE_CLEAR)); /* ...Still, we ask to auto-delete where supported: */ mode_str += std::string("D"); /* Per https://en.cppreference.com/w/cpp/io/c/tmpfile it is binary * for POSIX code, so match the behavior here: */ mode_str += std::string("b"); m_impl = ::fopen(filename, mode_str.c_str()); /* If it were not "const" we might assign it. But got no big need to. * m_name = std::string(filename); */ #else /* !WIN32 */ /* TOTHINK: How to make this use m_tmp_dir? Is it possible generally? */ /* Safer than tmpnam() but we don't know the filename here. * Not that we need it, system should auto-delete it. */ m_impl = ::tmpfile(); #endif /* !WIN32 */ if (nullptr == m_impl) { int err_code = errno; std::stringstream e; e << "Failed to create temporary file: " << err_code << ": " << ::strerror(err_code); #ifdef WIN32 e << ": tried using temporary location " << m_tmp_dir; if (filename[0] != '\0') e << ": OS suggested filename " << filename; #endif /* WIN32 */ throw std::runtime_error(e.str()); } } bool NutFile::exists(int & err_code, std::string & err_msg) const #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { struct stat info; int status; /* An opened file pointer is assumed to be backed by a file at this * moment (even if unlinked, temporary with unknown name, etc.) */ if (m_impl != nullptr) return true; /* Can not stat an unknown file name */ if (m_name.empty()) return false; status = ::stat(m_name.c_str(), &info); if (!status) return true; err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } const char * NutFile::strAccessMode(access_t mode) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { /* NOTE: Currently we use OS-default binary/text choice of content mode * since we primarily expect to manipulate user-editable config files */ static const char *read_only = "r"; static const char *write_only = "w"; static const char *read_write = "r+"; static const char *read_write_clear = "w+"; static const char *append_only = "a"; static const char *read_append = "a+"; const char *mode_str = nullptr; switch (mode) { case READ_ONLY: mode_str = read_only; break; case WRITE_ONLY: mode_str = write_only; break; case READ_WRITE: mode_str = read_write; break; case READ_WRITE_CLEAR: mode_str = read_write_clear; break; case READ_APPEND: mode_str = read_append; break; case APPEND_ONLY: mode_str = append_only; break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif default: /* Must not occur. */ break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } assert(nullptr != mode_str); return mode_str; } bool NutFile::open(access_t mode, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { const char *mode_str; /* Can not open an unknown file name */ if (m_name.empty()) { err_code = ENOENT; err_msg = std::string("No file name was specified"); return false; } if (nullptr != m_impl) { /* TOTHINK: Should we care about errors in this close()? */ ::fclose(m_impl); } #ifdef WIN32 /* This currently fails with mingw due to looking at POSIXified paths: * - Failed to open file /c/Users/abuild/Documents/FOSS/nut/conf/nut.conf.sample: 2: No such file or directory * while the file does exist (for git-bash and mingw shells): * $ ls -la /c/Users/abuild/Documents/FOSS/nut/conf/nut.conf.sample * -rw-r--r-- 1 abuild Users 4774 Jan 28 03:38 /c/Users/abuild/Documents/FOSS/nut/conf/nut.conf.sample * * For the test suite it is not a great problem, can be fixed * by using `cygpath` or `pwd -W` in `configure` script. * The run-time behavior is more troublesome: per discussion at * https://sourceforge.net/p/mingw/mailman/mingw-users/thread/gq8fi0$pk0$2@ger.gmane.org/ * mingw uses fopen() from msvcrt directly, and it does not know * such paths (e.g. '/c/Users/...' means "C:\\c\\Users\\..." to it). * Paths coming from MSYS shell arguments are handled by the shell, * and this is more than about slash type (WINNT is okay with both), * but also e.g. prefixing an msys installation path 'C:\\msys64' or * similar when using absolute POSIX-style paths. Do we need a private * converter?.. Would an end user have MSYS installed at all? */ /* NUT_WIN32_INCOMPLETE_DETAILED("might work, might fail"); */ #endif /* WIN32 */ mode_str = strAccessMode(mode); m_impl = ::fopen(m_name.c_str(), mode_str); if (nullptr != m_impl) return true; err_code = errno; err_msg = "Failed to open file '" + m_name + "': " + std::string(::strerror(err_code)); return false; } bool NutFile::flush(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { if (nullptr == m_impl) { err_code = EBADF; err_msg = std::string(::strerror(err_code)); return false; } err_code = ::fflush(m_impl); if (0 != err_code) { err_msg = std::string(::strerror(err_code)); return false; } return true; } bool NutFile::close(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { /* Already closed (or never opened) - goal achieved */ if (nullptr == m_impl) { return true; } err_code = ::fclose(m_impl); if (0 != err_code) { err_msg = std::string(::strerror(err_code)); return false; } m_impl = nullptr; return true; } bool NutFile::remove(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { /* Can not unlink an unknown file name */ if (m_name.empty()) { err_code = ENOENT; err_msg = std::string("No file name was specified"); return false; } /* FWIW, note that if the file descriptor is opened by this * or any other process(es), it remains usable only by them * after un-linking, and the file system resources would be * released only when everyone closes it. */ err_code = ::unlink(m_name.c_str()); if (0 != err_code) { err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } return true; } NutFile::NutFile(const std::string & name, access_t mode): m_name(name), m_impl(nullptr), m_current_ch('\0'), m_current_ch_valid(false) { openx(mode); } NutFile::NutFile(access_t mode): NutFile(ANONYMOUS) { const char *mode_str = strAccessMode(mode); m_impl = ::freopen(nullptr, mode_str, m_impl); if (nullptr == m_impl) { int err_code = errno; std::stringstream e; e << "Failed to re-open temporary file with mode '" << mode_str << "': " << err_code << ": " << ::strerror(err_code); throw std::runtime_error(e.str()); } } /** * \brief C fgetc wrapper * * \param[in] file File * \param[out] ch Character * * \retval NUTS_OK on success * \retval NUTS_EOF on end-of-file * \retval NUTS_ERROR on read error */ inline static NutStream::status_t fgetcWrapper(FILE * file, char & ch) { assert(nullptr != file); errno = 0; int c = ::fgetc(file); if (EOF == c) { if (0 == errno) return NutStream::NUTS_EOF; return NutStream::NUTS_ERROR; } ch = static_cast(c); return NutStream::NUTS_OK; } NutStream::status_t NutFile::getChar(char & ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { if (m_current_ch_valid) { ch = m_current_ch; return NUTS_OK; } if (nullptr == m_impl) return NUTS_ERROR; status_t status = fgetcWrapper(m_impl, ch); if (NUTS_OK != status) return status; // Cache the character for future reference m_current_ch = ch; m_current_ch_valid = true; return NUTS_OK; } void NutFile::readChar() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { m_current_ch_valid = false; } NutStream::status_t NutFile::getString(std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { if (m_current_ch_valid) str += m_current_ch; m_current_ch_valid = false; if (nullptr == m_impl) return NUTS_ERROR; // Note that ::fgetc is used instead of ::fgets // That's because of \0 char. support for (;;) { char ch; status_t status = fgetcWrapper(m_impl, ch); if (NUTS_ERROR == status) return status; if (NUTS_EOF == status) return NUTS_OK; str += ch; } } NutStream::status_t NutFile::putChar(char ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int c; if (nullptr == m_impl) return NUTS_ERROR; c = ::fputc(static_cast(ch), m_impl); return EOF == c ? NUTS_ERROR : NUTS_OK; } NutStream::status_t NutFile::putString(const std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int c; if (nullptr == m_impl) return NUTS_ERROR; c = ::fputs(str.c_str(), m_impl); return EOF == c ? NUTS_ERROR : NUTS_OK; } NutStream::status_t NutFile::putData(const std::string & data) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { // Unfortunately, C FILE interface doesn't have non C-string // put function (i.e. function for raw data output with size specifier for (size_t i = 0; i < data.size(); ++i) { status_t st = putChar(data.at(i)); if (NUTS_ERROR == st) return NUTS_ERROR; } return NUTS_OK; } NutFile::~NutFile() { if (nullptr != m_impl) closex(); } void NutSocket::Address::init_unix(Address & addr, const std::string & path) { #ifdef WIN32 /* FIXME: Windows pipes where available? See e.g. clone drivers */ NUT_UNUSED_VARIABLE(addr); NUT_UNUSED_VARIABLE(path); std::stringstream e; e << "Unix sockets not implemented for this platform yet: " << path; // addr.str() << ":" << path; /* NUT_WIN32_INCOMPLETE(); */ throw std::logic_error(e.str()); #else /* !WIN32 */ struct sockaddr_un * un_addr = reinterpret_cast(::malloc(sizeof(struct sockaddr_un))); if (nullptr == un_addr) throw std::bad_alloc(); un_addr->sun_family = AF_UNIX; assert(sizeof(un_addr->sun_path) / sizeof(char) > path.size()); for (size_t i = 0; i < path.size(); ++i) un_addr->sun_path[i] = path.at(i); un_addr->sun_path[path.size()] = '\0'; addr.m_sock_addr = reinterpret_cast(un_addr); addr.m_length = sizeof(*un_addr); #endif /* !WIN32 */ } void NutSocket::Address::init_ipv4(Address & addr, const std::vector & qb, uint16_t port) { assert(4 == qb.size()); uint32_t packed_qb = 0; struct sockaddr_in * in4_addr = reinterpret_cast(::malloc(sizeof(struct sockaddr_in))); if (nullptr == in4_addr) throw std::bad_alloc(); packed_qb = static_cast(qb.at(0)); packed_qb |= static_cast(qb.at(1)) << 8; packed_qb |= static_cast(qb.at(2)) << 16; packed_qb |= static_cast(qb.at(3)) << 24; in4_addr->sin_family = AF_INET; in4_addr->sin_port = htons(port); in4_addr->sin_addr.s_addr = packed_qb; addr.m_sock_addr = reinterpret_cast(in4_addr); addr.m_length = sizeof(*in4_addr); } void NutSocket::Address::init_ipv6(Address & addr, const std::vector & hb, uint16_t port) { assert(16 == hb.size()); struct sockaddr_in6 * in6_addr = reinterpret_cast(::malloc(sizeof(struct sockaddr_in6))); if (nullptr == in6_addr) throw std::bad_alloc(); in6_addr->sin6_family = AF_INET6; in6_addr->sin6_port = htons(port); in6_addr->sin6_flowinfo = 0; // TODO: check that in6_addr->sin6_scope_id = 0; // TODO: check that for (size_t i = 0; i < 16; ++i) in6_addr->sin6_addr.s6_addr[i] = hb.at(i); addr.m_sock_addr = reinterpret_cast(in6_addr); addr.m_length = sizeof(*in6_addr); } NutSocket::Address::Address( unsigned char msb, unsigned char msb2, unsigned char lsb2, unsigned char lsb, uint16_t port) { std::vector qb; qb.reserve(4); qb.push_back(msb); qb.push_back(msb2); qb.push_back(lsb2); qb.push_back(lsb); init_ipv4(*this, qb, port); } NutSocket::Address::Address(const std::vector & bytes, uint16_t port) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { switch (bytes.size()) { case 4: init_ipv4(*this, bytes, port); break; case 16: init_ipv6(*this, bytes, port); break; default: { std::stringstream e; e << "Unsupported IP address size: " << bytes.size(); throw std::logic_error(e.str()); } } } NutSocket::Address::Address(const Address & orig): m_sock_addr(nullptr), m_length(orig.m_length) { void * copy = ::malloc(m_length); if (nullptr == copy) throw std::bad_alloc(); ::memcpy(copy, orig.m_sock_addr, m_length); m_sock_addr = reinterpret_cast(copy); } /** * \brief Format IPv4 address * * \param packed 4 bytes in network byte order * * \return IPv4 address string */ static std::string formatIPv4addr(uint32_t packed) { std::stringstream ss; ss << (packed & 0x000000ff) << "."; ss << (packed >> 8 & 0x000000ff) << "."; ss << (packed >> 16 & 0x000000ff) << "."; ss << (packed >> 24 & 0x000000ff); return ss.str(); } /** * \brief Format IPv6 address * * \param bytes 16 bytes in network byte order * * \return IPv6 address string */ static std::string formatIPv6addr(unsigned char const bytes[16]) { // Check for special form addresses bool zero_at_0_9 = true; bool zero_at_0_14 = false; for (size_t i = 0; zero_at_0_9 && i < 10; ++i) zero_at_0_9 = 0 == bytes[i]; if (zero_at_0_9) { zero_at_0_14 = true; for (size_t i = 10; zero_at_0_14 && i < 15; ++i) zero_at_0_14 = 0 == bytes[i]; } // Loopback if (zero_at_0_14 && 1 == bytes[15]) return "::1"; std::stringstream ss; // IPv4 mapped on IPv6 address if (zero_at_0_9 && 0xff == bytes[10] && 0xff == bytes[11]) { ss << "::FFFF:"; ss << bytes[12] << '.' << bytes[13] << '.'; ss << bytes[14] << '.' << bytes[15]; return ss.str(); } // Standard form // TODO: ommition (REVIEW: omission?) of lengthy zero word strings ss << std::uppercase << std::hex << std::setfill('0'); for (size_t i = 0; ; ) { uint16_t w = static_cast(static_cast(bytes[2 * i]) << 8) | static_cast(bytes[2 * i + 1]); ss << std::setw(4) << w; if (8 == ++i) break; ss << ':'; } return ss.str(); } std::string NutSocket::Address::str() const { assert(nullptr != m_sock_addr); /* Note: we do not cache a copy of "family" because * its data type varies per platform, easier to just * request it each time - not a hot spot anyway. */ std::stringstream ss; ss << "nut::NutSocket::Address(family: " << m_sock_addr->sa_family; switch (m_sock_addr->sa_family) { #ifndef WIN32 case AF_UNIX: { struct sockaddr_un * addr = reinterpret_cast(m_sock_addr); ss << " (UNIX domain socket), file: " << addr->sun_path; break; } #else /* WIN32 */ /* FIXME: Add support for pipes on Windows? */ /* NUT_WIN32_INCOMPLETE(); */ #endif /* WIN32 */ case AF_INET: { struct sockaddr_in * addr = reinterpret_cast(m_sock_addr); ss << " (IPv4 address), " << formatIPv4addr(addr->sin_addr.s_addr) << ":" << addr->sin_port; break; } case AF_INET6: { struct sockaddr_in6 * addr = reinterpret_cast(m_sock_addr); ss << " (IPv6 address), " << formatIPv6addr(addr->sin6_addr.s6_addr) << ":" << addr->sin6_port; break; } default: { std::stringstream e; e << "NOT IMPLEMENTED: Socket address family " << m_sock_addr->sa_family << " unsupported"; throw std::logic_error(e.str()); } } ss << ")"; return ss.str(); } NutSocket::Address::~Address() { ::free(m_sock_addr); } /* NOTE: static class method */ bool NutSocket::accept( NutSocket & sock, const NutSocket & listen_sock, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { assert(-1 == sock.m_impl); struct sockaddr sock_addr; socklen_t sock_addr_size = sizeof(sock_addr); sock.m_impl = ::accept(listen_sock.m_impl, &sock_addr, &sock_addr_size); sock.m_domain = listen_sock.m_domain; sock.m_type = listen_sock.m_type; if (-1 != sock.m_impl) return true; err_code = errno; err_msg = std::string(::strerror(err_code)); // The following reasons of unsuccessful termination are non-exceptional switch (err_code) { case EAGAIN: // Non-blocking listen socket, no conn. pending case ECONNABORTED: // Connection has been aborted case EINTR: // Interrupted by a signal case EMFILE: // Open file descriptors per-process limit was reached case ENFILE: // Open file descriptors per-system limit was reached case EPROTO: // Protocol error return false; default: break; } std::stringstream e; e << "Failed to accept connection: " << err_code << ": " << err_msg; throw std::logic_error(e.str()); } NutSocket::NutSocket(domain_t dom, type_t type, proto_t proto): m_impl(-1), m_domain(dom), m_type(type), m_current_ch('\0'), m_current_ch_valid(false) { int cdom = static_cast(dom); int ctype = static_cast(type); int cproto = static_cast(proto); m_impl = ::socket(cdom, ctype, cproto); if (-1 == m_impl) { int erno = errno; std::stringstream e; e << "Failed to create socket domain: "; e << cdom << ", type: " << ctype << ", proto: " << cproto; e << ": " << erno << ": " << ::strerror(erno); throw std::runtime_error(e.str()); } } bool NutSocket::bind(const Address & addr, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { if (m_domain == NUTSOCKD_UNDEFINED) { m_domain = static_cast(addr.m_sock_addr->sa_family); } else if (static_cast(m_domain) != static_cast(addr.m_sock_addr->sa_family)) { err_code = EINVAL; err_msg = std::string(::strerror(err_code)) + ": bind() with a different socket address family than this object was created for"; } if (m_type == NUTSOCKT_UNDEFINED) { /* We should have this from constructor or accept() */ err_code = EINVAL; err_msg = std::string(::strerror(err_code)) + ": bind() with bad socket type"; } err_code = ::bind(m_impl, addr.m_sock_addr, addr.m_length); if (0 == err_code) return true; err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } bool NutSocket::listen(int backlog, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { err_code = ::listen(m_impl, backlog); if (0 == err_code) return true; err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } bool NutSocket::connect(const Address & addr, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { if (m_domain == NUTSOCKD_UNDEFINED) { m_domain = static_cast(addr.m_sock_addr->sa_family); } else if (static_cast(m_domain) != static_cast(addr.m_sock_addr->sa_family)) { err_code = EINVAL; err_msg = std::string(::strerror(err_code)) + ": connect() with a different socket address family than this object was created for"; } if (m_type == NUTSOCKT_UNDEFINED) { /* We should have this from constructor or accept() */ err_code = EINVAL; err_msg = std::string(::strerror(err_code)) + ": connect() with bad socket type"; } err_code = sktconnect(m_impl, addr.m_sock_addr, addr.m_length); if (0 == err_code) return true; err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } bool NutSocket::flush(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { if (-1 == m_impl) { err_code = EBADF; err_msg = std::string(::strerror(err_code)); return false; } if (m_type == NUTSOCKT_STREAM && m_domain == NUTSOCKD_INETv4) { /* Assume IPv4 TCP: https://stackoverflow.com/a/71417876/4715872 */ int flag = 1; if (!setsockopt(m_impl, IPPROTO_TCP, TCP_NODELAY, SOCK_OPT_CAST(&flag), sizeof(int))) { err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } if (!sktwrite(m_impl, nullptr, 0)) { err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } flag = 0; if (!setsockopt(m_impl, IPPROTO_TCP, TCP_NODELAY, SOCK_OPT_CAST(&flag), sizeof(int))) { err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } } /* else Unix, UDP (or several other socket families generally); PRs welcome */ return true; } bool NutSocket::close(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { err_code = sktclose(m_impl); if (0 == err_code) { m_impl = -1; return true; } err_code = errno; err_msg = std::string(::strerror(err_code)); return false; } NutSocket::~NutSocket() { if (-1 != m_impl) closex(); } NutStream::status_t NutSocket::getChar(char & ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { if (m_current_ch_valid) { ch = m_current_ch; return NUTS_OK; } // TBD: Perhaps we should buffer more bytes at once // However, buffering is already done in kernel space, // so unless we need greater reading efficiency, char-by-char // reading should be sufficient ssize_t read_cnt = ::read(m_impl, &ch, 1); if (1 == read_cnt) { m_current_ch = ch; m_current_ch_valid = true; return NUTS_OK; } if (0 == read_cnt) return NUTS_EOF; assert(-1 == read_cnt); // TODO: At least logging of the error (errno), if not propagation return NUTS_ERROR; } void NutSocket::readChar() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { m_current_ch_valid = false; } NutStream::status_t NutSocket::getString(std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { if (m_current_ch_valid) str += m_current_ch; m_current_ch_valid = false; char buffer[512]; for (;;) { ssize_t read_cnt = sktread(m_impl, buffer, sizeof(buffer) / sizeof(buffer[0])); if (read_cnt < 0) return NUTS_ERROR; if (0 == read_cnt) return NUTS_OK; str.append(buffer, static_cast(read_cnt)); } } NutStream::status_t NutSocket::putChar(char ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { ssize_t write_cnt = sktwrite(m_impl, &ch, 1); if (1 == write_cnt) return NUTS_OK; assert(-1 == write_cnt); // TODO: At least logging of the error (errno), if not propagation return NUTS_ERROR; } NutStream::status_t NutSocket::putString(const std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { size_t str_len = str.size(); // Avoid the costly system call unless necessary if (0 == str_len) return NUTS_OK; ssize_t write_cnt = sktwrite(m_impl, str.data(), str_len); // TODO: Under certain circumstances, less than the whole // string might be written // Review the code if async. I/O is supported (in which case // the function shall have to implement the blocking using // select/poll/epoll on its own (probably select for portability) assert(write_cnt > 0); if (static_cast(write_cnt) == str_len) return NUTS_OK; // TODO: At least logging of the error (errno), if not propagation return NUTS_ERROR; } } // end of namespace nut nut-2.8.3/common/timegm_fallback.c0000644000200500020050000000242114777767434014025 00000000000000/* Fallback timegm() for systems that lack one. * Algorithm: http://howardhinnant.github.io/date_algorithms.html * https://stackoverflow.com/a/58037981/4715872 */ #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif static int days_from_epoch_1970(int y, int m, int d) { y -= m <= 2; int era = y / 400; int yoe = y - era * 400; // [0, 399] int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365] int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] return era * 146097 + doe - 719468; } /* It does not modify broken-down time */ time_t timegm_fallback(struct tm const* t) { int year = t->tm_year + 1900; int month = t->tm_mon; // 0-11 int days_since_epoch_1970; if (month > 11) { year += month / 12; month %= 12; } else if (month < 0) { int years_diff = (11 - month) / 12; year -= years_diff; month += 12 * years_diff; } days_since_epoch_1970 = days_from_epoch_1970(year, month + 1, t->tm_mday); return 60 * (60 * (24L * days_since_epoch_1970 + t->tm_hour) + t->tm_min) + t->tm_sec; } nut-2.8.3/common/setenv.c0000644000200500020050000000111514777767434012227 00000000000000/* setenv.c Ben Collver */ #include "config.h" /* must be first */ #ifndef HAVE_SETENV #include #include #include "common.h" int nut_setenv(const char *name, const char *value, int overwrite) { char *val; char *buffer; int rv; if (overwrite == 0) { val = getenv(name); if (val != NULL) { return 0; } } buffer = xmalloc(strlen(value) + strlen(name) + 2); strcpy(buffer, name); strcat(buffer, "="); strcat(buffer, value); rv = putenv(buffer); /* man putenv, do not free(buffer) */ return (rv); } #endif /* !HAVE_SETENV */ nut-2.8.3/common/nutconf.cpp0000644000200500020050000013521315001552635012716 00000000000000/* nutconf.cpp - configuration API Copyright (C) 2012 Eaton Author: Emilien Kia Copyright (C) 2024-2025 NUT Community Author: Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nutconf.hpp" #include "nutwriter.hpp" #include #include #include #include #include #include namespace nut { /* Trivial implementations out of class declaration to avoid * error: 'ClassName' has no out-of-line virtual method definitions; its vtable * will be emitted in every translation unit [-Werror,-Wweak-vtables] */ Serialisable::~Serialisable() {} BaseConfiguration::~BaseConfiguration() {} GenericConfiguration::~GenericConfiguration() {} UpsConfiguration::~UpsConfiguration() {} NutParser::~NutParser() {} // // Tool functions // /** * Parse a specified type from a string and set it as Settable if success. */ template Settable StringToSettableNumber(const std::string & src) { if (typeid(T) == typeid(bool)) { static const Settable b0(false); static const Settable b1(true); // See also: GenericConfiguration::str2bool() // FIXME: Can these two methods be merged? if ("true" == src) return b1; if ("on" == src) return b1; if ("1" == src) return b1; if ("yes" == src) return b1; if ("ok" == src) return b1; return b0; } else { std::stringstream ss(src); T result; if(ss >> result) { return Settable(result); } else { return Settable(); } } } // // NutParser // NutParser::NutParser(const char* buffer, unsigned int options) : _options(options), _buffer(buffer), _pos(0) { } NutParser::NutParser(const std::string& buffer, unsigned int options) : _options(options), _buffer(buffer), _pos(0) { } void NutParser::setOptions(unsigned int options, bool set) { if(set) { _options |= options; } else { _options &= ~options; } } char NutParser::get() { if (_pos >= _buffer.size()) return 0; else return _buffer[_pos++]; } char NutParser::peek() { return _buffer[_pos]; } size_t NutParser::getPos()const { return _pos; } void NutParser::setPos(size_t pos) { _pos = pos; } char NutParser::charAt(size_t pos)const { return _buffer[pos]; } void NutParser::pushPos() { _stack.push_back(_pos); } size_t NutParser::popPos() { size_t pos = _stack.back(); _stack.pop_back(); return pos; } void NutParser::rewind() { _pos = popPos(); } void NutParser::back() { if (_pos > 0) --_pos; } /* Parse a string source for a CHARS and return its size if found or 0, if not. * CHARS ::= CHAR+ * CHAR ::= __ASCIICHAR__ - ( __SPACES__ | '\\' | '\"' | '#' ) * | '\\' ( __SPACES__ | '\\' | '\"' | '#' ) * TODO: accept "\t", "\s", "\r", "\n" ?? */ std::string NutParser::parseCHARS() { bool escaped = false; // Is char escaped ? std::string res; // Stored string pushPos(); for (char c = get(); c != 0 /*EOF*/; c = get()) { if (escaped) { if (isspace(c) || c == '\\' || c == '"' || c == '#') { res += c; } else { /* WTF ??? */ } escaped = false; } else { if (c == '\\') { escaped = true; } else if (isgraph(c) /*&& c != '\\'*/ && c != '"' && c != '#') { res += c; } else { back(); break; } } } popPos(); return res; } /* Parse a string source for a STRCHARS and return its size if found or 0, if not. * STRCHARS ::= STRCHAR+ * STRCHAR ::= __ASCIICHAR__ - ( '\\' | '\"') * | '\\' ( '\\' | '\"' ) * TODO: accept "\t", "\s", "\r", "\n" ?? */ std::string NutParser::parseSTRCHARS() { bool escaped = false; // Is char escaped ? std::string str; // Stored string pushPos(); for (char c = get(); c != 0 /*EOF*/; c = get()) { if (escaped) { if (isspace(c) || c == '\\' || c == '"') { str += c; } else { /* WTF ??? */ } escaped = false; } else { if (c == '\\') { escaped = true; } else if (isprint(c) && c != '\\' && c != '"') { str += c; } else { back(); break; } } } popPos(); return str; } /** Parse a string source for getting the next token, ignoring spaces. * \return Token type. */ NutParser::Token NutParser::parseToken() { /** Lexical parsing machine state enumeration.*/ typedef enum { LEXPARSING_STATE_DEFAULT, LEXPARSING_STATE_QUOTED_STRING, LEXPARSING_STATE_STRING, LEXPARSING_STATE_COMMENT } LEXPARSING_STATE_e; LEXPARSING_STATE_e state = LEXPARSING_STATE_DEFAULT; Token token; bool escaped = false; pushPos(); for (char c = get(); c != 0 /*EOF*/; c = get()) { switch (state) { case LEXPARSING_STATE_DEFAULT: /* Wait for a non-space char */ { if (c == ' ' || c == '\t') { /* Space : do nothing */ } else if (c == '[') { token = Token(Token::TOKEN_BRACKET_OPEN, c); popPos(); return token; } else if (c == ']') { token = Token(Token::TOKEN_BRACKET_CLOSE, c); popPos(); return token; } else if (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) { token = Token(Token::TOKEN_COLON, c); popPos(); return token; } else if (c == '=') { token = Token(Token::TOKEN_EQUAL, c); popPos(); return token; } else if (c == '\r' || c == '\n') { token = Token(Token::TOKEN_EOL, c); popPos(); return token; } else if (c == '#') { token.type = Token::TOKEN_COMMENT; state = LEXPARSING_STATE_COMMENT; } else if (c == '"') { /* Begin of QUOTED STRING */ token.type = Token::TOKEN_QUOTED_STRING; state = LEXPARSING_STATE_QUOTED_STRING; } else if (c == '\\') { /* Begin of STRING with escape */ token.type = Token::TOKEN_STRING; state = LEXPARSING_STATE_STRING; escaped = true; } else if (isgraph(c)) { /* Begin of STRING */ token.type = Token::TOKEN_STRING; state = LEXPARSING_STATE_STRING; token.str += c; } else { rewind(); return Token(Token::TOKEN_UNKNOWN); } break; } case LEXPARSING_STATE_QUOTED_STRING: { if (c == '"') { if (escaped) { escaped = false; token.str += '"'; } else { popPos(); return token; } } else if (c == '\\') { if (escaped) { escaped = false; token.str += '\\'; } else { escaped = true; } } else if (c == ' ' || c == '\t' || isgraph(c)) { token.str += c; } else if (c == '\r' || c == '\n') /* EOL */{ /* WTF ? consider it as correct ? */ back(); popPos(); return token; } else if (c == 0) /* EOF */ { popPos(); return token; } else /* Bad character ?? */ { /* WTF ? Keep, Ignore ? */ } /* TODO What about other escaped character ? */ break; } case LEXPARSING_STATE_STRING: { if (c == ' ' || c == '\t' || c == '"' || c == '#' || c == '[' || c == ']' || (c == ':' && !hasOptions(OPTION_IGNORE_COLON)) || c == '=' ) { if (escaped) { escaped = false; token.str += c; } else { back(); popPos(); return token; } } else if (c == '\\') { if (escaped) { escaped = false; token.str += c; } else { escaped = true; } } else if (c == '\r' || c == '\n') /* EOL */{ back(); popPos(); return token; } else if (c == 0) /* EOF */ { popPos(); return token; }else if (isgraph(c)) { token.str += c; } else /* Bad character ?? */ { /* WTF ? Keep, Ignore ? */ } /* TODO What about escaped character ? */ break; } case LEXPARSING_STATE_COMMENT: { if (c == '\r' || c == '\n') { return token; } else { token.str += c; } break; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif default: /* Must not occur. */ break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } } popPos(); return token; } std::list NutParser::parseLine() { std::list res; while (true) { NutParser::Token token = parseToken(); switch (token.type) { case Token::TOKEN_STRING: case Token::TOKEN_QUOTED_STRING: case Token::TOKEN_BRACKET_OPEN: case Token::TOKEN_BRACKET_CLOSE: case Token::TOKEN_EQUAL: case Token::TOKEN_COLON: res.push_back(token); break; case Token::TOKEN_COMMENT: res.push_back(token); // Should return (EOL)Token::TOKEN_COMMENT: return res; case Token::TOKEN_UNKNOWN: case Token::TOKEN_NONE: case Token::TOKEN_EOL: return res; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif default: /* Must not occur. */ break; #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } } } // // NutConfigParser // NutConfigParser::NutConfigParser(const char* buffer, unsigned int options) : NutParser(buffer, options) { } NutConfigParser::NutConfigParser(const std::string& buffer, unsigned int options) : NutParser(buffer, options) { } void NutConfigParser::parseConfig(BaseConfiguration* config) { NUT_UNUSED_VARIABLE(config); parseConfig(); } void NutConfigParser::parseConfig() { onParseBegin(); enum ConfigParserState { CPS_DEFAULT, CPS_SECTION_OPENED, CPS_SECTION_HAVE_NAME, CPS_SECTION_CLOSED, CPS_DIRECTIVE_HAVE_NAME, CPS_DIRECTIVE_VALUES } state = CPS_DEFAULT; Token tok; std::string name; std::list values; char sep = 0; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif while (1) { tok = parseToken(); if (!tok) break; switch (state) { case CPS_DEFAULT: switch (tok.type) { case Token::TOKEN_COMMENT: onParseComment(tok.str); /* Clean and return to default */ break; case Token::TOKEN_BRACKET_OPEN: state = CPS_SECTION_OPENED; break; case Token::TOKEN_STRING: case Token::TOKEN_QUOTED_STRING: name = tok.str; state = CPS_DIRECTIVE_HAVE_NAME; break; case Token::TOKEN_UNKNOWN: case Token::TOKEN_NONE: case Token::TOKEN_BRACKET_CLOSE: case Token::TOKEN_EQUAL: case Token::TOKEN_COLON: case Token::TOKEN_EOL: default: /* WTF ? */ break; } break; case CPS_SECTION_OPENED: switch (tok.type) { case Token::TOKEN_STRING: case Token::TOKEN_QUOTED_STRING: /* Should occur ! */ name = tok.str; state = CPS_SECTION_HAVE_NAME; break; case Token::TOKEN_BRACKET_CLOSE: /* Empty section name */ state = CPS_SECTION_CLOSED; break; case Token::TOKEN_COMMENT: /* Lack of closing bracket !!! */ onParseSectionName(name, tok.str); /* Clean and return to default */ name.clear(); state = CPS_DEFAULT; break; case Token::TOKEN_EOL: /* Lack of closing bracket !!! */ onParseSectionName(name); /* Clean and return to default */ name.clear(); state = CPS_DEFAULT; break; case Token::TOKEN_UNKNOWN: case Token::TOKEN_NONE: case Token::TOKEN_BRACKET_OPEN: case Token::TOKEN_EQUAL: case Token::TOKEN_COLON: default: /* WTF ? */ break; } break; case CPS_SECTION_HAVE_NAME: switch (tok.type) { case Token::TOKEN_BRACKET_CLOSE: /* Must occur ! */ state = CPS_SECTION_CLOSED; break; case Token::TOKEN_COMMENT: /* Lack of closing bracket !!! */ onParseSectionName(name, tok.str); /* Clean and return to default */ name.clear(); state = CPS_DEFAULT; break; case Token::TOKEN_EOL: /* Lack of closing bracket !!! */ onParseSectionName(name); /* Clean and return to default */ name.clear(); state = CPS_DEFAULT; break; case Token::TOKEN_QUOTED_STRING: case Token::TOKEN_BRACKET_OPEN: case Token::TOKEN_COLON: case Token::TOKEN_EQUAL: case Token::TOKEN_UNKNOWN: case Token::TOKEN_NONE: case Token::TOKEN_STRING: default: /* WTF ? */ break; } break; case CPS_SECTION_CLOSED: switch (tok.type) { case Token::TOKEN_COMMENT: /* Could occur ! */ onParseSectionName(name, tok.str); /* Clean and return to default */ name.clear(); state = CPS_DEFAULT; break; case Token::TOKEN_EOL: /* Could occur ! */ onParseSectionName(name); /* Clean and return to default */ name.clear(); state = CPS_DEFAULT; break; case Token::TOKEN_QUOTED_STRING: case Token::TOKEN_BRACKET_OPEN: case Token::TOKEN_BRACKET_CLOSE: case Token::TOKEN_UNKNOWN: case Token::TOKEN_NONE: case Token::TOKEN_STRING: case Token::TOKEN_COLON: case Token::TOKEN_EQUAL: default: /* WTF ? */ break; } break; case CPS_DIRECTIVE_HAVE_NAME: switch (tok.type) { case Token::TOKEN_COMMENT: /* Could occur ! */ onParseDirective(name, 0, std::list (), tok.str); /* Clean and return to default */ name.clear(); state = CPS_DEFAULT; break; case Token::TOKEN_EOL: /* Could occur ! */ onParseDirective(name); /* Clean and return to default */ name.clear(); state = CPS_DEFAULT; break; case Token::TOKEN_COLON: case Token::TOKEN_EQUAL: /* Could occur ! */ sep = tok.str[0]; state = CPS_DIRECTIVE_VALUES; break; case Token::TOKEN_STRING: case Token::TOKEN_QUOTED_STRING: /* Could occur ! */ values.push_back(tok.str); state = CPS_DIRECTIVE_VALUES; break; case Token::TOKEN_UNKNOWN: case Token::TOKEN_NONE: case Token::TOKEN_BRACKET_OPEN: case Token::TOKEN_BRACKET_CLOSE: default: /* WTF ? */ break; } break; case CPS_DIRECTIVE_VALUES: switch (tok.type) { case Token::TOKEN_COMMENT: /* Could occur ! */ onParseDirective(name, sep, values, tok.str); /* Clean and return to default */ name.clear(); values.clear(); sep = 0; state = CPS_DEFAULT; break; case Token::TOKEN_EOL: /* Could occur ! */ onParseDirective(name, sep, values); /* Clean and return to default */ name.clear(); values.clear(); sep = 0; state = CPS_DEFAULT; break; case Token::TOKEN_STRING: case Token::TOKEN_QUOTED_STRING: /* Could occur ! */ values.push_back(tok.str); state = CPS_DIRECTIVE_VALUES; break; case Token::TOKEN_UNKNOWN: case Token::TOKEN_NONE: case Token::TOKEN_BRACKET_OPEN: case Token::TOKEN_BRACKET_CLOSE: case Token::TOKEN_EQUAL: case Token::TOKEN_COLON: default: /* WTF ? */ break; } break; default: break; } } switch(state) { case CPS_SECTION_OPENED: case CPS_SECTION_HAVE_NAME: /* Lack of closing bracket !!! */ onParseSectionName(name); break; case CPS_SECTION_CLOSED: /* Could occur ! */ onParseSectionName(name); break; case CPS_DIRECTIVE_HAVE_NAME: /* Could occur ! */ onParseDirective(name); break; case CPS_DIRECTIVE_VALUES: /* Could occur ! */ onParseDirective(name, sep, values); break; case CPS_DEFAULT: /* TOTHINK: no-op? */ break; default: break; } #ifdef __clang__ #pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif onParseEnd(); } // // DefaultConfigParser // DefaultConfigParser::DefaultConfigParser(const char* buffer) : NutConfigParser(buffer) { } DefaultConfigParser::DefaultConfigParser(const std::string& buffer) : NutConfigParser(buffer) { } void DefaultConfigParser::onParseBegin() { // Start with empty section (i.e. global one) _section.clear(); } void DefaultConfigParser::onParseComment( const std::string& /*comment*/) { // Comments are ignored for now } void DefaultConfigParser::onParseSectionName( const std::string& sectionName, const std::string& /*comment*/) { // Comments are ignored for now // Process current section. if (!_section.empty()) { onParseSection(_section); _section.clear(); } // Start a new section _section.name = sectionName; } void DefaultConfigParser::onParseDirective( const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { // Comments are ignored for now // Separator has no specific semantic in this context // Save values _section.entries[directiveName].name = directiveName; _section.entries[directiveName].values = values; // TODO Can probably be optimized. } void DefaultConfigParser::onParseEnd() { // Process current (last) section if (!_section.empty()) { onParseSection(_section); _section.clear(); } } // // GenericConfigSection // bool GenericConfigSection::empty()const { return name.empty() && entries.empty(); } void GenericConfigSection::clear() { name.clear(); entries.clear(); } // // GenericConfigParser // GenericConfigParser::GenericConfigParser(const char* buffer): DefaultConfigParser(buffer), _config(nullptr) { } GenericConfigParser::GenericConfigParser(const std::string& buffer): DefaultConfigParser(buffer), _config(nullptr) { } void GenericConfigParser::parseConfig(BaseConfiguration* config) { if(config!=nullptr) { _config = config; NutConfigParser::parseConfig(); _config = nullptr; } } void GenericConfigParser::onParseSection(const GenericConfigSection& section) { if(_config!=nullptr) { _config->setGenericConfigSection(section); } } // // GenericConfiguration // void GenericConfiguration::setGenericConfigSection(const GenericConfigSection& section) { sections[section.name] = section; } void GenericConfiguration::parseFromString(const std::string& str) { GenericConfigParser parser(str); parser.parseConfig(this); } bool GenericConfiguration::parseFrom(NutStream & istream) { // TODO: The parser is highly inefficient, it should use NutStream, directly std::string str; if (NutStream::NUTS_OK != istream.getString(str)) return false; parseFromString(str); return true; } bool GenericConfiguration::writeTo(NutStream & ostream) const { GenericConfigWriter writer(ostream); return NutWriter::NUTW_OK == writer.writeConfig(*this); } bool GenericConfiguration::get(const std::string & section, const std::string & entry, ConfigParamList & params, bool caseSensitive) const { // Get section SectionMap::const_iterator section_iter = sections.find(section); if (section_iter == sections.end()) return false; // Get entry const GenericConfigSection::EntryMap & entries = section_iter->second.entries; GenericConfigSection::EntryMap::const_iterator entry_iter = entries.find(entry); if (entry_iter == entries.end()) { if (caseSensitive) return false; // Another pass, maybe slower and inefficient, for case-insensitive matching // We are already at one end of the entries, so scroll back to beginning GenericConfigSection::EntryMap::const_iterator entry_begin = entries.begin(); for (; entry_iter != entry_begin; entry_iter--) { if (!(::strcasecmp(entry_iter->first.c_str(), entry.c_str()))) goto found; } return false; } found: // Provide parameters values params = entry_iter->second.values; return true; } void GenericConfiguration::set(const std::string & section, const std::string & entry, const ConfigParamList & params) { // Get section SectionMap::iterator section_iter = sections.lower_bound(section); if (sections.end() == section_iter || section_iter->first != section) { section_iter = sections.insert(section_iter, std::pair(section, GenericConfigSection())); section_iter->second.name = section; } // Get entry GenericConfigSection::EntryMap & entries = section_iter->second.entries; GenericConfigSection::EntryMap::iterator entry_iter = entries.lower_bound(entry); if (entries.end() == entry_iter || entry_iter->first != entry) { entry_iter = entries.insert(entry_iter, std::pair(entry, GenericConfigSectionEntry())); entry_iter->second.name = entry; } // Set parameters values entry_iter->second.values = params; } void GenericConfiguration::add(const std::string & section, const std::string & entry, const ConfigParamList & params) { // No job is another job well done if (params.empty()) return; // Note that the implementation is quite naive and inefficient. // However, efficiency isn't our aim at the moment. // Get current parameters ConfigParamList current_params; get(section, entry, current_params); // Add the provided parameters current_params.insert(current_params.end(), params.begin(), params.end()); set(section, entry, current_params); } void GenericConfiguration::remove(const std::string & section, const std::string & entry) { // Get section SectionMap::iterator section_iter = sections.find(section); if (sections.end() == section_iter) return; // Get entry GenericConfigSection::EntryMap & entries = section_iter->second.entries; GenericConfigSection::EntryMap::iterator entry_iter = entries.find(entry); if (entries.end() == entry_iter) return; entries.erase(entry_iter); } void GenericConfiguration::removeSection(const std::string & section) { // Get section SectionMap::iterator section_iter = sections.find(section); if (sections.end() == section_iter) return; sections.erase(section_iter); } std::string GenericConfiguration::getStr(const std::string & section, const std::string & entry, bool caseSensitive) const { std::string str; ConfigParamList params; if (!get(section, entry, params, caseSensitive)) return str; if (params.empty()) return str; return params.front(); } void GenericConfiguration::setStr( const std::string & section, const std::string & entry, const std::string & value) { ConfigParamList param; param.push_back(value); set(section, entry, param); } bool GenericConfiguration::getBool( const std::string & section, const std::string & entry, bool val) const { std::string s = getStr(section, entry); if (s.empty()) return val; return str2bool(s); } bool GenericConfiguration::getFlag( const std::string & section, const std::string & entry) const { ConfigParamList params; if (!get(section, entry, params)) return false; // Flag - if exists then "true" return true; } void GenericConfiguration::setFlag( const std::string & section, const std::string & entry, bool val) { ConfigParamList param; if (val) { param.push_back("true"); set(section, entry, param); } else { remove(section, entry); } } long long int GenericConfiguration::getInt( const std::string & section, const std::string & entry, long long int val) const { ConfigParamList params; if (!get(section, entry, params)) return val; if (params.empty()) return val; // TBD: What if there are multiple values? std::stringstream val_str(params.front()); val_str >> val; return val; } void GenericConfiguration::setInt( const std::string & section, const std::string & entry, long long int val) { std::stringstream val_str; val_str << val; set(section, entry, ConfigParamList(1, val_str.str())); } long long int GenericConfiguration::getIntHex( const std::string & section, const std::string & entry, long long int val) const { ConfigParamList params; if (!get(section, entry, params)) return val; if (params.empty()) return val; // TBD: What if there are multiple values? std::string s = params.front(); size_t foundPos = s.rfind("0x", 0); if (foundPos == std::string::npos || foundPos != 0) { // Add the prefix for hex conversion s = "0x" + s; } std::stringstream val_str; val_str << std::hex << s; // Output into int type val_str >> std::hex >> val; return val; } void GenericConfiguration::setIntHex( const std::string & section, const std::string & entry, long long int val) { std::stringstream val_str; // Note NUT v2.8.1 introduced these as "hexnum" values, // but the strtoul() underneath knows to strip "0x" for // base16 conversions - so can we write them either way: // https://stackoverflow.com/a/61060765/4715872 // << std::showbase for "0x" in saved printouts val_str << std::nouppercase << std::hex << val; set(section, entry, ConfigParamList(1, val_str.str())); } double GenericConfiguration::getDouble( const std::string & section, const std::string & entry, double val) const { ConfigParamList params; if (!get(section, entry, params)) return val; if (params.empty()) return val; // TBD: What if there are multiple values? std::stringstream val_str(params.front()); val_str >> val; return val; } void GenericConfiguration::setDouble( const std::string & section, const std::string & entry, double val) { std::stringstream val_str; val_str << val; set(section, entry, ConfigParamList(1, val_str.str())); } nut::BoolInt GenericConfiguration::getBoolInt( const std::string & section, const std::string & entry, nut::BoolInt val) const { ConfigParamList params; if (!get(section, entry, params)) return val; if (params.empty()) return val; // TBD: What if there are multiple values? nut::BoolInt bi(params.front()); return bi; } bool GenericConfiguration::str2bool(const std::string & str) { if ("true" == str) return true; if ("on" == str) return true; if ("1" == str) return true; if ("yes" == str) return true; if ("ok" == str) return true; return false; } const std::string & GenericConfiguration::bool2str(bool val) { static const std::string b0("off"); static const std::string b1("on"); return val ? b1 : b0; } // // UpsmonConfiguration // UpsmonConfiguration::UpsmonConfiguration() { } void UpsmonConfiguration::parseFromString(const std::string& str) { UpsmonConfigParser parser(str); parser.parseUpsmonConfig(this); } UpsmonConfiguration::NotifyFlag UpsmonConfiguration::NotifyFlagFromString(const std::string& str) { if(str=="SYSLOG") return NOTIFY_SYSLOG; else if(str=="WALL") return NOTIFY_WALL; else if(str=="EXEC") return NOTIFY_EXEC; else if(str=="IGNORE") return NOTIFY_IGNORE; else return NOTIFY_IGNORE; } UpsmonConfiguration::NotifyType UpsmonConfiguration::NotifyTypeFromString(const std::string& str) { if(str=="ONLINE") return NOTIFY_ONLINE; else if(str=="ONBATT") return NOTIFY_ONBATT; else if(str=="LOWBATT") return NOTIFY_LOWBATT; else if(str=="FSD") return NOTIFY_FSD; else if(str=="COMMOK") return NOTIFY_COMMOK; else if(str=="COMMBAD") return NOTIFY_COMMBAD; else if(str=="SHUTDOWN") return NOTIFY_SHUTDOWN; else if(str=="REPLBATT") return NOTIFY_REPLBATT; else if(str=="NOCOMM") return NOTIFY_NOCOMM; else if(str=="NOPARENT") return NOTIFY_NOPARENT; else if(str=="CAL") return NOTIFY_CAL; else if(str=="NOTCAL") return NOTIFY_NOTCAL; else if(str=="OFF") return NOTIFY_OFF; else if(str=="NOTOFF") return NOTIFY_NOTOFF; else if(str=="BYPASS") return NOTIFY_BYPASS; else if(str=="NOTBYPASS") return NOTIFY_NOTBYPASS; else if(str=="ECO") /* inverter mode, not ups state, for notifications */ return NOTIFY_ECO; else if(str=="NOTECO") /* inverter mode, not ups state, for notifications */ return NOTIFY_NOTECO; else if(str=="ALARM") return NOTIFY_ALARM; else if(str=="NOTALARM") return NOTIFY_NOTALARM; else if(str=="OVER") return NOTIFY_OVER; else if(str=="NOTOVER") return NOTIFY_NOTOVER; else if(str=="TRIM") return NOTIFY_TRIM; else if(str=="NOTTRIM") return NOTIFY_NOTTRIM; else if(str=="BOOST") return NOTIFY_BOOST; else if(str=="NOTBOOST") return NOTIFY_NOTBOOST; else if(str=="OTHER") return NOTIFY_OTHER; else if(str=="NOTOTHER") return NOTIFY_NOTOTHER; else if(str=="SUSPEND_STARTING") return NOTIFY_SUSPEND_STARTING; else if(str=="SUSPEND_FINISHED") return NOTIFY_SUSPEND_FINISHED; else return NOTIFY_TYPE_MAX; } bool UpsmonConfiguration::parseFrom(NutStream & istream) { // TODO: The parser is highly inefficient, it should use NutStream, directly std::string str; if (NutStream::NUTS_OK != istream.getString(str)) return false; parseFromString(str); return true; } bool UpsmonConfiguration::writeTo(NutStream & ostream) const { UpsmonConfigWriter writer(ostream); return NutWriter::NUTW_OK == writer.writeConfig(*this); } // // UpsmonConfigParser // UpsmonConfigParser::UpsmonConfigParser(const char* buffer): NutConfigParser(buffer) { } UpsmonConfigParser::UpsmonConfigParser(const std::string& buffer): NutConfigParser(buffer) { } void UpsmonConfigParser::parseUpsmonConfig(UpsmonConfiguration* config) { if(config!=nullptr) { _config = config; NutConfigParser::parseConfig(); _config = nullptr; } } void UpsmonConfigParser::onParseBegin() { // Do nothing } void UpsmonConfigParser::onParseComment(const std::string& /*comment*/) { // Comments are ignored for now } void UpsmonConfigParser::onParseSectionName(const std::string& /*sectionName*/, const std::string& /*comment*/) { // There must not be sections in upsmon.conf. // Ignore it // TODO Add error reporting ? } void UpsmonConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { // NOTE: separators are always ignored if(_config) { if(!(::strcasecmp(directiveName.c_str(), "DEBUG_MIN"))) { // NOTE: We allow DEBUG_MIN in any casing as it can be copy-pasted // between different configs and they use different historic casing if(values.size()>0) { _config->debugMin = StringToSettableNumber(values.front()); } } else if(directiveName == "RUN_AS_USER") { if(values.size()>0) { _config->runAsUser = values.front(); } } else if(directiveName == "MONITOR") { if (values.size() == 5 || values.size() == 6) { UpsmonConfiguration::Monitor monitor; ConfigParamList::const_iterator it = values.begin(); std::stringstream upsAtHost(*it++); std::string wordToken; /* * Why didn't the original author just receive the words * into their target strings?.. e.g.: * std::getline(upsAtHost, monitor.upsname, '@'); * std::getline(upsAtHost, monitor.hostname); */ monitor.upsname = (static_cast(std::getline(upsAtHost, wordToken, '@')), wordToken); monitor.hostname = (static_cast(std::getline(upsAtHost, wordToken)), wordToken); monitor.port = (values.size() == 6 ? *StringToSettableNumber(*it++) : 0u); monitor.powerValue = StringToSettableNumber(*it++); monitor.username = *it++; monitor.password = *it++; monitor.isPrimary = (*it) == "primary"; // master for NUT v2.7.4 and older _config->monitors.push_back(monitor); } } else if(directiveName == "MINSUPPLIES") { if(values.size()>0) { _config->minSupplies = StringToSettableNumber(values.front()); } } else if(directiveName == "SHUTDOWNCMD") { if(values.size()>0) { _config->shutdownCmd = values.front(); } } else if(directiveName == "NOTIFYCMD") { if(values.size()>0) { _config->notifyCmd = values.front(); } } else if(directiveName == "POLLFREQ") { if(values.size()>0) { _config->pollFreq = StringToSettableNumber(values.front()); } } else if(directiveName == "POLLFREQALERT") { if(values.size()>0) { _config->pollFreqAlert = StringToSettableNumber(values.front()); } } else if(directiveName == "POLLFAIL_LOG_THROTTLE_MAX") { if(values.size()>0) { _config->pollFailLogThrottleMax = StringToSettableNumber(values.front()); } } else if(directiveName == "OFFDURATION") { if(values.size()>0) { _config->offDuration = StringToSettableNumber(values.front()); } } else if(directiveName == "OBLBDURATION") { if(values.size()>0) { _config->oblbDuration = StringToSettableNumber(values.front()); } } else if(directiveName == "OVERDURATION") { if(values.size()>0) { _config->overDuration = StringToSettableNumber(values.front()); } } else if(directiveName == "SHUTDOWNEXIT") { if(values.size()>0) { nut::BoolInt bi; bi << values.front(); _config->shutdownExit = bi; } } else if(directiveName == "CERTPATH") { if(values.size()>0) { _config->certPath = values.front(); } } else if(directiveName == "CERTIDENT") { if(values.size()==2) { _config->certIdent.certName = values.front(); _config->certIdent.certDbPass = (*(++values.begin())); } } else if(directiveName == "CERTHOST") { if(values.size()==4) { nut::CertHost certHost; ConfigParamList::const_iterator it = values.begin(); certHost.host = *it++; certHost.certName = *it++; certHost.certVerify = *it++; certHost.forceSsl = *it++; _config->certHosts.push_back(certHost); } } else if(directiveName == "CERTVERIFY") { if(values.size()>0) { nut::BoolInt bi; bi << values.front(); _config->certVerify = bi; } } else if(directiveName == "FORCESSL") { if(values.size()>0) { nut::BoolInt bi; bi << values.front(); _config->forceSsl = bi; } } else if(directiveName == "ALARMCRITICAL") { if(values.size()>0) { nut::BoolInt bi; bi << values.front(); _config->alarmCritical = bi; } } else if(directiveName == "HOSTSYNC") { if(values.size()>0) { _config->hostSync = StringToSettableNumber(values.front()); } } else if(directiveName == "DEADTIME") { if(values.size()>0) { _config->deadTime = StringToSettableNumber(values.front()); } } else if(directiveName == "POWERDOWNFLAG") { if(values.size()>0) { _config->powerDownFlag = values.front(); } } else if(directiveName == "NOTIFYMSG") { if(values.size()==2) { UpsmonConfiguration::NotifyType type = UpsmonConfiguration::NotifyTypeFromString(values.front()); if(type!=UpsmonConfiguration::NOTIFY_TYPE_MAX) { _config->notifyMessages[static_cast(type)] = *(++values.begin()); } } } else if(directiveName == "NOTIFYFLAG") { if(values.size()==2) { UpsmonConfiguration::NotifyType type = UpsmonConfiguration::NotifyTypeFromString(values.front()); if(type!=UpsmonConfiguration::NOTIFY_TYPE_MAX) { unsigned int flags = 0; std::string word; std::stringstream stream(*(++values.begin())); while( std::getline(stream, word, '+') ) { flags |= UpsmonConfiguration::NotifyFlagFromString(word); } _config->notifyFlags[static_cast(type)] = flags; } } } else if(directiveName == "RBWARNTIME") { if(values.size()>0) { _config->rbWarnTime = StringToSettableNumber(values.front()); } } else if(directiveName == "NOCOMMWARNTIME") { if(values.size()>0) { _config->noCommWarnTime = StringToSettableNumber(values.front()); } } else if(directiveName == "FINALDELAY") { if(values.size()>0) { _config->finalDelay = StringToSettableNumber(values.front()); } } else { // TODO WTF with unknown commands ? } } } void UpsmonConfigParser::onParseEnd() { // Do nothing } // // NutConfiguration // NutConfiguration::NutConfiguration(): mode(MODE_UNKNOWN) { } void NutConfiguration::parseFromString(const std::string& str) { NutConfConfigParser parser(str); parser.parseNutConfConfig(this); } NutConfiguration::NutMode NutConfiguration::NutModeFromString(const std::string& str) { if(str == "none") return MODE_NONE; else if(str == "standalone") return MODE_STANDALONE; else if(str == "netserver") return MODE_NETSERVER; else if(str == "netclient") return MODE_NETCLIENT; else if(str == "controlled") return MODE_CONTROLLED; else if(str == "manual") return MODE_MANUAL; else return MODE_UNKNOWN; } bool NutConfiguration::parseFrom(NutStream & istream) { // TODO: The parser is highly inefficient, it should use NutStream, directly std::string str; if (NutStream::NUTS_OK != istream.getString(str)) return false; parseFromString(str); return true; } bool NutConfiguration::writeTo(NutStream & ostream) const { NutConfConfigWriter writer(ostream); return NutWriter::NUTW_OK == writer.writeConfig(*this); } // // NutConfConfigParser // NutConfConfigParser::NutConfConfigParser(const char* buffer): NutConfigParser(buffer) { } NutConfConfigParser::NutConfConfigParser(const std::string& buffer): NutConfigParser(buffer) { } void NutConfConfigParser::parseNutConfConfig(NutConfiguration* config) { if(config!=nullptr) { _config = config; NutConfigParser::parseConfig(); _config = nullptr; } } void NutConfConfigParser::onParseBegin() { // Do nothing } void NutConfConfigParser::onParseComment(const std::string& /*comment*/) { // Comments are ignored for now } void NutConfConfigParser::onParseSectionName(const std::string& /*sectionName*/, const std::string& /*comment*/) { // There must not be sections in nutconf.conf. // Ignore it // TODO Add error reporting ? } void NutConfConfigParser::onParseDirective(const std::string& directiveName, char /*sep*/, const ConfigParamList& values, const std::string& /*comment*/) { // Comments are ignored for now // NOTE: although sep must be '=', sep is not verified. if(_config) { if(directiveName == "MODE") { if (values.size()==1) { std::string val = values.front(); NutConfiguration::NutMode mode = NutConfiguration::NutModeFromString(val); if(mode != NutConfiguration::MODE_UNKNOWN) _config->mode = mode; } } else if(directiveName == "ALLOW_NO_DEVICE") { if(values.size()>0) { _config->allowNoDevice = StringToSettableNumber(values.front()); } } else if(directiveName == "ALLOW_NOT_ALL_LISTENERS") { if(values.size()>0) { _config->allowNotAllListeners = StringToSettableNumber(values.front()); } } else if(directiveName == "UPSD_OPTIONS") { if(values.size()>0) { _config->upsdOptions = values.front(); } } else if(directiveName == "UPSMON_OPTIONS") { if(values.size()>0) { _config->upsmonOptions = values.front(); } } else if(directiveName == "POWEROFF_WAIT") { if(values.size()>0) { _config->poweroffWait = StringToSettableNumber(values.front()); } } else if(directiveName == "POWEROFF_QUIET") { if(values.size()>0) { _config->poweroffQuiet = StringToSettableNumber(values.front()); } } else if(directiveName == "NUT_DEBUG_LEVEL") { if(values.size()>0) { _config->debugLevel = StringToSettableNumber(values.front()); } } else { // TODO WTF with errors ? } } } void NutConfConfigParser::onParseEnd() { // Do nothing } // // UpsdConfiguration // UpsdConfiguration::UpsdConfiguration() { } void UpsdConfiguration::parseFromString(const std::string& str) { UpsdConfigParser parser(str); parser.parseUpsdConfig(this); } bool UpsdConfiguration::parseFrom(NutStream & istream) { // TODO: The parser is highly inefficient, it should use NutStream, directly std::string str; if (NutStream::NUTS_OK != istream.getString(str)) return false; parseFromString(str); return true; } bool UpsdConfiguration::writeTo(NutStream & ostream) const { UpsdConfigWriter writer(ostream); return NutWriter::NUTW_OK == writer.writeConfig(*this); } // // UpsdConfigParser // UpsdConfigParser::UpsdConfigParser(const char* buffer): NutConfigParser(buffer, NutParser::OPTION_IGNORE_COLON) { } UpsdConfigParser::UpsdConfigParser(const std::string& buffer): NutConfigParser(buffer, NutParser::OPTION_IGNORE_COLON) { } void UpsdConfigParser::parseUpsdConfig(UpsdConfiguration* config) { if(config!=nullptr) { _config = config; NutConfigParser::parseConfig(); _config = nullptr; } } void UpsdConfigParser::onParseBegin() { // Do nothing } void UpsdConfigParser::onParseComment(const std::string& comment) { // Comments are ignored for now NUT_UNUSED_VARIABLE(comment); } void UpsdConfigParser::onParseSectionName(const std::string& sectionName, const std::string& comment) { // There must not be sections in upsd.conf. // Ignore it // TODO Add error reporting ? NUT_UNUSED_VARIABLE(sectionName); NUT_UNUSED_VARIABLE(comment); } void UpsdConfigParser::onParseDirective(const std::string& directiveName, char sep, const ConfigParamList& values, const std::string& comment) { // NOTE: separators are always ignored NUT_UNUSED_VARIABLE(sep); NUT_UNUSED_VARIABLE(comment); if(_config) { if(!(::strcasecmp(directiveName.c_str(), "DEBUG_MIN"))) { // NOTE: We allow DEBUG_MIN in any casing as it can be copy-pasted // between different configs and they use different historic casing if(values.size()>0) { _config->debugMin = StringToSettableNumber(values.front()); } } else if(directiveName == "MAXAGE") { if(values.size()>0) { _config->maxAge = StringToSettableNumber(values.front()); } } else if(directiveName == "STATEPATH") { if(values.size()>0) { _config->statePath = values.front(); } } else if(directiveName == "MAXCONN") { if(values.size()>0) { _config->maxConn = StringToSettableNumber(values.front()); } } else if(directiveName == "TRACKINGDELAY") { if(values.size()>0) { _config->trackingDelay = StringToSettableNumber(values.front()); } } else if(directiveName == "ALLOW_NO_DEVICE") { if(values.size()>0) { _config->allowNoDevice = StringToSettableNumber(values.front()); } } else if(directiveName == "ALLOW_NOT_ALL_LISTENERS") { if(values.size()>0) { _config->allowNotAllListeners = StringToSettableNumber(values.front()); } } else if(directiveName == "DISABLE_WEAK_SSL") { if(values.size()>0) { _config->allowNotAllListeners = StringToSettableNumber(values.front()); } } else if(directiveName == "CERTFILE") { if(values.size()>0) { _config->certFile = values.front(); } } else if(directiveName == "CERTPATH") { if(values.size()>0) { _config->certPath = values.front(); } } else if(directiveName == "CERTIDENT") { if(values.size()==2) { _config->certIdent.certName = values.front(); _config->certIdent.certDbPass = (*(++values.begin())); } } else if(directiveName == "CERTREQUEST") { if(values.size()>0) { _config->certRequestLevel = StringToSettableNumber(values.front()); } } else if(directiveName == "LISTEN") { if(values.size()==1 || values.size()==2) { UpsdConfiguration::Listen listen; listen.address = values.front(); if(values.size()==2) { listen.port = StringToSettableNumber(*(++values.begin())); } _config->listens.push_back(listen); } } else { // TODO WTF with unknown commands ? } } } void UpsdConfigParser::onParseEnd() { // Do nothing } // // UpsdUsersConfiguration // UpsdUsersConfiguration::upsmon_mode_t UpsdUsersConfiguration::getUpsmonMode() const { std::string mode_str = getStr("upsmon", "upsmon"); if ("primary" == mode_str || "master" == mode_str) return UPSMON_PRIMARY; if ("secondary" == mode_str || "slave" == mode_str) return UPSMON_SECONDARY; return UPSMON_UNDEF; } void UpsdUsersConfiguration::setUpsmonMode(upsmon_mode_t mode) { assert(UPSMON_UNDEF != mode); setStr("upsmon", "upsmon", (UPSMON_PRIMARY == mode ? "primary" : "secondary")); /* NUT v2.7.4 and older: setStr("upsmon", "upsmon", (UPSMON_PRIMARY == mode ? "master" : "slave")); */ } bool UpsdUsersConfiguration::parseFrom(NutStream & istream) { // TODO: The parser is highly inefficient, it should use NutStream, directly std::string str; if (NutStream::NUTS_OK != istream.getString(str)) return false; parseFromString(str); return true; } bool UpsdUsersConfiguration::writeTo(NutStream & ostream) const { UpsdUsersConfigWriter writer(ostream); return NutWriter::NUTW_OK == writer.writeConfig(*this); } } /* namespace nut */ nut-2.8.3/common/parseconf.c0000644000200500020050000003462214777767434012714 00000000000000/* parseconf.c - state machine-driven dynamic configuration file parser Copyright (C) 2002 Russell Kroll This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* parseconf, version 4. * * This one abandons the "callback" system introduced last time. It * didn't turn out as well as I had hoped - you got stuck "behind" * parseconf too often. * * There is now a context buffer, and you call pconf_init to set it up. * All subsequent calls must have it as the first argument. There are * two entry points for parsing lines. You can have it read a file * (pconf_file_begin and pconf_file_next), take lines directly from * the caller (pconf_line), or go along a character at a time (pconf_char). * The parsing is identical no matter how you feed it. * * Since there are no more callbacks, you take the successful return * from the function and access ctx->arglist and ctx->numargs yourself. * You must check for errors with pconf_parse_error before using them, * since it might not be complete. This lets the caller handle all * error reporting that's nonfatal. * * Fatal errors are those that involve memory allocation. If the user * defines an error handler when calling pconf_init, that function will * be called with the error message before parseconf exits. By default * it will just write the message to stderr before exiting. * * Input vs. Output: * * What it reads --> What ends up in each argument * * this is a line --> "this" "is" "a" "line" * this "is also" a line --> "this" "is also" "a" "line" * embedded\ space --> "embedded space" * embedded\\backslash --> "embedded\backslash" * * Arguments are split by whitespace (isspace()) unless that whitespace * occurs inside a "quoted pair like this". * * You can also escape the double quote (") character. The backslash * also allows you to join lines, allowing you to have logical lines * that span physical lines, just like you can do in some shells. * * Lines normally end with a newline, but reaching EOF will also force * parsing on what's been scanned so far. * * Design: * * Characters are read one at a time to drive the state machine. * As words are completed (by hitting whitespace or ending a "" item), * they are committed to the next buffer in the arglist. realloc is * used, so the buffer can grow to handle bigger words. * * The arglist also grows as necessary with a similar approach. As a * result, you can parse extremely long words and lines with an insane * number of elements. * * Finally, there is argsize, which remembers how long each of the * arglist elements are. This is how we know when to expand them. * */ #include "config.h" /* should be first */ #include "common.h" #include #include #include #include #include #include #include #include #include "parseconf.h" #include "attribute.h" #include "nut_stdint.h" /* possible states */ #define STATE_FINDWORDSTART 1 #define STATE_FINDEOL 2 #define STATE_QUOTECOLLECT 3 #define STATE_QC_LITERAL 4 #define STATE_COLLECT 5 #define STATE_COLLECTLITERAL 6 #define STATE_ENDOFLINE 7 #define STATE_PARSEERR 8 static void pconf_fatal(PCONF_CTX_t *ctx, const char *errtxt) __attribute__((noreturn)); static void pconf_fatal(PCONF_CTX_t *ctx, const char *errtxt) { if (ctx->errhandler) ctx->errhandler(errtxt); else fprintf(stderr, "parseconf: fatal error: %s\n", errtxt); exit(EXIT_FAILURE); } static void add_arg_word(PCONF_CTX_t *ctx) { size_t argpos; size_t wbuflen; /* this is where the new value goes */ argpos = ctx->numargs; ctx->numargs++; /* when facing more args than ever before, expand the list */ if (ctx->numargs > ctx->maxargs) { ctx->maxargs = ctx->numargs; /* resize the lists */ ctx->arglist = realloc(ctx->arglist, sizeof(char *) * ctx->numargs); if (!ctx->arglist) pconf_fatal(ctx, "realloc arglist failed"); ctx->argsize = realloc(ctx->argsize, sizeof(size_t) * ctx->numargs); if (!ctx->argsize) pconf_fatal(ctx, "realloc argsize failed"); /* ensure sane starting values */ ctx->arglist[argpos] = NULL; ctx->argsize[argpos] = 0; } wbuflen = strlen(ctx->wordbuf); /* now see if the string itself grew compared to last time */ if (wbuflen >= ctx->argsize[argpos]) { size_t newlen; /* allow for the trailing NULL */ newlen = wbuflen + 1; /* expand the string storage */ ctx->arglist[argpos] = realloc(ctx->arglist[argpos], newlen); if (!ctx->arglist[argpos]) pconf_fatal(ctx, "realloc arglist member failed"); /* remember the new size */ ctx->argsize[argpos] = newlen; } /* strncpy doesn't give us a trailing NULL, so prep the space */ memset(ctx->arglist[argpos], '\0', ctx->argsize[argpos]); /* finally copy the new value into the provided space */ strncpy(ctx->arglist[argpos], ctx->wordbuf, wbuflen); } static void addchar(PCONF_CTX_t *ctx) { size_t wbuflen; wbuflen = strlen(ctx->wordbuf); /* CVE-2012-2944: only allow the subset of ASCII charset from Space to ~ */ if ((ctx->ch < 0x20) || (ctx->ch > 0x7f)) { fprintf(stderr, "addchar: discarding invalid character (0x%02x)!\n", (unsigned int)ctx->ch); return; } if (ctx->wordlen_limit != 0) { if (wbuflen >= ctx->wordlen_limit) { /* limit reached: don't append any more */ return; } } /* allow for the null */ if (wbuflen >= (ctx->wordbufsize - 1)) { ctx->wordbufsize += 8; ctx->wordbuf = realloc(ctx->wordbuf, ctx->wordbufsize); if (!ctx->wordbuf) pconf_fatal(ctx, "realloc wordbuf failed"); /* repoint as wordbuf may have moved */ ctx->wordptr = &ctx->wordbuf[wbuflen]; } *ctx->wordptr++ = (char)ctx->ch; *ctx->wordptr = '\0'; } static void endofword(PCONF_CTX_t *ctx) { if (ctx->arg_limit != 0) { if (ctx->numargs >= ctx->arg_limit) { /* don't accept this word - just drop it */ ctx->wordptr = ctx->wordbuf; *ctx->wordptr = '\0'; return; } } add_arg_word(ctx); ctx->wordptr = ctx->wordbuf; *ctx->wordptr = '\0'; } /* look for the beginning of a word */ static int findwordstart(PCONF_CTX_t *ctx) { /* newline = the physical line is over, so the logical one is too */ if (ctx->ch == 10) return STATE_ENDOFLINE; /* the rest of the line is a comment */ if (ctx->ch == '#') return STATE_FINDEOL; /* space = not in a word yet, so loop back */ if (isspace((size_t)ctx->ch)) return STATE_FINDWORDSTART; /* \ = literal = accept the next char blindly */ if (ctx->ch == '\\') return STATE_COLLECTLITERAL; /* " = begin word bounded by quotes */ if (ctx->ch == '"') return STATE_QUOTECOLLECT; /* at this point the word just started */ addchar(ctx); /* if the first character is a '=' this is considered a whole word */ if (ctx->ch == '=') { endofword(ctx); return STATE_FINDWORDSTART; } return STATE_COLLECT; } /* eat characters until the end of the line is found */ static int findeol(PCONF_CTX_t *ctx) { /* newline = found it, so start a new line */ if (ctx->ch == 10) return STATE_ENDOFLINE; /* come back here */ return STATE_FINDEOL; } /* set up the error reporting details */ static void pconf_seterr(PCONF_CTX_t *ctx, const char *errmsg) { snprintf(ctx->errmsg, PCONF_ERR_LEN, "%s", errmsg); ctx->error = 1; } /* quote characters inside a word bounded by "quotes" */ static int quotecollect(PCONF_CTX_t *ctx) { /* user is trying to break us */ if (ctx->ch == '#') { pconf_seterr(ctx, "Unbalanced word due to unescaped # in quotes"); endofword(ctx); /* this makes us drop all the way out of the caller */ return STATE_PARSEERR; } /* another " means we're done with this word */ if (ctx->ch == '"') { endofword(ctx); return STATE_FINDWORDSTART; } /* literal - special case since it needs to return here */ if (ctx->ch == '\\') return STATE_QC_LITERAL; /* otherwise save it and loop back */ addchar(ctx); return STATE_QUOTECOLLECT; } /* take almost anything literally, but return to quotecollect */ static int qc_literal(PCONF_CTX_t *ctx) { /* continue onto the next line of the file */ if (ctx->ch == 10) return STATE_QUOTECOLLECT; addchar(ctx); return STATE_QUOTECOLLECT; } /* collect characters inside a word */ static int collect(PCONF_CTX_t *ctx) { /* comment means the word is done, and skip to the end of the line */ if (ctx->ch == '#') { endofword(ctx); return STATE_FINDEOL; } /* newline means the word is done, and the line is done */ if (ctx->ch == 10) { endofword(ctx); return STATE_ENDOFLINE; } /* space means the word is done */ if (isspace((size_t)ctx->ch)) { endofword(ctx); return STATE_FINDWORDSTART; } /* '=' means the word is done and the = is a single char word*/ if (ctx->ch == '=') { endofword(ctx); findwordstart(ctx); return STATE_FINDWORDSTART; } /* \ = literal = accept the next char blindly */ if (ctx->ch == '\\') return STATE_COLLECTLITERAL; /* otherwise store it and come back for more */ addchar(ctx); return STATE_COLLECT; } /* take almost anything literally */ static int collectliteral(PCONF_CTX_t *ctx) { /* continue to the next line */ if (ctx->ch == 10) return STATE_COLLECT; addchar(ctx); return STATE_COLLECT; } /* clean up memory before going back to the user */ static void free_storage(PCONF_CTX_t *ctx) { unsigned int i; free(ctx->wordbuf); /* clear out the individual words first */ for (i = 0; i < ctx->maxargs; i++) free(ctx->arglist[i]); free(ctx->arglist); free(ctx->argsize); /* put things back to the initial state */ ctx->arglist = NULL; ctx->argsize = NULL; ctx->numargs = 0; ctx->maxargs = 0; } int pconf_init(PCONF_CTX_t *ctx, void errhandler(const char *)) { /* set up the ctx elements */ ctx->f = NULL; ctx->state = STATE_FINDWORDSTART; ctx->numargs = 0; ctx->maxargs = 0; ctx->arg_limit = PCONF_DEFAULT_ARG_LIMIT; ctx->wordlen_limit = PCONF_DEFAULT_WORDLEN_LIMIT; ctx->linenum = 0; ctx->error = 0; ctx->arglist = NULL; ctx->argsize = NULL; ctx->wordbufsize = 16; ctx->wordbuf = calloc(1, ctx->wordbufsize); if (!ctx->wordbuf) pconf_fatal(ctx, "malloc wordbuf failed"); ctx->wordptr = ctx->wordbuf; ctx->errhandler = errhandler; ctx->magic = PCONF_CTX_t_MAGIC; return 1; } static int check_magic(PCONF_CTX_t *ctx) { if (!ctx) return 0; if (ctx->magic != PCONF_CTX_t_MAGIC) { snprintf(ctx->errmsg, PCONF_ERR_LEN, "Invalid ctx buffer"); return 0; } return 1; } int pconf_file_begin(PCONF_CTX_t *ctx, const char *fn) { if (!check_magic(ctx)) return 0; ctx->f = fopen(fn, "r"); if (!ctx->f) { snprintf(ctx->errmsg, PCONF_ERR_LEN, "Can't open %s: %s", fn, strerror(errno)); return 0; } /* prevent fd leaking to child processes */ set_close_on_exec(fileno(ctx->f)); return 1; /* OK */ } static void parse_char(PCONF_CTX_t *ctx) { switch(ctx->state) { case STATE_FINDWORDSTART: ctx->state = findwordstart(ctx); break; case STATE_FINDEOL: ctx->state = findeol(ctx); break; case STATE_QUOTECOLLECT: ctx->state = quotecollect(ctx); break; case STATE_QC_LITERAL: ctx->state = qc_literal(ctx); break; case STATE_COLLECT: ctx->state = collect(ctx); break; case STATE_COLLECTLITERAL: ctx->state = collectliteral(ctx); break; default: break; } /* switch */ } /* return 1 if an error occurred, but only do it once */ int pconf_parse_error(PCONF_CTX_t *ctx) { if (!check_magic(ctx)) return 0; if (ctx->error == 1) { ctx->error = 0; return 1; } return 0; } /* clean up the ctx space */ void pconf_finish(PCONF_CTX_t *ctx) { if (!check_magic(ctx)) return; if (ctx->f) fclose(ctx->f); free_storage(ctx); ctx->magic = 0; } /* read from a file until a whole line is ready for use */ int pconf_file_next(PCONF_CTX_t *ctx) { if (!check_magic(ctx)) return 0; ctx->linenum++; /* start over for the new line */ ctx->numargs = 0; ctx->state = STATE_FINDWORDSTART; while ((ctx->ch = fgetc(ctx->f)) != EOF) { parse_char(ctx); if (ctx->state == STATE_PARSEERR) return 1; if (ctx->state == STATE_ENDOFLINE) return 1; } /* deal with files that don't end in a newline */ if (ctx->numargs != 0) { /* still building a word? */ if (ctx->wordptr != ctx->wordbuf) endofword(ctx); return 1; } /* finished with nothing left over */ return 0; } /* parse a provided line */ int pconf_line(PCONF_CTX_t *ctx, const char *line) { size_t i, linelen; if (!check_magic(ctx)) return 0; ctx->linenum++; /* start over for the new line */ ctx->numargs = 0; ctx->state = STATE_FINDWORDSTART; linelen = strlen(line); for (i = 0; i < linelen; i++) { ctx->ch = line[i]; parse_char(ctx); if (ctx->state == STATE_PARSEERR) return 1; if (ctx->state == STATE_ENDOFLINE) return 1; } /* deal with any lingering characters */ /* still building a word? */ if (ctx->wordptr != ctx->wordbuf) endofword(ctx); /* tie it off */ return 1; } #define PCONF_ESCAPE "#\\\"" char *pconf_encode(const char *src, char *dest, size_t destsize) { size_t i, srclen, destlen, maxlen; if (destsize < 1) return dest; memset(dest, '\0', destsize); /* always leave room for a final NULL */ maxlen = destsize - 1; srclen = strlen(src); destlen = 0; for (i = 0; i < srclen; i++) { if (strchr(PCONF_ESCAPE, src[i])) { /* if they both won't fit, we're done */ if (destlen >= maxlen - 1) return dest; dest[destlen++] = '\\'; } /* bail out when dest is full */ if (destlen >= maxlen) return dest; dest[destlen++] = src[i]; } return dest; } /* parse input a character at a time */ int pconf_char(PCONF_CTX_t *ctx, char ch) { if (!check_magic(ctx)) return -1; /* if the last call finished a line, clean stuff up for another */ if ((ctx->state == STATE_ENDOFLINE) || (ctx->state == STATE_PARSEERR)) { ctx->numargs = 0; ctx->state = STATE_FINDWORDSTART; } ctx->ch = ch; parse_char(ctx); if (ctx->state == STATE_ENDOFLINE) return 1; if (ctx->state == STATE_PARSEERR) return -1; return 0; } nut-2.8.3/LICENSE-DCO0000644000200500020050000000252614777534445010700 00000000000000Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. nut-2.8.3/VERSION_FORCED0000644000200500020050000000003315001555413011324 00000000000000NUT_VERSION_FORCED='2.8.3' nut-2.8.3/Makefile.in0000644000200500020050000032302515001555010011301 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # top-level Makefile for NUT VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = scripts/Aix/nut-aix.spec scripts/RedHat/ups \ scripts/avahi/nut.service \ scripts/external_apis/enphase/enphase-monitor@.service \ scripts/HP-UX/nut.psf scripts/valgrind/.valgrind.supp \ scripts/Windows/Installer/NUT-Installer.xml \ scripts/Aix/nut.init scripts/HP-UX/postinstall \ scripts/RedHat/upsd scripts/RedHat/upsmon \ scripts/external_apis/enphase/enphase-monitor \ scripts/python/app/NUT-Monitor-py2gtk2 \ scripts/python/app/NUT-Monitor-py3qt5 \ scripts/valgrind/valgrind.sh CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(datadir)" DATA = $(nodist_data_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/scripts/Aix/nut-aix.spec.in \ $(top_srcdir)/scripts/Aix/nut.init.in \ $(top_srcdir)/scripts/HP-UX/nut.psf.in \ $(top_srcdir)/scripts/HP-UX/postinstall.in \ $(top_srcdir)/scripts/RedHat/ups.in \ $(top_srcdir)/scripts/RedHat/upsd.in \ $(top_srcdir)/scripts/RedHat/upsmon.in \ $(top_srcdir)/scripts/Windows/Installer/NUT-Installer.xml.in \ $(top_srcdir)/scripts/avahi/nut.service.in \ $(top_srcdir)/scripts/external_apis/enphase/enphase-monitor.in \ $(top_srcdir)/scripts/external_apis/enphase/enphase-monitor@.service.in \ $(top_srcdir)/scripts/python/app/NUT-Monitor-py2gtk2.in \ $(top_srcdir)/scripts/python/app/NUT-Monitor-py3qt5.in \ $(top_srcdir)/scripts/valgrind/.valgrind.supp.in \ $(top_srcdir)/scripts/valgrind/valgrind.sh.in AUTHORS COPYING \ ChangeLog INSTALL NEWS README ar-lib compile config.guess \ config.sub install-sh ltmain.sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ # Automatically update the libtool script if it becomes out-of-date # See https://www.gnu.org/software/libtool/manual/html_node/LT_005fINIT.html LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ #all all-am-local all-local: # +@cd common && $(MAKE) $(AM_MAKEFLAGS) all # +@$(MAKE) $(AM_MAKEFLAGS) all-recursive # +@$(MAKE) $(AM_MAKEFLAGS) doc # +@$(MAKE) $(AM_MAKEFLAGS) doc bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ # include directory for aclocal ACLOCAL_AMFLAGS = -I m4 # Autotools' SUBDIRS (our values are listed below) allow for powerful recursive # recipe automation, with one notable weakness: the dirs are processed in a # loop sequentially, even in parallel builds (each such sub-make is parallel # then). In our case, the HTML/PDF render of ChangeLog can take a minute of # work in "docs" while we are not building anything in other dirs. On the up # side, that approach does allow for dirs with dependencies to get built first # deterministically. For more details search for "am__recursive_targets" in the # generated Makefile. # # The commonly suggested way out of this predicament is to consolidate numerous # Makefile.am recipes into one, which alone properly defines all the needed # interdependecies that are "known" to one instance of the `make` process. # This however loses the ability to quickly e.g. `cd tests && make check`, so # the next layer is to re-introduce Makefiles in sub-directories that define # a few popular targets to perform via the one big top-level Makefile. # # Our approach here is to merge the two solutions: do use SUBDIRS the way # autotools handle them for the hordes of `*-recursive` targets for us, but # define more explicitly the targets for hot code paths (all, check) so that # they can run first for certain different directories (in parallel if asked # to) with "knowledge" of dependencies, and then a bit wastefully maybe re-run # those directories via autotools integration. They should be quick no-ops by # then in the anticipated common use-cases. # # List of source subdirectories to build and distribute, used to spawn automake # (alas sequential) target recipes. The order matters, as several subdirectories # depend on stuff in "common" or tools being built first! SUBDIRS = include common clients conf data drivers tools \ lib scripts server tests docs/man docs # Note: not generated from SUBDIRS, because not all are recursive: SUBDIRS_ALL_RECURSIVE = \ all/include \ all/common \ all/clients \ all/conf \ all-recursive/data \ all-drivers \ all/tools/nut-scanner \ all/tools/nutconf \ all-recursive/tools \ all/lib \ all-recursive/scripts \ all/server \ all/tests/NIT \ all/tests \ all/docs \ all/docs/man \ all-recursive/docs \ all-recursive/tests # Library creation happens in a number of subdirectories, may be optional # (e.g. C++ ones are not built without a suitable compiler and enablement). # List maintenance is aided by this query: # git grep -E 'LTLIBRARIES' '*.am' SUBDIRS_ALL_LIBS_LOCAL = \ all-libs-local/include \ all-libs-local/common \ all-libs-local/clients \ all-libs-local/drivers \ all-libs-local/tests \ all-libs-local/tools \ all-libs-local/tools/nut-scanner # Verbosity for fanout rule tracing; 0/1 (or "default" that may auto-set # to 0 or 1 in some rules below) SUBDIR_MAKE_VERBOSE = default # COPYING and other autotools-standard files are included automatically # by automake. Note that the INSTALL file is (re-)imposed by autotools # runs and is essentially a manual on configure script general usage, so # NUT's actual installation notes have had to use a different filename. # Since the renaming of documentation to `*.adoc` extension to help IDE # and GitHub UIs to render the source files in a pretty fashion, we need # to list them: # Tarballs created by `make dist` include the `configure.ac` and `m4/*` sources # but lack NUT magic logic to recreate the `configure` script if someone would # want to adapt it to their autotools or locally fix a tarball-based build. EXTRA_DIST = LICENSE-GPL2 LICENSE-GPL3 LICENSE-DCO MAINTAINERS \ INSTALL.nut.adoc UPGRADING.adoc TODO.adoc NEWS.adoc \ README.adoc ci_build.adoc autogen.sh VERSION_DEFAULT @KEEP_NUT_REPORT_TRUE@nodist_data_DATA = config.nut_report_feature.log # Not too different from automake generated recursive rules at first sight, # but here we do not loop all subdirs sequentially - instead, a sub-make # (maybe parallel itself and with parallel flags passed) with a certain # target in specified dir is the goal, all as separate targets for this # level's Makefile: SUBDIR_TGT_RULE = ( \ [ x"$${TGT-}" != x ] || TGT="`echo '$@' | awk -F/ '{print $$1}'`" ; \ [ x"$${DIR-}" != x ] || DIR="`echo '$@' | sed 's,^[^/]*/,,'`" ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE STARTING: 'make $$TGT' in $$DIR ..." ; \ fi ; \ cd "$(abs_builddir)/$${DIR}" && \ $(MAKE) $(AM_MAKEFLAGS) $${SUBDIR_TGT_MAKEFLAGS-} "$${TGT}" || { RES=$$?; echo " SUBDIR-MAKE FAILURE: 'make $$TGT' in $$DIR" >&2 ; exit $$RES ; } ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE SUCCESS: 'make $$TGT' in $$DIR" ; \ fi ; \ ) # Note: we optionally sort of depend on ChangeLog.adoc so it is pre-made and # pre-processed for html/pdf renders (if any are requested), so they surely # do not compete for it to be made by independent "make" processes later on. # BUT we do not want to (re-)build ChangeLog if no (relevant) DOC_BUILD_LIST # types are enabled. MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY = 0 # ---------------------------------------------------------------------- # flags to pass to ./configure when calling "make distcheck" and "make # distcheck-light". Try to check as many features as possible! Also # need to give augeas-lenses-dir, hotplug-dir and udev-dir, and request # PyNUT to be installed near the NUT-Monitor app (if feasible) so that # staged install does not fail. Note that by default PyNUT tries to go # into the system Python site-packages location, and autotools does not # tweak paths not using ${prefix} so `make distcheck` fails for it as # it does not play with a `DESTDIR` either. DISTCHECK_FLAGS = --with-all --with-ssl --with-doc=auto --with-pynut=app --with-nut_monitor=force CXXFLAGS='@NUT_CONFIG_CXXFLAGS@' CFLAGS='@NUT_CONFIG_CFLAGS@' CPPFLAGS='@NUT_CONFIG_CPPFLAGS@' LDFLAGS='@NUT_CONFIG_LDFLAGS@' DISTCHECK_LIGHT_FLAGS = --with-all=auto --with-ssl=auto --with-doc=auto --with-pynut=app --with-nut_monitor=force CXXFLAGS='@NUT_CONFIG_CXXFLAGS@' CFLAGS='@NUT_CONFIG_CFLAGS@' CPPFLAGS='@NUT_CONFIG_CPPFLAGS@' LDFLAGS='@NUT_CONFIG_LDFLAGS@' DISTCHECK_LIGHT_MAN_FLAGS = --with-all=auto --with-ssl=auto --with-doc=man --with-pynut=app --with-nut_monitor=force CXXFLAGS='@NUT_CONFIG_CXXFLAGS@' CFLAGS='@NUT_CONFIG_CFLAGS@' CPPFLAGS='@NUT_CONFIG_CPPFLAGS@' LDFLAGS='@NUT_CONFIG_LDFLAGS@' DISTCHECK_VALGRIND_FLAGS = --with-all=auto --with-ssl=auto --with-doc=skip --with-valgrind CXXFLAGS='@NUT_CONFIG_CXXFLAGS@ -g' CFLAGS='@NUT_CONFIG_CFLAGS@ -g' CPPFLAGS='@NUT_CONFIG_CPPFLAGS@' LDFLAGS='@NUT_CONFIG_LDFLAGS@' --with-pynut=app --with-nut_monitor=force # Note: this rule uses envvar DISTCHECK_FLAGS expanded at run-time DISTCHECK_CONFIGURE_FLAGS = ${DISTCHECK_FLAGS} \ PKG_CONFIG_PATH='@PKG_CONFIG_PATH@' \ --with-systemdsystemunitdir='$${prefix}/lib/systemd/system' \ --with-systemdsystempresetdir='$${prefix}/usr/lib/systemd/system-preset' \ --with-systemdshutdowndir='$${prefix}/lib/systemd/system-shutdown' \ --with-systemdtmpfilesdir='$${prefix}/usr/lib/tmpfiles.d' \ --with-augeas-lenses-dir='$${prefix}/usr/share/augeas/lenses' \ --with-hotplug-dir='$${prefix}/etc/hotplug' \ --with-udev-dir='$${prefix}/etc/udev' \ --with-devd-dir='$${prefix}/etc/devd' \ --with-pynut=app --with-nut_monitor=force # Files made by our targets: CLEANFILES = *-spellchecked *.adoc-parsed cppcheck*.xml \ config.log.inplace-outer VERSION_DEFAULT.tmp # Most of the files generated by custom rules in the configure script # or by autogen.sh are cleaned by the Makefile.am in their directories. # Files below are re-created by running `configure` script and may be # wiped by a `make distclean`: #???# configure.ac~ DISTCLEANFILES = ChangeLog config.log configure~ include/config.h.in~ # Files made by autotools and common rituals of the configure script, # these are needed to run the configure script itself so are not wiped # by a mere `make distclean`; most of these are copied by autotools # from their installation, or made by `automake` etc. on the system # which generates `configure`; rebuilding NUT after deleting these # requires `autogen.sh` script to be re-run (and tools available): # ---------------------------------------------------------------------- # Automatically generate the ChangeLog from Git logs: # CI builds can leave a log of selected features: MAINTAINERCLEANFILES = INSTALL aclocal.m4 config.guess config.sub \ configure depcomp install-sh ltmain.sh test-driver ar-lib \ m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 \ m4/lt~obsolete.m4 Makefile.in .dirstamp include/config.h.in \ ChangeLog config.nut_report_feature.log* \ $(MAINTAINERCLEANFILES_DISTBALL) \ $(MAINTAINERCLEANFILES_PACKAGES) # Hook the documentation building and validating recipes # Note: these are optionally available (as determined during configure runs) # Only require SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes for the last entry # (reduce noise for spellcheck-interactive) # Maint: grep -l 'SPELLCHECK_' `git grep -lw spellcheck '*.am'` SPELLCHECK_DIRS_MOST = \ spellcheck/docs \ spellcheck/docs/man \ spellcheck/conf \ spellcheck/data \ spellcheck/data/html \ spellcheck/scripts \ spellcheck/scripts/Solaris \ spellcheck/scripts/Windows \ spellcheck/scripts/devd \ spellcheck/scripts/external_apis \ spellcheck/scripts/hotplug \ spellcheck/scripts/installer \ spellcheck/scripts/python \ spellcheck/scripts/systemd \ spellcheck/scripts/udev \ spellcheck/scripts/upsdrvsvcctl # Same but with an info notice, so runs alone last SPELLCHECK_DIRS_LAST = spellcheck/tests/NIT SPELLCHECK_DIRS = $(SPELLCHECK_DIRS_MOST) $(SPELLCHECK_DIRS_LAST) # Workarounds for https://github.com/github/markup/issues/1095 # require direct definition of our attributes in each source # document, in order for GitHub Web-UI to render them nicely # (unfortunately, asciidoc configs and includes are not handled # at this time). Hopefully this will go away at some point. # The following rule updates definitions in source asciidoc files # between GH_MARKUP_1095_INCLUDE_BEGIN/END tags with contents of # current docs/asciidoc-vars.conf file. It is intended to be used # by maintainers (or brave contributors who would dare edit those # definitions), to apply them into the committed document sources. # Not bothering about with "make dist" constraints etc. - changes # the contents of srcdir directly and intentionally. # NOTE: Using `read -r` per POSIX standard to avoid backslashes # being treated as escape characters: # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html MAINTAINER_ASCIIDOCS_RECIPE_DEBUG_STREAM = /dev/null # Let the analysis get regenerated due to any change in source; # but note that with our different make implementations to support, # we can not either $(shell find ...) nor blindly say e.g. *.cpp # for each FS structure layer because e.g. there are no ./*.cpp # in the root dir of the codebase (and so make complains there is # `No rule to make target `*.cpp', needed by `cppcheck-cxx11.xml'`) # # Note that the actual `cppcheck` scan finds all files it likes # (so if CPPCHECK_SRC_* misses something, it just won't trigger # automagically a rebuild of the XML in developer working cycles). @HAVE_CPPCHECK_TRUE@CPPCHECK_SRC_H = $(top_srcdir)/*/*.h $(top_srcdir)/*/*/*.h # CPPCHECK_SRC_H += $(top_srcdir)/*.h @HAVE_CPPCHECK_TRUE@CPPCHECK_SRC_C = $(top_srcdir)/*/*.c $(top_srcdir)/*/*/*.c # CPPCHECK_SRC_C += $(top_srcdir)/*.cpp @HAVE_CPPCHECK_TRUE@CPPCHECK_SRC_CXX = $(top_srcdir)/*/*.cpp # Older boundary of the ChangeLog commits range # It can be a tag ('v2.2.0'), a commit hash, a date, ... # See gitrevisions for more information on specifying ranges GITLOG_START_POINT = v2.6.0 @WITH_PDF_NONASCII_TITLES_FALSE@WITH_PDF_NONASCII_TITLES_ENVVAR = WITH_PDF_NONASCII_TITLES=no @WITH_PDF_NONASCII_TITLES_TRUE@WITH_PDF_NONASCII_TITLES_ENVVAR = WITH_PDF_NONASCII_TITLES=yes # Be sure to not confuse with a DIST'ed file (and so try to overwrite it); # do however avoid re-generating it if already made on a previous pass and # the Git HEAD pointer (branch) or its actual "index" or "object" database # did not change since then - meaning the local developer or CI did not # modify the metadata (subsequent generation of the huge PDF/HTML files # can cost dearly). # Note there's a bit more fuss about Git internals which NUT should not # really care about encapsulation-wise (detection of NUT_GITDIR location # which may reside elsewhere, e.g. with local repo clones with reference # repo configuration, or submodules). But this is a Git-crawling target # anyway, and in the worst case (Git's design changes) we would spend a # bit of time researching the FS in vain, and go on to re-generate the # ChangeLog when maybe we should not have - oh well. # WARNING: The CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR=true mode here is # default to allow for prettier documentation, but it can require too much # memory for weaker build systems. Set it to false when calling make there. CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR_ENVVAR = true # ---------------------------------------------------------------------- # targets from old build system (pre-automake). # supported for a period of time for backward "compatibility". WARN = "----------------------------------------------------------------------" @HAVE_SYSTEMD_FALSE@HAVE_SYSTEMD = false @HAVE_SYSTEMD_TRUE@HAVE_SYSTEMD = true @WITH_SYSTEMD_TMPFILES_FALSE@WITH_SYSTEMD_TMPFILES = false @WITH_SYSTEMD_TMPFILES_TRUE@WITH_SYSTEMD_TMPFILES = true @WITH_SYSTEMD_PRESET_FALSE@WITH_SYSTEMD_PRESET = false @WITH_SYSTEMD_PRESET_TRUE@WITH_SYSTEMD_PRESET = true @WITH_CGI_FALSE@WITH_CGI = false @WITH_CGI_TRUE@WITH_CGI = true @WITH_SOLARIS_SMF_FALSE@WITH_SOLARIS_SMF = false @WITH_SOLARIS_SMF_TRUE@WITH_SOLARIS_SMF = true @WITH_SOLARIS_INIT_FALSE@WITH_SOLARIS_INIT = false @WITH_SOLARIS_INIT_TRUE@WITH_SOLARIS_INIT = true # Clean the dist tarball and packages MAINTAINERCLEANFILES_DISTBALL = nut-*.tar.gz # HP-UX: # AIX as below, and RedHat-compatible (cover binary and source packages): # Debian-compatible (cover binary and source packages): # Solaris SVR4 package archives: # Newer Solaris IPS (aka "pkg(5)" format archives) MAINTAINERCLEANFILES_PACKAGES = \ NUT_HPUX_package@PACKAGE_VERSION@.depot \ NUT_HPUX_package-@PACKAGE_VERSION@.depot nut*rpm nut*deb \ NUT_solaris_*_package@PACKAGE_VERSION@.local.gz \ NUT_solaris_*_package-@PACKAGE_VERSION@.local.gz *.p5p all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): scripts/Aix/nut-aix.spec: $(top_builddir)/config.status $(top_srcdir)/scripts/Aix/nut-aix.spec.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/RedHat/ups: $(top_builddir)/config.status $(top_srcdir)/scripts/RedHat/ups.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/avahi/nut.service: $(top_builddir)/config.status $(top_srcdir)/scripts/avahi/nut.service.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/external_apis/enphase/enphase-monitor@.service: $(top_builddir)/config.status $(top_srcdir)/scripts/external_apis/enphase/enphase-monitor@.service.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/HP-UX/nut.psf: $(top_builddir)/config.status $(top_srcdir)/scripts/HP-UX/nut.psf.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/valgrind/.valgrind.supp: $(top_builddir)/config.status $(top_srcdir)/scripts/valgrind/.valgrind.supp.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/Windows/Installer/NUT-Installer.xml: $(top_builddir)/config.status $(top_srcdir)/scripts/Windows/Installer/NUT-Installer.xml.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/Aix/nut.init: $(top_builddir)/config.status $(top_srcdir)/scripts/Aix/nut.init.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/HP-UX/postinstall: $(top_builddir)/config.status $(top_srcdir)/scripts/HP-UX/postinstall.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/RedHat/upsd: $(top_builddir)/config.status $(top_srcdir)/scripts/RedHat/upsd.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/RedHat/upsmon: $(top_builddir)/config.status $(top_srcdir)/scripts/RedHat/upsmon.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/external_apis/enphase/enphase-monitor: $(top_builddir)/config.status $(top_srcdir)/scripts/external_apis/enphase/enphase-monitor.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/python/app/NUT-Monitor-py2gtk2: $(top_builddir)/config.status $(top_srcdir)/scripts/python/app/NUT-Monitor-py2gtk2.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/python/app/NUT-Monitor-py3qt5: $(top_builddir)/config.status $(top_srcdir)/scripts/python/app/NUT-Monitor-py3qt5.in cd $(top_builddir) && $(SHELL) ./config.status $@ scripts/valgrind/valgrind.sh: $(top_builddir)/config.status $(top_srcdir)/scripts/valgrind/valgrind.sh.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt install-nodist_dataDATA: $(nodist_data_DATA) @$(NORMAL_INSTALL) @list='$(nodist_data_DATA)'; test -n "$(datadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(datadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(datadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(datadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(datadir)" || exit $$?; \ done uninstall-nodist_dataDATA: @$(NORMAL_UNINSTALL) @list='$(nodist_data_DATA)'; test -n "$(datadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(datadir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(datadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-libtool \ distclean-local distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-nodist_dataDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic \ maintainer-clean-local mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-nodist_dataDATA .MAKE: $(am__recursive_targets) install-am install-data-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \ dist-tarZ dist-xz dist-zip dist-zstd distcheck distclean \ distclean-generic distclean-libtool distclean-local \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-data-hook install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-nodist_dataDATA install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic maintainer-clean-local mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-nodist_dataDATA .PRECIOUS: Makefile # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ # First target often defines default behavior, and in automake is always at least: # all: all-recursive # with maybe custom dependencies of "all:" from a Makefile.am tacked on too # (which used to cause us a lot of headache, building same things twice at # the same time). #all all-recursive all-am-local all-local: all-fanout-maybe all-recursive: all-fanout-maybe # Run the standard build if going sequential (or with unknown MAKEFLAGS), # or fanout if parallel (presuming GNU/BSD/Sun make at least): all-fanout-maybe: +@if [ x"$(NUT_MAKE_SKIP_FANOUT)" = xtrue ] ; then \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: skip optimization for parallel make - NUT_MAKE_SKIP_FANOUT is set" ; \ fi ; \ exit 0 ; \ fi ; \ case "-$(MAKEFLAGS) $(AM_MAKEFLAGS)" in \ *-j|*-j" "*|*-{j,l}{0,1,2,3,4,5,6,7,8,9}*|*-[jl][0123456789]*|*{-l,--jobs,--load-average,--max-load}" "{-,0,1,2,3,4,5,6,7,8,9}*|*--jobserver*|*--jobs" "[0123456789]*|*--load-average" "[0123456789]*|*--max-load" "[0123456789]*) \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: implement optimization for parallel make as 'make all-fanout-subdirs'" ; \ fi ; \ $(MAKE) $(AM_MAKEFLAGS) all-fanout-subdirs ;; \ *) \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: skip optimization for parallel make - we seem to run sequentially now, seen MAKEFLAGS='$(MAKEFLAGS)' AM_MAKEFLAGS='$(AM_MAKEFLAGS)'" ; \ fi ;; \ esac # We start with a pass to `make all` in `common` dir because our wild recipes # (with other subdirs ensuring the libraries they need have been built) can # sometimes cause parallel compilation and library generation for same files # driven by different make processes that do not know they aim for same goal, # with some "make" implementations... # Just in case we followed up with "make doc", since our wild recipes could end # up writing into same files and so corrupting them (fixes applied, but...) # FIXME: Alas, we still tend to step on our toes when making everything at # once from scratch, so still do benefit from pre-making the libraries: all-fanout-staged: +$(MAKE) $(AM_MAKEFLAGS) all/include +$(MAKE) $(AM_MAKEFLAGS) all/common +$(MAKE) $(AM_MAKEFLAGS) all-fanout-libs +$(MAKE) $(AM_MAKEFLAGS) all-fanout-subdirs all-fanout-subdirs: $(SUBDIRS_ALL_RECURSIVE) all-fanout-libs all-libs-local: $(SUBDIRS_ALL_LIBS_LOCAL) libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status libtool # A way to quickly handle SUBDIRS_ALL_LIBS_LOCAL as dependency for all others # (aka `make all-libs-local` also in root dir). Libs themselves have complex # inter-dependencies which we do not spell out here and let one recipe handle # the intimate details of other directories' deliverables (so far?). Query: # git grep -E '(LTLIBRARIES|\.la([ :'"`printf '\t'`"']|$))' '*.am' ### Delivers: nut_version.h all-libs-local/include: +@$(SUBDIR_TGT_RULE) ### Delivers: libcommon.la libcommonclient.la libcommonstr.la ### Delivers: libparseconf.la libnutconf.la libnutwincompat.la ### Requires-ext: include/nut_version.h ### Requires-int: libparseconf.la libcommonclient.la all-libs-local/common: all-libs-local/include +@$(SUBDIR_TGT_RULE) ### Delivers: libupsclient.la libnutclient.la libnutclientstub.la ### Delivers: libupsclient-version.h ### LIB-Requires-ext: common/libcommonclient.la ### Requires-ext: common/libcommon.la common/libcommonclient.la ### Requires-ext: common/libparseconf.la ### Requires-int: libupsclient.la all-libs-local/clients: all-libs-local/common +@$(SUBDIR_TGT_RULE) ### Delivers: libdummy.la libdummy_serial.la libdummy_upsdrvquery.la ### Delivers: libdummy_mockdrv.la libserial-nutscan.la ### LIB-Requires-ext: common/libcommon.la common/libparseconf.la ### Requires-ext: common/libcommon.la common/libparseconf.la ### Requires-ext: clients/libupsclient.la (dummy-ups only) ### Requires-int: libdummy.la libdummy_upsdrvquery.la ### Requires-int: libdummy_serial.la all-libs-local/drivers: all-libs-local/common +@$(SUBDIR_TGT_RULE) ### Delivers: libdriverstubusb.la ### LIB-Requires-ext: #COMMENTED-AWAY# common/libcommon.la ### Requires-ext: common/libcommon.la common/libnutconf.la ### Requires-ext: clients/libnutclient.la clients/libnutclientstub.la ### Requires-ext: drivers/libdummy_mockdrv.la ### Requires-int: libdriverstubusb.la all-libs-local/tests: all-libs-local/common +@$(SUBDIR_TGT_RULE) ### Delivers: generated sources and/or headers for nut-scanner ### No dependencies: actually runs as part of autogen.sh but may be ### re-run during development when USB or SNMP driver sources change. all-libs-local/tools: +@$(SUBDIR_TGT_RULE) ### Delivers: libnutscan.la ### LIB-Requires-ext: drivers/libserial-nutscan.la ### LIB-Requires-ext: common/libnutwincompat.la common/libcommonstr.la ### HDR-Requires-ext: clients/libupsclient-version.h ### HDR-Requires-ext: nut-scanner/nutscan-snmp.h nut-scanner/nutscan-usb.h ### (generated by nut-scanner-deps/tools aliased as all-libs-local/tools) ### Requires-int: libnutscan.la ### Note: indirectly (ltdl) may use installed libupsclient.so ### however does directly use libupsclient-version.h ### for hints to find it at run-time all-libs-local/tools/nut-scanner: all-libs-local/drivers all-libs-local/common all-libs-local/clients all-libs-local/tools +@$(SUBDIR_TGT_RULE) # Handle all SUBDIRS_ALL_RECURSIVE in a way that dependencies can be specified, # and portably to different make program implementations. Note we may revisit # some dirs via "all-recursive" of a parent after "all" in them first, but it is # expected to be a quick no-op (beneficial overall in parallel make situation). # NOTE: "lib" dir only delivers pkg-config metadata or legacy scripts for any # third-party development to integrate with NUT libs, no library recipes there. all/conf \ all/lib \ .ChangeLog.adoc-parsed.latest/docs \ ChangeLog.adoc-parsed/docs \ all-recursive/data: +@$(SUBDIR_TGT_RULE) all/include: all-libs-local/include +@$(SUBDIR_TGT_RULE) prep-src-docs/docs/man: +@SUBDIR_TGT_MAKEFLAGS='MAINTAINER_DOCS_PREP_MAN_DELAY=3'; export SUBDIR_TGT_MAKEFLAGS; $(SUBDIR_TGT_RULE) prep-src-docs/docs: +@DOCS_NO_MAN=true; export DOCS_NO_MAN; $(SUBDIR_TGT_RULE) all/docs/man: prep-src-docs/docs/man +@$(SUBDIR_TGT_RULE) all/docs: prep-src-docs/docs/man +@case "@DOC_BUILD_LIST@" in \ *pdf*|*html-single*|*html-chunked*) \ echo " DOC-CHANGELOG-ASCIIDOC Pre-generate ChangeLog artifacts before the bulk of $@ ..." ; \ MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY="$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" \ export MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY && \ $(MAKE) $(AM_MAKEFLAGS) MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY="$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" ChangeLog.adoc && \ $(MAKE) $(AM_MAKEFLAGS) MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY="$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" .ChangeLog.adoc-parsed.latest/docs && \ echo " DOC-CHANGELOG-ASCIIDOC Pre-generate ChangeLog artifacts before the bulk of $@ : SUCCESS" ;; \ *) ;; \ esac +@$(MAKE) $(AM_MAKEFLAGS) prep-src-docs/docs +@DOCS_NO_MAN=true; export DOCS_NO_MAN; $(SUBDIR_TGT_RULE) all-recursive/docs: all/docs all/docs/man +@$(SUBDIR_TGT_RULE) # Dependencies below are dictated by who needs whose library from another dir # (generated by a sub-make there, so we pre-emptively ensure it exists to avoid # conflicts of several make's writing to same files). Aided by this query: # git grep -E '/[^ ]*\.la([ :]|$)' '*.am' # It does help to spell out all dependencies, even if transitive, to ensure # that the top-level make completes needed (all-libs*) targets before drilling. ### Requires-int: libparseconf.la libcommonclient.la all/common: all/include all-libs-local/common +@$(SUBDIR_TGT_RULE) ### Requires-ext: common/libcommon.la common/libcommonclient.la ### Requires-ext: common/libparseconf.la ### Requires-int: libupsclient.la all/clients: all/common all-libs-local/clients +@$(SUBDIR_TGT_RULE) ### Summary of drivers/ subdir dependencies: ### Requires-ext: common/libcommon.la common/libparseconf.la ### Requires-ext: clients/libupsclient.la (dummy-ups only) ### Requires-int: libdummy.la libdummy_upsdrvquery.la ### Requires-int: libdummy_serial.la # TODO in the future: propagate the knowledge of whether we are building # dummy-ups by default (if only SOME_DRIVERS are requested) from configure.ac, # and so decide if a goal to build it would conflict or not with "all/drivers" # (or alternately if it should be or not be part of "all-drivers", keeping the # current web of definitions in place). Primarily for the benefit of tests/NIT. # NOTE: The dummy-ups driver program relies on both libupsclient (ext) and # libdummy_upsdrvquery.la (int) - and so requires all-libs-local/drivers too. # Here we do wholesale subdir all-libs-local at the moment, to # build whichever drivers are enabled (no idea if dummy-ups is # in the default list - FIXME: configure.ac could tell us, so # we could provide it for tests/NIT anyway...) @SOME_DRIVERS_TRUE@all/drivers: all-libs-local/clients all-libs-local/common all-libs-local/drivers @SOME_DRIVERS_TRUE@ +@$(SUBDIR_TGT_RULE) @SOME_DRIVERS_TRUE@all-drivers: all/drivers # We build all drivers, let dummy-ups be built with respect for # libupsclient while not blocking other driver builds on that. # NUTSW_DRIVERLIST_DUMMY_UPS acts as an equivalent of DOCS_NO_MAN # in a way, to let other (non dummy-ups) drivers get built in a # separate target with separate dependency trail, then "all-drivers" # should depend on both "dummy-ups" and the rest in so constrained # "all/drivers". This allows to ultimately not order one after another. @SOME_DRIVERS_FALSE@dummy-ups$(EXEEXT)/drivers: all-libs-local/clients all-libs-local/common all-libs-local/drivers @SOME_DRIVERS_FALSE@ +@$(SUBDIR_TGT_RULE) @SOME_DRIVERS_FALSE@all/drivers: all/common all-libs-local/drivers @SOME_DRIVERS_FALSE@ +@SUBDIR_TGT_MAKEFLAGS='NUTSW_DRIVERLIST_DUMMY_UPS=dummy'; export SUBDIR_TGT_MAKEFLAGS; $(SUBDIR_TGT_RULE) @SOME_DRIVERS_FALSE@all-drivers: dummy-ups$(EXEEXT)/drivers all/drivers ### Requires-ext: common/libcommon.la common/libparseconf.la all/server: all-libs-local/common +@$(SUBDIR_TGT_RULE) ### LIB-Requires-ext: drivers/libserial-nutscan.la ### LIB-Requires-ext: common/libnutwincompat.la common/libcommonstr.la ### Requires-ext: include/nut_version.h ### Requires-ext: clients/libupsclient-version.h ### Requires-int: libnutscan.la all/tools/nut-scanner: all-libs-local/include all-libs-local/common \ all-libs-local/drivers all-libs-local/clients \ all-libs-local/tools/nut-scanner +@$(SUBDIR_TGT_RULE) # only libnutscan is needed for nutconf, # but we do wholesale subdir all-libs-local at the moment... ### Requires-ext: common/libcommon.la common/libnutconf.la ### Requires-ext: tools/nut-scanner/libnutscan.la all/tools/nutconf: all-libs-local/tools/nut-scanner all-libs-local/common +@$(SUBDIR_TGT_RULE) all-recursive/tools: all/tools/nutconf all/tools/nut-scanner +@$(SUBDIR_TGT_RULE) # Prereqs for NIT are runnable upsd, upsc, upsmon, dummy-ups, sample configs... # For the actual "make check-NIT" runs - also python scripts and/or compiled # tests/cppnit (if available). # FIXME: technically of all drivers we need dummy-ups here; # if it is not enabled among SOME_DRIVERS, things can get funny... # But then we should also consider what is enabled by configure and what is not. # Maybe we are doing a quick build not to be tested at all? :-/ all/tests/NIT: all/clients all/server all-drivers all-recursive/tools all-recursive/data +@$(SUBDIR_TGT_RULE) ### LIB-Requires-ext: #COMMENTED-AWAY# common/libcommon.la ### Requires-ext: common/libcommon.la common/libnutconf.la ### Requires-ext: clients/libnutclient.la clients/libnutclientstub.la ### Requires-ext: drivers/libdummy_mockdrv.la ### Requires-int: libdriverstubusb.la all/tests: all-libs-local/tests all-libs-local/drivers all-libs-local/common all-libs-local/clients +@$(SUBDIR_TGT_RULE) all-recursive/tests: all/tests/NIT all/tests +@$(SUBDIR_TGT_RULE) ### Requires-ext: common/libcommon.la @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@all/scripts/Windows: all-libs-local/common @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_TRUE@ +@$(SUBDIR_TGT_RULE) @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_FALSE@all/scripts/Windows: @HAVE_MINGW_RESGEN_TRUE@@HAVE_WINDOWS_FALSE@ +@$(SUBDIR_TGT_RULE) @HAVE_MINGW_RESGEN_FALSE@all/scripts/Windows: @HAVE_MINGW_RESGEN_FALSE@ +@$(SUBDIR_TGT_RULE) all-recursive/scripts: all/scripts/Windows +@$(SUBDIR_TGT_RULE) # Note: trickery with prefix below is needed to expand it from # DISTCHECK_CONFIGURE_FLAGS defaults defined above in a manner # that is meaningful for sub-make program (gets stripped away # otherwise and breaks custom distchecks). # Helper for CI runs: ensure presence of pre-built man pages # (even if faked where lack and can not build them), so that # the majority of distcheck logic can pass. # See also docs/man/Makefile.am @DOC_INSTALL_DISTED_MANS_TRUE@@KNOWN_UNABLE_MANS_TRUE@distcheck-ci: distcheck @DOC_INSTALL_DISTED_MANS_TRUE@@KNOWN_UNABLE_MANS_TRUE@dist-ci: dist @DOC_INSTALL_DISTED_MANS_FALSE@@KNOWN_UNABLE_MANS_TRUE@distcheck-ci: distcheck-fake-man @DOC_INSTALL_DISTED_MANS_FALSE@@KNOWN_UNABLE_MANS_TRUE@dist-ci: dist-fake-man @KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_TRUE@distcheck-ci: distcheck @KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_TRUE@dist-ci: dist @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_FALSE@distcheck-ci: distcheck @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_FALSE@dist-ci: dist @DOC_INSTALL_DISTED_MANS_TRUE@@HAVE_ASCIIDOC_FALSE@@KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_FALSE@distcheck-ci: distcheck @DOC_INSTALL_DISTED_MANS_TRUE@@HAVE_ASCIIDOC_FALSE@@KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_FALSE@dist-ci: dist @DOC_INSTALL_DISTED_MANS_FALSE@@HAVE_ASCIIDOC_FALSE@@KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_FALSE@distcheck-ci: distcheck-fake-man @DOC_INSTALL_DISTED_MANS_FALSE@@HAVE_ASCIIDOC_FALSE@@KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_FALSE@dist-ci: dist-fake-man # Helper for a number of recipes below that explicitly agree to not require # always real man pages (but require them to dist => distcheck-something) # for CI or developer iterations on environments with incomplete tool kits: distcheck-light-DIST_ALL_PAGES: @echo "Starting $@" >&2 +@cd "$(abs_builddir)/docs/man" && $(MAKE) $(AM_MAKEFLAGS) all +@cd "$(abs_builddir)/docs/man" && $(MAKE) $(AM_MAKEFLAGS) distcheck-light-DIST_ALL_PAGES @echo "Completed $@: preparation of pre-built man pages for dist tarball, possibly faked" >&2 # In some recipes we `configure --with-docs=skip`, so "make dist" should not # hiccup on lack of the page files (nor try to make them); not using simple # distcheck-light-DIST_ALL_PAGES step due to custom logic! distcheck-light-DIST_ALL_PAGES-docs-skipped: @echo "Starting $@" >&2 +@cd $(abs_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) prep-src-docs +@cd $(abs_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) FAKE_PAGES_BUMP_SRC=false distcheck-light-DIST_ALL_PAGES @echo "Completed $@: preparation of pre-built man pages for dist tarball, possibly faked" >&2 # Here we generate man pages (if absent) or fake them # Require other dependencies as usual distcheck does; # be sure to pass through caller's DISTCHECK_FLAGS (if any) distcheck-fake-man: distcheck-light-DIST_ALL_PAGES @echo "Starting $@" >&2 +prefix='$${prefix}'; if test x"$(DISTCHECK_FLAGS)" = x ; then \ $(MAKE) $(AM_MAKEFLAGS) distcheck ; \ else \ $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_FLAGS)" distcheck ; \ fi @echo "Completed $@: strict distcheck, but with possibly faked pre-built man pages" >&2 dist-fake-man: distcheck-light-DIST_ALL_PAGES @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) dist @echo "Completed $@: strict dist, but with possibly faked pre-built man pages" >&2 # Here we allow to skip docs if tools are absent, so "make dist" # should not hiccup on lack of the page files (but MAY make them # if it can); be relaxed toward other dependencies. distcheck-light: distcheck-light-DIST_ALL_PAGES @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_LIGHT_FLAGS)" distcheck @echo "Completed $@: relaxed distcheck, with possibly faked pre-built man pages" >&2 # Require man pages to be built (or fail trying), but not other docs; # be relaxed toward other dependencies. distcheck-light-man: @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_LIGHT_MAN_FLAGS)" distcheck @echo "Completed $@: relaxed distcheck, with real man pages" >&2 # Make the check in current build, if possible @HAVE_VALGRIND_TRUE@memcheck: @HAVE_VALGRIND_TRUE@ @echo "Starting $@" >&2 @HAVE_VALGRIND_TRUE@ @echo "See also scripts/valgrind in NUT sources for a helper tool" @HAVE_VALGRIND_TRUE@ +@cd $(builddir)/tests && $(MAKE) $(AM_MAKEFLAGS) -s $@ # Make a distcheck (and check in particular) with enabled valgrind and debug info # Here we skip docs so "make dist" should not hiccup on lack of the page files # (nor try to make them); not using simple distcheck-light-DIST_ALL_PAGES step # due to custom logic! @HAVE_VALGRIND_TRUE@distcheck-valgrind: distcheck-light-DIST_ALL_PAGES-docs-skipped @HAVE_VALGRIND_TRUE@ @echo "Starting $@" >&2 @HAVE_VALGRIND_TRUE@ @echo "See also scripts/valgrind in NUT sources for a helper tool" @HAVE_VALGRIND_TRUE@ +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_VALGRIND_FLAGS)" distcheck @HAVE_VALGRIND_TRUE@ @echo "Completed $@: relaxed distcheck, without man pages ('pre-built' placeholders in dist archive), running tests under valgrind" >&2 @HAVE_VALGRIND_FALSE@memcheck distcheck-valgrind: @HAVE_VALGRIND_FALSE@ @echo "Starting $@" >&2 @HAVE_VALGRIND_FALSE@ @echo "See also scripts/valgrind in NUT sources for a helper tool" @HAVE_VALGRIND_FALSE@ @echo " SKIP $@ : valgrind was not detected on this system by configure script" >&2 # workaround the dist generated files that are also part of the distribution # Note that distcleancheck is disabled for now, while waiting for a proper # solution, that do not break older unix systems #distcleancheck_listfiles = \ # find . -type f -exec sh -c 'test -f $(srcdir)/{} || echo {}' ';' distcleancheck: @: # Quick alias for root dir recipe: realclean: maintainer-clean # Executed after default rules maintainer-clean-local: $(AM_V_at)rm -f missing || true # Do not let $SUBDIRS/Makefile rules delete their local .deps because # this breaks our ability to clean up (e.g. some common/.../*.Plo files # are included by generated Makefiles from other subdirectories, so they # should be available during their clean-up). Just in case, we make sure # here that their sub-distcleans complete first. distclean-local: +@for DIR in $(SUBDIRS) ; do \ if test -f "$${DIR}/Makefile" ; then \ echo " DISTCLEAN in $${DIR}" >&2 ; \ ( cd "$${DIR}" && $(MAKE) $(AM_MAKEFLAGS) -s distclean ) || exit ; \ fi ; \ done $(AM_V_at)rm -rf .inst tmp autom4te.cache $(AM_V_at)find "$(builddir)" -type d -name '.deps' | while read DIR ; do rm -rf "$${DIR}" ; done $(SPELLCHECK_DIRS_MOST): prep-src-docs/docs/man prep-src-docs/docs +@TGT="$(SPELLCHECK_TGT)"; export TGT; $(SUBDIR_TGT_RULE) $(SPELLCHECK_DIRS_LAST): prep-src-docs/docs/man prep-src-docs/docs $(SPELLCHECK_DIRS_MOST) +@SUBDIR_TGT_MAKEFLAGS="SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes"; \ export SUBDIR_TGT_MAKEFLAGS; \ TGT="$(SPELLCHECK_TGT)"; export TGT; \ $(SUBDIR_TGT_RULE) # We want to check all files even if some have errors, so sub-make with "-k": # Tricky TGT to pass sort-of-same rules (and dir list) as spellcheck, # but using the correct make target for this goal: # FIXME: fanned-out recipes tend to fail early despite "make -ks", so for # now we retry with a not-fanned-out attempt to cover most touch-files spellcheck spellcheck-interactive: +@SUBDIR_TGT_MAKEFLAGS="$${SUBDIR_TGT_MAKEFLAGS-} -k -s " ; export SUBDIR_TGT_MAKEFLAGS ; \ if [ x"$(NUT_MAKE_SKIP_FANOUT)" = xtrue ] ; then \ RES=0 ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: skip optimization for parallel make - NUT_MAKE_SKIP_FANOUT is set" ; \ fi ; \ (cd $(builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) -k -s $(abs_top_builddir)/docs/.prep-src-docs) || RES=$$? ; \ (cd $(builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) -k -s $(abs_top_builddir)/docs/man/.prep-src-docs) || RES=$$? ; \ for D in $(SPELLCHECK_DIRS_MOST) ; do \ D="`echo "$$D" | sed 's,^spellcheck/,,'`" ; \ (cd "$(builddir)/$$D" && $(MAKE) $(AM_MAKEFLAGS) -k -s $@) || RES=$$? ; \ done ; \ for D in $(SPELLCHECK_DIRS_LAST) ; do \ D="`echo "$$D" | sed 's,^spellcheck/,,'`" ; \ (cd "$(builddir)/$$D" && $(MAKE) $(AM_MAKEFLAGS) SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes -k -s $@) || RES=$$? ; \ done ; \ exit $$RES ; \ fi ; \ SUBDIR_MAKE_VERBOSE="$(SUBDIR_MAKE_VERBOSE)" ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" = xdefault ] ; then \ SUBDIR_MAKE_VERBOSE=0 ; \ fi ; \ export SUBDIR_MAKE_VERBOSE ; \ $(MAKE) $(AM_MAKEFLAGS) SPELLCHECK_TGT='$@' SUBDIR_MAKE_VERBOSE="$${SUBDIR_MAKE_VERBOSE}" -k -s $(SPELLCHECK_DIRS) && exit ; \ echo "WARNING: FAILED fanned-out attempt in $@, retrying with NUT_MAKE_SKIP_FANOUT" >&2 ; \ $(MAKE) $(AM_MAKEFLAGS) NUT_MAKE_SKIP_FANOUT=true SPELLCHECK_TGT='$@' -k -s $(SPELLCHECK_DIRS) # Auto-parallel recipe (if current 'make' implementation supports the "-j N" # syntax; the optional MAXPARMAKES may be set in NUT CI farm style builds): spellcheck-quick: +@case " $(MAKEFLAGS) $(AM_MAKEFLAGS)" in \ *"j"*) $(MAKE) $(AM_MAKEFLAGS) -k -s spellcheck && exit ;; \ *) \ if ! [ "$${MAXPARMAKES-}" -gt 1 ] 2>/dev/null ; then \ MAXPARMAKES=8 ; \ fi ; \ $(MAKE) $(AM_MAKEFLAGS) -k -s -j $${MAXPARMAKES} spellcheck \ && exit ;; \ esac # Run auto-parallel recipe, and if something fails - re-run interactively: spellcheck-interactive-quick: +@$(MAKE) $(AM_MAKEFLAGS) -k -s spellcheck-quick && exit ; \ echo "WARNING: in $@: make spellcheck-quick failed, retrying with spellcheck-interactive" >&2 ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" = xdefault ] ; then \ SUBDIR_MAKE_VERBOSE=1 ; export SUBDIR_MAKE_VERBOSE ; \ fi ; \ $(MAKE) $(AM_MAKEFLAGS) -k -s spellcheck-interactive # Note: the "all-docs" and "check-docs" targets may require tools not # found by `configure` script (and so avoided by conventional recipes) # such as PDF generators, so it should only be called at developer's # discretion, choice and risk. The "check-man" targets covers source # texts, man pages and HTML rendering of man pages, as enabled by tools. doc spellcheck-sortdict spellcheck-report-dict-usage \ all-docs check-docs \ man all-man man-man check-man check-man-man html-man all-html: +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) -s $(abs_top_builddir)/docs/.prep-src-docs +cd $(abs_top_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) -s $(abs_top_builddir)/docs/man/.prep-src-docs +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) $@ INSTALL.nut UPGRADING NEWS README: +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) ../$(@F).adoc-parsed && cp -f ../$(@F).adoc-parsed ../$(@F) #MAINTAINER_ASCIIDOCS_RECIPE_DEBUG_STREAM = &2 maintainer-asciidocs: @USEDREV="`git log -1 --oneline --pretty=format:'%h (%cs) %s' docs/asciidoc-vars.conf`" || exit ; \ USEDREV_NOSUBJ="`git log -1 --oneline --pretty=format:'%h (%cs)' docs/asciidoc-vars.conf`" || exit ; \ echo "$@: Updating asciidoc text sources with docs/asciidoc-vars.conf as of commit: $${USEDREV}"; \ echo "//GH_MARKUP_1095_INCLUDE_BEGIN//$${USEDREV}" > docs/asciidoc-vars.conf.lastrev.tmp || exit ; \ find . -name '*.adoc' -or -name '*.txt' | ( \ FILES=""; \ while read F ; do \ grep -E '^//+GH_MARKUP_1095_INCLUDE_(BEGIN|END)' "$$F" >/dev/null \ || { echo "$@: SKIP: no GH_MARKUP_1095_INCLUDE_* tags: $$F"; continue ; } ; \ rm -f "$${F}"*.tmp || exit ; \ EXT="1.tmp"; \ while IFS='' read -r LINE ; do \ case "$${LINE}" in \ "//GH_MARKUP_1095_INCLUDE_BEGIN"*) EXT="2.tmp" ; continue ;; \ "//GH_MARKUP_1095_INCLUDE_END"*|"////GH_MARKUP_1095_INCLUDE_END"*) EXT="3.tmp" ; continue ;; \ esac ; \ printf '%s\n' "$${LINE}" >> "$${F}.$${EXT}" || exit ; \ done < "$$F" || { echo "$@: FAILED injection for $${F}" >&2; exit 1; } ; \ if test -s "$${F}.2.tmp" && test -z "`diff "$${F}.2.tmp" docs/asciidoc-vars.conf | tr -d '\n'`" ; then \ rm -f "$${F}"*.tmp ; \ echo "$@: SKIP: no changes: $$F"; continue ; \ fi; \ cat "$${F}.1.tmp" docs/asciidoc-vars.conf.lastrev.tmp docs/asciidoc-vars.conf > "$${F}.tmp" \ && echo '//GH_MARKUP_1095_INCLUDE_END//' >> "$${F}.tmp" \ && cat "$${F}.3.tmp" >> "$${F}.tmp" \ && mv -f "$${F}.tmp" "$${F}" \ || { echo "$@: FAILED injection for $${F}" >&2; exit 1; } ; \ echo "$@: UPDATED: $$F"; \ FILES="$${FILES} $${F}"; \ rm -f "$${F}"*.tmp ; \ done; \ rm -f docs/asciidoc-vars.conf.lastrev.tmp; \ if test -z "$${FILES}" ; then \ echo "$@: OVERALL-SKIP: No text files found with GH_MARKUP_1095_INCLUDE_ tags, or obsoleted docs/asciidoc-vars.conf contents";\ else \ echo "$@: OVERALL-UPDATED: You may now want to:"; \ echo " make spellcheck-interactive-quick"; \ echo " git add -p $${FILES} && git commit -sm 'Update NUT documentation sources with current docs/asciidoc-vars.conf: $${USEDREV_NOSUBJ}'"; \ fi; \ ) check-NIT check-NIT-devel check-NIT-sandbox check-NIT-sandbox-devel: +cd $(builddir)/tests/NIT && $(MAKE) $(AM_MAKEFLAGS) $@ VERSION_DEFAULT: dummy-stamp @abs_top_srcdir='$(abs_top_srcdir)' ; \ abs_top_builddir='$(abs_top_builddir)' ; \ export abs_top_srcdir ; export abs_top_builddir ; \ NUT_VERSION_QUERY=UPDATE_FILE '$(abs_top_srcdir)/tools/gitlog2version.sh' # Best-effort delivery for (overly?) customized distros, e.g. via # echo NUT_VERSION_FORCED_SEMVER=1.1.1 > VERSION_FORCED_SEMVER dist-hook: for D in "$(abs_top_srcdir)" "$(abs_top_builddir)" ; do \ for F in VERSION_FORCED VERSION_FORCED_SEMVER ; do \ if [ -s "$$D/$$F" ] ; then \ cat "$$D/$$F" > "$(top_distdir)/$$F" || true ; \ fi ; \ done ; \ done # This target adds syntax-checking for committed shell script files, # to avoid surprises and delays in finding fatal typos after packaging ### ### Note: currently, shellcheck target calls check-scripts-syntax ### so when both are invoked at once, in the end the check is only ### executed once. Later it is anticipated that shellcheck would ### be implemented by requiring, configuring and calling the tool ### named "shellcheck" for even more code inspection and details. ### Still, there remains value in also checking the script syntax ### by the very version of the shell interpreter that would run ### these scripts in production usage of the resulting packages. ### check-scripts-syntax: @echo 'NOTE: modern bash complains about scripts using backticks (warning not error), which we ignore in NUT codebase for portability reasons: `...` obsolete, use $$(...)' @RUNBASH=bash; if [ -x /bin/bash ] && /bin/bash -c 'echo $${BASH_VERSION}' | grep -E '^[456789]\.' ; then RUNBASH=/bin/bash ; else if [ -x /usr/bin/env ] ; then RUNBASH="/usr/bin/env bash"; fi; fi ; \ for F in `git ls-files || find . -type f` ; do \ case "`file "$$F"`" in \ *"Bourne-Again shell script"*) ( set -x ; $$RUNBASH -n "$$F" ; ) ;; \ *"POSIX shell script"*|*"shell script"*) ( set -x ; /bin/sh -n "$$F" ; ) ;; \ esac || { RES=$$? ; echo "ERROR: Syntax check failed for script file: $$F" >&2 ; exit $$RES ; } ; \ done @echo 'SUCCESS: Shell scripts syntax is acceptable, no fatal issues were found' shellcheck-disclaimer: @echo "===============================================================================" @echo "NOTICE: 'make shellcheck' is currently an alias for 'make check-scripts-syntax'" @echo "Later it may become a call to the real shellcheck tool (if available on the" @echo "build system during the configure phase)" @echo "===============================================================================" # Note: currently not part of shellcheck target, because the script below # can test the logic with numerous SHELL_PROGS in a CI setting, and because # check-scripts-syntax probably has checked the basic syntax above already. shellcheck-nde: cd $(srcdir)/tests && SERVICE_FRAMEWORK="selftest" ./nut-driver-enumerator-test.sh shellcheck: shellcheck-disclaimer check-scripts-syntax @HAVE_CPPCHECK_TRUE@cppcheck: cppcheck-cxx11.xml cppcheck-c99.xml # CPPCHECK_SRC_CXX += $(top_srcdir)/*.cpp $(top_srcdir)/*/*/*.cpp @HAVE_CPPCHECK_TRUE@cppcheck-cxx11.xml: $(CPPCHECK_SRC_CXX) $(CPPCHECK_SRC_H) @HAVE_CPPCHECK_TRUE@ $(CPPCHECK) --std=c++11 --enable=all --inconclusive --xml --xml-version=2 . 2>$@ @HAVE_CPPCHECK_TRUE@cppcheck-c99.xml: $(CPPCHECK_SRC_C) $(CPPCHECK_SRC_H) @HAVE_CPPCHECK_TRUE@ $(CPPCHECK) --std=c99 --enable=all --inconclusive --xml --xml-version=2 . 2>$@ @HAVE_CPPCHECK_FALSE@cppcheck: @HAVE_CPPCHECK_FALSE@ @echo "CPPCHECK analysis not available since 'cppcheck' was not found." sockdebug: +cd $(builddir)/server && $(MAKE) $(AM_MAKEFLAGS) sockdebug$(EXEEXT) # Force ChangeLog regeneration upon make dist (due to nonexistant 'dummy-stamp'), # in case it has already been generated previously # Note that the script is hard-coded to inspect Git workspace which contains # the current dir, and defaults to generate a "ChangeLog" in the current dir. # The script itself is generated from a template, so resides in builddir. dummy-stamp: ChangeLog: dummy-stamp +@$(MAKE) $(AM_MAKEFLAGS) $(abs_top_builddir)/ChangeLog $(abs_top_builddir)/ChangeLog: tools/gitlog2changelog.py dummy-stamp @cd $(abs_top_srcdir) && \ if test -e .git ; then \ NUT_GITDIR=".git" ; if test -r "$${NUT_GITDIR}" -a ! -d "$${NUT_GITDIR}" ; then GD="`grep -E '^gitdir:' "$${NUT_GITDIR}" | sed 's/^gitdir: *//'`" && test -n "$$GD" -a -d "$$GD" && NUT_GITDIR="$$GD" ; fi ; \ if test -s "$@" -a -d "$${NUT_GITDIR}" && test -z "`find "$${NUT_GITDIR}" -newer "$@" 2>/dev/null`" ; then \ echo " DOC-CHANGELOG-GENERATE $@ : SKIP (keep existing)" ; \ echo "Using still-valid ChangeLog file generated earlier from same revision of Git source metadata in '$${NUT_GITDIR}'" >&2 ; \ else \ if test -s "$@" ; then \ echo " DOC-CHANGELOG-GENERATE $@ : RE-GENERATE (older than Git workspace metadata) ..." ; \ else \ echo " DOC-CHANGELOG-GENERATE $@ : GENERATE (currently absent) ..." ; \ fi ; \ CHANGELOG_FILE="$@" $(WITH_PDF_NONASCII_TITLES_ENVVAR) \ CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR="$(CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR_ENVVAR)" \ $(abs_top_builddir)/tools/gitlog2changelog.py $(GITLOG_START_POINT) \ && { echo " DOC-CHANGELOG-GENERATE $@ : SUCCESS"; } \ || { \ echo " DOC-CHANGELOG-GENERATE $@ : FAILED (non-fatal)" >&2 ; \ printf "gitlog2changelog.py failed to generate the ChangeLog.\n\nNOTE: See https://github.com/networkupstools/nut/commits/master for change history.\n\n" > "$@" ; \ } ; \ fi ; \ else \ if test x"$(abs_top_srcdir)" != x"$(abs_top_builddir)" -a -s ./ChangeLog ; then \ echo " DOC-CHANGELOG-GENERATE $@ : SKIP (keep existing)" ; \ if ! diff ./ChangeLog "$@" >/dev/null 2>/dev/null ; then \ echo "Using distributed ChangeLog file from sources (and builddir is not srcdir)" >&2 ; \ rm -f "$@" || true ; \ cp -pf ./ChangeLog "$@" || { cat ./ChangeLog > "$@" ; touch -r ./ChangeLog "$@" || true ; } ; \ else \ echo "Using distributed ChangeLog file from sources (and builddir already has content identical to one in srcdir)" >&2 ; \ fi ; \ else \ if test -s "$@" ; then \ echo " DOC-CHANGELOG-GENERATE $@ : SKIP (keep existing)" ; \ echo "Using distributed ChangeLog file from sources (and builddir is srcdir)" >&2 ; \ else \ echo " DOC-CHANGELOG-GENERATE $@ : FAILED (non-fatal)" >&2 ; \ printf "Failed to generate the ChangeLog.\n\nNOTE: See https://github.com/networkupstools/nut/commits/master for change history.\n\n" > "$@" ; \ fi ; \ fi ; \ fi ChangeLog.adoc: ChangeLog +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) ../ChangeLog.adoc nut_version.h include/nut_version.h: +cd $(abs_top_builddir)/include && $(MAKE) $(AM_MAKEFLAGS) nut_version.h tools/gitlog2changelog.py: tools/gitlog2changelog.py.in +cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) -s $(@F) # ---------------------------------------------------------------------- # Maintainers targets: distribution signature and hashes # Assume tools are available (and maintainer GPG keys) dist-files: dist dist-sig dist-hash nut-@PACKAGE_VERSION@.tar.gz: dist nut-@PACKAGE_VERSION@.tar.gz.sig: dist-sig nut-@PACKAGE_VERSION@.tar.gz.md5 nut-@PACKAGE_VERSION@.tar.gz.sha256: dist-hash dist-sig: nut-@PACKAGE_VERSION@.tar.gz rm -f nut-@PACKAGE_VERSION@.tar.gz.sig gpg --detach-sign nut-@PACKAGE_VERSION@.tar.gz dist-hash: nut-@PACKAGE_VERSION@.tar.gz md5sum nut-@PACKAGE_VERSION@.tar.gz > nut-@PACKAGE_VERSION@.tar.gz.md5 sha256sum nut-@PACKAGE_VERSION@.tar.gz > nut-@PACKAGE_VERSION@.tar.gz.sha256 build: @echo $(WARN) @echo "Warning: 'make build' is deprecated. Use 'make all' instead." @echo $(WARN) +$(MAKE) $(AM_MAKEFLAGS) all install-bin: @echo $(WARN) @echo "Warning: 'make install-bin' is deprecated." @echo "Use 'make install-exec' instead for a similar effect." @echo $(WARN) +cd common; $(MAKE) $(AM_MAKEFLAGS) install +cd drivers; $(MAKE) $(AM_MAKEFLAGS) install +cd server; $(MAKE) $(AM_MAKEFLAGS) install +cd clients; $(MAKE) $(AM_MAKEFLAGS) install install-man: install-data-recursive @echo $(WARN) @echo "Warning: 'make install-man' is deprecated." @echo "Use 'cd docs/man; make install' instead." @echo $(WARN) +cd docs/man; $(MAKE) $(AM_MAKEFLAGS) install install-conf: @echo $(WARN) @echo "Warning: 'make install-conf' is deprecated." @echo "Use 'cd conf; make install' instead." @echo $(WARN) +cd conf; $(MAKE) $(AM_MAKEFLAGS) install # The target install-data already has a standardized meaning under automake install-dirs: @echo $(WARN) @echo "Warning: 'make install-dirs' is deprecated." @echo "Use 'make installdirs' instead." @echo $(WARN) +$(MAKE) $(AM_MAKEFLAGS) installdirs cgi build-cgi install-cgi install-cgi-dir install-cgi-bin \ install-cgi-man install-cgi-conf install-cgi-html: @echo "Error: 'make $@' no longer exists." @echo "Use './configure --with-cgi' instead." install-lib: @echo "Error: 'make $@' no longer exists." @echo "Use './configure --with-dev' instead." usb build-usb install-usb: @echo "Error: 'make $@' no longer exists." @echo "Use './configure --with-usb' instead." snmp build-snmp install-snmp install-snmp-mgr install-snmp-man: @echo "Error: 'make $@' no longer exists." @echo "Use './configure --with-snmp' instead." setver: @echo "Error: 'make setver' no longer exists." @echo "Edit configure.ac to set version number." # Adjust permissions when installing as `root` into the actual system. # We honour DESTDIR anyway, as someone can install into a chroot etc. # NOTE: Might be an 'install-data-hook' (for dirs) and/or 'install-exec-hook' # (for service restart) but better not force this on everyone? # It is also up to the end-user making such an installation to remove (or not) # dirs and files made below. # To err on the safe side in cross builds, we ignore Windows builds and those # not built for the same system as the build host. install-data-hook: @case "@target_os@" in *mingw*) exit 0;; esac ; \ if [ x"@host_os@" != x"@build_os@" ]; then exit 0 ; fi ; \ if [ x"@target_os@" != x"@build_os@" ]; then exit 0 ; fi ; \ if (command -v id) && [ x"`id -u`" = x0 ] && [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \ echo "================================================================================" >&2 ; \ echo "| NUT data files have been installed into the system, now consider running |" >&2 ; \ echo "| '(sudo) make install-as-root' to apply permissions and service state changes |" >&2 ; \ echo "================================================================================" >&2 ; \ fi # TODO: Actually move this into scripts like Solaris/postinstall # using OS-specific `useradd`/`groupadd`, etc. # Note that as we stop services, we may be dealing with (older) # distros that do not follow current naming in NUT code base. install-as-root: @+echo "$@: starting (no-op if not root)" >&2 ; \ case "@target_os@" in *mingw*) echo "$@: SKIP: not supported for this target_os='@target_os@'" >&2 ; exit 0;; esac ; \ if [ x"@host_os@" != x"@build_os@" ]; then echo "$@: SKIP: build_os='@build_os@' is not host_os='@host_os@'" >&2 ; exit 0 ; fi ; \ if [ x"@target_os@" != x"@build_os@" ]; then echo "$@: SKIP: build_os='@build_os@' is not target_os='@target_os@'" >&2 ; exit 0 ; fi ; \ if (command -v id) && [ x"`id -u`" = x0 ] ; then \ echo "$@: we seem to be root, PROCEEDING" >&2 ; \ else \ echo "$@: SKIP: we seem to NOT be root" >&2 ; \ exit 0 ; \ fi ; \ prefix="@prefix@"; \ if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \ if $(HAVE_SYSTEMD) ; then \ echo "$@: Stop NUT services, if any" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-monitor.service nut-server.service || true ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-driver.service || true ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-driver.target || true ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-udev-settle.service || true ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut.target || true ; \ fi ; \ if $(WITH_SOLARIS_SMF) || $(WITH_SOLARIS_INIT) ; then \ if $(WITH_SOLARIS_SMF) ; then \ echo "$@: Stop NUT services, if any" >&2 ; \ SMF_ACTIVE="`/usr/bin/svcs -a -Hostate,fmri | grep svc:/system/power/ | grep -v disabled | awk '{print $$2}'`" ; \ for S in $$SMF_ACTIVE ; do \ /usr/sbin/svcadm disable -ts $$S || true ; \ done ; \ fi ; \ $(top_builddir)/scripts/Solaris/preremove \ || exit ; \ fi ; \ fi ; \ $(MAKE) $(AM_FLAGS) DESTDIR="$(DESTDIR)" install || exit ; \ if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \ if $(WITH_SOLARIS_SMF) || $(WITH_SOLARIS_INIT) ; then \ $(top_builddir)/scripts/Solaris/preinstall && \ $(top_builddir)/scripts/Solaris/postinstall ; \ exit ; \ fi ; \ fi ; \ echo " MKDIR $(DESTDIR)/@STATEPATH@ $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \ $(MKDIR_P) "$(DESTDIR)/@STATEPATH@/upssched" && \ for D in "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" "@CONFPATH@" ; do \ case x"$$D" in \ x|x@*) ;; \ *) echo " MKDIR $(DESTDIR)/$$D" >&2 ; \ $(MKDIR_P) "$(DESTDIR)/$$D" \ || exit ;; \ esac ; \ done ; \ if (command -v chmod) ; then \ echo " CHMOD(0770) $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \ chmod 0770 "$(DESTDIR)/@STATEPATH@/upssched" \ || exit ; \ for D in "@STATEPATH@" "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" ; do \ case x"$$D" in \ x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \ *) echo " CHMOD(0770) $(DESTDIR)/$$D" >&2 ; \ chmod 0770 "$(DESTDIR)/$$D" \ || exit ;; \ esac ; \ done ; \ case x"@CONFPATH@" in \ x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \ *) echo " CHMOD(0751) $(DESTDIR)/@CONFPATH@" >&2 ; \ chmod 0751 "$(DESTDIR)/@CONFPATH@" \ || exit ;; \ esac ; \ for F in hosts.conf.sample upsstats-single.html.sample upsstats.html.sample upsset.conf.sample ; do \ echo " CHMOD(0644) CGI: $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \ chmod 0644 "$(DESTDIR)/@CONFPATH@/$$F" \ || { if $(WITH_CGI) ; then exit 1 ; else true ; fi ; } ; \ done ; \ for F in nut.conf.sample ups.conf.sample upsd.conf.sample upsd.users.sample upsmon.conf.sample upssched.conf.sample ; do \ echo " CHMOD(0640) $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \ chmod 0640 "$(DESTDIR)/@CONFPATH@/$$F" \ || exit ; \ done ; \ else \ echo "$@: WARNING: Can not CHMOD created locations!" >&2 ; \ fi ; \ if (command -v chown) && test 0 -lt "`id -u '@RUN_AS_USER@'`" \ && ( test 0 -lt "`getent group '@RUN_AS_GROUP@' | awk -F: '{print $$3}'`" || test 0 -lt "`id -g '@RUN_AS_GROUP@'`" ) \ ; then \ echo " CHOWN(@RUN_AS_USER@:@RUN_AS_GROUP@) $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \ chown "@RUN_AS_USER@:@RUN_AS_GROUP@" "$(DESTDIR)/@STATEPATH@/upssched" \ || exit ; \ for D in "@STATEPATH@" "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" ; do \ case x"$$D" in \ x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \ *) echo " CHOWN(@RUN_AS_USER@:@RUN_AS_GROUP@) $(DESTDIR)/$$D" >&2 ; \ chown "@RUN_AS_USER@:@RUN_AS_GROUP@" "$(DESTDIR)/$$D" \ || exit ;; \ esac ; \ done ; \ case x"@CONFPATH@" in \ x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \ *) echo " CHOWN(root:@RUN_AS_GROUP@) $(DESTDIR)/@CONFPATH@" >&2 ; \ chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@" \ || exit ;; \ esac ; \ for F in hosts.conf.sample upsstats-single.html.sample upsstats.html.sample upsset.conf.sample ; do \ echo " CHOWN(root:@RUN_AS_GROUP@) CGI: $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \ chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@/$$F" \ || { if $(WITH_CGI) ; then exit 1 ; else true ; fi ; } ; \ done ; \ for F in nut.conf.sample ups.conf.sample upsd.conf.sample upsd.users.sample upsmon.conf.sample upssched.conf.sample ; do \ echo " CHOWN(root:@RUN_AS_GROUP@) $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \ chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@/$$F" \ || exit ; \ done ; \ else \ echo "$@: WARNING: Can not CHOWN created locations!" >&2 ; \ fi ; \ if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \ applied_udev=false ; \ if $(HAVE_SYSTEMD) ; then \ echo "$@: Activate default systemd layout, restart services:" >&2 ; \ if $(WITH_SYSTEMD_TMPFILES) ; then \ echo "$@: Apply systemd-tmpfiles presets" >&2 ; \ @SYSTEMD_TMPFILES_PROGRAM@ --create || exit ; \ fi ; \ echo "$@: Learn systemd definition changes" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ daemon-reload || exit ; \ if $(WITH_SYSTEMD_PRESET) ; then \ echo "$@: Apply systemd enabled/disabled service presets" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ preset-all || exit ; \ else \ echo "$@: Apply systemd enabled/disabled service defaults" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ disable nut.target nut-driver.target nut-udev-settle.service nut-monitor nut-server nut-driver-enumerator.path nut-driver-enumerator.service || exit ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ enable nut.target nut-driver.target nut-udev-settle.service nut-monitor nut-server nut-driver-enumerator.path nut-driver-enumerator.service || exit ; \ fi ; \ echo "$@: Reconfigure nut-driver-enumerator (service instance wrapping)" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ restart udev && applied_udev=true || true ; \ $(top_builddir)/scripts/upsdrvsvcctl/nut-driver-enumerator.sh --reconfigure || { RES=$$?; if [ $$RES != 42 ] ; then exit $$RES ; fi ; } ; \ echo "$@: Restart NUT services" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ restart nut-driver-enumerator.service nut-monitor.service nut-server.service || exit ; \ fi ; \ if ! $${applied_udev} && (command -v udevadm); then \ udevadm control --reload-rules && udevadm trigger && applied_udev=true || true ; \ fi ; \ fi ; \ echo "$@: finished SUCCESSFULLY" >&2 package: dist +DESTDIR="$(abs_builddir)/_install_pkgprotodir" ; export DESTDIR; \ rm -rf "$$DESTDIR"; \ case "`uname -s`" in \ "HP-UX") \ ( cd scripts/HP-UX && \ $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$DESTDIR" package && \ mv NUT_HPUX_package.depot $(abs_top_builddir)/NUT_HPUX_package-@PACKAGE_VERSION@.depot ) ;; \ "SunOS") \ $(MAKE) $(AM_MAKEFLAGS) && \ $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$DESTDIR" install && \ ( cd scripts/Solaris && \ $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$DESTDIR" package ) && \ $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$DESTDIR" uninstall && \ rm -rf "$$DESTDIR" || \ { echo "FAILED to produce SunOS packages, inspect '$$DESTDIR' for clues" >&2 ; exit 1; } ;; \ "AIX") \ if test -d /usr/src/packages/SPECS -a -w /usr/src/packages/SPECS ; then : ; else echo "Can not write to /usr/src/packages/SPECS" >&2 ; exit 1; fi ; \ if test -d /usr/src/packages/SOURCES -a -w /usr/src/packages/SOURCES ; then : ; else echo "Can not write to /usr/src/packages/SOURCES" >&2 ; exit 1; fi ; \ $(MAKE) $(AM_MAKEFLAGS) dist && \ cp scripts/Aix/nut-aix.spec /usr/src/packages/SPECS && \ cp scripts/Aix/nut.init nut-@PACKAGE_VERSION@.tar.gz /usr/src/packages/SOURCES && \ rpm -ba /usr/src/packages/SPECS/nut-aix.spec && \ mv /usr/src/packages/RPMS/nut*rpm $(abs_top_builddir)/ ;; \ *) echo "Unsupported OS for 'make $@' (no recipe bound)" >&2; exit 1;; \ esac # Steam-roll over all executables/libs we have placed in DESTDIR and copy over # any resolved dependencies from the cross-build (or native MSYS2) environment. # Then hardlink libraries for sbin... (alternative: all bins in one dir) # TOTHINK: Are there more dirs to consider? So far we cover bindir, sbindir and # driverexecdir (e.g. some Linux distros place drivers to /lib/nut while tools # and daemons are in /usr/bin and /usr/sbin), and cgiexecdir, and occasional # helpers like "sockdebug.exe" in libexecdir; anything else?.. # Note we hold existance of cgiexecdir as optional, but the name is expected to # be defined. Other dirs are "just assumed" to exist (that we are not packaging # some NUT build without drivers/tools/daemons). Subject to change if needed. # Currently this is handled by a CHECKING... step that should fail if it hits # anything. @HAVE_WINDOWS_TRUE@install-win-bundle: all @HAVE_WINDOWS_TRUE@ @if test -z "$(DESTDIR)" ; then echo "ERROR: '$@': Bundle may only be installed to some DESTDIR prototype area'" >&2 ; exit 1; fi @HAVE_WINDOWS_TRUE@ +$(MAKE) $(AM_MAKEFLAGS) DESTDIR='$(DESTDIR)' install @HAVE_WINDOWS_TRUE@ +$(MAKE) $(AM_MAKEFLAGS) DESTDIR='$(DESTDIR)' install-win-bundle-thirdparty @HAVE_WINDOWS_TRUE@install-win-bundle-thirdparty: @HAVE_WINDOWS_TRUE@ @if test -z "$(DESTDIR)" ; then echo "ERROR: '$@': Bundle may only be installed to some DESTDIR prototype area'" >&2 ; exit 1; fi @HAVE_WINDOWS_TRUE@ @echo "Searching which DLLs need to be bundled with NUT for Windows..." >&2 @HAVE_WINDOWS_TRUE@ @if test -z "$$ARCH" ; then \ @HAVE_WINDOWS_TRUE@ if test -n "$(target)" ; then \ @HAVE_WINDOWS_TRUE@ ARCH='$(target)' \ @HAVE_WINDOWS_TRUE@ ; else \ @HAVE_WINDOWS_TRUE@ if test -n "$(target_triplet)" ; then ARCH='$(target_triplet)' ; fi ; \ @HAVE_WINDOWS_TRUE@ fi ; \ @HAVE_WINDOWS_TRUE@ fi ; \ @HAVE_WINDOWS_TRUE@ if test -n "$$ARCH" ; then export ARCH ; fi ; \ @HAVE_WINDOWS_TRUE@ DESTDIR='$(DESTDIR)' ; export DESTDIR ; \ @HAVE_WINDOWS_TRUE@ ( cd '$(DESTDIR)' || exit ; \ @HAVE_WINDOWS_TRUE@ DESTDIR="" '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ @HAVE_WINDOWS_TRUE@ | while read D ; do \ @HAVE_WINDOWS_TRUE@ echo " DLL->bin $$D" 2>&1 ; \ @HAVE_WINDOWS_TRUE@ cp -pf "$$D" './$(bindir)/' ; \ @HAVE_WINDOWS_TRUE@ done ; \ @HAVE_WINDOWS_TRUE@ ) || exit ; \ @HAVE_WINDOWS_TRUE@ ( if test x"$(bindir)" = x"$(sbindir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ cd '$(DESTDIR)/$(sbindir)' || exit ; \ @HAVE_WINDOWS_TRUE@ '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ @HAVE_WINDOWS_TRUE@ | while read D ; do \ @HAVE_WINDOWS_TRUE@ echo " DLL->sbin $$D" 2>&1 ; \ @HAVE_WINDOWS_TRUE@ ln -f '$(DESTDIR)/$(bindir)'/"`basename "$$D"`" ./ ; \ @HAVE_WINDOWS_TRUE@ done ; \ @HAVE_WINDOWS_TRUE@ ) || exit ; \ @HAVE_WINDOWS_TRUE@ ( if test x"$(driverexecdir)" = x"$(bindir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ if test x"$(driverexecdir)" = x"$(sbindir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ cd '$(DESTDIR)/$(driverexecdir)' || exit ; \ @HAVE_WINDOWS_TRUE@ '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ @HAVE_WINDOWS_TRUE@ | while read D ; do \ @HAVE_WINDOWS_TRUE@ echo " DLL->drv $$D" 2>&1 ; \ @HAVE_WINDOWS_TRUE@ ln -f '$(DESTDIR)/$(bindir)'/"`basename "$$D"`" ./ ; \ @HAVE_WINDOWS_TRUE@ done ; \ @HAVE_WINDOWS_TRUE@ ) || exit ; \ @HAVE_WINDOWS_TRUE@ ( if test -z "$(cgiexecdir)" -o ! -d "$(DESTDIR)/$(cgiexecdir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ if test x"$(cgiexecdir)" = x"$(bindir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ if test x"$(cgiexecdir)" = x"$(sbindir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ if test x"$(driverexecdir)" = x"$(cgiexecdir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ cd '$(DESTDIR)/$(cgiexecdir)' || exit ; \ @HAVE_WINDOWS_TRUE@ '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ @HAVE_WINDOWS_TRUE@ | while read D ; do \ @HAVE_WINDOWS_TRUE@ echo " DLL->cgi $$D" 2>&1 ; \ @HAVE_WINDOWS_TRUE@ ln -f '$(DESTDIR)/$(bindir)'/"`basename "$$D"`" ./ ; \ @HAVE_WINDOWS_TRUE@ done ; \ @HAVE_WINDOWS_TRUE@ ) || exit ; \ @HAVE_WINDOWS_TRUE@ ( if test x"$(libexecdir)" = x"$(bindir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ if test x"$(libexecdir)" = x"$(sbindir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ if test x"$(libexecdir)" = x"$(driverexecdir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ if test x"$(libexecdir)" = x"$(cgiexecdir)" ; then exit 0 ; fi ; \ @HAVE_WINDOWS_TRUE@ cd '$(DESTDIR)/$(libexecdir)' || exit ; \ @HAVE_WINDOWS_TRUE@ '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ @HAVE_WINDOWS_TRUE@ | while read D ; do \ @HAVE_WINDOWS_TRUE@ echo " DLL->libexec $$D" 2>&1 ; \ @HAVE_WINDOWS_TRUE@ ln -f '$(DESTDIR)/$(bindir)'/"`basename "$$D"`" ./ ; \ @HAVE_WINDOWS_TRUE@ done ; \ @HAVE_WINDOWS_TRUE@ ) || exit @HAVE_WINDOWS_TRUE@ @echo "CHECKING if any executable files were installed to locations other than those covered by this recipe, so might not have needed DLLs bundled near them" >&2 ; \ @HAVE_WINDOWS_TRUE@ relbindir="`echo './$(bindir)/' | sed 's,//*,/,g'`" ; \ @HAVE_WINDOWS_TRUE@ relsbindir="`echo './$(sbindir)/' | sed 's,//*,/,g'`" ; \ @HAVE_WINDOWS_TRUE@ reldriverexecdir="`echo './$(driverexecdir)/' | sed 's,//*,/,g'`" ; \ @HAVE_WINDOWS_TRUE@ relcgiexecdir="`echo './$(cgiexecdir)/' | sed 's,//*,/,g'`" ; \ @HAVE_WINDOWS_TRUE@ rellibexecdir="`echo './$(libexecdir)/' | sed 's,//*,/,g'`" ; \ @HAVE_WINDOWS_TRUE@ cd '$(DESTDIR)' || exit ; \ @HAVE_WINDOWS_TRUE@ find . -type f | grep -Ei '\.(exe|dll)$$' \ @HAVE_WINDOWS_TRUE@ | grep -vE "^($${relbindir}|$${relsbindir}|$${reldriverexecdir}|$${relcgiexecdir}|$${rellibexecdir})" \ @HAVE_WINDOWS_TRUE@ | ( RES=0 ; while IFS= read LINE ; do echo "$$LINE" ; RES=1; done; exit $$RES ) @HAVE_WINDOWS_FALSE@install-win-bundle: @HAVE_WINDOWS_FALSE@ @echo " SKIP '$@' : not enabled for current build configuration" @HAVE_WINDOWS_FALSE@install-win-bundle-thirdparty: @HAVE_WINDOWS_FALSE@ @echo " SKIP '$@' : not enabled for current build configuration" print-MAINTAINERCLEANFILES print-REALCLEANFILES: @echo $(MAINTAINERCLEANFILES) print-DISTCLEANFILES: @echo $(DISTCLEANFILES) # TODO: Recursive mode to consider patterns defined in sub-dir makefiles git-realclean-check: @if test -e .git && (command -v git); then \ git status --ignored || while read F ; do \ for P in $(MAINTAINERCLEANFILES) ; do \ case "$$F" in \ */$$P) exit 1 ;; \ esac ; \ done; \ done ; \ fi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/INSTALL0000644000200500020050000003661415001555010010272 00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command './configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the 'README' file for instructions specific to this package. Some packages provide this 'INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. 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, and a file 'config.log' containing compiler output (useful mainly for debugging 'configure'). It can also use an optional file (typically called 'config.cache' and enabled with '--cache-file=config.cache' or simply '-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. 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 you are using the cache, and at some point 'config.cache' contains results you don't want to keep, you may remove or edit it. The file 'configure.ac' (or 'configure.in') is used to create 'configure' by a program called 'autoconf'. You need 'configure.ac' 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. Running 'configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type 'make' to compile the package. 3. Optionally, type 'make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type 'make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the 'make install' phase executed with root privileges. 5. Optionally, type 'make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior 'make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing 'make clean'. To also remove the files that 'configure' created (so you can compile the package for a different kind of computer), type 'make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type 'make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide 'make distcheck', which can by used by developers to test that all other targets like 'make install' and 'make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the 'configure' script does not know about. Run './configure --help' for details on some of the pertinent environment variables. You can give 'configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. 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 can use 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 '..'. This is known as a "VPATH" build. With a non-GNU 'make', it is safer 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. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple '-arch' options to the compiler but only a single '-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the 'lipo' tool if you have problems. Installation Names ================== By default, 'make install' installs the package's commands under '/usr/local/bin', include files under '/usr/local/include', etc. You can specify an installation prefix other than '/usr/local' by giving 'configure' the option '--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option '--exec-prefix=PREFIX' to 'configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like '--bindir=DIR' to specify different values for particular kinds of files. Run 'configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of '${prefix}', so that specifying just '--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to 'configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the 'make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, 'make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of '${prefix}'. Any directories that were specified during 'configure', but not in terms of '${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the 'DESTDIR' variable. For example, 'make install DESTDIR=/alternate/directory' will prepend '/alternate/directory' before all installation names. The approach of 'DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of '${prefix}' at 'configure' time. Optional Features ================= 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'. 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. Some packages offer the ability to configure how verbose the execution of 'make' will be. For these packages, running './configure --enable-silent-rules' sets the default to minimal output, which can be overridden with 'make V=1'; while running './configure --disable-silent-rules' sets the default to verbose, which can be overridden with 'make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX 'make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its '' header file. The option '-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put '/usr/ucb' early in your 'PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in '/usr/bin'. So, if you need '/usr/ucb' in your 'PATH', put it _after_ '/usr/bin'. On Haiku, software installed for all users goes in '/boot/common', not '/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features 'configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, 'configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the '--build=TYPE' option. TYPE can either be a short name for the system type, such as 'sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS 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 machine type. If you are _building_ compiler tools for cross-compiling, you should use the option '--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with '--host=TYPE'. 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. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to 'configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the 'configure' command line, using 'VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified 'gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 'configure' Invocation ====================== 'configure' recognizes the following options to control how it operates. '--help' '-h' Print a summary of all of the options to 'configure', and exit. '--help=short' '--help=recursive' Print a summary of the options unique to this package's 'configure', and exit. The 'short' variant lists options used only in the top level, while the 'recursive' variant lists options also present in any nested packages. '--version' '-V' Print the version of Autoconf used to generate the 'configure' script, and exit. '--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally 'config.cache'. FILE defaults to '/dev/null' to disable caching. '--config-cache' '-C' Alias for '--cache-file=config.cache'. '--quiet' '--silent' '-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to '/dev/null' (any error messages will still be shown). '--srcdir=DIR' Look for the package's source code in directory DIR. Usually 'configure' can determine that directory automatically. '--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. '--no-create' '-n' Run the configure checks, but stop before creating any output files. 'configure' also accepts some other, not widely useful, options. Run 'configure --help' for more details. nut-2.8.3/VERSION_FORCED_SEMVER0000644000200500020050000000004215001555413012405 00000000000000NUT_VERSION_FORCED_SEMVER='2.8.3' nut-2.8.3/aclocal.m40000644000200500020050000016207715001555006011111 00000000000000# generated automatically by aclocal 1.16.3 -*- Autoconf -*- # Copyright (C) 1996-2020 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) 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 ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have 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_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. 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 ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl 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 $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$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 AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [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])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [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 .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR # Copyright (C) 2002-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # Copyright (C) 2011-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_AR([ACT-IF-FAIL]) # ------------------------- # Try to determine the archiver interface, and trigger the ar-lib wrapper # if it is needed. If the detection of archiver interface fails, run # ACT-IF-FAIL (default is to abort configure with a proper error message). AC_DEFUN([AM_PROG_AR], [AC_BEFORE([$0], [LT_INIT])dnl AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([ar-lib])dnl AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) : ${AR=ar} AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], [AC_LANG_PUSH([C]) am_cv_ar_interface=ar AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a ]) AC_LANG_POP([C])]) case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) m4_default([$1], [AC_MSG_ERROR([could not determine $AR interface])]) ;; esac AC_SUBST([AR])dnl ]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_COND_IF -*- Autoconf -*- # Copyright (C) 2008-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_COND_IF # _AM_COND_ELSE # _AM_COND_ENDIF # -------------- # These macros are only used for tracing. m4_define([_AM_COND_IF]) m4_define([_AM_COND_ELSE]) m4_define([_AM_COND_ENDIF]) # AM_COND_IF(COND, [IF-TRUE], [IF-FALSE]) # --------------------------------------- # If the shell condition COND is true, execute IF-TRUE, otherwise execute # IF-FALSE. Allow automake to learn about conditional instantiating macros # (the AC_CONFIG_FOOS). AC_DEFUN([AM_COND_IF], [m4_ifndef([_AM_COND_VALUE_$1], [m4_fatal([$0: no such condition "$1"])])dnl _AM_COND_IF([$1])dnl if test -z "$$1_TRUE"; then : m4_n([$2])[]dnl m4_ifval([$3], [_AM_COND_ELSE([$1])dnl else $3 ])dnl _AM_COND_ENDIF([$1])dnl fi[]dnl ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAINTAINER_MODE([DEFAULT-MODE]) # ---------------------------------- # Control maintainer-specific portions of Makefiles. # Default is to disable them, unless 'enable' is passed literally. # For symmetry, 'disable' may be passed as well. Anyway, the user # can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], [m4_case(m4_default([$1], [disable]), [enable], [m4_define([am_maintainer_other], [disable])], [disable], [m4_define([am_maintainer_other], [enable])], [m4_define([am_maintainer_other], [enable]) m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode's default is 'disable' unless 'enable' is passed AC_ARG_ENABLE([maintainer-mode], [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], am_maintainer_other[ make rules and dependencies not useful (and sometimes confusing) to the casual installer])], [USE_MAINTAINER_MODE=$enableval], [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST([MAINT])dnl ] ) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/ax_c___attribute__.m4]) m4_include([m4/ax_c_pragmas.m4]) m4_include([m4/ax_check_compile_flag.m4]) m4_include([m4/ax_compare_version.m4]) m4_include([m4/ax_realpath.m4]) m4_include([m4/ax_realpath_lib.m4]) m4_include([m4/ax_run_or_link_ifelse.m4]) m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) m4_include([m4/nut_arg_with.m4]) m4_include([m4/nut_check_asciidoc.m4]) m4_include([m4/nut_check_aspell.m4]) m4_include([m4/nut_check_bool.m4]) m4_include([m4/nut_check_cppcheck.m4]) m4_include([m4/nut_check_headers_windows.m4]) m4_include([m4/nut_check_libavahi.m4]) m4_include([m4/nut_check_libfreeipmi.m4]) m4_include([m4/nut_check_libgd.m4]) m4_include([m4/nut_check_libgpiod.m4]) m4_include([m4/nut_check_libltdl.m4]) m4_include([m4/nut_check_libmodbus.m4]) m4_include([m4/nut_check_libneon.m4]) m4_include([m4/nut_check_libnetsnmp.m4]) m4_include([m4/nut_check_libnss.m4]) m4_include([m4/nut_check_libopenssl.m4]) m4_include([m4/nut_check_libpowerman.m4]) m4_include([m4/nut_check_libregex.m4]) m4_include([m4/nut_check_libsystemd.m4]) m4_include([m4/nut_check_libusb.m4]) m4_include([m4/nut_check_libwrap.m4]) m4_include([m4/nut_check_os.m4]) m4_include([m4/nut_check_pkgconfig.m4]) m4_include([m4/nut_check_python.m4]) m4_include([m4/nut_check_socketlib.m4]) m4_include([m4/nut_compiler_family.m4]) m4_include([m4/nut_func_getnameinfo_argtypes.m4]) m4_include([m4/nut_report_feature.m4]) m4_include([m4/nut_stash_warnings.m4]) m4_include([m4/nut_type_socklen_t.m4]) nut-2.8.3/test-driver0000755000200500020050000001112715001555011011430 00000000000000#! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2018-03-07.03; # UTC # Copyright (C) 2011-2020 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, 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 file is maintained in Automake, please report # bugs to or send patches to # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <$log_file 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then tweaked_estatus=1 else tweaked_estatus=$estatus fi case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report the test outcome and exit status in the logs, so that one can # know whether the test passed or failed simply by looking at the '.log' # file, without the need of also peaking into the corresponding '.trs' # file (automake bug#11814). echo "$res $test_name (exit status: $estatus)" >>$log_file # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: nut-2.8.3/NEWS.adoc0000644000200500020050000054200015001552635010646 00000000000000ifdef::txt[] NUT Release Notes ================= endif::txt[] If you're upgrading from an earlier version, see the link:UPGRADING.adoc[] file. Please note that web and source document links, product and service names listed in historic entries of past releases may no longer be relevant. For a complete and more detailed list of changes, please refer to the ChangeLog file (generated for release archives), or to the Git version control history for "live" codebase. Release notes for NUT 2.8.3 - what's new since 2.8.2 ---------------------------------------------------- https://github.com/networkupstools/nut/milestone/11 - Fix fallout of development in NUT v2.8.0 and/or v2.8.1 and/or v2.8.2: * Move of `NUT_DEBUG_LEVEL` and "-D" CLI option handling to start of driver programs for issue #2259 in NUT v2.8.2 release misfired with regard to data-dump mode (it no longer caused foreground by default). [#2408] * The `nut-driver-enumerator.sh` improvements misfired in v2.8.2 release with an overlooked bit of shell syntax, and caused `nut-driver@upsname` instances to not auto-restart when `ups.conf` is edited. [#682, #2410] * Addition of "NUT Simulated devices" support to `nut-scanner` in v2.8.2 broke detection of (in-)ability to find and query "Old NUT" servers via `libupsclient.so` (internal flag got always enabled). [#2246] * A fix for `upsmon` v2.8.1 setting of `OFFDURATION` [PR #2108, issue #2104, revisiting PR #2055, issue #2044] was overly zealous and impacted also the `OB` state in cases where communications to the data server were severed and `DEADTIME` setting was not honored. [PR #2462, issue #2454] * Using `drivername -c reload` (e.g. facilitated by `nut-driver-enumerator` script and service when editing `ups.conf`) led to disconnected Unix sockets and a tight polling loop that hogged CPU. While the underlying bug is ancient, it took recent development to hit it as a practical regression. [issue #1904, issue #2484] * Fallback `localtime_r()` and `gmtime_r()` for some platform builds where a `*_s()` variant was available was not handled correctly. [PR #2583] * A recently introduced `allow_killpower` did not actually work as an `ups.conf` flag (only as a protocol command). [issue #2605, PR #2606] * The ability of two copies of the driver program to talk to each other with `upsdrvquery.c` code was not complete for the case of indefinite `select()` wait timeout. Now `upsdrvquery_read_timeout()` fixed private use of `struct timeval={-1,-1}` as a trigger to `select(..., NULL)`, as logged in one part of code and not handled in the other, for the indefinite wait [#1922, #2392, #2686, #2670] * The `disable_fix_report_desc` option introduced for `usbhid-ups` driver since NUT v2.8.1 was not applied for early dialog with the device while its report descriptors were being discovered. Now this flag, as well as `interruptsize` and `interruptonly`, are considered before we first try to open the USB device handle. [#1575, #1512] * In `cps_fix_report_desc()` we intended to fix-up input and output voltages in certain cases against high voltage transfer, we only fixed-up one of them. [#1245] * `upsd` should now handle `TRACKING` value of `STAT_CONVERSION_FAILED` introduced in NUT v2.8.2 for the socket protocol (between driver and data server), by returning "ERR INVALID-ARGUMENT", so there is no change for the network protocol definition. [#2182] * The `configure --enable-inplace-runtime` option added in NUT v2.8.1 should now also try to detect and set default values for the `--with-drvpath`, `--with-cgipath`, `--datadir` and `--libdir` options to more closely match a packaged setup and avoid confusion with e.g. two incompatible NUT client libraries in system default search path. [#2895] - Large parts of the NUT User Manual and NUT Developer Guide were relocated into the new NUT Quality Assurance and Build Automation Guide (maintained in `docs/qa-guide.adoc`), accompanied by new chapters written and detailed for this subject; the chapter about `ci_build.sh` script became a separate `ci_build.adoc` document included into the new document. Overall, this guide intended to help the current and future maintainers of NUT itself, as well as to inspire any other projects that investigate similar solutions. [#2832] - SEMVER, know thyself! * Development iterations of NUT should now identify with not only the semantic version of a preceding release, but with git-derived information about the amount of iterations that followed (if available): the three-number "semver" would be seen on release snapshots, while other builds would expose the added components: one with the amount of commits on the main development trunk since the preceding release which are ancestors of the built code base, and in case of feature development branches -- another component with the amount of commits unique to this branch (which are not part of the development trunk yet). This allows to produce more relevant (monotonously growing) version identifiers for packages and similar artifacts, with more meaningful upgrades via development snapshots, eventually. A copy of the current version information would be embedded into "dist" archives as a `VERSION_DEFAULT` file, among provisions for packager tuning. [#1949] * Documentation about this would be maintained in `docs/nut-versioning.adoc` * SMF manifests and systemd units now refer to man pages and their online variants under `NUT_WEBSITE_BASE` dependent on codebase maturity (development or release snapshot); many programs now display such references in their command-line usage help, method `suggest_doc_links()` was introduced for this purpose. [issue #722, PR #2733] - A technologically and practically interesting revamp of NUT mesh of link:https://www.gnu.org/software/automake/[automake] (`Makefile.am`) recipes was completed, allowing for a more parallelizable build routine on multi-CPU machines -- utilizing more cores and completing in less "wall-clock" time that the standard `SUBDIRS` driven approach -- when running `make -j (N)` from the project root directory to build everything enabled by the `configure` script. + This was tested with several (GNU, BSD, Sun) implementations of the "make" program on the few dozen platforms that NUT CI farm tests on. Notably, GNU make 4.x and newer seems to process parallel high-level goals and sub-`make` runs better than the competition (including GNU make 3.x). + It is not a radical rewrite like some other research suggested, and so retains the general structure and certain benefits and flexibility of that standard `automake` approach, including developer build workflows with a bespoke `Makefile` in every significant directory. This also retains (and builds upon) the benefits of older work done in NUT, for builds in one directory to depend on libraries and other artifacts built (once) in another. + Overall, NUT CI farm build times got 25%+ shorter (which is important as some scenarios had hit the 1-hour timeout imposed by providers of free CI hosting coupled with the weak machines provided in their free layer), and we suppose this is an interesting case for other projects to draw inspiration from for their recipe refactoring. [PR #2825] - As an aid for developers and maintainers, a new spell-checking recipe was added to first run non-interactive spelling checks in parallel, and *only* if something fails -- run an interactive check to edit the text and/or the dictionary file. The `make spellcheck` rule now also benefits from the rewritten recipes, as detailed above, to visit directories with text files in parallel. Overall, these changes may save time on multi-CPU systems, if compared to a sequential walk of all texts (or their directories) as was done before. [#2871] - The `make dist` goal now takes more care to require availability of the man pages to put into the prepared distribution archive. These may come either from the current build, or inherited from its sources (if using a tarball initially) on a platform without tooling required for man page generation. + This requirement compromises usability of `make distcheck` on platforms without such tools from sources without pre-built man pages (e.g. builds from git), so a couple of new goals were introduced in PR #2842: - `make distcheck-fake-man` generates placeholder files named like pre-built man pages for any missing files, just for the purpose of constructing a sane-looking dist archive to `distcheck` strictly otherwise; - `make distcheck-ci` is routed to `distcheck` or `distcheck-fake-man` based on build circumstances (ability to build man pages or presence of pre-built pages, or lack of either); - Similarly, `make dist-ci` is routed to provide a strict or faked tarball; - Earlier defined goals like `distcheck-light` or `distcheck-valgrind` now take advantage of these mechanisms to also produce usable dist archives for their relaxed or purpose-specific tests. - Revised behaviors for the `upsnotify()` common code introduced in recent NUT releases (integrating with service management frameworks, etc.): * It was a bit cryptic when it reported a *failure to notify* (e.g. when a NUT program was not running as a service currently), fixed now to report human-friendly text instead of internal enum codes. Follow-up to [issue #1590, PR #1777, PR #2136] * Drivers should no longer print warning messages about not-initializing the notification subsystem because not running as a service when they are either started explicitly to show the help message, or when their CLI arguments are fatally wrong (no UPS name, no `port`, invalid trailing keywords...) * NUT programs generally should default to not "spam" about lack of known notification technology if our first message to be suppressed is already about stopping that program. This might help nag distros into getting a service framework, or integrating theirs with NUT, but is generally annoying to end-users where there's little they can do about it (other than suppressing the message with `NUT_QUIET_INIT_UPSNOTIFY` envvar). - Drivers, `upsd`, `upsmon`: reduce "scary noise" about failure to `fopen()` the PID file (which most of the time means that no previous instance of the daemon was running to potentially conflict with), especially useless since in recent NUT releases the verdicts from `sendsignal*()` methods are analyzed and lead to layman worded situation reports in these programs. [issue #1782, PR #2384] - Drivers started with the `-FF` command-line option (e.g. wrapped into the systemd units to stay "foregrounded" *and* save a PID file anyway) should now also handle an existing PID file to interact with the earlier instance of the driver program, if still running (e.g. started manually). [#2384] - Drivers executed to force an UPS shutdown (with `-k` CLI option) should now try harder to kill off a daemonized sibling, if it still runs (and did not handle a `driver.killpower` INSTCMD well). [#2666] - Extended instant commands for driver reloading with a `driver.exit` command for a protocol equivalent of sending a `SIGTERM`, e.g. when a newer instance of the driver program tries to start. [#1903, #2392] - A new `NUT_QUIET_INIT_BANNER` envvar (presence or "true" value) can now prevent the tool name and NUT version banner from being unilaterally printed out when NUT programs start. [issues #1789 vs. #316; #2573] - Drivers would now report the socket they are listening on, and server would report full path to the driver socket it tries to connect to. A new `NUT_QUIET_INIT_LISTENER` envvar (presence or "true" value) can prevent the socket name from being unilaterally printed out when NUT drivers start. [#2764] - The `upsdrvctl` tool improvements: * It should now warn if executed on systems where NUT was built with support for service management frameworks like systemd or SMF, so nut-driver service units prepared by `nut-driver-enumerator` would conflict with manually-executed driver programs. This warning can be hushed by exporting a `NUT_QUIET_INIT_NDE_WARNING` environment variable with any value. * Extended `upsdrvctl` with a `list` operation (or `-l` option) to report manageable device configuration names (possible `` arguments to `start`, `stop` etc. operations), or to confirm a single name that it is known, and a `status` operation for more information. [#2567] * Fixed support of `maxstartdelay` at the level of driver section in `ups.conf`; added support of `maxretry` and `retrydelay` at this level; bumped the default `maxstartdelay` from 45 to 75 seconds to accommodate for longer device initialization (e.g. due to support of more Megatec Qx dialects by `nutdrv_qx`). [#2885, #2888] - `riello_ser` updates: * Added `localcalculation` option to compute `battery.runtime` and `battery.charge` if the device provides bogus values [issue #2390, following in the footsteps of #1692, #1685 done for `riello_usb`] (similar to `runtimecal` in some other drivers, may be refactored to that configuration and logic model in later NUT releases) - `apcsmart` updates: * Revised code to use `strncpy()` and avoid potential overflows that are possible with `strcpy()` used before. [PR #2564] * Lost communications led to a logging flood, should not anymore. In fact, the driver should try fully reconnecting upon getting into a prolonged data stale condition. [issue #704, PR #2564] - `nutdrv_qx` updates: * Added Visench C1K (using serial port converter with USB ID `1a86:7523`) as known supported by `nutdrv_qx` (Megatec protocol) since at least NUT v2.7.4 release. [#2395] * Introduced `innovart31` protocol support for Innova RT 3/1 UPSes. [#2712, #2798] * Introduced `q2` and `q6` protocol support; currently also based/tested on Innova devices, but other models than RT 3/1. [#2798] * Introduced a `gtec` subdriver and protocol, tested over USB with a Gtec ZP120N device. [#2818] * Fixed `hunnox_protocol()` to honour the optional `novendor` setting for devices that are confused by such query, e.g. DEXP LCD EURO 1200VA. [#2839] * Extended Voltronic protocol to support longer numbers as remaining `battery.runtime` value. [#2765] - GPIO drivers: * Extended to support library API of not only libgpiod v1.x releases, but also v2.x; introduced a NUT `WITH_LIBGPIO_VERSION` C macro (in `config.h`) to differentiate the library variants. [issue #2833] - New NUT drivers: * `bicker_ser`: added new driver for Bicker 12/24Vdc UPS via RS-232 serial communication protocol, which supports any UPS shipped with the PSZ-1053 extension module. [PR #2448] * `liebert-gxe`: added new driver with support for Liebert GXE Series UPS (serial or USB posing as a serial port). [#2629] * `nhs_ser`: added new driver for numerous NHS Nobreaks, senoidal line -- UPS models with serial port, made by NHS Sistemas Eletronicos LTDA and popular in Brazil. Currently this driver only builds on Linux. [#2692] * `phoenixcontact_modbus` driver: Introduced Phoenix Contact QUINT4-UPS/24DC management (only new modbus addresses). [#2689, #2716] - Added `scripts/external_apis` with an example script integrating a non-native protocol with NUT (as live-stream input for `dummy-ups` NUT driver to publish further); that example can be installed using `configure --enable-extapi-enphase`. [issue #2807, PR #2813] - `usbhid-ups` and `netxml-ups` updated to handle "No battery installed!" alarm also to set the `RB` (Replace Battery) value in `ups.status`. This may cause dual triggering of notifications (as an `ALARM` generally and as an important `REPLBATT` status in particular) in `upsmon`, but better safe than sorry. [#415] - `usbhid-ups` updates: * Support of the `onlinedischarge_log_throttle_hovercharge` in the NUT v2.8.2 release was found to be incomplete. [#2423, follow-up to #2215] * Added support for `interrupt_pipe_no_events_tolerance=N` setting to optionally prevent UPS lockup, indicated by continuous "Got 0 HID Objects" situation as a clue, by reconnecting on stale data. Note that while some devices just report information upon subsequent poll and just have nothing urgent to declare with an USB interrupt, others (e.g. APC BXnnnnMI) were seen to lock up until a full connection restart. [#2671, #2681] * Added support for `lbrb_log_delay_sec=N` setting to delay propagation of `LB` or `LB+RB` state (buggy with APC BXnnnnMI devices circa 2023-2024). This may work better with flags like `onlinedischarge_calibration` and `lbrb_log_delay_without_calibrating` for some devices. [#2347] * General suggestion from `possibly_supported()` message method for devices with VendorID=`0x06da` (Phoenixtec), seen in some models supported by MGE HID or Liebert HID, updated to suggest trying `nutdrv_qx`. [#334] * MGE HID list of `mge_model_names[]` was extended for Eaton 9E, 5PX and 5SC series (largely guessing, feedback and PRs for adaptation to actual string values reported by devices via USB are welcome), so these devices would now report `battery.voltage` and `battery.voltage.nominal`. Also a device from 5S series (5S1200AU) was tested, although it identifies as an "Ellipse PRO" in USB metadata. [#2380] * Added `ups.beeper.status` support for Masterpower MF-UPS650VA using the MGE HID subdriver. [#2662] * Added basic support for EcoFlow River 3 Plus and Delta 3 Plus models. [issue #2735, PRs #2740, #2837] * Added support for `0x09D6:0x0001` devices using the MGE HID subdriver assuming devices made by KSTAR (alternately using MGE vendor ID). [#2661] * `powercom-hid` subdriver sent UPS shutdown commands in wrong byte order, at least for devices currently in the field. A toggle was added to set the old behavior (if some devices do need it), while a fix is applied by default: `powercom_sdcmd_byte_order_fallback`. [PR #2480] * `cps-hid` subdriver now supports more variables, as available on e.g. CP1350EPFCLCD model, including temperature. [PRs #2540, #2711] * Loudly suggest to set `pollonly` flag and default a shorter `pollfreq` for CPS devices, to try avoiding device-driven timeouts. [#1689] Also adjust default `offdelay` and `ondelay` to reasonable values, and warn the users with CPS devices if their configured values are not multiples of 60. [#432, #1394] * In `cps-hid` subdriver, `cps_fix_report_desc()` method should now handle mismatched `LogMax` ranges for input and output voltages, whose USB Report Descriptors are wrongly encoded by some firmware versions. [#1512] * In `cps-hid` subdriver, try to fix frequency scaling based on the values we see from the device and/or configuration overrides (low, nominal, high) so `499.0 Hz` reading that comes from some firmware versions gets reported properly as `49.9Hz`. [#2717] * USB parameters (per `usb_communication_subdriver_t`) are now set back to their default values during enumeration after probing each subdriver. Having an unrelated device connected with a VID:PID matching the `arduino-hid` subdriver prevented use of an actual `usb-hid` device due to changes made to this struct during probe. [#2611] - USB-capable drivers generally: * ...could earlier log `(nut_)libusb_get_string: Success` due to either reading an empty string or getting a success code `0` from libusb. This difference should now be better logged, and not into syslog. [#2399] * ...now can benefit from a new `nut_usb_get_string()` method which can do a fallback `en_US` query for devices which report a broken "langid" language identifier value. This notably manifested in inability to query the device Manufacturer, Model and Serial Number values with some buggy device firmware or hardware. [PR #2604, issues #1925, #414] * Currently this was tested to fix certain device discovery with the `usbhid-ups` driver; but should also apply out of the box to same discovery logic in `blazer_usb`, `nutdrv_qx`, `riello_usb` and `tripplite_usb` drivers. * Also applied to `nut-scanner` and `libnutscan`. [issue #2615] * More work may be needed for other USB-capable drivers (`richcomm_usb`, `nutdrv_atcl_usb`) and for general code to collect string readings and other data points, and to configure the fallback locale or choose one if several are served by the device. [issues #2613, #2614, #2615] * ...should now be more likely to succeed with iterative detection of an UPS interface on a composite USB device or when looking at devices with non-default interface/endpoint/config numbers. [PR #2611] * ...should now accept a `LIBUSB_DEBUG=INTEGER` setting in `ups.conf` (as well as an environment variable that can be generally set via `nut.conf` or service unit methods or init script), to enable troubleshooting of LibUSB itself. [issue #2616] * ...should now not log "insufficient permissions on everything" alone when some devices were accessible but just did not match -- clarify that case in the next line, when applicable. [PR #2699] * ...should now track the fact of `assumed_LogMax` (typically when firmware encoding logic is wrong, and `-1` is resolved by parser). [#1512, #1040] - `snmp-ups` updates: * Added support to monitor BayTech RPC3-NC PDUs, with `baytech-rpc3nc-mib` serving same basic data points as were available in `baytech-mib.c`, but checking for a different model OID subtree and different OIDs for the device model information. [#2779] * Fixed `netvision-mib`: sync `netvision_output_info` with currently available `SOCOMECUPS-MIB.txt`. [#2803] - `mge-utalk` driver will no longer set non-standard status values `COMMFAULT` and `ALARM` (for a specific status bit); instead, it will set modern `ups.alarm` with values `COMMFAULT` and/or `DEVICEALARM` (and raise an `ALARM` in `ups.status` for either, as standard alarms go). [#2708] - Introduced a new driver concept for interaction with OS-reported hardware monitoring readings. Currently instantiated as `hwmon_ina219` specifically made for Texas Instruments INA219 chip as exposed in the Linux "hwmon" subsystem of its "sysfs" interface (and talking I2C under the hood), this approach seems to have good potential to expand into covering more devices and perhaps platforms. [#2430] - Introduced `ECO` status concept for "ECO mode" (or "High Efficiency" mode, or "Energy Saver System"...) as named and defined by hardware vendors. One common aspect is that this is a balance of electrical efficiency vs. robust outage protection (which may be overkill for IT equipment whose PSU can survive several milliseconds on capacitors alone) which can be selected at run-time. Previously such choice was made at the time of purchase, with the UPSes only supporting some one protection strategy. [issue #2495, PR #2637] * Updated documentation, end-user clients (CGI, NUT-Monitor UI); * Updated `upsmon` client with ability to report entering and exiting the ECO mode if reported by the driver; * Initial implementation for Eaton devices with `usbhid-ups` driver. - Introduced handling for the `ALARM` status, which already existed as a common denominator for devices seen with active `ups.alarm` variables. UPS devices in an `ALARM` status are generally considered volatile and may be considered critical/dead by the `upsmon` client earlier than in other statuses (e.g. in no-communication situations). It has to be noted that there is no common standard for what constitutes an alarm and such alarm states were also previously observed for less severe reasons. This depends on the manufacturer/device-specific implementation in the driver. [issues #415, #2657, PR #2658] * Updated documentation, end-user clients (CGI, NUT-Monitor UI); * Updated `upsmon` client with ability to report entering and exiting the ALARM status if reported by the driver; * Updated `upsmon` client with setting to toggle whether an `ALARM` status can prompt the UPS to become critical in certain situations. - The `upsmon` client can now also report entering and exiting the `OVER` (UPS overloaded), `TRIM` and `BOOST` (adjusting for bad input voltage) states. A setting `OVERDURATION` was introduced to define a timeout after which a non-communicating UPS that was last seen in state `OVER` should be considered critical (or not). [PR #1074, issue #2877] - Revised `upssched` timer handler that can be called from `upsmon` as its `NOTIFYCMD` to not report confusing environment variable values of `NOTIFYTYPE` and `UPSNAME` from the original call when a timer eventually fires -- these values are irrelevant at that distant future. The NIT (NUT Integration Tests) suite was extended to configure and call this tool, facilitating its development and troubleshooting. Also the `upssched` timer daemon part can now save its PID file (so that NIT can terminate it after tests). [#2890] - New `libupsclient` API methods added: * `upscli_str_add_unique_token()` and `upscli_str_contains_token()`, to help C NUT clients process `ups.status` and similarly structured strings same way as NUT core code base. [#2852, #2859] * `upscli_connect()` was previously always blocking; now this is sort of optional, with new `upscli_set_default_connect_timeout()` able to change the implicit timeout from default zero (meaning blocking) to a positive value (or back to 0). Several NUT clients (`upsc`, `upscmd`, `upsrw`, `upslog`, `upsmon`, `upsimage`, `upsset` and `upsstats`) were updated to default with a 10-second timeout in case of name resolution lags or unresponsive hosts (notably a problem with `upsmon` contacting many remote systems at once). The `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable can be used to modify this timeout for all clients. Further new methods here include `upscli_get_default_connect_timeout()` to retrieve a copy of the last stored timeout, and `upscli_init_default_connect_timeout()` to initialize the value from a number of sources with different priorities. [#2847] * Symbols exported from `libupsclient` now include `nut_debug_level*` so that NUT clients can be usefully debugged (e.g. using `NUT_DEBUG_LEVEL` environment variable). [#2847] - Several NUT clients including `upscmd`, `upsrw`, `upsimage`, `upsset`, `upsstats`, and `upslog` (during reconnection), did not `UPSCLI_CONN_TRYSSL` so went plaintext even when secure connections were possible. Fixed to at least try being secure, same way as `upsc` does for a long time. [#2847] - `upsmon` updates: * It was realized that the `POWERDOWNFLAG` must be explicitly set in the configuration file, there is no built-in default in the binary program (the settings facilitated by the `configure` script during build "only" impact the `upsmon.conf.sample`, init-scripts and similar files generated from templates). [issue #321, PR #2383] * Added an `OBLBDURATION` (seconds) setting to optionally delay raising the alarm for immediate shutdown in critical situation. [#321] * Optimized `parse_status()` by not checking further strings if we had a match; report unexpected tokens in debug log. [#415] * Revised internal `do_notify()` method to support formatting strings with two `%s` placeholders, to use if certain use-cases pass any extra information (e.g. not just "we have alarms" but their values too). [#415] * Introduced handling for "unknown" `ups.status` tokens, reporting them as "OTHER" notification type (whenever the set of such tokens appears or changes) or "NOTOTHER" when they disappear. [#415] - `upslog` updates: * Added support for limiting the loop count. Using in NIT (NUT Integration Test) suite for double profit (checking the tool and fallback in NIT). * If you use the legacy CLI options for single-system logging (`-s ` and `-l `) along with newer tuple(s) for multiple-system logging (repeatable `-m `), previously the single-system options were overridden by the tuple(s); now they become part of the list. * Internally, changed from use of shared global variables to query one UPS at a time, populated from the new list of tuples during each loop cycle, to passing and using the new tuple structures directly. * The `upsname` in the `system=upsname[@hostname[:port]]` parameter may be an asterisk `*` to query for devices currently served by the hostname. * Same log file may safely be used in different logging tuples (it is then recommended to use `%UPSHOST%` in a custom formatting string). * Fixed printing of `%UPSHOST%` when multiple systems are being logged. * A `%t` for a TAB character can now be used in the formatting string. * Added `-N` to prefix `%UPSHOST%%t` before the format string (whether default or custom). Useful when logging many systems into same target. * Added `-D` for debugging (and foregrounding by default), like with other NUT daemons. * Added systemd and SMF service integration. [#1803] - More systemd integration: * Introduced a `nut-sleep.service` unit which stops `nut.target` when a system sleep was requested, and starts it when the sleep is finished. This helps avoid NUT shutting down a woken-up system just because its power state was critical before the sleep (called as a `SHUTDOWNCMD` implementation by the end-user), and a next-read timestamp was not seen (deemed to be a stale UPS, meaning lost communications during critical state, so must go down ASAP). While not as elegant as native systemd "inhibitor interface" support, this approach does work. [#1833, #1070] * Introduced support for the "inhibitor interface" as well (should be available on systems with systemd version 183 or newer) for a better handling of the time jump specifically in the `upsmon` client via new `Inhibit()` method in `common.c`. [#1070] * As an extension of the logic introduced above, hopefully now `upsmon` would behave better in face of any significant and unexpected clock jumps (on POSIX builds so far), even if they are not suspend/hibernate events (or they were but we could not have an inhibit lock). Now they should be handled similar (avoid stale UPS data and rash decisions) for summer/winter time change on non-UTC deployments, a debugger suspending the `upsmon` process, etc. [#2597] * Introduced delivery of default systemd presets (lists of enabled/disabled units). [#2721] * A `nut-udev-settle.service` was introduced to replace dependency on the `systemd-udev-settle.service` which is deprecated and causes warnings on some systems. It was shown to benefit NUT use-cases however. [#2638] - `gamatronic` driver revised for safer memory operations; this was reported to have fixed a Segmentation Fault seen in earlier NUT releases with some of the devices supported by this driver. [#2427] - `upsd` updates: * `upsd_cleanup()` is now traced, to more easily see that the daemon is exiting (and/or start-up has aborted due to configuration or run-time issues). Warning about "world readable" files clarified. [#2417] * Failure to `LISTEN` on an invalid host name (e.g. `localhost:3493` or `1.2.3.4/24`) is now logged in a more actionable manner. [#2665] - `nut-scanner` updates: * The tool relies on dynamic loading of shared objects (library files) orchestrated at run-time rather than pre-compiled, to avoid excessively huge package footprints. This however relies on knowing (or sufficiently safely guessing) the library file names to use, and short `libname.so` is not ubiquitously available. With the new `m4` macro `AX_REALPATH_LIB` we can store and try to use the file name which was present on the build system, while we search for a suitable library. [#2431] + NOTE: A different but functionally equivalent trick is done for `libupsclient` during a NUT build. * Fixed support for IPv6 addresses (passed in square brackets) for both `-s` start/`-e` end command-line options, and for `-m cidr/mask` option. [issue #2512, PR #2518] * Newly added support to scan several IP addresses (single or ranges) with the same call, by repeating command-line options; also `-m auto{,4,6}` can be specified (once) to select IP (all, IPv4, IPv6) address ranges of configured local network interfaces. An `/ADDRLEN` suffix can be added to the option, to filter out discovered subnets with too many bits available for the host address part (avoiding millions of scans in the extreme cases). [issue #2244, issue #2511, PR #2509, PR #2513, PR #2517] * Implemented parallel scanning for IPMI bus, otherwise default scan for all supported buses with `-m auto` takes unbearably long. [#2523] * Bumped version of `libnutscan` to 2.6.0, it now includes a few more methods and symbols from `libcommon`. [issue #2244, PR #2509] * Do not actively suggest `vendor(id)`, `product(id)`, and `serial` options for `bcmxcp_usb`, `richcomm_usb` and `nutdrv_atcl_usb` drivers for now [#1763, #1764, #1768, #2580] - All drivers should now support the optional `sdcommands` setting with a site-local list of instant commands to handle `upsdrv_shutdown()`, which may be useful in cases when the driver's built-in commands (or their order) do not meet the goals of particular NUT deployment. This can also help with shutdown endgame testing, using a mock command like starting the beeper (where supported) to verify that the UPS communications happen as expected, without compromising the load connected to the UPS. + Also defined `EF_EXIT_SUCCESS` and `EF_EXIT_FAILURE` in `include/common.h` to avoid magic numbers in code like `set_exit_flag(-2)`, and revised whether it is getting set at all in "killpower" vs. other cases, based on new `handling_upsdrv_shutdown` internal flag. + NOTE: during this overhaul, many older drivers got their first ever supported INSTCMD such as `shutdown.return`, `shutdown.stayoff` or `load.off`. Default logic that was previously the content of `upsdrv_shutdown()` methods was often relocated into new `shutdown.default` INSTCMD definitions. [#2670] - Common code: * `upscli_splitname()` should now recognize `upsname:port` typos (missing the `@hostname` part) and error out gracefully. * Introduced a `NUT_DEBUG_SYSLOG` environment variable to tweak activation of syslog message emission (and related detachment of `stderr` when backgrounding), primarily useful for NIT and perhaps systemd. Most methods relied on logging bits being set, so this change aims to be minimally invasive to impact setting of those bits (or not) in the first place. [#2394] * `root`-owned daemons now use not the hard-coded `PIDPATH` value set by the `configure` script during build, but can override it with a `NUT_PIDPATH` environment variable in certain use-cases (such as tests). [#2407] * Allow drivers to set `STATEPATH` via `ups.conf` to match `upsd` custom configuration ability; the data server would prefer the value from `ups.conf` over the one in `upsd.conf`, if both are present. Note that `NUT_STATEPATH` environment variable trumps both. [issue #694] * Introduced a check for daemons working with PID files to double-check that if they can resolve the program name of a running process with this identifier, that such name matches the current program (avoid failures to start NUT daemons if PID files are on persistent storage, and some unrelated program got that PID after a reboot). This might introduce regressions for heavily customized NUT builds (e.g. those embedded in NAS or similar devices) where binary file names differ significantly from a `progname` string defined in the respective NUT source file, so a boolean `NUT_IGNORE_CHECKPROCNAME` environment variable support was added to optionally disable this verification. Also the NUT daemons should request to double-check against their run-time process name (if it can be detected). [issue #2463] * Introduced `m4` macros to check during `configure` phase for the platform, and a `nut_bool.h` header with `nut_bool_t` type to use during build, to avoid the numerous definitions of Boolean types and values (or macros) in the NUT codebase. [issue #1176, issue #31] * Custom `distcheck-something` targets did not inherit `DISTCHECK_FLAGS` properly. [#2541] * Added `status_get()` in NUT driver state API, to check if a status token string had been set recently, and to avoid duplicate settings; fixed `status_set()` for multi-token arguments. [PR #2565, issue #2708] * Local socket/pipe protocol introduced a `LOGOUT` command for cleaner disconnection handling. [#2572] * Codebase adapted to the liking of `clang-18` and newer revisions of `gcc-13`+ whose static analyzers on NUT CI farm complained about some imperfections after adding newer OS revisions to the population of build agents. [#2585, #2588] * New checks in `clang-19` brought new findings about mismatched formatting strings and `int`-ish parameters of respective methods. Overall, had to change formatting strings in some cases, variable types in others (e.g. flags or notification types do not make sense as signed) and added casting in a few places that remained, because: - `%x` style formatting requires an `unsigned int` variable - Numeric literals and macros are `int` by default - Results of math with unsigned types like `uint16_t`, done in some cases, are up-scaled into `int` by default - `char`'s, `unsigned` or not, seem to be also up-scaled into `int` - Updated `docs/nut-names.txt` with items defined by 42ITy NUT fork. [#2339] - Various recipe, documentation and source files were revised to address respective warnings issued by the new generations of analysis tools. [#823, #2437, link:https://github.com/networkupstools/nut-website/issues/52[nut-website issue #52]] - Fixed `configure` script to use default (target-specific) values of `CFLAGS`, `LIBS` etc. when probing relevant settings for each third-party dependency; as a consequence, on systems that support building for many targets, we check relevant build-ability for that target and not for the building system itself. [issue #2673, PR #2675] - Fixed dynamic linking of Mozilla NSS on systems like Solaris/illumos, where the shared objects are not packaged into the common RPATH. [issue #2674, PR #2675] - Added `scripts/valgrind` with a helper script and suppression file to ignore common third-party problems. [#2511] - Fixed `configure --with-valgrind=PATH` vs. detection of its usability; fixed some portability issues with detection of usability per se, tried `--with-valgrind=auto` the default to auto-detect and use the feature (in tests) wherever possible, but too many NUT CI farm agents disagreed; so for now the default is `no`. [#2823] - When drivers dump collected data (during troubleshooting), flush `stdout` buffer immediately for sane logging (especially on Windows). [PR #2699] - Revised `nut.exe` (the NUT for Windows wrapper for all-in-one service) to be more helpful with command-line use (report that it failed to start as a service, have a help message, pass debug verbosity to launched NUT programs...) and add a man page for it. [issue #2432, PR #2446] - The `scripts/Windows/build-mingw-nut.sh` helper script was extended to use `nut_build_${ARCH}` and `nut_install_${ARCH}` directories by default, with the older `nut_build` and `nut_install` short names becoming just a symbolic link to the latest executed build: this should help compare the differences of 32/64-bit builds, without them stepping on each other's toes. - NUT binding for Python and the `NUT-Monitor` Python UI client updates: * The `PyNUTClient` module should no longer rely on presence of a `telnetlib` module in the build or execution environment (deprecated in Python 3.11, removed since Python 3.13). [issue #2183, PR #2792] * The PyPI distribution of the `PyNUTClient` module tarball should now use a lower-cased file name (and immediate versioned directory name inside) to match the requirements of link:https://peps.python.org/pep-0625/[PEP-0625]. The Python module name (and its directory) should remain camel-cased. [#2773] * Added man page for the `NUT-Monitor` Python UI client. * The `NUT-Monitor` Python UI client itself was revised to report the `PACKAGE_VERSION` and `NUT_WEBSITE_BASE` strings in the "About" dialog contents; localization support for the dialog and some other resources was revised to work in Py3Qt5 variant of the script. [#722] - Documentation recipe updates: * Enabled installation of built single-file PDF and HTML (including man page renditions) under the configured `docdir`. It seems that previously they were only built (if requested) but not installed via `make`, unlike the common man pages which are delivered automatically. [#2445] + NOTE: The `html-chunked` documents are currently still not installed. * Added support to `./configure --with-doc=man=dist-auto` to use the distributed manual page files if present; only fall back to (re-)building them if we can. [#2473] * Added a `make distcheck-light-man` recipe to require verification that the manual page files can be built using the prepared "tarball" archive. [#2473] * Revised the documentation building recipes, with the goal to avoid building the `ChangeLog` products and their intermediate files more than once (but still react to `git` metadata changes during development), and to sanity-check the resulting final document (currently only for `html-single` mode). + As part of this, the `CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR` setting was added (for `make` calls and used by `tools/gitlog2changelog.py.in` script), and it defaults to `true` allowing for better ordered documents at the cost of some memory during document generation. [#2510] * Updated man page generation with `configure` script options to specify that manual section codes on the target platform differ from (Linux-based) defaults hard-coded into page sources; this should allow to simplify NUT packaging recipe maintenance in those diverse distributions (no more need to update patches for changed or added documentation sources). * Lines in first section of NUT configuration report (which can optionally remain as `config.nut_report_feature.log` and be installed into shared documentation of a NUT package) are now better grouped as miscellaneous features and detection results, then drivers and programs/tools. [#2676] - Added a `common/Makefile.am` build product for a new internal library `libcommonstr.la` which allows a smaller selection of helper methods for tools like `nut-scanner` which do not need the full `libcommon.la` nor `libcommonclient.la`. [#2478, #2491] - Added a `drivers/Makefile.am` build product for a new internal library `libserial-nutscan.la` to simplify `tools/nut-scanner/Makefile.am` recipes. [#2490] - Build of `snmp-ups` and `netxml-ups` drivers now explicitly brings linker dependency on chosen SSL libraries. [#2479] - Introduced `configure --with-modbus+usb` option to require an USB-capable libmodbus, and defaulted a couple of specific situations as if this was required (implicitly): `configure --with-modbus --with-usb` and either `--with-drivers=*apc_modbus*` (actually implies `--with-modbus`) or `--with-modbus-includes=... --with-modbus-libs=...` as a way to avoid surprises with custom NUT builds aiming to have an USB-capable `apc_modbus` driver (currently this requires a custom-built libmodbus). Also fixed (re-)detection of libmodbus RTU USB support with static libmodbus builds. [#2666] - Drivers built with libmodbus (`phoenixcontact_modbus`, `generic_modbus`, `huawei-ups2000`, `socomec_jbus`, `adelsystem_cbi`, `apc_modbus`) should now report whether the library is linked dynamically or statically -- this can help in troubleshooting (especially of `apc_modbus` which may be using a custom build of the library not delivered by the operating system). [#2897] - Brought keyword dictionaries of `nutconf` and `augeas` NUT configuration file parsers up to date; restored automated checks for `augeas` lenses. [issue #657, issue #2294] + NOTE: Some known issues remain with augeas lens definitions, so currently they should be able to parse common simple use-cases but not certain types of more complex configurations (e.g. some line patterns that involve too many double-quote characters) which are valid for NUT proper. [#657] - Cross-builds using only a host implementation of `pkg-config` program should now ignore host `*.pc` files and avoid confusion. - NUT CI farm build recipes, documentation and some `m4`/`configure.ac` sources updated to handle a much larger build scope on MacOS. Also migrated the builders to Apple Silicon from x86 (deprecated by CircleCI). Disabled `HOMEBREW_NO_AUTO_UPDATE` to gain 40 min per build at cost of slightly older environment. [#2502, #1579] - Introduced a simple experiment to expose NUT client readings as filesystem objects via FUSE, in `scripts/fuse/execfuse-nut` now. [#2591] - Introduced `make install-as-root` to create directories not directly populated by `make install` and NUT build artifacts, apply permissions and (on some platforms) restart services involved with NUT. [#1298] Release notes for NUT 2.8.2 - what's new since 2.8.1 ---------------------------------------------------- https://github.com/networkupstools/nut/milestone/10 - Fix fallout of development in NUT v2.8.0 and/or v2.8.1: * dstate machinery: a segmentation fault (null pointer dereference) was possible with `INSTCMD` processing of commands without parameters nor `TRACKING` identifier. [#2155] * USB bus number detection for libusb-1.0 builds was overly zealous and wrongly considered zero values as an error. [#2198] * `upsmon` recognition of `CAL` state could linger after the calibration activity was completed by the hardware, which led to mis-processing of shutdown triggers. Also, notification was added to report "finished calibration". [issue #2168, PR #2169] * `upsmon` recognition of `OFF` state as a trigger for FSD (forced shut down) criticality considered also the input line state, which may be an independently evolving circumstance. [issue #2278, PR #2279] * `upsmon` support for `POLLFAIL_LOG_THROTTLE_MAX` did not neuter the applied setting when live-reloading configuration, so commenting it away in `upsmon.conf` did not have the effect of resetting the logging frequency to default. It also did not reset the counters to certainly follow the new configuration for existing faults. [issue #2207, PR #2209] * `upsmon` support for `POLLFAIL_LOG_THROTTLE_MAX` had an off-by-one error (e.g. reporting "Data stale" or "Driver not connected" every 30 sec with `POLLFAIL_LOG_THROTTLE_MAX 5` and `POLLFREQ 5` settings). [#2207] * Drivers running with non-default user account (e.g. with `user=root` in their configuration) failed to apply group ownership and permissions to their Unix socket file for interaction with the local data server. [#2185, #2096] * Dispatcher script `scripts/python/app/NUT-Monitor` referenced `py3qt3` instead of the correct `py3qt5`. It also tries to check both `py2gtk2` and `py3qt5` implementations verbosely, even if one is not installed. [#2199, #2201] * Set the `DesktopFileName` in `scripts/python/app/NUT-Monitor-py3qt5`, this binds the application with the desktop file and allow the Open Desktop compatible implementation to display the proper icon and application name. [#2205] * Original recipe for `apc_modbus` strictly required USB support even if building NUT without it. [#2262] * Builds requested with a specific C/C++ language standard revision via `CFLAGS` and `CXXFLAGS` should again be honoured. [PR #2306] * Allow requesting detailed debug builds (with disabled optimizations for binaries to best match the source code) for supported compilers using `configure` script option `--with-debuginfo`. Note that default autoconf behavior usually embeds moderate optimizations and debug information on its own. [PR #2310] * A fix applied among clean-ups between NUT v2.7.4 and v2.8.0 releases backfired for `usbhid-ups` subdriver `belkin-hid` which in practice relied on the broken older behavior; more details in its entry below. [PR #2371] - nut-usbinfo.pl, nut-scanner and libnutscan: * Library API version for `libnutscan` was bumped from 2.2.0 to 2.5.0 during evolution of this NUT release. * USB VendorID:ProductID support list files generated by the script for different OS frameworks now include a comment with other possibly compatible driver names, where the respective file format allows for comments. * Added the concept of `alt_driver_names` in `nutscan_device_t` structure for ability to suggest a comment with other possibly compatible driver names in configuration snippets generated by `nut-scanner`; practical support implemented for USB connected drivers. * Added the concept of commented-away suggested option values `comment_tag` and a method to `nutscan_add_commented_option_to_device()`, instead of hacks in prepared config data which broke some use-cases. [#2221] * Command-line option `-U` for USB scan can now be specified several times to increase the detail level about hardware link to the device (this was previously always suggested, but may be not reliable if USB enumeration gets changed over time). [#2221] * Added generation of FreeBSD/pfSense quirks for USB devices supported by NUT (may get installed to `$datadir` e.g. `/usr/local/share/nut` and need to be pasted into your `/boot/loader.conf.local`). [#2159] * nut-scanner now avoids creating ambiguous `nutdevN` device section names when called separately to scan different media buses (one at a time). Now the "bus" name would be embedded (e.g. non-colliding `nutdev-usb1` and `nutdev-snmp1`). [#2247] * nut-scanner can now discover NUT simulated devices (`.dev` and `.seq` files) located in your sysconfig directory, and prepare configuration sections with the simulation driver (currently `dummy-ups`). [#2246] * nut-scanner now reports `dummy-ups` as driver when scanning NUT "bus" with Old or Avahi method. [#2236, #2245] - upsd: Fixed conditions for "no listening interface available" diagnosis to check how many listeners we succeeded with, not whether the first one succeeded or not. If not all requested (non-localhost) listeners were available, default to fail the daemon start-up attempt; support for an `ALLOW_NOT_ALL_LISTENERS` setting was added to control this behavior. [#723] - NUT CI improvements: * Added publishing recipes for PyNUT client bindings for NUT, so it ends up in the link:https://pypi.org/project/PyNUTClient[PyPI repository]. [#2158] * Added support for new `ccache` namespace concept, where possible. [#2256] * Fixed an issue for builds configured `--without-usb`. [#2263] * Added a fallback for `libgd` discovery (for CGI etc. builds). [#2287] * Made `aspell` TeX module detection more reliable. [#2206] * Fixed recipes for completely out-of-tree builds to pass with documentation generation and checking on all tested "make" implementations. [#2318] * Various other recipe and documentation clean-up efforts. [#2284, #2269, #2261] - main driver core codebase: * Help users of drivers that can be built to support optionally USB and other media (like `nutdrv_qx` built for serial-only support), and built in fact without USB support but used for USB devices, with some more information to make troubleshooting easier. [issue #2259, PR #2260] * Driver programs with debug tracing support via `-D` CLI option and/or the `NUT_DEBUG_LEVEL` environment variable now check those earlier in their life-time, so that initialization routine can be debugged. [#2259] * Multiple USB-capable drivers got options to customize `usb_config_index` `usb_hid_rep_index`, `usb_hid_desc_index`, `usb_hid_ep_in` and `usb_hid_ep_out` hardware connection settings via `ups.conf` options. This is treated as experimental, not all code paths may be actually using such values from `struct usb_communication_subdriver_t` rather than hard-coded defaults. Discovery of correct values is up to the user at the moment (using `lsusb`, internet search, luck...) [#2149] - nut-driver-enumerator (NDE) service/script: * The optional daemon mode (primarily useful for systems which monitor a large and dynamic population of power devices) was enhanced with a `--daemon-after` variant which parses the configuration once before daemonization and this has a chance to fail while not forked off, as well as to allow only completing the service unit initialization when everything is actually ready to work (so further dependencies can start at the proper time). [#682] * Also applied other optimizations to the script implementation. [#682] - powerpanel text driver now handles status responses in any format and should support most devices. [#2156] - tripplite_usb driver now allows any device to match if a particular Unit ID was not specified in `ups.conf`. [PR #2297, issues #2282 and #2258] - snmp-ups driver: * added support for Eaton EMP002 sensor for ATS16 NM2 sub-driver. [#2286] * mapping table updates for apc-mib sub-driver. [#2264] - usbhid-ups driver: * `arduino-hid` subdriver was enhanced from "initial bare bones" experimental set of mapped data points to support some 20 more mappings to make it more useful as an UPS driver, not just a controller developer sandbox. [#2188] * `cps-hid` subdriver now supports devices branded as Cyber Energy and built by cooperation with Cyber Power Systems. [#2312] * `belkin-hid` subdriver now supports Liebert PSI5 devices which have a different numeric reading scale than earlier handled models. [issue #2271, PR #2272, PR #2369] Generally the wrong-scale processing was addressed, including a regression in NUT v2.8.0 which led to zero values in voltage data points which NUT v2.7.4 reported well [#2371] * The `onlinedischarge` configuration flag name was too ambiguous and got deprecated (will be supported but no longer promoted by documentation), introducing `onlinedischarge_onbattery` as the meaningful alias. [#2213] * Logged notifications about `OL+DISCHRG` state should now be throttled (see the driver manual page for more details) [#2214, #2215]: - If `battery.charge` is available, make the message when entering the state and then only if the charge differs from that when we posted the earlier message (e.g. really discharging) and is under `onlinedischarge_log_throttle_hovercharge` value (defaults to 100%); - Also can throttle to a time frequency configurable by a new option `onlinedischarge_log_throttle_sec`, by default 30 sec if `battery.charge` is not reported by the device (should be frequent by default, in case the UPS-reported state combination does reflect a bad power condition). - nutdrv_qx driver: * Fixed handling of `battery_voltage_reports_one_pack` configuration flag introduced in NUT v2.8.1. [originally by PR #1279; fixed by PR #2324, issue #2325] - Various code and documentation fixes for NSS crypto support. [#2274, #2268] - Laid foundations for the SmartNUT effort (aiming to integrate drivers with some other backends than the networked NUT data server process). - Eaton contributed recipes and scripts used to create the IPP for Unix bundle (aka Eaton IPSS Unix or UPP), a freely available value-added packaging of NUT distributed as the UPS software companion for OSes where their more complex UPS monitoring/management tools had not been ported. This allows for delivery of NUT packages with an interactive installer and some system integration scripts (events, notifications, status, shutdown daemon...), and was contributed to the NUT upstream project by Eaton -- provided "as is" at the moment, and may later serve as foundation or inspiration for new NUT features. [#2288] - nutconf (C++ library and tool to read and manage NUT configuration files) was started in the open by Eaton employees and used in the IPP installer, but the code lingered in a side branch. It was now brushed up to our common best practices and added to the main codebase. As of this import, there are known deficiencies in Windows platform support, as well as some un-awareness about configuration key words which appeared in NUT since 2013. [#2290] - The `tools/gitlog2changelog.py.in` script was revised, in particular to convert section titles (with contributor names coming from Git metadata) into plain ASCII character set, for `dblatex` versions which do not allow diacritics and other kinds of non-trivial characters in sections. This can cause successful builds of `ChangeLog.pdf` file on more platforms, but at expense of a semi-cosmetic difference in those names. [PR #2360, PR #2366] Release notes for NUT 2.8.1 - what's new since 2.8.0 ---------------------------------------------------- https://github.com/networkupstools/nut/milestone/8 - "UPS management protocol", Informational RFC 9271 published by IETF at https://www.rfc-editor.org/info/rfc9271 and the IANA port number registry was updated accordingly at https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=3493 (even though this RFC is not formally an Internet Standard) - NUT documentation files were rearranged, renaming some to `*.adoc` pattern to facilitate automatic rendering in GitHub and IDE GUIs, and adding recipe support for GitHub issue/PR links. This `NEWS` file is now proper asciidoc rendered into `release-notes.pdf` (and HTML versions). [issue #1953, PR #2048] Internally, the documents would use a new way to define cross-linking to other pages and their chapters, to facilitate different renderers (including GitHub UI), and file names created for "chunked HTML" documentation format will no longer have the "chapter number, section number" format which is not easy to maintain over time with independent builds of documentation in NUT and the actual and historic snapshots for nut-website for example. Chapter/Section names will be adapted to produce "chunked HTML" file names instead. Documentation links rendered in GitHub UI should point to the HTML pages served by a current iteration of the NUT website. [PR #226, PR #669] - A new `configure --enable-spellcheck` toggle should add spelling checks to `make check` (by default, if tools are available) to facilitate quicker acceptance of contributions. [#2067] - Published a new maintainer GPG key to sign tags and release artifacts, and possibly git commits as well, as part of solution for issue #1410. You can pull it from common OpenPGP servers with the following command: + ---- :; gpg --recv-key DE0184DA7043DCF7 gpg: key DE0184DA7043DCF7: public key "Jim Klimov (Doing FOSS since last millennium) " imported gpg: Total number processed: 1 gpg: imported: 1 ---- + as part of https://github.com/networkupstools/nut/issues/1410 solution. - Bug fixes for fallout possible due to "fightwarn" effort and other evolution in NUT v2.8.0 release: * The `upsdebugx()` and similar methods were converted to macros in #685 to avoid useless data manipulations and requests for logged information, whose results would be ignored instantly because the debug level is too low. As issue #1455 and PR #1495 found, in two cases the called commands did "meaningfully" modify data -- so without debug logs the program misbehaved. A known regression for `upscode2` driver; might be or not be a problem with `upsd` server in NUT v2.8.0 release, fixed for NUT v2.8.1. * A table in `cyberpower-mib` (for `snmp-ups` driver) sources was arranged in NUT v2.8.0 release in a way that precluded the driver logic from looking at all of its entries. Also a fix for instant command definitions had in fact broken them due to other development. Regressions fixed for NUT v2.8.1 [#1432, #2029] * A change for file-change detection in `dummy-ups` driver for NUT v2.8.0 release misfired on some platforms. Regression fixed for NUT v2.8.1 [#1420] * Fixed building of NUT man pages when just a few drivers are selected by `configure` script for custom builds [#1467] * Now that `upsdrvctl` can pass debugging level through to the launched driver(s), they would by default stay in the foreground. This can complicate (or simplify, when intentional) the management of service instances. Now there are explicit `upsdrvctl` options for choosing this (`-F`/`-B`), although default behavior is retained. Note that explicit foregrounding mode also keeps `upsdrvctl` tool from exiting and would not wait for one driver to complete initialization before starting another in case of mass-management loop to start all drivers (without specifying the single device) [#1759, #1806, #1875] * The `apcsmart` and `apcsmart-old` handled invalid data too zealously and aborted instead of skipping over it, like they did before [#2015] * A bit maths optimization in `riello_ser` and `riello_usb` misfired [#2137] * Something about compile-time macros or other warnings-related refactoring seems to have confused the MGE SHUT (Serial HID UPS Transfer) driver support [#2022] * Some warnings were not detected by the tools or build scenarios used earlier, and only got addressed now - An issue was identified which could cause `libupsclient` parser of device and host names to crash upon bad inputs (e.g. poorly resolved environment variables in scripts). Now it should fail more gracefully [#2052] - New `configure --enable-inplace-runtime` option should set default values for `--sysconfdir`, `--with-user` and `--with-group` options to match an existing NUT deployment -- for users who are trying if a custom build of recent codebase solves their practical issues. For "quick tests", a shortcut operation `./ci_build.sh inplace` was added [#1714] - State tree structure and methods (including "dstate" wrapper for common driver internals) was enhanced with time-stamping of last modification (setting, changing, deleting the value or some fields in an entry): this allows to detect stale information in a centralized fashion [#2010] - We lacked log information about changes of chroot jail (uncommon) and of UID/GID (everywhere), which makes troubleshooting harder (e.g. lack of access to config files or USB device nodes). Now we have it [#1694] - A `NUT_DEBUG_PID` envvar (presence) support was added to add current process ID to tags with debug-level identifiers. This may be useful when many NUT daemons write to the same console or log file. [#2118] - huawei-ups2000 is now known to support more devices, noted in docs and for auto-detection [#1448, #1684] - nutdrv_qx updates: * a `battery_voltage_reports_one_pack` driver option was added for devices which "natively" report a `battery.voltage` for a single battery pack or cell, not for the whole assembly [#1279] * the `voltronic_qs_protocol` should now accept both "V" (as before) and newly "H" dialects, which otherwise seem interchangeable [#1623] * the `armac` subdriver was enhanced to support devices with a different response pattern than previously expected per initial contribution. It was tested to work with Vultech V2000 and Armac PF1 series. [#1978] - nutdrv_qx and blazer updates: * extended default ranges for max battery voltage when guessing [#1279] - sms_ser, a driver for SMS Brazil UPS Protocol 1Phase, was introduced. NOTE: it may later become a subdriver under nutdrv_qx. [#2090] - usbhid-ups updates: * added support for `subdriver` configuration option, to select the USB HID subdriver for the device manually where automatic match does not suffice (e.g. new devices for which no `vendorid`/`productid` pair was built into any driver, or for different-capability devices with same interface chips, notably "phoenixtec/liebert" and "mge") [#1369] * cps-hid subdriver now applies same report descriptor fixing logic to devices with ProductID 0x0601 as done earlier for 0x0501, to get the correct output voltage data [#1497] * apc-hid subdriver now also supports ProductID 0x0004 [#1429] * ever-hid subdriver reported a `powerfactor` without a namespace (bug in 2.8.0 release), fixed to `outlet.powerfactor` * the `usbhid-ups` driver should now reconnect if `libusb` returned a memory allocation error [#1422] (seen as "Can't retrieve Report 0a: Resource temporarily unavailable"), which can cause practical problems in the field -- the driver otherwise interpreted the situation as `ups.status` being `OL OFF` and cut the power supply. * powercom-hid subdriver: fixed `UPS.Battery.ManufacturerDate` to map to `battery.mfr.date` (not `battery.date` which is the maintenance replacement date) [#1644] * added `onlinedischarge_calibration` option for UPSes that report `OL+DISCHRG` when they are in calibration mode [#2104] - riello_usb updates: * added `localcalculation` option to compute `battery.runtime` and `battery.charge` if the device provides bogus values [#1692, #1685] (similar to `runtimecal` in some other drivers, may be refactored to that configuration and logic model in later NUT releases) - powercom driver should now try harder to refresh data from device [#356] - tripplite_usb driver now supports configuration of `upsid` to match the specific device (not all firmware/hardware models support this) [#2075] - apcupsd-ups: * improvement for `POLL_INTERVAL_MIN` from PR #797 was buggy [#2007] * fix to clean obsoleted readings (if any) AFTER getting new info from an `apcupsd` daemon, to avoid the gap when NUT driver knows nothing [#2007] - apc_modbus driver was introduced, to cover the feature gap between existing NUT drivers for APC hardware and the actual USB-connected devices (or their firmwares) released since roughly 2010, which deprecated standard USB HID support in favor of Modbus-based protocol which is used across the board (also with their network management cards). The new driver can monitor APC UPS devices over TCP and Serial connections, as well as USB with a patched libmodbus (check https://github.com/EchterAgo/libmodbus/commits/rtu_usb for now, PR pending). [#139, #2063] * For a decade until this driver got introduced, people were advised to use apcupsd project as the actual program which talks to a device, and NUT apcupsd-ups driver to relay information back and forth. This was a limited solution due to lack of command and variable setting support, as well as relaying of just some readings (just whatever apcupsd exposes, further constrained by what our driver knows to re-translate), with little leverage for NUT to tap into everything the device has to offer. There were also issues on some systems due to packaging (e.g. marking NUT and apcupsd as competing implementations of the same features) which required clumsy workarounds to get both installed and running. Finally, there is a small matter of long-term viability of that approach: last commits to apcupsd sources were in 2017 (with last release 3.14.14 in May 2016): https://sourceforge.net/p/apcupsd/svn/HEAD/tree/ - dummy-ups: * Added an `repeater_disable_strict_start` option to disable the driver exiting upon encountering any kind of error at startup (as repeater). This option should allow for collective `upsdrvctl` startup despite individual target UPS to be repeated or `upsd` not having come up yet. [#2132] * Revised detection of file path (for "dummy" mode) which misfired under some conditions, and unified several implementations. [#2118] - NUT for Windows: * Ability to build NUT for Windows, last tackled with a branch based on NUT v2.6.5 a decade ago, has been revived with the 2.8.x era codebase [#5]. It is known that at this time some features are not complete, for more details see https://github.com/orgs/networkupstools/projects/2/views/1 * Cross-builds of NUT for Windows using Linux and MinGW (and many custom built dependency packages, as documented in the link:scripts/Windows/README.adoc[scripts/Windows/README.adoc file]) are now regularly tested on NUT CI farm with moderate integration via custom build script `scripts/Windows/build-mingw-nut.sh` [#1489] * Semi-native NUT for Windows builds with MSYS2/MinGW x64 environment are now regularly tested on AppVeyor, with the same `ci_build.sh` script and `Makefile` checks as used across the board for local developer builds, Linux/illumos/FreeBSD/OpenBSD/... on dedicated NUT CI farm on Fosshost, and MacOS on CircleCI [#1552] - snmp-ups updates: * Fixed detection for device agents which wrongly return the sysOID value as a string instead of an OID [#1710] * Clearer messages about skipping MIBs during driver initialization [#2037] * IETF MIB mapping updated for data points where negative readings are invalid [#1558] * Added SNMP subdriver "apc-epdu-mib" for APC easy PDU support [#1674] * Added SNMP subdriver "eaton-pdu-nlogic-mib" for nLogic (rebranded Eaton) support [#1698] * Added SNMP subdriver "hpe-pdu3-cis-mib" for HPE G2 Metered & Switched PDU initial "unitary" support (no daisychain support yet); also note that due to SNMP v1 implementation limitations on this device, you should prefer SNMP v3 to get both read and write rights [#1713] * Fixed processing loop for large SNMPv2/SNMPv3 responses where one item in the middle has a type error [#1682] * Better manage the slight nuances (especially in `ups.status`) between Eaton UPSs, and rename mibs from `pw` to `eaton_pw_nm2`, and from `pxgx_ups` to `eaton_pxg_ups` [#1715] * Fixed the long standing "Warning: excessive poll failures" issue, that was tied to non-existent OIDs, not well handled in some parts of the driver [#1716] * `baytech-mib.c` subdriver: fixed `baytech_outlet_status_info[]` set of valid outlet status values [#1871] * `cyberpower-mib.c` subdriver: support devices which report the shorter Vendor OID as their sysOID, e.g. "CyberPower PowerPanel Personal" [#1997] and support more data points including hardware status alarms [#1982] - The `bestfortress` driver shutdown handling was fixed to use a non-trivial default timeout [#1820] - The `optiups` driver only gave accurate voltage information with 120VAC models and assumed a 12V battery when calculating capacity. There is a protocol command that gives a (fixed) voltage which correlates with the voltage selection DIP switches on the back of the UPS, taking into account whether it is a 120 or 240VAC model. Likewise, now the battery capacity fix is applied globally, based on whether or not the battery voltage is greater than 20V. [#2089] - GPIO drivers [#1855]: * Added a new category of drivers, using GPIO interface to locally connected devices (currently limited to 2018+ Linux libgpiod, but its architecture was designed to support more OSes with their equivalents - PRs welcome) * `generic_gpio_libgpiod` driver using `libgpiod` backend was added (defaults to be required on Linux, optional on other platforms) - Added support for `make install` of PyNUT module and NUT-Monitor desktop application [#1462, #1504] - Regular CI coverage for NUT codebase enhanced with CircleCI running some scenarios on MacOS, might add Windows in the future. Fixed some build issues for MacOS that had crept into NUT v2.8.0 release [#1415, #1421] - NUT software-only drivers (dummy-ups, clone, clone-outlet) separated from serial drivers in respective Makefile and configure script options [#1446] - Fixed support for common USB matching options ("vendor", "device", "bus", etc.) for `riello_usb` and `richcomm_usb` [#1763] and updated man pages of all USB drivers using these options to include the same description [#1766] - Added a "busport" USB matching option (if supported by the hardware, OS and libusb on the particular deployment, it should allow to specify physical port numbers on an USB hub, rather than logical "device" enumeration values, and in turn -- this should be less volatile across reboots etc.) [#2043] - Added an `allow_duplicates` flag for common USB matching options which may help monitor several related no-name devices (although without knowing reliably which one is which... better than nothing) [#1756] - The `nut-scanner` program should now suggest same configuration fields as those used by common USB matching options in (most of the) drivers, e.g. adding "device" to the generated configuration section [#1790] - Stuck drivers that do not react to `SIGTERM` quickly are now retried with `SIGKILL` [#1424] - Each driver should now report its `driver.state` to help readers determine whether it is initializing, reconnecting, or running regular loops [#1767] - Code which resolves full paths to libraries should now consider the common environment variable `LD_LIBRARY_PATH` as a preferred possible override to built-in paths (note that most operating systems advise against setting this variable unless troubleshooting, although other systems rely on it) [#805] - Debug information tracing methods like `upsdebugx()` should now be less limited in the sizes of messages that they can print, such as path names that may be quite long. Note that the OS methods manipulating the strings, and receivers such as logging systems, may still impose limits of their own. - The `nut-scanner` usage and debug printouts now include the loadable library search paths, to help troubleshooting especially in multi-platform builds; pre-filtering of the built-in paths was introduced (to walk only existing and unique directory names) [#317] - The nut-scanner program was updated to fall back to loading unresolved library filenames, hoping that `lt_dlopen()` implementation on the current platform would find library files better [#805] - Detection of `libltdl` in `configure` script updated with fallback code to find it on systems that deliver the library to `/usr/local/lib` (e.g. on FreeBSD) [#1577] - An explicit `configure --with-nut-scanner` toggle was added, specifically so that build environments requesting `--with-all` but lack `libltdl` would abort and require either to install the dependency or explicitly forfeit the tool (some distro packages missed it quietly in the past) [#1560] - The `nut-scanner` program should now by default warn about serial numbers which do not make much sense (are duplicate, empty, all same character, etc) [#1810] - Existing openssl-1.1.0 support added for NUT v2.8.0 release was tested to be sufficient without deprecation warnings for builds against openssl-3.0.x (but no real-time testing was done yet) [#1547] - upslog: Added support for logging multiple devices with one call to the program [#1604] - Documentation to integrate NUT USB driver startup with `usb_resetter` script has been contributed to `scripts/usb_resetter` (the script itself is tracked externally on GitHub), along with a configuration example for Linux+systemd [#1887] - Some fixes applied to Solaris/illumos packaging and SMF service support [#1554, #1564] - Some fixes for builds on older OSes with less functional default system shell interpreters - now `autogen.sh` supports a `CONFIG_SHELL` envvar to inject its value into generated `configure` script [#1736] * Note that you may have to install additional tools (possibly from third-party FOSS packaging efforts) to prepare and build the NUT codebase, and/or prefer non-default system provided implementations (e.g. to use the XPG4 `grep` with `-E` support on Solaris as detailed in https://github.com/networkupstools/nut/issues/1736 comments) * Build environment configuration notes in link:docs/config-prereqs.txt[] file refreshed to cover building of current NUT codebase in CentOS 6 [#1804] and Solaris 8 [#1736, #1738] - `configure` script, reference init-script and packaging templates updated to eradicate `@PIDPATH@/nut` ambiguity in favor of `@ALTPIDPATH@` for the unprivileged processes vs. `@PIDPATH@` for those running as root [#1719] - `configure` script enhanced: `--with-unmapped-data-points` option allows to build SNMP and USB-HID subdrivers with entries discovered by the scripts which generated them from data walks, but developers did not rename yet to NUT mappings conforming to link:docs/nut-names.txt[] standards [#1699] - PyNUT.py version bumped to 1.5.0 with some improvements: * `ListClients()` method fixed (was broken in many ways), and is now CI-tested [#549] * `DeviceLogin()` method added (mostly as aid to CI-test `ListClients()` in a practically relevant manner, so far) - nutclient C++ library: * added `listDeviceClients()` and `deviceGetClients(dev)` to `Client` classes, and `Device::getClients()` to match PyNUT capabilities [#549] * published artifacts may include a `libnutclientstub` which is an implementation of a NUT TCP client in C++ with in-memory data store. - upsclient C library: * added support for `NUT_QUIET_INIT_SSL` environment variable to hide the infamous "Init SSL without certificate database" warning [#1662] - The `upsd.conf` listing of `LISTEN` addresses was previously inverted (the last listed address was applied first), which was counter-intuitive and fixed for this release [#2012] - The `upsd` configured to listen on IPv6 addresses should handle only IPv6 (and not IPv4-mappings) to avoid surprises and insecurity; it will now warn if a host name resolves to several addresses (and will only listen on the first hit, as before in such cases) [#2012] - A definitive behavior for `LISTEN *` directives became specified, to try handling both IPv4 and IPv6 "any" address (subject to `upsd` CLI options to only choose one, and to OS abilities). When both address families are enabled, the `upsd` data server will first try to open an IPv6 socket asking for disabled IPv4-mapped IPv6 address support (if the OS honors that), and then an IPv4 socket (which may fail if the IPv6 socket already covers it anyway); in other words, you can end up with one or two separate listening sockets. [#2012] - sstate (server state, e.g. upsd) should now "PING" drivers also if they last reported themselves as "stale" (and might later crash) so their connections would be terminated if really no longer active [#1626] - Clarified documentation in codebase according to end-user feedback [#1721, #1750 and others over time] - upsmon client changes include: * Several fixes for `upsmon` behavior [#1761, #1680...], including new ability to configure default POWERDOWNFLAG location -- packagers are encouraged to pick optimal location for their distributions (which remains mounted at least read-only late in shutdown) and a new optional POLLFAIL_LOG_THROTTLE_MAX setting [#529, #506] * Also `upsmon` should now recognize `OFF` and `BYPASS` flags in `ups.status` and report that these states begin or end. The `OFF` state usually means than an administrative action happened to power off the load, but the UPS device is still alive and communicating (USB, SNMP, etc.); corresponding `MONITOR`'ed amount of power sources are considered not being "fed" for the power value calculation purposes. The `BYPASS` state is now treated similarly to `ONBATT`: currently this UPS "feeds" its load, but if later communications fail, it is considered dead. This may have unintended consequences for devices (or NUT drivers) that do not report these modes correctly (e.g. an APC calibration routine seems to start with a few seconds of "OFF" state), so the reported status is only considered as a loss of feed if it persists for more than `OFFDURATION` seconds. [#2044, #2104] * Introduced `SHUTDOWNEXIT no` configuration toggle for systems which require a long time to stop their workload such as virtual machines. Since the disconnection of a "secondary" client is treated by the "primary" system as permission to proceed with its own shutdown and power-off for the UPS, the original (now merely default) behavior to call `SHUTDOWNCMD` and immediately exit could be counter-productive. An optional delay can also be introduced. [#2133] * Note there were other changes detailed below which impacted several NUT programs, including `upsmon`. - Extended Linux systemd support with optional notifications about daemon state (READY, RELOADING, STOPPING) and watchdog keep-alive messages [#1590] * Normally *inability* to send such notifications (e.g. lack of systemd or similar framework on the particular platform) would be reported once per daemon uptime on its console log, to help troubleshooting situations where such lack of notifications can cause automated service restarts. These messages can be hidden by setting `NUT_QUIET_INIT_UPSNOTIFY=true` environment variable in init-scripts on platforms where such frameworks are not expected. [#2136] - Extended Linux systemd units with aliases named after the daemons: `nut-server.service` as `upsd.service`, and `nut-monitor.service` as `upsmon.service` (so simple `systemctl reload upsd` can work) [#1777] - Extended driver-server socket protocol with `BROADCAST (num)` keyword, and a `NOBROADCAST` as a shortcut for `BROADCAST 0`. This allows clients to toggle whether they want to receive `send_to_all()` updates from a driver, or only answers to requests they send [#1914] - Added support for `make sockdebug` for easier developer access to the tool; also if `configure --with-dev` is in effect, it would now be installed to the configured `libexec` location. A man page was also added. [#1936] - Numerous daemons (`upsd`, `upsmon`, drivers, `upsdrvctl`, `upssched`) which accepted `-D` option for debug setting previously, now can also honour a `NUT_DEBUG_LEVEL=NUM` environment variable if no `-D` arguments were provided. Unlike those arguments, the environment variable does not enforce that daemons run in foreground mode by default [#1915] * Note that unlike some other NUT daemons, `upssched` with enabled debug does not stop reporting on `stderr`! [#1965] - A bug in `upssched` was discovered and fixed, where it ran a tight loop stressing the CPU; it was presumably introduced between NUT v2.7.4 and v2.8.0 releases [#1964, #1965] - Implemented generic support for INSTCMD and SETVAR use-cases shared by all drivers, and in particular to see and change active debug verbosity using the driver-server and server-client protocol (at higher priority than CLI or config file choices) per [#1285], e.g. ------ # Set verbosity level 6: :; upsrw -s driver.debug=6 UPS # Set verbosity level 0 to disable the noise (even if debug_min is set): :; upsrw -s driver.debug=0 UPS1@localhost # Un-set the protocol override, honour CLI or config-file settings again: :; upsrw -s driver.debug=-1 remoteUPS@1.2.3.4 ------ + and a `driver.killpower` instant command (for safety, must be unlocked by `driver.flag.allow_killpower` protocol setting or `allow_killpower` configuration flag), which is now the first choice for `driver -k` operations [#1917, #1923] - Implemented basic support for `ups.conf` reloading in NUT drivers, with a `driver.reload-with-error` instant command (more commands and signal handling may be available depending on platform), with a goal of changing inconsequential settings like `debug_min` for a running driver. This can also benefit the drivers on systems managed by real-time `nut-driver-enumerator` and for simpler changes the drivers get only reloaded and not redefined and restarted. Reload signals should also be reasonably supported with `upsdrvctl` tool. Relevant CLI options for `-c CMD` handing were added to drivers and `upsdrvctl`, although their availability may vary between operating systems [#1903, #1914, #1924] - Drivers should now accept `SIGURG` (or `SIGWINCH` on systems that lack the former) on POSIX platforms to dump their current state information and move on. Such report goes to `stdout` of the driver process (may be disconnected when background mode is used) -- this can help with troubleshooting [#1907] - Recipes and `main.c` code were enhanced to produce a `libdummy_mockdrv.la` helper library during build (not intended to be installed nor distributed), in order to facilitate creation of test programs which behave like a driver [#1855] - Further revision of public headers delivered by NUT was done, particularly to address lack of common data types (`size_t`, `ssize_t`, `uint16_t`, `time_t` etc.) in third-party client code that earlier sufficed to only include NUT headers. Sort of regression by NUT 2.8.0 (note those consumers still have to re-declare some numeric variable types used) [#1638, #1615] - The `COPYING` file was updated with licenses and attribution for certain source code files and blocks coming from the Internet originally [#1758] - The `tools/gitlog2changelog.py.in` script was revised, in particular to generate the `ChangeLog` file more consistently with different versions of Python interpreter, and without breaking the long file paths in the resulting mark-up text [#1945, #1955] - The "NUT client for VMware ESXi" project (by René Garcia) got its build recipes published on GitHub at https://github.com/rgc2000/NutClient-ESXi [#1961] Release notes for NUT 2.8.0 - what's new since 2.7.4 ---------------------------------------------------- NOTE: Earlier discussions (mailing list threads, GitHub issues, etc.) could refer to this change set (too long in the making) as NUT 2.7.5. - New (optional) keywords for configuration files were added, so existing NUT 2.7.x builds would not accept them if some deployments switch versions back and forth -- due to this, semantically the version was bumped to NUT 2.8.x. - Add support for openssl-1.1.0 (Arjen de Korte) - libusb-1.0 API support in addition to libusb-0.1 API [#300] - Add support for `DISABLE_WEAK_SSL=true` in upsd.conf to disable older/weaker SSL/TLS protocols and ciphers: when NUT is built against relatively recent versions of OpenSSL or NSS it will be restricted to TLSv1.2 or better. For least-surprise, currently defaults to `false` and complains in log [PR #1043] - Add support for `ALLOW_NO_DEVICE=true` (as an upsd.conf flag or environment variable passed from caller of the program), to allow starting the data server initially without any device configurations and reloading it later to apply config changes on the fly [PR #766] - Add support for `debug_min=NUM` setting (ups.conf, upsd.conf, upsmon.conf) to specify the minimum debug verbosity for daemons. This allows "in-vivo" troubleshooting of service daemons without editing init scripts or service unit definitions. - Improve support for upsdrvctl for managing of numerous device configs, including default "maxretry=3" and a "nowait" option to complete the "start of everything" mode after triggering the drivers and not waiting for them to complete initializing. This matters on systems that monitor from dozens to hundreds of devices. - Drivers support a new value for `synchronous` setting, which is the new default now: `auto`. Initially after driver start-up this mode acts as the older default `off`, but would fall back to `on` in case the driver fails to send reports to `upsd` by overflowing the socket buffer in async mode -- so the next connections of this driver uptime would be synchronized (potentially slower, but safer -- blocking on writes to the data server). This adaptation would primarily impact and benefit devices with many (hundreds of) data points, such as ePDUs and daisy chains. [issue #1309, PR #1315] - Daemons such as upsd, upsmon, upslog, and device drivers previously implied that enabled debugging (or upslog to stdout) means foreground running, otherwise the daemon was always sent to the background. Now there are explicit options for this (`-F`/`-B`), although default behavior is retained. This change is used for simplified service unit definitions. - Improvements for device discovery or driver "lock-picking", including general support for: * "Standalone" mode (`-s` option), to monitor a device which is not detailed or mentioned in ups.conf * `NUT_ALTPIDPATH` and `NUT_STATEPATH` environment variables to override the paths built into the driver binary [PR #473 and #507] * "Driver data dump" mode (`-d` option), to poll a device for one or few ('update_count' ) loops, report discovered values (dump the data tree in upsc-like format), and exit. This complements the `nut-scanner` for finding and identifying devices. - support for new devices: * IBM 6000 VA LCD 4U Rack UPS; 5396-1Kx (USB) * Phoenix Contact QUINT-UPS model 2320461 (Modbus) * Tripp-Lite SU3000LCD2UHV (USB; protocol 1330) * Emerson Avocent PM3000 PDU (SNMP) * HPE ePDU (SNMP) - nutdrv_qx: enhanced estimation of remaining battery runtime based on speed of voltage drop, which varies as they age [PR #1027] - nutdrv_qx: several subdrivers added or improved, including: * "snr" subdriver with USB connection, for SNR-UPS-LID-XXXX [PR #1008]. Note that end-users should reference explicitly the `snr` subdriver in their `ups.conf` settings because of USB chip using the same values of VendorID/ProductID as fabula_subdriver, fuji_subdriver, and krauler_subdriver. * "hunnox" subdriver, as a dialect of earlier "fabula" [PR #638] adds support for Hunnox HNX-850 with USB connection and reported to work for Powercool, Iron Guardian, ARES devices and possibly many others from discussions linking to the pull request which introduced the driver. * "phoenixtec" subdriver for Masterguard A and E series, device series A700/1000/2000/3000(-19) and E40/60/100(-19). [PR #975] * "ablerex" subdriver provided by the OEM vendor, note that it replaces "krauler_subdriver" as default handler for VID:PID 0xffff:0x0000 [PR #1135] * Legrand HID defined and handled by "krauler_subdriver" by default [PR #1075, issue #616] * add new "armac" subdriver, tested with Armac R/2000I/PSW, but should support other UPSes that work with "PowerManagerII" software from Richcomm Technologies from around 2004-2005 [PR #1239, issue #1238] - microsol-apc (starting at version 0.68 as derived from solis 0.67): adding support for newer APC Back-UPS BR hardware, such as APC Back-UPS BZ1500, BZ2200BI and BZ2200I [PR #994] - pijuice: added new i2c bus driver for PiJuice HAT, a battery UPS module for the Raspberry Pi systems [PR #730] - huawei-ups2000: added new driver for USB (Linux 5.12+ so far) and Serial RS-232 Modbus device support of Huawei UPS2000/2000A (1kVA-3kVA) series, and possibly some related FSP UPS models. [PR #954] - socomec_jbus: added new driver for modbus-based JBUS protocol over serial RS-232 for Socomec UPS (tested with a DIGYS 3/3 15kVA model, working on Linux x86-64 and Raspberry Pi 3 ARM). [PR #1313] - adelsystem_cbi: added new driver for ADELSYSTEM CBI2801224A, an all-in-one 12/24Vdc DC-UPS, which supports the modbus RTU communication protocol [PR #1282] - generic_modbus: added new driver for TCP and Serial Modbus device support. The driver has been tested against PULS UPS (model UB40.241) via MOXA ioLogikR1212 (RS485) and ioLogikE1212 (TCP/IP), and configuration allows to map custom registers and addresses to NUT events [PR #1052] - genericups: added support for FTTx battery backup devices, and new signal type mappings for the contact closure pins interpretation (RB for replace battery, BYPASS for disconnected battery, and "none" or NULL for signals to ignore) [PR #1061] - add devices to HCL/DDL: * APC Back-UPS CS (USB) * CPS CP1500EPFCLCD (USB) * CPS EC350G, EC750G (USB) * CPS PR2200LCDRT2U (SNMP) * Eaton ATS 16 and 30 (SNMP) * Eaton 5E2200VA (USB) * Eaton 9PX Split Phase 6/8/10 kVA (XML/USB/SHUT) * Eaton 9PX (XML/USB/SHUT) * Eaton Ellipse PRO 650 VA (USB) * Ippon Back Comfo Pro II 650/850/1050 (USB) * Numeric Digital 800 (USB) * Opti-UPS PS1500E (USB) * Powercool 350VA to 1600VA (USB) - C++11 support in nutclient library and cppunit tests - Added C++ testing mock for TcpClient class (nutclientmem/MemClientStub: data stored in local memory) [PR #1034] - Dual Python 2 and 3 compatibility in development scripts; ability to run build activities and resulting built NUT programs on systems that do not have a binary named "python" [PR #1115 and some before it] - Added Russian translation for NUT-Monitor GUI client [PR #806] - Separated NUT-Monitor UI into two applications, NUT-Monitor-py2gtk2 and NUT-Monitor-py3qt5, suitable for two generations of Python ecosystem with their great differences; `NUT-Monitor` name is retained for wrapper script which calls one of these, such that the current system can execute [PRs #1310, #1354] - Various USB driver families: expanded device-matching with "device" in addition to "bus" and generic USB fields. This is needed to support multiple attached devices that seem identical by other fields (e.g. same vendor, same model, same USB bus, and no serial number) [PR #974] - Various USB driver families: Improved HID parsing for byte-stream to number conversions on different CPU architectures [PR #1024] - Various USB HID driver families: added support for composite devices utilizing interface greater than 0 for the UPS interface [PR #1044] - usbhid-ups: * added generic framework for fixing Report Descriptors which can be used for different manufacturers by adding code to the appropriate subdriver rather than polluting the main code with UPS specific exceptions, and applied fixes for known mistakes in (some releases of firmware for) CyberPower CPS*EPFCLCD [issue #439, PR #1245] * added `onlinedischarge` option for UPSes that report `OL+DISCHRG` when wall power is lost [PR #811] * changed detection of VendorID 0x06da handling of which is claimed by Liebert/Phoenixtec HID historically, and MGE HID (for AEG PROTECT NAS UPSes) since NUT 2.7.4, so that the higher-priority MGE subdriver would not grab each and all of the devices exposing that ID [PR #1357] * CPS HID: add input.frequency and output.frequency * OpenUPS2: only check OEM Information string once (fewer log messages) * Liebert GXT4 USB VID:PID [10AF:0000] * add battery voltage and input/output transfer voltage and frequency in Liebert/Phoenixtec HID mapping, to support PowerWalker VFI 2000 TGS better [PR #564, issue #560] * add a little delay between multicommands [PR #1228] * fix Eaton/MGE mapping for beeper handling * add IBM USB VID * add deep battery test for CyberPower OL3000RMXL2U * report the libusb version used * fixed CPU architecture dependent bitmask math issues, causing wrong numbers interpreted from wire protocol data in Big-Endian LP64 builds (SPARC64, s390x, etc.) [issue #1023, PRs #1024, #1040, #1055, #1226] * add Delta UPS Amplon R Series, tested on R1K and R3K model [PR #987] * add Delta Minuteman UPS VID/PID [PR #1230, issues #555 and #1227] * add AMETEK Powervar UPM [PR #733] * add Tripplite AVR750U (ProductID 0x3024) [PR #963] * add Arduino HID device support with new arduino-hid subdriver [PR #1044] * add new salicru-hid subdriver, tested with Salicru SPS Home 850 VA [PR #1199, issue #732] * add new ever-hid subdriver to support EVER UPS devices (Sinline RT Series, Sinline RT XL Series, ECO PRO AVR CDS Series) [PR #431] * add ability to set `battery.mfr.date` for APC HID UPS [PR #1318] - usbhid-ups / mge-shut: compute a realpower output load approximation for Eaton UPS when the needed data is not present - snmp-ups: * APC ePDU MIB support * add `input.phase.shift` variable * add configurable write-able `ondelay` (`ups.delay.start`) and `offdelay` (`ups.delay.shutdown`) as timeticks support [PR #276] * outlet groups * fix the rounding / truncation of some values * add outlet.N.name for Eaton ePDU * add input.bypass.frequency for Eaton 3ph * fix support for Eaton 2-phase ("split phase") UPS * add flag to list currently loaded MIB-to-NUT mappings * fix input.L2.voltage on Eaton G2/G3 PDU * update Eaton Aphel Revelation MIB * support Raritan Dominion PX2 PDU * support Emerson Avocent PM3000 PDU * improve ALARM flag handling * add firmware version for new HPE Network card * add ups.load, battery.charge, input.{voltage,frequency} and output.voltage for CyberPower, as well as shutdown and other instant commands * several rounds of updates for Eaton devices, including new ATS and ePDU hardware families * fixed bit mask values for flags to surely use different numbers behind logical items (inevitably changing some of those macro symbols) [PR #1180] - snmp-ups and nut-scanner should now support more SNMPv3 Auth and Priv protocols, as available at NUT build time [PRs #1165, #1172] - nut-scanner: various improvements, including: * detection of libraries at runtime * tracing information * limiting parallelism (thread count) [PRs #1158, #1164] - nut-ipmipsu: improve FreeIPMI support to build cleanly against older and newer FreeIPMI versions [PR #1179] - the powerpanel driver now also supports CyberPower OR1500LCDRTXL2U with serial cable [PR #538] - powercom driver: implement `nobt` config parameter to skip battery check on initialization/startup [PR #1256] - netxml-ups: * Report calibration status * Fix for erroneous battery info (MGEXML/0.30) [PR #1069] - solis: various improvements and fixes - liebert-esp2: Correct battery V scaling, update docs, implement split-phase unit support [PR #412] - tripplite: the "Tripp-Lite SmartUPS driver" as tested with SMART2200NET learned to discover the firmware generation and some device features, and in particular to manage power separately on one or two outlet groups [PR #1048] - tripplite_usb: updated to recognize the "3005" protocol [PR #584] - libnutclient: introduce getDevicesVariableValues() to improve performances when querying many devices (up to 15 times faster) - nut-driver-enumerator: introduced a script for Linux systemd and Solaris/illumos SMF to inspect current NUT configuration in ups.conf file and generate service management instances for each currently tracked power device. Also introduced services to monitor the NUT configuration and react to editions of this file, mostly intended for deployments that do massive monitoring of dynamically changing farms of power devices. - Fix File descriptors leaks by upsmon and upssched (SELinux errors) - systemd support improvements: * POWEROFF_WAIT * reload support for upsd * Deliver systemd-tmpfiles config to pre-create runtime locations [PR #1037 for Issue #1030] * Update units with SyslogIdentifier=%N for better logging [PR #1054] - upsrw: display the variable type beside ENUM / RANGE - Added `PROTVER` as alias to `NETVER` to report the protocol version in use. Note that NUT codebase itself does not use this value and handles commands and reported errors individually [issue #1347] - Implement status tracking for instant commands (instcmd) and variables settings (setvar): this allows to get the actual execution status from the driver, and is available in libraries and upscmd / upsrw [PR #659] - Add support for extra parameter for instant commands, both in library and in upscmd - dummy-ups can now specify `mode` as a driver argument, and separates the notion of `dummy-once` (new default for `*.dev` files that do not change) vs. `dummy-loop` (legacy default for `*.seq` and others) [issue #1385] - new protocol variables: * `input.phase.shift` * `outlet.N.name` * `outlet.N.type` * `battery.voltage.cell.max`, `battery.voltage.cell.min` * `battery.temperature.cell.max`, `battery.temperature.cell.min` * `battery.status` * `battery.capacity.nominal` * `battery.date.maintenance` (and clarified purpose of `battery.date`) * `battery.packs.external` (and clarified purpose of `battery.packs`) * `experimental.*` namespace introduced [PR #1046] to facilitate introduction of NUT drivers and their data points for which we do not yet have concepts, or which the original driver contributors did not map well per suitable NUT standards: this allows to balance having those drivers available in the project vs. least surprise for when the explicitly experimental names are changed to something stable and standardized. * Proposed to track Date and Time values (still as "opaque strings") preferably in representations compatible to ISO-8601/RFC-3339 [PR #1076] (standards update; changes to actual codebase to be applied in the future) ** New routine to convert a US formatted date string "MM/DD/YYYY" to an ISO 8601 Calendar date "YYYY-MM-DD" was added to snmp-ups.c [PR #1078] - Master/Slave terminology was deprecated in favor of Primary/Secondary modes of `upsmon` client: * Respective keywords in the configuration files (`upsd.users` and `upsmon.conf`) are supported as backwards-compatible settings, but the obsoleted values are no longer documented. * Protocol keyword support was similarly updated, with `upsmon` now first trying to elevate privileges with `PRIMARY ` request, and falling back to `MASTER ` just in case it talks to an older build of an `upsd` server. * For the principle of least surprise, NUT codebase still exposes the `net_master()` (as handler for `MASTER` net command) in header and C code for the sake of existing linked binaries, and returns the `OK MASTER-GRANTED` line to the older client that invoked it. * Newly introduced `net_primary()` (as handler for `PRIMARY` net command) calls the exact same application logic, but returns `OK PRIMARY-GRANTED` line to the client. * Python binding updated to handle both cases, as the only found in-tree protocol consumer of the full-line text. * For more details see issue #840 and several pull requests referenced from it, and discussions on NUT mailing lists. - Build fixes: * In general, numerous fixes were applied to ensure portability and avoid warnings (fixing a number of real bugs that caused them); CI was extended to keep the codebase free of those types of warnings which we have got rid of, requiring builds to succeed cleanly in several dozen combinations of compiler versions, C standard revisions (C99 upwards, though on many OSes with GNU99+ extensions), operating systems and CPU architectures. * Public CI introduced to automatically test every contribution (PR) and resulting increment of main NUT codebase, including Travis CI and LGTM.com services, and a Jenkins farm on virtual hardware donated by Fosshost.org; this augments testing earlier provided for some branches by Buildbot. * Added cppunit testing with valgrind for the C++ client library * Make targets added for shell script syntax checks for helper and service scripts * Make targets added for spellcheck and for maintenance of the dictionary, including incremental spellcheck to only parse recently edited text files * The AsciiDoc detection has been reworked to allow NUT to be built from source without requiring asciidoc/a2x (using pre-built man pages from the distribution tarball, for instance) * Makefile contents rearranged for more resilient out-of-tree and in-tree builds beside those made from the root workspace directory * Makefiles are tested with GNU Make and BSD Make to ensure portable recipes * More use of `pkg-config` to detect dependencies at configure time, as well as fail-safe detection of presence of pkg-config (and its macros) to survive and build without it too * "slibtool" pedantic nuances now supported, allowing an alternative to GNU libtool * Build scripts updated to remove obsoleted calls to cleanly work with autoconf-2.70 releases in 2020 (also works with 2.69 which was the earlier release since 2012) * Dynamic library loading used in certain programs and use-cases improved, especially for 64-bit vs. 32-bit builds on multiple-bitness OSes * Logging routines like `upsdebugx()` were refactored as macros so there is slightly less overhead when logging is disabled [PRs #685 and #1100] * Numerous classes of compilation warnings eradicated, many of those being potential issues with implicit data type conversions and varied numeric type width, signedness, string buffer size, uninitialized variables or structure fields; some more in progress * Several logical errors found and fixed during this walk over codebase. * Cases where compilers were overly zealous and particular code was written the way wit was intentionally, including some comparisons that help with different-bitness builds but indeed seem superfluous in a certain single bitness, were commented and encased in pragmas to disable the warnings * Basic coding style (indentations, lack of trailing white space) applied per developer guide, but not automatically enforced/checked yet. - Due to changes needed to resolve build warnings, mostly about mismatching data types for some variables, some structure definitions and API signatures of several routines had to be changed for argument types, return types, or both. Primarily this change concerns internal implementation details (may impact update of NUT forks with custom drivers using those), but a few changes also happened in header files installed for builds configured `--with-dev` and so may impact `upsclient` and `nutclient` (C++) consumers. At the very least, binaries for those consumers should be rebuilt to remain stable with NUT 2.8.0 and not mismatch int-type sizes and other arguments. - As usual, more bugfixes, cleanup and improvements, on both source code and documentation. Release notes for NUT 2.7.4 - what's new since 2.7.3 ---------------------------------------------------- - New class of device supported: ATS - Automatic Transfer Switch are now supported in NUT. Eaton ATS are supported, and APC ones should be too. Users are welcomed to test and provide feedback - NUT command and variable naming scheme: * Document battery.charger.status, which will in time replace the historic CHRG and DISCHRG flags published in ups.status * Many extensions to support outlets groups, thresholds / alarms (ambient, input, output, outlet and outlet.group) - support for new devices: * AEG PROTECT B / NAS * APC ATS AP7724 (should be supported) * Asium P700 * Eaton ATS * Eaton 5E 1100iUSB * Eaton E Series DX UPS 1-20 kVA * Eaton Powerware 9125-5000g * Electrys UPS 2500 * Fideltronic INIGO Viper 1200 * Legrand Keor Multiplug * LYONN CTB-800V * Micropower LCD 1000 * NHS Laser Senoidal 5000VA * Sweex model P220 * TS Shara * Various APCUPSD-controlled APC devices - snmp-ups: * Improve automatic detection algorithm * Provide access to Net-SNMP timeout and retries * Proper handling of integer RW variables * Implement support for alarms, through ups.alarm and outlet.n.alarm * Improve log/debug output trace * Fix loss of precision when setting values, using upsrw * Support for outlets group management * Many improvements and simplification * Add support for Tripplite units using IETF mib * Improve communication staleness detection and recovery * Add devices MAC address publication * Register values enumerations, when available * Many improvements and fixes to the SNMP subdriver creation script - Eaton: * 3ph SNMP: Many improvements to Powerware / XUPS MIB, for data and commands Add support for Eaton Power Xpert Gateway UPS Card Improve support for temperature and humidity, including low / high values Alarms handling * ePDU (G2 and G3): Improve support for ambient sensor, including thresholds and dry contacts Outlet groups handling, including data, thresholds, settings and commands Alarms handling * XML/PDC (netxml-ups): Fix Eaton XML published data Add some settings (R/W flags) on ambient thresholds - bcmxcp_usb: improvements for device claiming and multi-packets responses - dummy-ups: allow any variable to be modified - libnutclient: Fix for reads when the socket was closed by NUT server - macosx-ups: * fix for 10.10 (Yosemite), v1.1 * gracefully handle disconnection of UPS (return "data stale") - nutdrv_atcl_usb: point to nutdrv_qx (fuji) for 0001:0000 - nutdrv_qx: * Add new 'sgs' USB subdriver to support TS Shara units * various improvements and simplification, to the code and documentation - nut-ipmipsu: improve FreeIPMI support - nut-scanner: * Don't depend on development libraries, by looking at some known paths, including the one provided through --libdir, to find the correct libraries * Fix a crash on a 2nd call to libnutscan with SNMP method - powercom: fix the processing of input and output voltage for KIN units - solis: * many improvements and cleanup * resync with end-of-packet character * fixes for Microsol Back-Ups BZ1200-BR - tripplitesu: Fix initialization when tripplite firmware is buggy (for Tripplite SU1000RT2U and possibly more) - usbhid-ups: * various minor improvements * support for Eaton UPS with dual HID report descriptor in HID Parser * handle missing USB strings in APC code - SSL support through Mozilla NSS: Rework the NSS tests to ensure that NSS is actually installed and usable for enabling SSL support in NUT - Augeas support: Augeas lens for ups.conf was updated to add various missing global directives and ups fields - scripts/systemd/nut-server.service.in: Restore systemd relationship since it was preventing upsd from starting whenever one or more drivers, among several, was failing to start - Fix UPower device matching for recent kernels, since hiddev* devices now have class "usbmisc", rather than "usb" - Network protocol information: default to type NUMBER for variables that are not flagged as STRING . This point is subject to improvements or change in the next release 2.7.5. Refer to link:docs/net-protocol.txt[] for more information - As usual, more bugfixes, cleanup and improvements, on both source code and documentation. Release notes for NUT 2.7.3 - what's new since 2.7.2 ---------------------------------------------------- - reverted POWERDOWNFLAG to /etc/killpower as in 2.6.5 (packagers may want to put this in another filesystem, though) - configure/make fixes for `systemdsystemunitdir` - apcsmart: fix command set parsing for protocol version 4 (e.g. Smart-UPS RT 10000 XL) - upslog: SIGUSR1 forces an immediate log entry - riello_usb/_ser: USB interface claim fix; improved error handling - usbhid-ups: add support for OpenUPS2 (PID: D005), Liebert GXT3 (PID: 0008) APC AP9584 Serial->USB kit (PID: 0000), and some Powercom models (PID: 0001). Fixed scaling for Cyberpower 0764:0501. - USB core: do not call usb_set_altinterface(0) by default - nutdrv_qx: * added fabula, fuji USB and Voltronic-QS-HEX subdrivers * add bestups subdriver to supersede the old standalone bestups driver - NUT Monitor: added FreeDesktop AppData file (including screenshots) - renamed udev rules file to 62-nut-usbups.rules (permissions fix) - added AIX packaging - asem: added a driver for the UPS in ASEM PB1300 embedded PCs - solis: updated to support APC Microsol units sold in Brazil - tripplite_usb: * updated to use dv/dq charge calculation for all models (also exposes battery_min and battery max as configuration variables) * added binary 3005 protocol support (such as for SMART500RT1U) - genericups: better debugging while parsing the cable description flags - all drivers: a new 'synchronous' driver flag is available for very verbose units, such as some ePDUs - Eaton: * Add support for EnergySaving features for Eaton UPSs (HID USB/SHUT and XCP USB/serial) * Fix and complete Eaton ePDUs G2/G3 support * ABM (Advanced Battery Monitoring) support through battery.charger.status in HID (USB and SHUT), XCP (USB and serial) and SNMP (Powerware XUPS MIB) - support for new devices: * APC Back-UPS 1200BR and Back-UPS BZ2200BI-BR (Microsol) * ASEM SPA PB1300 UPS * Belkin Regulator PRO-USB * Cyber Power Systems Value 1500ELCD-RU * EUROCASE EA200N 2000VA * Fideltronik LUPUS 500 * Flight Technic & International (FTUPS) FT-1000BS and FT-1000BS(T) * Grafenthal PR-3000-HS * JAWAN JW-UPSLC02 * Lacerda New Orion 800VA * Mecer ME-1000-WTU * NHS Sistemas de Energia Expert C Online 6000/8000/10000 * NHS Sistemas de Energia Expert S Online 6000/8000/10000 * Powercom BNT-xxxAP (USB product id: 0001) * Rucelf UPOII-3000-96-EL * Tripp Lite OMNIVSINT800 * Voltronic Power Apex 1KVA and Imperial 1KVA Release notes for NUT 2.7.2 - what's new since 2.7.1 ---------------------------------------------------- - This release is the second interim release of the 2.7 testing series. - libupsclient had undefined references related to functions of libcommon. This issue was reported on Debian (bug #731156) and is now fixed - support for new devices: * CABAC UPS-1700DV2 * Eaton Powerware 3105 * Emerson Network Power Liebert PSI 1440 * MicroDowell B.Box LP 500 * Numeric Digital 800 plus * OptiUPS vs. 575C * Tripp Lite SU10KRT3/1X - FreeDesktop Hardware Abstraction Layer (HAL) support was removed. - nutdrv_atcl_usb: new driver for 'ATCL FOR UPS' - al175: re-introduced this driver (actually, it was in 2.7.1) - upsdrvctl now provides retry options for upsdrvctl and driver(s) - snmp-ups: add support for XPPC-MIB and Tripp Lite SU10KRT3/1X. Also fix erroneous status in HP/Compaq SNMP MIB (with the most recent HP firmware (1.76); improved various MIBs (APC, HP/Compaq, ...) - nutdrv_qx: add new 'fallback' Q1 subdriver, with minimal 'Q1' support. General improvements on all subdrivers. - mge-shut: partially revert PnP/RTS change, for initializing the communication with the UPS. Note that nut-scanner similar function was not modified however. - FreeBSD DEVD support: generate devd.conf files for USB UPSes This adds a --with-devd-dir=PATH option to ./configure - The NUT website was moved to a standalone website. A separate code repository and source archive are now available. - As usual, more bugfixes, cleanup and improvements, on both source code and documentation. Release notes for NUT 2.7.1 - what's new since 2.6.5 ---------------------------------------------------- NOTE: There was no public NUT 2.7.0 release. - This release is an interim release, part of the testing series, and the first release after the transition from Subversion to Git. The last release (2.6.5) is almost a year old. A lot of work has been done, but a good amount remains to achieve 2.8.0 goals. Please read the link:UPGRADING.adoc[] notes. - Added support for SSL via the Mozilla NSS library, in addition to the existing OpenSSL support. - Added a new driver, nutdrv_qx, for Megatec/Qx devices. This driver will eventually replace the blazer_ser and blazer_usb drivers. In particular, it adds support for Voltronic Power devices. - Increased USB_TIMEOUT to standards-compliant 5.000 seconds in most drivers. This should reduce the number of timeouts on low-speed USB 1.1 devices. - The jNut Java source has been split into a separate GitHub repository. - Added many devices to the HCL. Of particular note are many Tripp Lite USB HID PDC models which were tested against NUT by Tripp Lite. - Reworked some visual elements of the HCL. The output is better tailored for graphical and text-only browsers, but suggestions are welcome for additional accessibility enhancements. - Also increased timeouts and added redundant commands to improve reliability of mge-utalk driver. - Added the apcupsd-ups driver to interoperate with apcupsd installations. - Added documentation on creating subdrivers for snmp-ups and nutdrv_qx. - Added new drivers for the Riello UPS product line (riello_ser/riello_usb). - Many improvements to the BCM/XCP drivers have been merged in. This includes an improved data reception loop, and additional mappings. - Added a few variables to the Powercom HID mappings. - Updated the apcsmart driver, and renamed the previous driver to apcsmart-old. - Fixed the battery percentage calculation in the bestfcom driver. - libnutclient has been added as a C++ alternative to libupsclient. - Packaging files for Solaris and HP-UX (sponsored by Eaton) - Fix shutdown of Eaton HID, using usbhid-ups and mge-shut - usbhid-ups: final fix for APC Back UPS ES. APC Back UPS ES devices have buggy firmware, and this version does not cause a regression. The max_report variable should be set automatically based on the USB identification values. * UPDATE: known as `maxreport` flag for `usbhid-ups` driver, and as a `max_report_size` setting in code, as of NUT v2.8.2 release. - nut-scanner: fix crash - IPMI support can handle more different versions of FreeIPMI - Support power supplies scan over the network nut-scanner can now scan for power supplies with IPMI over LAN. This is currently limited to IPMI 1.5 only - Implement a framework to spell check documentation source files, using Aspell. This includes an interactive build target (make spellcheck-interactive), and an automated one (make spellcheck), mainly for QA / Buildbot purpose. Note that a base NUT dictionary is also available (link:docs/nut.dict[]), providing a glossary of terms related to power devices and management - Improve systemd integration - snmp-ups: Fixed a crash on outlet management, and added delta_ups MIB support. Also fixed mappings for upsBypassVoltage, upsBypassCurrent, and upsBypassPower in three-phase IETF MIB. Release notes for NUT 2.6.5 - what's new since 2.6.4 ---------------------------------------------------- - This release fixes an important regression in upssched: any upssched.conf command that takes a second argument resulted in a defective frame sent to the parent process. Thus, the command was not executed (report and patch from Oliver Schonefeld) - Website hosting: free NUT from Eaton website hosting + + NUT website (https://www.networkupstools.org) is no longer hosted by Eaton. Arnaud Quette (NUT project leader) has taken over NUT hosting on his own, to give NUT back some independence. + + This effort is also part of a logic to stop crediting Eaton for contributions from others (especially Arnaud Quette, as an individual). The new hosting service is located, as for Arnaud's blog (http://arnaud.quette.fr) on Gandi servers, using PaaS. + + This will allow more flexibility and automation of the release process. - macosx-ups: new OS X Power Sources meta-driver * Mac OS X provides UPS status information in a format similar to what is shown for laptop batteries. This driver will convert that information into a format compatible with NUT (Charles Lepple). - support for new devices: * Eaton ePDU Switched * Online Zinto A (USB ID 0x06da:0x0601) * REDi Blazer 400VA / 600VA / 800VA * UNITEK Alpha650ipF and Alpha650ipE (USB ID 0x0f03:0x0001) - mge-shut driver has been replaced by a new implementation (newmge-shut). In case of issue with this new version, users can revert to oldmge-shut. UPDATE: oldmge-shut was dropped between 2.7.4 and 2.8.0 releases. - First NUT virtualization package: NUT now supports integration with VMware ESXI 5.0, through a native VIB package. This is, for the time being, an external effort from René Garcia (refer to the Download section on NUT website). But work is underway to improve this integration, and include it in the NUT source tree - IPMI support (nut-ipmipsu driver and nut-scanner): prepare for supporting API changes in upcoming FreeIPMI versions 1.1.x and 1.2.x. - snmp-ups now supports high precision values for APC, and more variables - the NUT variables and commands namespace has been fixed and completed, with the known and used variables that were missing. - more bugfixes, cleanup and improvements, on both source code and documentation. Release notes for NUT 2.6.4 - what's new since 2.6.3 ---------------------------------------------------- - This release fixes an important vulnerability in upsd (CVE-2012-2944: upsd can be remotely crashed) + + NUT server (upsd), from versions 2.4.0 to 2.6.3, are exposed to crashes when receiving random data from the network. + + This issue is related to the way NUT parses characters, especially from the network. Non printable characters were missed from strings operation (such as strlen), but still copied to the buffer, causing an overflow. + + Thus, fix NUT parser, to only allow the subset of ASCII charset from `Space` to `~` (Reported by Sebastian Pohle, Alioth bug #313636, CVE-2012-2944) + + A separate patch, which applies to any faulty version, is also available: http://trac.networkupstools.org/projects/nut/changeset/3633 + + For more information, refer to the Common Vulnerabilities and Exposures: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2944 - A static source code analysis has been done by Michal Hlavinka from RedHat, using Coverity (12 issues fixed). - Add new "LIST CLIENTS" and "NETVER" commands to NUT network protocol. "NETVER" allows to retrieve the Network protocol version, while "LIST CLIENTS" provides the list of clients connected to a device. Refer to the developer guide, "Network protocol information" section for more information. - Support of ranges of values for writable variables has been added, to complete the existing enumerated values mechanism. This will start to appear in some drivers soon, beginning with Eaton. Refer to the developer guide, "Creating a new driver..." section for more information. - PyNUT.py has been updated to version 1.2.2, adding support for LIST CLIENTS, FSD, HELP and VER (Rene Martín Rodríguez) - support for new devices: * AEG Power Solutions PROTECT HOME * more APC SNMP cards * ATEK Defensor range * all Borri models * all COVER ENERGY SA * CyberPower OR700LCDRM1U, PR6000LCDRTXL5U and CP1000PFCLCD * Dell UPS Network Management Card * Dynamix 1000VA USB * Eaton Management Card Contact (ref 66104) * EVER POWERLINE RT / 11 / 31 and DUO II Pro * GE Digital Energy GT Series 1000-3000 VA * Gtec models * all recent HP serial / USB UPS (G2, G3 and R/T models, ) and HP UPS Management Module * Ippon INNOVA RT * KOLFF BLACK NOVA * Lexis X-power Tigra 1kVA * Microline C-Lion Innova * Online Yunto YQ450 * PowerShield Defender 1200VA * PowerWalker Online VFI LCD, Line-Interactive VI LCD and Line-Interactive VI * Riello Netman Plus 102 SNMP Card * Tripp-Lite OMNISMART500 - apcsmart has received some fixes to work better on Mac OS X, and in general - bcmxcp has improved support for battery status, and better supports PW9120 units - bestfortress has improved Best Fortress LI675VA support - blazer_ser and blazer_usb now try to automatically estimate high and low voltages, to be able to calculate battery charge; support for online Innova UPS (T, RT and 3/1 T) has been added; Best UPS support has been improved, to prepare for superseding bestups driver - bestups has also received some care, though users are encouraged to switch to blazer_ser, since bestups will soon be deprecated. - newmge-shut has been heavily improved. However, replacement of the current mge-shut has been postponed to the next release, due to the CVE issue. - oneac 0.80 improves support for all families of Oneac (EG, ON, OZ and OB), including more data and instant commands (Bill Elliot). - usbhid-ups: for Eaton devices, ups.start.auto is now automatically adjusted for shutdown.{return,stayoff} to behave as expected; Liebert firmwares with incorrect exponents have also been addressed. - snmp-ups now provides support for UPS shutdown, based on usbhid-ups mechanisms (composite commands and fallback). Composite commands are also supported now. This means, for example, that if 'shutdown.return' is not supported, a combination of 'load.off' + 'load.on' may be used; Actual validity of instant commands is now tested before commands addition; Eaton/MGE MIB has been cleaned and completed; 3-phases support has been added to Socomec Netvision MIB; HP/Compaq MIB has been completed, with thresholds, nominal values and more commands. - nut-scanner now also has libupsclient has a weak runtime dependency; more docs and bugfixes have also happened. - Provide an Uncomplicated Firewall (UFW) profile (nut.ufw.profile) - Riello protocols have been officially published in NUT protocols library: https://www.networkupstools.org/ups-protocols.html#_riello - Duplicate instances of upsd / upsmon are now detected upon startup - NUT variables namespace has been completed with missing variables and commands that are already known and standard - upslog now comes with a companion file, for logrotate configuration - more devices embed NUT for power protection, now including Thecus NAS range - more bugfixes, cleanup and improvements, on both source code and documentation, with a good bunch from Greg A. Woods. Release notes for NUT 2.6.3 - what's new since 2.6.2 ---------------------------------------------------- - nut-scanner is now more portable, and provides more coherent option names. IPMI support has also been added, to discover local power supplies. This version brings weak runtime dependencies in libnutscan, which allows to compile nut-scanner with all options and to run according to the available dependencies (USB, SNMP, IPMI, ...). - libnutscan now provides pkg-config support and the needed header files are distributed. Some documentation is also available in the developer guide and manual pages have been updated and completed. - support for new devices: * Cyber Power Systems with SNMP RMCARD (100, 201, 202 and 301) * Dynamix 650VA USB * LDLC UPS-1200D * Tecnoware UPS ERA LCD 0.65 * Powercom BNT-xxxAP (USB ID 0d9f:0004) * Various USB devices using UPSilon 2000 software - apcsmart has received minor correction. - bcmxcp_usb now handles disconnection issues and reconnection mechanism. - blazer_usb enables again inclusion of buggy USB Device and Vendor IDs in udev rules file; language ID support has been added for USB units from LDLC, Dynamix and other no names. - nut-ipmipsu has also received some improvements. - snmp-ups has fixed outlets reported current in aphel_genesisII MIB; MGE 3 phases handles better low battery condition; support for Cyber Power Systems with SNMP RMCARD has been added; support of the newer Eaton ePDUs has been improved. - upsd doesn't anymore fail to start if at least one of the listening interface is available. This is needed on systems where either IPv4 or IPv6 is disabled, and no explicit LISTEN directive has been specified. - Avahi support is now automatically enabled, upon detection - jNut (NUT Java interface) adds device discovery support, through a nut-scanner wrapper; jNutWebAPI, a HTTP/JSON web service interface, has also been added to interact with upsd and nut-scanner. - Base files for HPUX packaging have been added. This is still a work in progress. - Compilation on IBM AIX has been fixed (namespace conflict with ctypes). - more bugfixes, cleanup and improvements, on both source code and documentation. Release notes for NUT 2.6.2 - what's new since 2.6.1 ---------------------------------------------------- - NUT can now monitor power supply units (PSU) in servers, through IPMI, using the new experimental 'nut-ipmipsu' driver. Users are encouraged to test it, and send feedback and debug output to the development mailing list. This requires GNU FreeIPMI (0.8.5 or higher) development package or files. Thanks goes to Al Chu, FreeIPMI project leader, for his help during this development. - NUT now provides a tool, called 'nut-scanner', to discover supported devices, both local and remote. nut-scanner will help to ease the configuration step, and power infrastructure discovery. + + This development, sponsored by Eaton, supports the following methods: * USB, * SNMP, * XML/HTTP (from Eaton), * NUT servers, using the classic connect or Avahi / mDNS methods. + + IPMI support will be added in the next release. + + A separate library, called 'libnutscan', is also available to provide these feature. Future NUT releases will provides binding for the supported languages (Perl, Python and Java). - NUT now provides a Java interface called 'jNut'. This development, sponsored by Eaton, is currently limited to the client interface. But it will be broaden to device discovery and configuration in the future. + + For more info, refer to nut/scripts/java/README, or the developer guide (chapter 'Creating new client'). Javadoc documentation is also provided, along with Java archives (.jar) in the Download section. - support for new devices: * Eaton 3S * Cyber Power Systems CP1000AVRLCD * various APC models equipped with APC AP9618 management card, including APC Smart-UPS RT XL * Orvaldi 750 / 900SP * POWEREX VI 1000 LED * PowerWalker VI 850 LCD * SVEN Power Pro+ series (USB ID ffff:0000) - A regression has been fixed in udev rules file. This previously caused permission issues to owners of some USB devices. - Avahi support has been added, for NUT mDNS publication, through a static service file (nut/scripts/avahi/nut.service). - usbhid-ups has had Eaton completion: some features have been improved, such as 'output.voltage.nominal'; 3S Eco control support has been added, along with battery.runtime.low and end of battery life (life cycle monitoring) support; new measurements for 5 PX are also supported now (outlet power factor, power, real power and current). - apcsmart has been updated to support more variables and features; the previous driver is however still available as 'apcsmart-old', in case of issues. - bcmxcp now supports per outlet startup and shutdown delays setting; shutdown delay is also used, when available, for outlet.n.shutdown.return instead of the default 3 seconds. - snmp-ups.c has a new initialization method, that uses sysObjectID, which is a pointer to the preferred MIB of the device, to detect supported devices. This speeds up even more init stage and should render void the use of 'mib' option. SNMP v3 session initialization has also been fixed, and Eaton PDU support has been completed. - Initial support has been added for systemd, the System and Service Manager from RedHat. - The chapter 'NUT configuration management with Augeas' of the developer guide has received some completion: a complete Python Augeas example code is now provided. - Finally, after years of dedication to NUT, Arjen de Korte is now retired. Sincere thanks to you Arjen from us all. Release notes for NUT 2.6.1 - what's new since 2.6.0 ---------------------------------------------------- - the various recent USB regressions have been definitely fixed. - NUT now propose a variable to expose UPS efficiency (ups.efficiency). Eaton 5 PX already uses it. - the Perl module from Gabor Kiss (rewritten from Kit Peters') is now distributed with NUT source code. - support for new devices: * Eaton Ellipse ECO, Powerware 9140, Eaton 5 PX, and ambient sensor on Eaton ePDU managed * GE EP series * Inform Sinus SS 210 * IPAR Mini Energy ME 800 * Mustek Yukai PowerMust 1000 USB * Numeric 3000 SW * SVEN Power Pro+ series (recent models) * Vivaldi EA200 LED - liebert-esp2: Improved Liebert ESP II support, including UPS shutdown (poweroff), 1 and 3-phase input and output variables, and most input / output / bypass / nominal variables. There is also a fix for the USB to serial cable (Farkas Levente and Spiros Ioannou). - powercom has improved PowerCom BNT 1500A and BNT-other support, along with driver documentation and code conformance to the NUT rules (Keven L. Ates). - apcsmart has more improved UPS poweroff support and options (Michal Soltys). - blazer has also seen some improvements. - usbhid-ups has completed a bit supported variables for APC and Eaton / MGE. - on the quality assurance side, Eaton has worked on fixing a few non-conformance issues, like C++ style comments and warnings, using a newly developed verification tool (Prachi Gandhi). - fix remaining references to LIBSSL_LDFLAGS, instead of LIBSSL_LIBS, which cause unresolved symbol on libupsclient users (Fabrice Coutadeur). - the website has now a better support for Internet Explorer 6. - graphic illustrations, used for the Features page on the website Features and chapter of the user manual, have been refreshed (courtesy of Eaton). - more bugfixes, cleanup and improvements, on both source code and documentation. Release notes for NUT 2.6.0 - what's new since 2.4.3 ---------------------------------------------------- NOTE: Per original semantic versioning, there were no public NUT 2.5.x releases. - the main focus of this release is the complete documentation revamping, using AsciiDoc. This includes a new website, user manual, developer guide, packager guide and manual pages, available in various formats (single and multiple pages HTML, and PDF at the moment). + + Be sure to check the `--with-doc` option help of `configure` script, and link:docs/configure.txt[] for more information. - Add Augeas support, to provide easy NUT configuration management, through tools and development APIs. For more information, refer to the developer guide, or link:scripts/augeas/README.adoc[] in the source directory. - support for new devices: * APC 5G * Eaton PowerWare 5119 RM (smart mode using upscode2 driver) * Eaton Best Ferrups (using older ConnectUPS card) * Eaton 9395 (serial interface) * Eaton ConnectUPS X / BD / E Slot * HP T1000 INTL * HP T1500 INTL * HP T750 G2 * HP R1500 G2 INTL * iDowell iBox UPS * Tripp Lite SmartOnline SU1000XLA * Tripp Lite Smart1000LCD * and some more USB/HID devices IDs * CyberPower CP1500AVRLCD and CP1350AVRLCD * PowerWalker Line-Interactive VI 1400 * Rocketfish RF-1000VA / RF-1025VA - usbhid-ups has better support for shutting down APC SmartUPS RM series, and finally fix the "buffer size" issue, which was breaking some devices data retrieval, or truncating some data on others. - snmp-ups now support SNMP v3 and its security parameters. IETF MIB support has also been extended. - fix dummy-ups simulation driver status handling bug, and add the capability to remove exposed variables on the fly. - the belkin driver now support control commands and status reporting for beeper and battery test. - the powerpanel driver supports more older CyberPower units. - mge-utalk, upscode2, blazer and liebert-esp2 have also received some care, and been improved. - NUT-Monitor and the PyNUT client module have been updated to 1.3, adding more features like automatic connection to the first local device and i18n support. - improve configure time dependencies checking and processing. - improve older Unix systems support (HP-UX, AIX, ...) for missing functions. - refresh and improve USB helper files (udev and UPower). - more generation automation: the ChangeLog file is now generated automatically at distribution time, along with the files needed for the website hardware compatibility list. - SSL support has also received some improvements. - tcp-wrapper now allows hostnames in /etc/hosts.allow too (not only IPv4 and/or IPv6 addresses). - many bugfixes, cleanup and improvements. Release notes for NUT 2.4.3 - what's new since 2.4.2 ---------------------------------------------------- - this is a bugfix release that only solves the regression on IPv6 activation. Release notes for NUT 2.4.2 - what's new since 2.4.1 ---------------------------------------------------- - the general USB support has been vastly improved, including many bug fixes, better OS support, new features and devices. - NUT now talks to Solar Controller Devices with the new ivtscd driver. - the snmp-ups driver supports more PDU, with a smaller disk footprint. - apcsmart supports more older SmartUPS and Matrix units. - the bestfortress driver is resurrected. - the virtual driver has been renamed to 'clone'. - the netxml-ups driver has received some care. - various debugging and development improvements have been done, around driver output; dummy-ups with more interaction and scripting and the device-recorder.sh script. - the build system has received many bugfixes and improvements. - the UPower (previously known as DeviceKit-power) rules file is now generated by NUT. - support for new devices: * Apollo 1000A and 1000F * various Baytech RPC * old Best Power Fortress * Cyber Power Systems PR3000E, CP 1500C and OR2200LCDRM2U * all the new Dell UPS range (serial, USB and network) * Eaton E Series NV and DX UPS, and Powerware 9130 * older HP T500 and T750, newer T750 INTL (USB) and R1500 G2 (serial) * Inform Informer Compact 1000VA * many serial and USB devices from Ippon, like Back Comfo Pro, Smart Power Pro and Smart Winner * IVT SCD series * Liebert GXT2-3000RT230 and PowerSure PSA * Mustek PowerMust 424 / 636 / 848 USB * all new PowerCOM USB devices with HID PDC interface * Tripp-Lite INTERNETOFFICE700, SMART700USB and ECO550UPS * UPSonic DS-800 (USB) Release notes for NUT 2.4.1 - what's new since 2.4.0 ---------------------------------------------------- - the microdowell driver has appeared to support various MicroDowell Enterprise units (see the "new devices" list below). - support for new devices: * MicroDowell Enterprise B8, B10, N8, N11, N15, N20, N22, N30, N40, N50, N60 and HiBox ST. - NUT-Monitor now better handles the ups.status field, and has switched to version 1.1. - the situation of the build toolchain has been fixed, with regard to the "make clean" target and the wrongly removed generated USB files. This broke further configure call. Release notes for NUT 2.4.0 - what's new since 2.2.2 ---------------------------------------------------- NOTE: Per original semantic versioning, there were no public NUT 2.3.x releases. - preliminary support for Power Distribution Units (PDUs): NUT can now support PDUs, either natively (ie using NUT snmp-ups driver), or through a binding to the Powerman daemon. The list of supported PDUs is already quite long, including: * Eaton ePDUs (Managed and Monitored), * some Aphel models, * some Raritan PDUs, * and the whole list of Powerman supported devices: http://powerman.sourceforge.net/supported.html - support for new devices: * the various PDUs cited above * Chloride Desk Power 650 * Cyber Power Systems Value 400E/600E/800E (USB models) * Delta GES602N * Digitus DN-170020 * the whole Eaton ranges (mostly composed of MGE Office Protection Systems and Powerware units) including BladeUPS * Forza Power Technologies SL-1001 * HP PowerTrust 2997A * HP R/T 2200 G2 * Infosec XP 1000 and XP 500 * Ippon Back Power Pro (serial and USB) * Kebo 1200D/D Series * Liebert PowerSure Personal XT * MGE Office Protection Systems Protection Station * Neus 400va and 600va * Phasak 400VA and 600VA * Plexus 500VA * Powercom Black Knight PRO / King PRO and Imperial * PowerKinetics BlackOut Buster * Sweex 1000 USB * UNITEK Alpha 500 * WinPower CPM-800 - NUT now embeds Python client support through the PyNUTClient module and the NUT-Monitor application. Both are from David Goncalves, and are still available from http://www.lestat.st. For more information, refer to link:scripts/python/README.adoc[]. - the dummy-ups driver now supports a "repeater" mode. This allows it to act as a NUT client, and to forward data. This can be useful for supervision and load sharing purposes. - tcp-wrappers support has been added to the upsd server, to grant users access by source IP for commands that require to be logged into the server. This replaces the previous internal implementation (ACL in upsd.conf). - the nut.conf file has been introduced to standardize startup configuration across the various systems. - NUT now ships a bash completion function for 'upsc' command (scripts/misc/nut.bash_completion). Simply copy it to /etc/bash_completion.d - many internal changes to improve maintainability, while lowering the maintenance cost (thus allowing developers to focus on what matters: the code!). Examples of this are: - the USB information automatic extraction to generate the various USB helper files, - the upsdrv_info_t structure to track more driver information, and remove the need for the upsdrv_banner() function - common USB code refactoring, as it is done for the serial functions. - tons of bugfixes, cleanup and improvements to make NUT stronger than ever! Release notes for NUT 2.2.2 - what's new since 2.2.1 ---------------------------------------------------- - support for new devices: APC BACK-UPS XS LCD, Atlantis Land, Mustek Powermust Office 650, Oneac XAU models, Powerware PW5115 and PW9120 (USB), Nitram Elite 2005 - Integrated Power Management (NUT HAL integration) has reached a major milestone: it is now the most advanced UPS integration into Power Management layer known in existing OSs. It has received many corrections and improvements, and allows to PowerOff the UPS at the end of a power cycle (which is the most important feature, not supported on other systems). The various files are now installed into the correct location. - the usbhid-ups driver has received attention. Most notably, the shutdown handling has been reworked, and support for MGE UPS SYSTEMS 3 phases units has been added. - snmp-ups now supports MGE* Environment Sensor (ref 66 846). The ambient.temperature reporting has also been fixed for units other than APC. - the netxml-ups driver has appeared to support MGE* network HTTP/XML cards. - NUT now distributes by default the shared version of libupsclient (version 1.0.0), and use this for the provided clients (upsmon, upsc, upsrw, upscmd). This is part of an effort to reduce NUT's footprint, both on disk and in memory. - powerpanel has reach a new step toward the replacement of nitram and cpsups drivers. The final step is scheduled for NUT 2.4. - many changes, cleanup and fixes to the NUT core and various drivers. Release notes for NUT 2.2.1 - what's new since 2.2.0 ---------------------------------------------------- - support for new devices: * all MGE Office Protection Systems units * Advice TopGuard 2000 * Belkin F6H375-USB * Dynamix UPS1700D * Effekta RM2000MH, * Jageson Technology Jasuny USPS * Powercom SMK-1500A and SXL-1500A * PowerWalker Line-Interactive VI 400/800 and 600 * Powerware 9110 * UNITEK Alpha 2600 * UPSonic CXR1000 * some vintage serial APC UPSs - the usbhid-ups driver has been improved, and fixed in many areas, through a backport of the development (trunk) version. - the udev rules, for Linux hotplug support of the USB UPSs, has been updated to support kernel newer than 2.6.22. - the megatec and megatec_usb drivers have also been backported from the development (trunk) version. - the client development files have also received some care: the upsclient pkg-config file has been fixed, and the upsclient.h file allows older NUT clients to continue using the UPSCONN structure. Release notes for NUT 2.2.0 - what's new since 2.0.5 ---------------------------------------------------- NOTE: Per original semantic versioning, there were no public NUT 2.1.x releases. - The new build infrastructure, using automake, is now used. This has major impact on the compilation and installation procedures, and thus on the NUT packaging. For more information, refer to link:UPGRADING.adoc[] and packaging/debian/ for an example of migration. - NUT now provides support for FreeDesktop Hardware Abstraction Layer (HAL) which brings full Plug And Play experience to USB UPS owners. For more information, refer to link:docs/nut-hal.txt[]. - support for new devices: * Ablerex 625L * ActivePower 400VA, 2000VA; * Belkin Home Office F6H350-SER, F6H500-SER, F6H650-SER * Belkin Office Series F6C550-AVR * Belkin Universal UPS F6C100-UNV (USB), F6C1100-UNV (USB), F6C1200-UNV (USB), F6H350deUNV (serial), F6H350ukUNV (serial), F6H650ukUNV (serial) * Compaq R3000h * Cyber Power Systems PR2200 * Dynex DX-800U * Geek Squad GS1285U * Krauler UP-M500VA * Mecer ME-2000 * MGE UPS SYSTEMS Ellipse MAX * Online Zinto D * PowerTech SMK-800 * SVEN Power Pro+ series * Power Smart RM 2000 * Tripp-Lite SmartOnline SU1500RTXL2ua, smart2200RMXL2U. - added IPv6 support, - the newmge-shut driver has appeared. This one uses the same HID core as usbhid-ups, but communicate over a serial link. It will eventually replace the current mge-shut driver. - client commands (upsc, upsrw and upscmd): hostname is now optional, and defaults to "localhost" - many drivers have been improved and have received bug fixes: powerpanel, megatec, megatec_usb, safenet, tripplite_usb, gamatronic, - the hotplug and udev scripts, in charge of setting the right permissions on the USB devices, are now installed automatically when appropriate. - more generally, the NUT core and documentation, including the manpages, have been improved and updated. Release notes for NUT 2.0.5 - what's new since 2.0.4 ---------------------------------------------------- This release is a backport of the development version. Many changes have already been backported previously. Thus it is more a synchronization release, though it includes many bugfixes and support for new models. - support for new devices: * APC Smart-UPS with 6TI firmware * Belkin Small Enterprise F6C1500-TW-RK * Compaq R3000 XR, R5500 XR * Cyber Power 550SL, 725SL, 685AVR, 800AVR, 1200AVR, AE550 * Eltek * Inform GUARD * Microsol Rhino * Opti-UPS PowerES 420E * PowerMan RealSmart, BackPro * Powerware PW9315 3-phase * SOLA 305 * Tripp-Lite SMART550USB, SMART2200RMXL2U, OMNI1000LCD, OMNI900LCD, OMNI650LCD, 1500 LCD, AVR550U * Viewsonic PowerES 420E - bcmxcp: added 3-phase support - megatec: better hardware support, more instant commands - mge-hid: support more instant commands - newhidups: fixed APC and Tripp Lite bugs, various memory bugs, improved report buffering, improved Solaris support, added '-x explore' option for easy diagnosis of new devices - solis: shutdown programming, support new cables, Solaris support - tripplite_usb: updated SMARTPRO support, fixed OL/OB reporting, better error handling, some memory bugs - new dummy-ups driver simulator - added HTML interface for access to CGI scripts Release notes for NUT 2.0.4 - what's new since 2.0.3 ---------------------------------------------------- - The newhidups critical bug (segmentation fault) has been fixed. It has also received some more care, like bugfixes and new models support and enhancement for Solaris. [Peter Selinger and Arnaud Quette] - A bug has been fixed in NUT core to support resuming from suspend-to-disk. This should also fix other similar issues, like time synchronization through the NTP - Network Time Protocol. [Arjen de Korte] - The mge-shut driver now better detects the Low Battery status, support new models and fixes some wrong status and data. It also fixes some issue where the UPS wasn't restarting (refer to mge-shut manpage). [Arnaud Quette] - The genericups custom configuration through ups.conf is working again [Arjen de Korte] - The genericups driver type 22 also support CyberPower 725SL (and maybe others SL models) [David Kaufman] - The new megatec driver, which will replace a bunch of drivers by nut 2.2 (refer to link:docs/megatec.txt[] and link:UPGRADING.adoc[]) has been backported from the trunk (Development tree). The powermust driver has also received some attention. [Carlos Rodrigues] - The new rhino driver was added to support Microsol Rhino UPS hardware The solis has also been improved for Solaris compatibility, and internal / external shutdown programming. solis can now save external shutdown programming to ups, and support new cables for solis 3 [Silvino B. Magalhães] - Several fixes and improvements have been made to upsrw, upsset, cpsups, tripplite_usb and the FAQ. [Arjen de Korte and Charles Lepple] Release notes for NUT 2.0.3 - what's new since 2.0.2 ---------------------------------------------------- - The recent and major newhidups changes have been backported from the Development tree. It now: - supports models from MGE UPS SYSTEMS, APC and Belkin. Mustek and Unitek units are also recognized for development purpose, - handles better device reopening, after a disconnection, - handles multiple devices, with several parameters to find the right UPS. [Peter Selinger, Charles Lepple and Arnaud Quette] - The bcmxcp_usb driver has been added to support Powerware USB units. [Wolfgang Ocker and Kjell Claesson] - The tripplite_usb driver has been added to support Tripp Lite USB units. [Charles Lepple] - The sec driver is back as gamatronic [Gamatronic, Nadav Moskovitch] - The genericups driver has received official care from Gamatronic to add support for the Gamatronic UPS with alarm interface. [Gamatronic, Nadav Moskovitch] - The powermust driver now supports Soyntec Sekury C 500 and C 800 units. [Hanno Borns] - The mge-shut driver has received a bit of attention too, and enhance ups.model retrieval for some specific case (release 0.65) - The drivers don't change to the "statepath" directory anymore at initialization time if called using -k. This avoid unneeded failure to poweroff the UPS if /var is already unmounted. [Gaspar Bakos] - The belkinunv driver now supports Belkin F6C1100-UNV [Dave Breiland] - The isbmex driver has been upgraded to version 0.05, which fixes various errors in formulas, add shutdown capability and revert back baudrate to B9600 (instead of B2400), as it broke the communication [Ricardo Martinezgarza] - The support of Sysgration UPGUARDS Pro650 in fentonups has been fixed [Simon J. Rowe] - The packaging files for Red Hat have received various fixes [Thomas Jarosch] - The solis driver has been fixed to avoid a naming collision and compile on Solaris [Paweł Kierdelewicz] - The snmp-ups driver has corrected the problem when exposing certain time data. Release notes for NUT 2.0.2 - what's new since 2.0.1 ---------------------------------------------------- - the newhidups USB driver has been improved a lot and is no more experimental. It also now has a basic APC support, which will soon replace the legacy hidups driver. - The mge-utalk driver has improved its support for old units. - The mge-shut driver has been improved for restart/shutdown sequences which was previously blocking the serial port. - The general MGE support has been added Pulsar EXtreme C / EX RT, Comet EX RT, Pulsar SV, Pulsar PSX, Ellipse Office and NOVA AVR USB. - The genericups driver now supports Generic RUPS 2000, AEC MiniGuard UPS 700 (using Megatec M2501 cable), and Powerware 3110. [Nick Barnes, Paul Andreassen] - The powermust driver now supports SquareOne Power QP1000, Mustek PowerMust 1400VA Plus and 2000VA USB. [Carlos Rodrigues] - The fentonups driver has been enhanced and now supports Sysgration UPGUARDS Pro650. [Michel Bouissou, Simon J. Rowe] - The cpsups driver now supports MicroDowell B.Box BP 500/750/1000/1500. [Armin Diehl] - The snmp-ups driver now supports Socomec SNMP devices (Netvision MIB), and Powerware ConnectUPS SNMP cards. [Thanos Chatziathanassiou, Olli Salvia] - The bcmxcp driver is back with support for Powerware UPSs. [Tore Ørpetveit, Kjell Claesson] - The cyberpower driver now supports CyberPower 1000AVR. [Dave Huang] - The new solis driver supports Microsol units: Solis 1.0, 1.5, 2.0 and 3.0. [Silvino B. Magalhaes] - The apcsmart driver has fixed APC600 support. - The etapro driver fixes brokenness due to ser_get_line use [Marek Michalkiewicz] - The new upscode2 driver supports Fiskars, Compaq and Powerware devices. [Niels Baggesen, Havard Lygre] - The tripplite driver has fixed a battery charge bug [Cedric Tefft] Release notes for NUT 2.0.1 - what's new since 2.0.0 ---------------------------------------------------- - The bestuferrups driver has been forked into the new bestfcom driver which has better handling of the inverter status alarm messages and more. [Kent Hill] - Mustek UPS support returns with two drivers which have overlapping coverage: mustek and powermust. [powermust: Carlos Rodrigues, mustek: Martin Hajduch] - Additional CyberPower Systems hardware is supported with the new cpsups driver. Three recognized models are the CPS1500AVR, CPS1100VA, and OP500TE. [Walt Holman, Brad Sawatzky] - The genericups driver can now generate staleness warnings in specific cases where the UPS provides a way to test for its presence. See the "CON" setting in ups.conf for more details. [stan / saticed.me.uk] - Documentation for monitoring a Back-UPS RS 500 on a system without USB ports has been added to the cables directory. [Martin Edlman] - The everups driver now supports types 73-76 (NET 700/1000/1400/500-DPC) [hunter] - The new metasys driver supports Meta System models: Line, HF Millennium, HF Top Line, ECO Network, ECO, Ally HF, Megaline [BlaXwan] - The ippon driver now allows user-defined settings for the delay before switching off, and the delay before powering on. [Yuri Elizarov] - The victronups driver is now at version 0.1.9, which adds many instant commands: calibration control, battery and front panel tests, and bypass control. [Gert Lynge] - The tripplite driver has received a major overhaul to bring it up to working condition for the 2.0 tree, including code cleanups, several new variables, commands, and user-definable parameters. See ChangeLog for more. [Nicholas J Kain] - The mge-utalk driver has been upgraded to version 0.81, which fixes the lack of read-write variables and loss of sync on models which don't support restoring settings. [Arnaud Quette] - The Micro Ferrups model RE is now supported by the bestuferrups driver. The driver will also now read the ambient temperature and will no longer constantly report the data as stale. [Tim Thompson] - The fentonups driver's init sequence has been reworked to work better with some hardware, including a fix to the parser code. [MLH] - A workaround has been added to the hidups driver to avoid variables which are stuck by calling HIDIOCINITREPORT in every poll. [Stuart D. Gathman] - SOLA 610 UPS hardware and others which do not support the ID command may now be monitored by the bestups driver after forcing ID= in ups.conf. [Jason White] - "pollinterval" is now available via driver.parameter for consistency. [Arnaud Quette] - The mge-shut and newhidups drivers, along with the supporting hidparser/libhid code have received many updates, including lowering USB bandwidth consumption, driver unbinding (only in Linux), code cleanups, and more which can be seen in the ChangeLog file. [Arnaud Quette] - The fentonups driver now recognizes several more Megatec protocol units: * SuperPower HP360, Hope-550 [Denis Zaika] * Unitek Alpha 1000is [Antoine Cuvellard] - Some variables like uc_sigmask were renamed to avoid clashes with symbols on systems like HP/UX. - All man pages have been reworked to switch literal "-" characters to hyphens or "\-" as appropriate. [Shaul Karl] - upssched's CANCEL events were broken following the change to text-based socket messages in 1.5 and have been fixed. [Steven Schoch] - Calls to varargs functions with raw strings from the config files without an intervening "%s" have been fixed in upsmon, upssched, snmp-ups and upsd. [Ulf Harnhammar] Release notes for NUT 2.0.0 - what's new since 1.4.x ---------------------------------------------------- - The new naming scheme for variables and commands (introduced in 1.4) is now mandatory. The 1.4 tree supported both the old (STATUS) and the new (ups.status) as a transitional release, and now that time is over. + + This means that 2.0 is generally smaller than 1.4 code, since the interim compatibility hacks have been removed. - New serial handling code has been added, with greatly simplified operations. The old mess involving repeated calls to sigaction, alarm, and read has been condensed to a select-read loop. + + This change allows drivers which don't do any serial communications at all (hidups, snmp-ups) to drop that baggage, so they are a bit smaller when compiled. - The drivers now recognize "chroot=' and 'user=' in the global section of ups.conf. This means you don't have to use -r and -u when starting upsdrvctl. - upsmon now supports the -K argument to check for the presence of the POWERDOWNFLAG file. If it exists and contains the magic string, then upsmon will exit(EXIT_SUCCESS). Otherwise, it will exit(EXIT_FAILURE). + + This feature can be used to simplify shutdown scripts, since now you don't have to keep the script in sync with the upsmon.conf. - Many small things like signed value comparisons, int vs. size_t and proper use of const/struct were fixed throughout the source. These were mostly for correctness, but a few potential bugs involving very big or very small numbers were fixed at the same time. - The access control system in upsd.conf has been reworked and simplified. Since access levels have become meaningless in recent releases, the new system is just ACCEPT or REJECT . + + If you are upgrading from a previous version of the software, you will have to edit your upsd.conf to use this method. See the link:UPGRADING.adoc[] file for more details. - The build process now halts when make fails in one of the subdirectories. [Petter Reinholdtsen, Charles Lepple] - Helper data for using upsclient via pkgconfig is now created if pkgconfig is detected when configure runs. [Arnaud Quette] - The polling interval in drivers may now be set with 'pollinterval' in ups.conf. [Gabriel Faber] - Blazer UPS equipment is now supported with the blazer driver. [Phil Hutton] - Energizer USB UPS hardware is now supported on Linux with a new experimental driver. [Viktor T. Toth] - The newhidups driver has been merged as the first step towards portable USB UPS support. This will eventually replace the old Linux-only hidups driver. The newhidups driver is tagged experimental since it is under active development. [Arnaud Quette, Charles Lepple] - The newapc driver has been renamed to apcsmart, replacing the old driver with that name. If you used the newapc driver, be sure to delete the old binary and fix your ups.conf. - The apcsmart driver now supports asynchronous notification data from the hardware, which means it can wake up as soon as something happens. This affects the OL/OB/LB/RB data in ups.status, and generally reduces the latency in dispatching status changes by a few seconds. - The apcsmart driver can now support quirky hardware which does not provide the usual listing of valid command characters. This feature is necessary to monitor new models like the APC CS 350 and old ones like the Matrix 5000. It also now has sdtype=4 to handle the strange shutdown behavior on the CS series. - The belkin driver now works around broken firmware version 001, avoiding a lengthy delay at startup. It also implements the shutdown sequence differently, and should actually work on more hardware now. - The bestups driver has been slowed down to play nicer with the hardware, and is much more reliable as a result. Among other things, it should always detect the UPS on the first try, meaning no more "dot dot dot" when it starts. - The cyberpower driver is no longer tagged experimental, and now supports powering off the load. It also supports battery tests via instcmds. - Effekta MT 2000 RM hardware is now supported by the fentonups driver. [Christoph Moar] - The new safenet driver supports UPS hardware that uses the protocol of the same name. This includes models from many manufacturers, including Fairstone, Fenton, Gemini, Powerwell, Repotec, Soltec and Sweex. See the README or driver.list for the full details. [Arjen de Korte] - The genericups driver now has type 20 to monitor the Powerware 5119 RM. See http://lists.exploits.org/ups/Oct2003/00052.html. [Daniel Thompson] - The belkinunv driver has been added to allow monitoring Belkin Universal UPS hardware. [Peter Selinger] - Cyber Power Systems 1100AVR hardware which has a different protocol than the existing binary type (supported by 'cyberpower') is now supported by the experimental cyberpower1100 driver. [Walt Holman] - upsdrvctl now returns success or failure information in the exit code. Any failure during a requested operation will result in a nonzero value (specifically EXIT_FAILURE). Release notes for NUT 1.4.0 - what's new since 1.2.x ---------------------------------------------------- - The drivers and upsd now communicate over Unix domain sockets instead of state files, shared memory, or state files with mmap. This change makes many things possible, including the new dynamic variable and command naming scheme described below. + + There is a new development tool called sockdebug in the server directory for debugging driver-server communications on the sockets. - The old static variable scheme has been replaced by a new dynamic implementation. Vague names have been turned into meaningful names that fit into an organized system. UTILITY is now input.voltage. OUTVOLT is now output.voltage. + + This also applies to the names of instant commands. BTEST1 is test.battery.start, and BTEST0 is test.battery.stop. + + The old names are still supported for compatibility with older clients. This compatibility mode will be maintained throughout the 1.4 series, and will be gone by the release of 2.0. Users with older clients are encouraged to upgrade their software during this time. - The network protocol has been expanded to handle these new names. Older functions which only apply to the old names will continue to be supported through the 1.4 series. - The drivers and server (upsd) can now change their user ids and chroot themselves with the new -u and -r arguments. This lets you create a "chroot jail" with the bare minimum components. + + This technique is used to provide a higher degree of security. If someone exploited upsd to get a shell somehow, they would be stuck in the jail. - upssched now explicitly confirms reception of timer commands before exiting. This was done to avoid a race where one process would exit right when another one was starting. The second one would believe its command had been handled when it had been lost. - upslog has been reworked to use standard getopt parsing to provide the monitoring settings. The old way of specifying arguments is still supported for backwards compatibility. + + upslog has also been changed to only parse the format string once, rather than doing it every time through the loop. This should provide a minuscule drop in CPU utilization. - Usernames are now required in upsmon and upsd. This means that you must add a username to your MONITOR lines in upsmon.conf and then create a matching user in upsd.users. + + Installations from the 1.2 era probably already used usernames, so this mostly affects those from 1.0 and before. - Drivers are now pinged regularly by upsd when they aren't posting updates about the UPS status. This provides another check in the data validation process. If upsd fails to get a response within a few seconds, the UPS will be marked stale. - A few minor memory leaks were discovered with valgrind and squashed. - upsstats now reuses connections to upsd when cycling through multiple entries in the hosts.conf. This makes things a bit faster and avoids some of the noise in the syslog. + + This only applies to entries that are adjacent. To take advantage of this feature, you may have to rearrange them per example below. + + Connection reuse for nonadjacent entries may be considered in the future. ---- MONITOR ups-1@host-1 ... MONITOR ups-1@host-2 ... MONITOR ups-2@host-2 ... MONITOR ups-3@host-3 ... ---- - upsd now warns about insecure configuration files at startup. These files (upsd.conf, upsd.users, and the certfile) should only be readable by upsd. Never make them world-readable. - The programs no longer print "shutting down" when they are just exiting. This was changed to avoid confusion about the term, since "shutting down" has a special meaning in UPS software. - Signal handlers no longer do any significant amount of work. Some of the programs used to do numerous things in there, raising concerns about reentrancy. They now set flags and allow the main loop to do the actual work from there. - A bug in upsmon where NOTIFYFLAG settings could be ignored was fixed. - Group handling has been changed. configure no longer accepts --with-group, and the programs no longer setgid() to a hardcoded value. They now setgid() to the primary group of whatever the user value may be. + + This may be compiled in with --with-user as before, and many programs accept -u to override it at runtime. - The state path is no longer created during 'make install'. Users are now expected to create it themselves. This removes a lot of evil complexity from the build and install sequences. - upsd no longer implements the DROP access command, as it could confuse the clients by getting them out of sync. DROP is now implemented as DENY, which sends an error message. If you use DROP, you should change it to DENY rather than relying on this compatibility measure. - The belkin driver no longer reports OFF and OL at the same time. - The bestups driver no longer sleeps during polls, which makes it more responsive to things like instant commands. - The cyberpower driver now has much better hardware detection code and no longer freezes at startup under some conditions. It also now supports the shutdown function. Instant commands for shutdowns and battery tests were also added. - The dummyups testing driver has been removed. The dummycons testing driver can do everything that dummyups once did and much more. dummycons is also now built by default for easier testing. - The newapc driver has been reworked to take advantage of the new internal driver state functions. Some variables without an obvious purpose were dropped. - The newapc driver now sends all five bytes when using sdtype 1. Previously it didn't send the entire string, and it didn't work. [Don Lewis] - The hidups driver has been expanded to allow for setting variables, a shutdown sequence, and more. [Arnaud Quette] - The mge-utalk driver had trouble establishing communications in some cases due to the RTS line being set. This has been fixed. + + The mge-shut driver has been added to the tree, and has replaced the older mge-ellipse driver. [Arnaud Quette, Philippe Marzouk] - Outlet-level control has been defined in the variable tree, and will be added to drivers where the hardware supports it. This can be used to shut down some components earlier than others to prolong your runtime on battery. + + This is supported in the mge-shut driver now, and may show up in others before long. [Arnaud Quette] - KIN-2200AP hardware is now recognized by the powercom driver. This change may also support other KIN-xxxxAP equipment. [Preston A. Elder] - The 1.1kVA UPS is now supported by the bestuferrups driver. This driver was also changed to allow easy addition of more models in the future. [Bob Apodaca] - The fentonups driver can now handle devices which implement the "I" detection differently, and now supports the Giant/WELI 500 as a result. [Joon Guillen] - The serial number of the UPS being monitored can now be specified with serial= in ups.conf in the genericups driver. [Shaul Karl] - The newapc driver now sends ESC to break out of menus when the initial detection fails. Some new APC models have interactive menus on the serial port, and the driver couldn't handle them before. - The snmp-ups driver now reports ambient temperature and humidity data for APC equipment. It also now supports the shutdown.reboot and shutdown.reboot.graceful commands. [Dmitry Frolov] - The list of supported variables and commands in the snmp-ups driver has been expanded. [Arnaud Quette, J.W. Hoogervorst] - Various drivers now report bypass mode with the BYP status word. [Arnaud Quette] - Energy Sistem equipment is now supported with the esupssmart driver. [Antonio Trujillo Coronado] - The Tripp-Lite SU series (SmartOnline) is supported with the new tripplitesu driver. [Allan Hessenflow] - The HP PowerTrust A2994A is now recognized by the hp driver. [Jan Sporbeck] - Many drivers were cleaned up to perform basic sanity checks on the status data before using it. - An explicit cleanup function has been added to the driver core to ensure that all dynamic resources are freed before exiting. This is part of the larger process to check for memory leaks and other bad things. [Arnaud Quette] - upsd now provides variable descriptions from an auxiliary file. This file is optional, which allows for a smaller memory footprint. It can also be edited for localization or other customizations. - upsimage and upsstats can now render BATTVOLT data. [Andrew R. Ghali] - String handling has been cleaned up throughout the tree. Calls to functions like strcpy and strcat were either replaced with other (range-checking) functions or were rewritten to avoid it. - Many compile-time defaults may now be overridden at runtime. In the environment NUT_CONFPATH and NUT_STATEPATH may be used. upsdrvctl has been changed to execve to pass these along to the drivers. ups.conf now supports driverpath=, and upsd.conf supports DATAPATH. [Bryan Henderson] - The configure --with-gd switches now actually do something useful when gd has been installed outside the default search directories. [Patrik Schindler] - The inline keyword is now handled properly on systems which do not support it or have it specified as another name. This was breaking compiles on some systems. [Petter Reinholdtsen] Release notes for NUT 1.2.2 - what's new since 1.2.1 ---------------------------------------------------- - The snmp-ups driver has been upgraded and expanded. It now supports multiple MIBs, meaning it can handle RFC 1628, APCC, and MGE equipment. You can pick the right one with "mibs=" in ups.conf. + + Support for setting variable and instant commands is also available. [Arnaud Quette and Dmitry Frolov] - The powernet driver has been upgraded. It now supports more variables, has cleaner logging, and may now be considered stable. [Dmitry Frolov] - The hidups driver now supports physical port IDs. This avoids most of the problems where the hiddev* names can jump around too easily. It will now stay in the same place as long as you keep it plugged into the same physical port. See the ChangeLog file for more details. [David Brownell] - The hidups driver now also supports the MFR variable on APC Back-UPS ES equipment. [Jonathan A. Davis] - The sms driver has been updated to version 0.70. [Marcio Gomes] - The bestups driver now recognizes Best Power Axxium Rackmount equipment. [Ales Casar] - The liebert driver now uses O_NONBLOCK, and should now work consistently on OpenBSD as a result. [Alex Cichowski] - The liebert driver also now uses debouncing logic on the status lines. It was possible to get false readings that would start a shutdown or just annoy users with excessive onbatt/online notify messages. The new code forces the status to settle down for 3 polls before accepting the new value. + + This means that very short power events may not be detected. The alternative is having your machine shut down just because it decided to wiggle over to OB LB for a few seconds. - upsmon has had the disconnect logic fixed so the "communications lost" (COMMBAD) notify will actually go out when the connection fails. [Steve Monett] - upssched now uses a lock file to prevent a race where two could start at the same time. The second upssched would "win", and the first one would be unreachable. This had the side-effect of not being able to cancel timers on the first one. + + If you use upssched, you must define the LOCKFN directive when upgrading to this version, or it will not work. [Gaspar Bakos] - The packaging and scripts for Red Hat systems have been updated. [Antonino Albanese] - upsd is now a bit more lenient about access levels in the 'numlogins' check, which is what caused the problem in upsmon (next item). - upsmon no longer gets stuck in slavesync() when upsd is configured to drop certain queries. This usually happened at the worst possible time: in the middle of a shutdown. [John David Garza] - The upsclient functions now do more sanity checking on data from upsd so a short read won't return garbage to the callers. - upsset now works properly with ENUM/VARTYPE values for multiple UPSes on a single upsd. [Dmitry Frolov] - Various portability fixes for building on SGI were applied. [Andrea Suatoni] - upsd no longer tries to reference a deleted client structure if the client disconnects at the wrong time. Previously, it tried to use that pointer after the sendback() function had already failed on write and deleted the client. This could cause upsd to segfault depending on what areas were accessed. [Patrik Schindler] Release notes for NUT 1.2.1 - what's new since 1.2.0 ---------------------------------------------------- - The sms driver is back, with support for Microlink Manager III hardware. [Marcio Gomes] - Fideltronik Ares Series hardware is now supported as genericups type 19. [Tomek Orzechowski and Arkadiusz Mikiewicz] - The drivers no longer silently drop instant commands or set commands from upsd that happen to get fragmented in transit. [linux@horizon.com] - The old multilink driver is back with a new name: liebert. It supports Liebert UPStation GXE hardware with the contact-closure cable. This is currently an experimental driver as there is no way to power down the load. - configure now picks up the right flags for gd automatically if gd 2.0.8 or higher is installed. This greatly simplifies the CGI build process for most users. - Shutdowns on FreeBSD using the genericups driver should work again. [Petri Riihikallio] Historic releases ----------------- More ancient history is not covered in detail here. You can see link:docs/history.txt[] for more details. nut-2.8.3/install-sh0000755000200500020050000003577615001555010011255 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # 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 # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # 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. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # 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 $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: nut-2.8.3/README.adoc0000644000200500020050000011265514777767434011070 00000000000000Network UPS Tools Overview ========================== // NOTE: No blank line here, document-header include processing should kick in! //GH_MARKUP_1095//ifdef::top_srcdir[] //GH_MARKUP_1095//include::{top_srcdir}docs/asciidoc-vars.conf[] //GH_MARKUP_1095//endif::top_srcdir[] //GH_MARKUP_1095//ifndef::top_srcdir[] //GH_MARKUP_1095//include::docs/asciidoc-vars.conf[] //GH_MARKUP_1095//endif::top_srcdir[] //GH_MARKUP_1095_INCLUDE_BEGIN//a6bd83d48 (2025-03-20) docs/asciidoc-vars.conf: document that linkdoc may have further args ifndef::asciidoc-vars-nut-included[] :asciidoc-vars-nut-included: true // NOTE: The big block of comments and definitions below comes from // NUT::docs/asciidoc-vars.conf and is included into top-level document // sources by maintenance recipes directly (`make maintainer-asciidocs`), // due to current limitations of the GitHub Web UI asciidoc renderer. // Hopefully it can be dropped in favor of compact include definitions // (see README.adoc for anticipated example) after this issue is resolved // on their side: // * https://github.com/github/markup/issues/1095 // // This file should be included into NUT documentation sources to consistently // define certain expandable attributes, with contents defined based on the // rendition target (e.g. GitHub Web UI, plain text, locally built HTML/PDF...) // Note that currently GitHub Web UI references lead to nut-website (as of // last built and published revision), not to neighboring documents in the // source browser (which would make sense for branch revisions, etc.) due // to certain complexity about referencing other-document sections with a // partially functional rendering engine there. Exploration and fixes are // welcome (actually working links like // https://github.com/networkupstools/nut/tree/master#installing or // https://github.com/networkupstools/nut/blob/master/UPGRADING.adoc#changes-from-274-to-280 // do seem promising)! // // Since the GitHub UI does not allow use of custom asciidoc configuration // files, or generally does not process the `include:` requests at this time, // clumsy expandable attributes had to be used (usually a set including a // prefix with meaningful name, and one or more separators and/or a suffix // with shortened names). For our classic documentation renditions, they // should resolve to properly defined macros from `docs/asciidoc.conf` // (usually named same as the variables defined here, for simplicity): // * `linksrcdoc` allows to refer to a source of documentation file // relative to the root of NUT code base. // * `linkdoc` allows to refer to a file under `docs/` directory (or // its nut-website rendition). // * `xref` substitutes the asciidoc shorthand '<< >>' syntax with // attributes that conditionally expand to: // - links on GitHub (references can point at most to a section of // level docs/common.xsl's ), or // - xref asciidoc macros when generating docs. // * `linksingledoc` guarantees that, when chunked HTML is generated, // the link always points to a non-chunked file. // * `linkman2` allows to support different names for the manpage and // the command shown. This is also needed to properly display links // to manpages in both GitHub and generated docs without defining an // attribute for each manpage. // * `linkmanext` and `linkmanext2` macros repeat the behavior of the default ones. // These macros are intended for system man pages (e.g. HTML links might lead // to a generic internet site, or possibly to a distro-provided library // online or locally). // // Optional attributes set by callers: // * `website-url` (defaulted below) may be used for "historic website" // snapshot builds... hopefully // * `website` is used as a boolean toggle in our recipes for nut-website // vs. offline documentation renditions // * `env-github` is used as a boolean toggle, set by GitHub Web-UI renderer // * `(top_)srcdir` and `(top_)builddir` can be set by `Makefile.am` // calling the `a2x` tool, since some of the files with the asciidoc // mark-up are only generated or post-processed during build and // (due to `make dist` restrictions) being build products, they may // not reside in same directory as static source text files which // reference or include them. Note that the non-`top` paths would // normally differ based on location of the `Makefile` involved // (e.g. workspace root, or the `docs`, or `docs/man` directories). // These variables are expected to be absolute paths, or ones relative // to asciidoc-selected `:base_dir`, and to end with a relevant path // separator, or be empty -- so in all cases letting the resulting // string resolve meaningfully in the filesystem during docs build. // // Please keep the remaining comments and definitions as one big block // so it does not become a series of empty paragraphs in the rendered // documents! // ifndef::website-url[] :website-url: https://www.networkupstools.org/ endif::website-url[] // ifndef::srcdir[] :srcdir: endif::srcdir[] // ifndef::builddir[] :builddir: endif::builddir[] // ifndef::top_srcdir[] :top_srcdir: endif::top_srcdir[] // ifndef::top_builddir[] :top_builddir: endif::top_builddir[] // // // Address links on GitHub vs. docs // (note: 'env-github' attribute is set on GitHub) // // - when generating docs: ifndef::env-github[] // * xref -> xref // syntax: {xref}{x-s}[] // -> xref:[] :xref: xref: :x-s: // * link to doc -> our macro // syntax: {linksrcdoc} // -> linksrcdoc:[] :linksrcdoc: linksrcdoc: // * link to doc -> our macro (optional 2/3/4 args) // syntax: {linkdoc}{ld-s}[{,{,{,}}}] // -> linkdoc:[{,{,{,}}}] :linkdoc: linkdoc: :ld-s: // * link to single doc -> our macro // syntax: {linksingledoc}{lsd-s}[] // -> linksingledoc:[] :linksingledoc: linksingledoc: :lsd-s: // * link to manpage -> our macro // syntax: {linkman2}{lm-s}{lm-c}{lm-e} // -> linkman2:[,] :linkman2: linkman2: :lm-s: [ :lm-c: , :lm-e: ] :linkmanext: https://www.die.net/search/?q= :linkmanext2: https://www.die.net/search/?q= endif::env-github[] // // - on GitHub: ifdef::env-github[] // In our normal builds, Makefile variables convey the needed paths // (used relatively below as `image:images/ci/...png` etc.) :imagesdir: docs // * xref -> link // syntax: {xref}{x-s}[] // In order for it to work, can reference at most a section of // level docs/common.xsl's // -> {website-url}docs/user-manual.chunked/.html[] :xref: {website-url}docs/user-manual.chunked/ :x-s: .html // * link to doc -> our macro // syntax: {linksrcdoc} // -> link:[] :linksrcdoc: link:{top_srcdir}/ // * link to doc -> link (FIXME: ignore or use 2/3/4 args; currently they are all pasted as contents!) // syntax: {linkdoc}{ld-s}[{,{,{,}}}] // -> {website-url}docs/.chunked/index.html[] :linkdoc: {website-url}docs/ :ld-s: .chunked/index.html // * link to single doc -> link // syntax: {linksingledoc}{lsd-s}[] // -> {website-url}docs/.html[] :linksingledoc: {website-url}docs/ :lsd-s: .html // * link to manpage -> link // syntax: {linkman2}{lm-s}{lm-c}{lm-e} // All the fields are mandatory. // -> {website-url}docs/man/.html[()] :linkman2: {website-url}docs/man/ :lm-s: .html[ :lm-c: ( :lm-e: )] :linkmanext: https://www.die.net/search/?q= :linkmanext2: https://www.die.net/search/?q= endif::env-github[] endif::asciidoc-vars-nut-included[] // //GH_MARKUP_1095_INCLUDE_END// Description ----------- Network UPS Tools is a collection of programs which provide a common interface for monitoring and administering UPS, PDU and SCD hardware. It uses a layered approach to connect all of the parts. Drivers are provided for a wide assortment of equipment. They understand the specific language of each device and map it back to a compatibility layer. This means both an expensive high end UPS, a simple "power strip" PDU, or any other power device can be handled transparently with a uniform management interface. This information is cached by the network server `upsd`, which then answers queries from the clients. upsd contains a number of access control features to limit the abilities of the clients. Only authorized hosts may monitor or control your hardware if you wish. Since the notion of monitoring over the network is built into the software, you can hang many systems off one large UPS, and they will all shut down together. You can also use NUT to power on, off or cycle your data center nodes, individually or globally through PDU outlets. Clients such as `upsmon` check on the status of the hardware and do things when necessary. The most important task is shutting down the operating system cleanly before the UPS runs out of power. Other programs are also provided to log information regularly, monitor status through your web browser, and more. NUT and the ecosystem --------------------- NUT comes pre-packaged for many operating systems and embedded in storage, automation or virtualization appliances, and is also often shipped as the software companion by several UPS vendors. Of course, it is quite normal and supported to build your own -- whether for an operating system which lacks it yet, or for an older distribution which lacks the current NUT version; whether to take advantage of new features or to troubleshoot a new UPS deployment with a debugger in hand. Given its core position at the heart of your systems' lifecycle, we make it a point to have current NUT building and running anywhere, especially where older releases did work before (including "abandonware" like the servers and OSes from the turn of millennium): if those boxes are still alive and in need of power protection, they should be able to get it. [TIP] ===== If you like how the NUT project helps protect your systems from power outages, please consider sponsoring or at least "starring" it on GitHub at https://github.com/networkupstools/nut/ - these stars are among metrics which the larger potential sponsors consider when choosing how to help FOSS projects. Keeping the lights shining in such a large non-regression build matrix is a big undertaking! ifndef::pdf_format[] image:https://api.star-history.com/svg?repos=networkupstools/nut&type=Date[link="https://star-history.com/#networkupstools/nut&Date" alt="NUT GitHub Star History Chart"] endif::pdf_format[] See <> for an overview of the shared effort. ===== As a FOSS project, for over a quarter of a century we welcome contributions of both core code (drivers and other features), build recipes and other integration elements to make it work on your favourite system, documentation revisions to make it more accessible to newcomers, as well as hardware vendor cooperation with first-hand driver and protocol submissions, and just about anything else you can think of. NUT Support Policy ~~~~~~~~~~~~~~~~~~ The Network UPS Tools project is a community-made open-source effort, primarily made and maintained by people donating their spare time. The support channels are likewise open, with preferred ones being link:https://github.com/networkupstools/nut/issues[the NUT project issue tracker on GitHub] and the NUT Users mailing list, as detailed at https://networkupstools.org/support.html page. Please keep in mind that any help is provided by community members just like yourself, as a best effort, and subject to their availability and experience. It is expected that you have read the Frequently Asked Questions, looked at the link:https://github.com/networkupstools/nut/wiki[NUT wiki], and have a good grasp about the three-layer design and programs involved in a running deployment of NUT, for a discussion to be constructive and efficient. Be patient, polite, and prepare to learn and provide information about your NUT deployment (version, configuration, OS...) and the device, to collect logs, and to answer any follow-up questions about your situation. Finally, note that NUT is packaged and delivered by packaging into numerous operating systems, appliances and monitoring projects, and may be bundled with third-party GUI clients. It may be wise of end-users to identify such cases and ask for help on the most-relevant forum (or several, including the NUT support channels). It is important to highlight that the NUT project releases have for a long time been essentially snapshots of better-tested code, and we do not normally issue patches to "hot-fix" any older releases. Any improvements of NUT itself are made in the current code base, same as any other feature development, so to receive desired fixes on your system (and/or to check that they do solve your particular issue), expect to be asked to build the recent development iteration from GitHub or work with your appliance vendor to get a software upgrade. Over time, downstream OS packaging or other integrations which use NUT, may issue patches as new package revisions, or new baseline versions of NUT, according to *their* release policies. It is not uncommon for distributions, especially "stable" flavours, to be a few years behind upstream projects. Installing ---------- If you are installing these programs for the first time, go read the {xref}_installation_instructions{x-s}[installation instructions] to find out how to do that. This document contains more information on what all of this stuff does. Upgrading --------- When upgrading from an older version, always check the {xref}Upgrading_notes{x-s}[upgrading notes] to see what may have changed. Compatibility issues and other changes will be listed there to ease the process. Configuring and using --------------------- Once NUT is installed, refer to the {xref}Configuration_notes{x-s}[configuration notes] for directions. Documentation ------------- This is just an overview of the software. You should read the man pages, included example configuration files, and auxiliary documentation for the parts that you intend to use. Network Information ------------------- These programs are designed to share information over the network. In the examples below, `localhost` is used as the hostname. This can also be an IP address or a fully qualified domain name. You can specify a port number if your upsd process runs on another port. In the case of the program `upsc`, to view the variables on the UPS called sparky on the `upsd` server running on the local machine, you'd do this: /usr/local/ups/bin/upsc sparky@localhost The default port number is 3493. You can change this with "configure --with-port" at compile-time. To make a client talk to upsd on a specific port, add it after the hostname with a colon, like this: /usr/local/ups/bin/upsc sparky@localhost:1234 This is handy when you have a mixed environment and some of the systems are on different ports. The general form for UPS identifiers is this: [@[:]] Keep this in mind when viewing the examples below. Manifest -------- This package is broken down into several categories: - *drivers* - These programs talk directly to your UPS hardware. - *server* - upsd serves data from the drivers to the network. - *clients* - They talk to upsd and do things with the status data. - *cgi-bin* - Special class of clients that you can use with your web server. - *scripts* - Contains various scripts, like the Perl and Python binding, integration bits and applications. Drivers ------- These programs provide support for specific UPS models. They understand the protocols and port specifications which define status information and convert it to a form that upsd can understand. To configure drivers, edit ups.conf. For this example, we'll have a UPS called "sparky" that uses the apcsmart driver and is connected to `/dev/ttyS1`. That's the second serial port on most Linux-based systems. The entry in `ups.conf` looks like this: [sparky] driver = apcsmart port = /dev/ttyS1 To start and stop drivers, use upsdrvctl of upsdrvsvcctl (installed on operating systems with a service management framework supported by NUT). By default, it will start or stop every UPS in the config file: /usr/local/ups/sbin/upsdrvctl start /usr/local/ups/sbin/upsdrvctl stop However, you can also just start or stop one by adding its name: /usr/local/ups/sbin/upsdrvctl start sparky /usr/local/ups/sbin/upsdrvctl stop sparky On operating systems with a supported service management framework, you might wrap your NUT drivers into individual services instances with: /usr/local/ups/sbin/upsdrvsvcctl resync and then manage those service instances with commands like: /usr/local/ups/sbin/upsdrvsvcctl start sparky /usr/local/ups/sbin/upsdrvsvcctl stop sparky To find the driver name for your device, refer to the section below called "HARDWARE SUPPORT TABLE". Extra Settings ~~~~~~~~~~~~~~ Some drivers may require additional settings to properly communicate with your hardware. If it doesn't detect your UPS by default, check the driver's man page or help (-h) to see which options are available. For example, the usbhid-ups driver allows you to use USB serial numbers to distinguish between units via the "serial" configuration option. To use this feature, just add another line to your ups.conf section for that UPS: [sparky] driver = usbhid-ups port = auto serial = 1234567890 Hardware Compatibility List ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The {xref}HCL{x-s}[Hardware Compatibility List] is available in the source directory ('nut-X.Y.Z/data/driver.list'), and is generally distributed with packages. For example, it is available on Debian systems as: /usr/share/nut/driver.list This table is also available link:{website-url}stable-hcl.html[online]. If your driver has vanished, see the {linksingledoc}FAQ{lsd-s}[FAQ] and {xref}Upgrading_notes{x-s}[Upgrading notes]. Generic Device Drivers ~~~~~~~~~~~~~~~~~~~~~~ NUT provides several generic drivers that support a variety of very similar models. - The `genericups` driver supports many serial models that use the same basic principle to communicate with the computer. This is known as "contact closure", and basically involves raising or lowering signals to indicate power status. + This type of UPS tends to be cheaper, and only provides the very simplest data about power and battery status. Advanced features like battery charge readings and such require a "smart" UPS and a driver which supports it. + See the {linkman2}genericups{lm-s}genericups{lm-c}8{lm-e} man page for more information. - The `usbhid-ups` driver attempts to communicate with USB HID Power Device Class (PDC) UPSes. These units generally implement the same basic protocol, with minor variations in the exact set of supported attributes. This driver also applies several correction factors when the UPS firmware reports values with incorrect scale factors. + See the {linkman2}usbhid-ups{lm-s}usbhid-ups{lm-c}8{lm-e} man page for more information. - The `nutdrv_qx` driver supports the Megatec / Q1 protocol that is used in many brands (Blazer, Energy Sistem, Fenton Technologies, Mustek, Voltronic Power and many others). + See the {linkman2}nutdrv_qx{lm-s}nutdrv_qx{lm-c}8{lm-e} man page for more information. - The `snmp-ups` driver handles various SNMP enabled devices, from many different manufacturers. In SNMP terms, `snmp-ups` is a manager, that monitors SNMP agents. + See the {linkman2}snmp-ups{lm-s}snmp-ups{lm-c}8{lm-e} man page for more information. - The `powerman-pdu` is a bridge to the PowerMan daemon, thus handling all PowerMan supported devices. The PowerMan project supports several serial and networked PDU, along with Blade and IPMI enabled servers. + See the {linkman2}powerman-pdu{lm-s}powerman-pdu{lm-c}8{lm-e} man page for more information. - The `apcupsd-ups` driver is a bridge to the Apcupsd daemon, thus handling all Apcupsd supported devices. The Apcupsd project supports many serial, USB and networked APC UPS. + See the {linkman2}apcupsd-ups{lm-s}apcupsd-ups{lm-c}8{lm-e} man page for more information. UPS Shutdowns ~~~~~~~~~~~~~ upsdrvctl can also shut down (power down) all of your UPS hardware. [WARNING] ========= If you play around with this command, expect your filesystems to die. Don't power off your computers unless they're ready for it: /usr/local/ups/sbin/upsdrvctl shutdown /usr/local/ups/sbin/upsdrvctl shutdown sparky ========= You should read the {xref}UPS_shutdown{x-s}[Configuring automatic UPS shutdowns] chapter to learn more about when to use this feature. If called at the wrong time, you may cause data loss by turning off a system with a filesystem mounted read-write. Power distribution unit management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NUT also provides an advanced support for power distribution units. You should read the {xref}outlet_management{x-s}[NUT outlets management and PDU notes] chapter to learn more about when to use this feature. Network Server -------------- `upsd` is responsible for passing data from the drivers to the client programs via the network. It should be run immediately after `upsdrvctl` in your system's startup scripts. `upsd` should be kept running whenever possible, as it is the only source of status information for the monitoring clients like `upsmon`. Monitoring client ----------------- `upsmon` provides the essential feature that you expect to find in UPS monitoring software: safe shutdowns when the power fails. In the layered scheme of NUT software, it is a client. It has this separate section in the documentation since it is so important. You configure it by telling it about UPSes that you want to monitor in upsmon.conf. Each UPS can be defined as one of two possible types: a "primary" or "secondary". Primary ~~~~~~~ The monitored UPS possibly supplies power to this system running `upsmon`, but more importantly -- this system can manage the UPS (typically, this instance of `upsmon` runs on the same system as the `upsd` and driver(s)): it is capable and responsible for shutting it down when the battery is depleted (or in another approach, lingering to deplete it or to tell the UPS to reboot its load after too much time has elapsed and this system is still alive -- meaning wall power returned at a "wrong" moment). The shutdown of this (primary) system itself, as well as eventually an UPS shutdown, occurs after any secondary systems ordered to shut down first have disconnected, or a critical urgency threshold was passed. If your UPS is plugged directly into a system's serial or USB port, the `upsmon` process on that system should define its relation to that UPS as a primary. It may be more complicated for higher-end UPSes with a shared network management capability (typically via SNMP) or several serial/USB ports that can be used simultaneously, and depends on what vendors and drivers implement. Setups with several competing primaries (for redundancy) are technically possible, if each one runs its own full stack of NUT, but results can be random (currently NUT does not provide a way to coordinate several entities managing the same device). For a typical home user, there's one computer connected to one UPS. That means you would run on the same computer the whole NUT stack -- a suitable driver, `upsd`, and `upsmon` in primary mode. Secondary ~~~~~~~~~ The monitored UPS may supply power to the system running `upsmon` (or alternatively, it may be a monitoring station with zero PSUs fed by that UPS), but more importantly, this system can't manage the UPS -- e.g. shut it down directly (through a locally running NUT driver). Use this mode when you run multiple computers on the same UPS. Obviously, only one can be connected to the serial or USB port on a typical UPS, and that system is the primary. Everything else is a secondary. For a typical home user, there's one computer connected to one UPS. That means you run a driver, `upsd`, and `upsmon` in primary mode. Additional Information ~~~~~~~~~~~~~~~~~~~~~~ More information on configuring upsmon can be found in these places: - The {linkman2}upsmon{lm-s}upsmon{lm-c}8{lm-e} man page - {xref}BigServers{x-s}[Typical setups for big servers] - {xref}UPS_shutdown{x-s}[Configuring automatic UPS shutdowns] chapter - The stock `upsmon.conf` that comes with the package Clients ------- Clients talk to upsd over the network and do useful things with the data from the drivers. There are tools for command line access, and a few special clients which can be run through your web server as CGI programs. For more details on specific programs, refer to their man pages. upsc ~~~~ `upsc` is a simple client that will display the values of variables known to `upsd` and your UPS drivers. It will list every variable by default, or just one if you specify an additional argument. This can be useful in shell scripts for monitoring something without writing your own network code. `upsc` is a quick way to find out if your driver(s) and upsd are working together properly. Just run `upsc ` to see what's going on, i.e.: morbo:~$ upsc sparky@localhost ambient.humidity: 035.6 ambient.humidity.alarm.maximum: NO,NO ambient.humidity.alarm.minimum: NO,NO ambient.temperature: 25.14 ... If you are interested in writing a simple client that monitors `upsd`, the source code for `upsc` is a good way to learn about using the upsclient functions. See the {linkman2}upsc{lm-s}upsc{lm-c}8{lm-e} man page and {xref}nut-names{x-s}[NUT command and variable naming scheme] for more information. upslog ~~~~~~ `upslog` will write status information from `upsd` to a file at set intervals. You can use this to generate graphs or reports with other programs such as `gnuplot`. upsrw ~~~~~ `upsrw` allows you to display and change the read/write variables in your UPS hardware. Not all devices or drivers implement this, so this may not have any effect on your system. A driver that supports read/write variables will give results like this: ---- $ upsrw sparky@localhost ( many skipped ) [ups.test.interval] Interval between self tests Type: ENUM Option: "1209600" Option: "604800" SELECTED Option: "0" ( more skipped ) ---- On the other hand, one that doesn't support them won't print anything: ---- $ upsrw fenton@gearbox ( nothing ) ---- `upsrw` requires administrator powers to change settings in the hardware. Refer to {linkman2}upsd.users{lm-s}upsd.users{lm-c}5{lm-e} for information on defining users in `upsd`. upscmd ~~~~~~ Some UPS hardware and drivers support the notion of an instant command - a feature such as starting a battery test, or powering off the load. You can use upscmd to list or invoke instant commands if your hardware/drivers support them. Use the -l command to list them, like this: ---- $ upscmd -l sparky@localhost Instant commands supported on UPS [sparky@localhost]: load.on - Turn on the load immediately test.panel.start - Start testing the UPS panel calibrate.start - Start run time calibration calibrate.stop - Stop run time calibration ... ---- `upscmd` requires administrator powers to start instant commands. To define users and passwords in `upsd`, see {linkman2}upsd.users{lm-s}upsd.users{lm-c}5{lm-e}. CGI Programs ------------ The CGI programs are clients that run through your web server. They allow you to see UPS status and perform certain administrative commands from any web browser. Javascript and cookies are not required. These programs are not installed or compiled by default. To compile and install them, first run `configure --with-cgi`, then do `make` and `make install`. If you receive errors about "gd" during configure, go get it and install it before continuing. You can get the source here: - http://www.libgd.org/ In the event that you need libpng or zlib in order to compile gd, they can be found at these URLs: - http://www.libpng.org/pub/png/pngcode.html - http://www.zlib.net/ Access Restrictions ~~~~~~~~~~~~~~~~~~~ The CGI programs use hosts.conf to see if they are allowed to talk to a host. This keeps malicious visitors from creating queries from your web server to random hosts on the Internet. If you get error messages that say "Access to that host is not authorized", you're probably missing an entry in your hosts.conf. upsstats ~~~~~~~~ `upsstats` generates web pages from HTML templates, and plugs in status information in the right places. It looks like a distant relative of APC's old Powerchute interface. You can use it to monitor several systems or just focus on one. It also can generate IMG references to `upsimage`. upsimage ~~~~~~~~ This is usually called by upsstats via IMG SRC tags to draw either the utility or outgoing voltage, battery charge percent, or load percent. upsset ~~~~~~ `upsset` provides several useful administration functions through a web interface. You can use `upsset` to kick off instant commands on your UPS hardware like running a battery test. You can also use it to change variables in your UPS that accept user-specified values. Essentially, `upsset` provides the functions of `upsrw` and `upscmd`, but with a happy pointy-clicky interface. `upsset` will not run until you convince it that you have secured your system. You *must* secure your CGI path so that random interlopers can't run this program remotely. See the `upsset.conf` file. Once you have secured the directory, you can enable this program in that configuration file. It is not active by default. Version Numbering ----------------- The version numbers historically worked like this: if the middle number is odd, it's a development tree, otherwise it is the stable tree. The past stable trees were 1.0, 1.2, 1.4, 2.0, 2.2 and 2.4, with the latest such stable tree designated 2.6. The development trees were 1.1, 1.3, 1.5, 2.1 and 2.3. Since the 2.4 release, there is no real separate development branch anymore since the code is available through a revision control system (namely, Git -- or actually Subversion back then), development happens in feature branches that are eventually merged into the main trunk, and its snapshots become published releases. As a result, subsequent versions (2.7 and 2.8) were released without regard for even/odd values of the minor version component. Since 2.7 line of releases, sources are tracked in Git revision control system, with the project ecosystem being hosted on GitHub, and any code improvements or other contributions merged through common pull request approach and custom NUT CI testing on multiple platforms. Major release jumps are mostly due to large changes to the features list. There have also been a number of architectural changes which may not be noticeable to most users, but which can impact developers. Since NUT v2.8.2 or so, development iterations have additional version components, to account for the amount of commits on the main branch (`master`) since the last known Git tag, and amount of commits on the developed feature branch that are unique to it compared to main branch. This allows for a reasonably growing version of stable baseline and local development, so that experimental packages can be installed as upgrades (or well-exposed downgrades). While the NUT releases retain the semantic versioning three-component standard, interim builds (trunk snapshots and development branches) can expose a much more complex structure with the amount of commits in the trunk since last release, and amount of commits on the branch unique to it (not in the trunk). Additional data may include overall amount of commits in the current build since last release, and the git commit has identifier of the built code base. More details can be seen in `docs/nut-versioning.adoc` file in the NUT source code base. Backwards and Forwards Compatibility ------------------------------------ The network protocol for the current version of NUT should be backwards-compatible all the way back to version 1.4. A newer client should fail gracefully when querying an older server. If you need more details about cross-compatibility of older NUT releases (1.x vs. 2.x), please see the {xref}Project_History{x-s}[Project history] chapter. Support / Help / etc. --------------------- If you are in need of help, refer to the {xref}Support_Request{x-s}[Support instructions] in the user manual. Hacking / Development Info -------------------------- Additional documentation can be found in: - the {linkdoc}developer-guide{ld-s}[Developer Guide], - the {linkdoc}packager-guide{ld-s}[Packager Guide]. Acknowledgements / Contributions -------------------------------- The many people who have participated in creating and improving NUT are listed in the user manual {xref}Acknowledgements{x-s}[acknowledgements appendix]. [[acknowledgements-ci-ops]] We would like to highlight some organizations which provide continuous support to the NUT project (and many other FOSS projects) on technological and organizational sides, such as helping keep the donations transparent, NUT CI farm afloat, and public resources visible. Thanks for keeping the clocks ticking, day and night: //////////// FIXME: Use different (better-resolution) images for PDF rendering? FIXME: PDF cells seem to align weirdly, like setting the bottom of the first line of text to be on the same level as bottom of the image, or similar to that. NOTE: GitHub renderer (or CSS stack?) ignores style settings and squashes the logo column into a fixed-width monster with either our specified heights, or with teeny-tiny thumbnail magnitude images, so it is prettier to leave it as a "single-column table" by default. Grid/Frame settings are also ignored, but we can try our best anyway. NOTE: The classic asciidoc/a2x renderer seems to not support link/url options, but at least does not complain about them either. //////////// ifndef::env-github[] [frame="none",grid="none",cols="^.<1,<.<2"] endif::env-github[] ifdef::env-github[] [frame="none",grid="none",cols="<1*"] endif::env-github[] |=== | image:images/ci/GitHub-Mark-140pxW.png[alt="GitHub logo",width="140",height="140",link="https://github.com/"] | The link:https://github.com/networkupstools/["NetworkUPSTools" organization on GitHub] arranges a lot of things, including source code hosting for NUT itself and several related projects, team management, projects, issue and pull request discussions, sponsorship, nut-website rendering and hosting, some automated actions, and more... | image:images/ci/jenkins-nut-transparent-bg-140pxW.png[alt="Jenkins and NUT logo",width="139",height="104",link="https://www.jenkins.io/"] | The link:https://www.jenkins.io/[Jenkins CI] project and its huge plugin ecosystem provides the technological foundation for the largest island of the link:https://ci.networkupstools.org/[self-hosted NUT CI farm]. There is a fair amount of cross-pollination between the upstream project and community, and the development done originally for the NUT CI farm. See more at link:https://stories.jenkins.io/user-story/jenkins-is-the-way-for-networkupstools/[Jenkins is the way to build multi-platform NUT] article. | image:images/ci/fosshost_org_Host_Light_38px.png[alt="Fosshost logo",width="112",height="38"] | Fosshost provided virtual machines where the multi-platform NUT CI farm with a link:https://github.com/networkupstools/jenkins-dynamatrix/[jenkins-dynamatrix] link:https://github.com/networkupstools/nut/blob/master/Jenkinsfile-dynamatrix[setup] runs to arrange builds in numerous operating environments and a lot of toolkit versions and implementations. Some workers running on NUT community members' machines can also dial in to provide an example of their favourite platforms. Literally hundreds of NUT builds run for each iteration, to make sure NUT can always build and work everywhere. This allows us to ensure that NUT remains portable across two decades' worth of operating systems, compilers, script interpreters, tools and third-party dependencies. | image:images/ci/CircleCI_vertical_black_logo.png[alt="CircleCI logo",width="130",height="107",link="https://circleci.com/"] | The link:https://app.circleci.com/pipelines/github/networkupstools/nut/[CircleCI NUT pipeline] allows us to test NUT CI builds on MacOS. | image:images/ci/AppVeyor_logo-ar21.png[alt="AppVeyor logo",width="120",height="60",link="https://www.appveyor.com/"] | The link:https://ci.appveyor.com/project/nut-travis/nut/[AppVeyor NUT pipeline] allows us to test NUT CI builds on Windows (and publish preview tarballs with binaries). | image:images/ci/DO_Powered_by_Badge_blue_140pxW.png[alt="DigitalOcean logo",width="140",height="29",link="https://www.digitalocean.com/?refcode=d2fbf2b9e082&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge"] | The link:https://www.digitalocean.com/?refcode=d2fbf2b9e082&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge[DigitalOcean] droplets allow us to host NUT CI farm Jenkins controller and the build agents for multiple operating systems. | image:images/ci/gandi-ar21.png[alt="Gandi.Net logo",width="120",height="60",link="https://www.gandi.net/"] | link:https://www.gandi.net/[Gandi.Net] took up the costs of NUT DNS hosting. | image:images/ci/OC_logo_merged_140x26.png[alt="Open Collective logo",width="140",height="26",link="https://opencollective.com/"] | https://opencollective.com/networkupstools allows us to arrange monetary donations and spending, with public transparency of everything that happens. |=== nut-2.8.3/README0000644000200500020050000000005315001555000010104 00000000000000Please see README.adoc for actual contents nut-2.8.3/ltmain.sh0000755000200500020050000117716715001555004011101 00000000000000#! /bin/sh ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in ## by inline-source v2014-01-03.01 # libtool (GNU libtool) 2.4.6 # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996-2015 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. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.6 Debian-2.4.6-15" package_revision=2.4.6 ## ------ ## ## Usage. ## ## ------ ## # Run './libtool --help' for help with using this script from the # command line. ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # After configure completes, it has a better idea of some of the # shell tools we need than the defaults used by the functions shared # with bootstrap, so set those here where they can still be over- # ridden by the user, but otherwise take precedence. : ${AUTOCONF="autoconf"} : ${AUTOMAKE="automake"} ## -------------------------- ## ## Source external libraries. ## ## -------------------------- ## # Much of our low-level functionality needs to be sourced from external # libraries, which are installed to $pkgauxdir. # Set a version string for this script. scriptversion=2015-01-20.17; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 # Copyright (C) 2004-2015 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. # 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. # As a special exception to the GNU General Public License, if you distribute # this file as part of a program or library that is built using GNU Libtool, # you may include this file under the same distribution terms that you use # for the rest of that program. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNES 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 . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # Evaluate this file near the top of your script to gain access to # the functions and variables defined here: # # . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh # # If you need to override any of the default environment variable # settings, do that before evaluating this file. ## -------------------- ## ## Shell normalisation. ## ## -------------------- ## # Some shells need a little help to be as Bourne compatible as possible. # Before doing anything else, make sure all that help has been provided! 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 # NLS nuisances: We save the old values in case they are required later. _G_user_locale= _G_safe_locale= for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test set = \"\${$_G_var+set}\"; then save_$_G_var=\$$_G_var $_G_var=C export $_G_var _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Make sure IFS has a sensible default sp=' ' nl=' ' IFS="$sp $nl" # There are apparently some retarded systems that use ';' as a PATH separator! 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 ## ------------------------- ## ## Locate command utilities. ## ## ------------------------- ## # func_executable_p FILE # ---------------------- # Check that FILE is an executable regular file. func_executable_p () { test -f "$1" && test -x "$1" } # func_path_progs PROGS_LIST CHECK_FUNC [PATH] # -------------------------------------------- # Search for either a program that responds to --version with output # containing "GNU", or else returned by CHECK_FUNC otherwise, by # trying all the directories in PATH with each of the elements of # PROGS_LIST. # # CHECK_FUNC should accept the path to a candidate program, and # set $func_check_prog_result if it truncates its output less than # $_G_path_prog_max characters. func_path_progs () { _G_progs_list=$1 _G_check_func=$2 _G_PATH=${3-"$PATH"} _G_path_prog_max=0 _G_path_prog_found=false _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} for _G_dir in $_G_PATH; do IFS=$_G_save_IFS test -z "$_G_dir" && _G_dir=. for _G_prog_name in $_G_progs_list; do for _exeext in '' .EXE; do _G_path_prog=$_G_dir/$_G_prog_name$_exeext func_executable_p "$_G_path_prog" || continue case `"$_G_path_prog" --version 2>&1` in *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; *) $_G_check_func $_G_path_prog func_path_progs_result=$func_check_prog_result ;; esac $_G_path_prog_found && break 3 done done done IFS=$_G_save_IFS test -z "$func_path_progs_result" && { echo "no acceptable sed could be found in \$PATH" >&2 exit 1 } } # We want to be able to use the functions in this file before configure # has figured out where the best binaries are kept, which means we have # to search for them ourselves - except when the results are already set # where we skip the searches. # Unless the user overrides by setting SED, search the path for either GNU # sed, or the sed that truncates its output the least. test -z "$SED" && { _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for _G_i in 1 2 3 4 5 6 7; do _G_sed_script=$_G_sed_script$nl$_G_sed_script done echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed _G_sed_script= func_check_prog_sed () { _G_path_prog=$1 _G_count=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo '' >> conftest.nl "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin rm -f conftest.sed SED=$func_path_progs_result } # Unless the user overrides by setting GREP, search the path for either GNU # grep, or the grep that truncates its output the least. test -z "$GREP" && { func_check_prog_grep () { _G_path_prog=$1 _G_count=0 _G_path_prog_max=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo 'GREP' >> conftest.nl "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin GREP=$func_path_progs_result } ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # All uppercase variable names are used for environment variables. These # variables can be overridden by the user before calling a script that # uses them if a suitable command of that name is not already available # in the command search PATH. : ${CP="cp -f"} : ${ECHO="printf %s\n"} : ${EGREP="$GREP -E"} : ${FGREP="$GREP -F"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} ## -------------------- ## ## Useful sed snippets. ## ## -------------------- ## sed_dirname='s|/[^/]*$||' sed_basename='s|^.*/||' # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s|\([`"$\\]\)|\\\1|g' # Same as above, but do not quote variable references. sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' # Sed substitution that converts a w32 file name or path # that contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-'\' parameter expansions in output of sed_double_quote_subst that # were '\'-ed in input to the same. If an odd number of '\' preceded a # '$' in input to sed_double_quote_subst, that '$' was protected from # expansion. Since each input '\' is now two '\'s, look for any number # of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. _G_bs='\\' _G_bs2='\\\\' _G_bs4='\\\\\\\\' _G_dollar='\$' sed_double_backslash="\ s/$_G_bs4/&\\ /g s/^$_G_bs2$_G_dollar/$_G_bs&/ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" ## ----------------- ## ## Global variables. ## ## ----------------- ## # Except for the global variables explicitly listed below, the following # functions in the '^func_' namespace, and the '^require_' namespace # variables initialised in the 'Resource management' section, sourcing # this file will not pollute your global namespace with anything # else. There's no portable way to scope variables in Bourne shell # though, so actually running these functions will sometimes place # results into a variable named after the function, and often use # temporary variables in the '^_G_' namespace. If you are careful to # avoid using those namespaces casually in your sourcing script, things # should continue to work as you expect. And, of course, you can freely # overwrite any of the functions or variables defined here before # calling anything to customize them. EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. # Allow overriding, eg assuming that you follow the convention of # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # # debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: # By convention, finish your script with: # # exit $exit_status # # so that you can set exit_status to non-zero if you want to indicate # something went wrong during execution without actually bailing out at # the point of failure. exit_status=$EXIT_SUCCESS # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath=$0 # The name of this program. progname=`$ECHO "$progpath" |$SED "$sed_basename"` # Make sure we have an absolute progpath for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` progdir=`cd "$progdir" && pwd` progpath=$progdir/$progname ;; *) _G_IFS=$IFS IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS=$_G_IFS test -x "$progdir/$progname" && break done IFS=$_G_IFS test -n "$progdir" || progdir=`pwd` progpath=$progdir/$progname ;; esac ## ----------------- ## ## Standard options. ## ## ----------------- ## # The following options affect the operation of the functions defined # below, and should be set appropriately depending on run-time para- # meters passed on the command line. opt_dry_run=false opt_quiet=false opt_verbose=false # Categories 'all' and 'none' are always available. Append any others # you will pass as the first argument to func_warning from your own # code. warning_categories= # By default, display warnings according to 'opt_warning_types'. Set # 'warning_func' to ':' to elide all warnings, or func_fatal_error to # treat the next displayed warning as a fatal error. warning_func=func_warn_and_continue # Set to 'all' to display all warnings, 'none' to suppress all # warnings, or a space delimited list of some subset of # 'warning_categories' to display only the listed warnings. opt_warning_types=all ## -------------------- ## ## Resource management. ## ## -------------------- ## # This section contains definitions for functions that each ensure a # particular resource (a file, or a non-empty configuration variable for # example) is available, and if appropriate to extract default values # from pertinent package files. Call them using their associated # 'require_*' variable to ensure that they are executed, at most, once. # # It's entirely deliberate that calling these functions can set # variables that don't obey the namespace limitations obeyed by the rest # of this file, in order that that they be as useful as possible to # callers. # require_term_colors # ------------------- # Allow display of bold text on terminals that support it. require_term_colors=func_require_term_colors func_require_term_colors () { $debug_cmd test -t 1 && { # COLORTERM and USE_ANSI_COLORS environment variables take # precedence, because most terminfo databases neglect to describe # whether color sequences are supported. test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} if test 1 = "$USE_ANSI_COLORS"; then # Standard ANSI escape sequences tc_reset='' tc_bold=''; tc_standout='' tc_red=''; tc_green='' tc_blue=''; tc_cyan='' else # Otherwise trust the terminfo database after all. test -n "`tput sgr0 2>/dev/null`" && { tc_reset=`tput sgr0` test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` tc_standout=$tc_bold test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` } fi } require_term_colors=: } ## ----------------- ## ## Function library. ## ## ----------------- ## # This section contains a variety of useful functions to call in your # scripts. Take note of the portable wrappers for features provided by # some modern shells, which will fall back to slower equivalents on # less featureful shells. # func_append VAR VALUE # --------------------- # Append VALUE onto the existing contents of VAR. # We should try to minimise forks, especially on Windows where they are # unreasonably slow, so skip the feature probes when bash or zsh are # being used: if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then : ${_G_HAVE_ARITH_OP="yes"} : ${_G_HAVE_XSI_OPS="yes"} # The += operator was introduced in bash 3.1 case $BASH_VERSION in [12].* | 3.0 | 3.0*) ;; *) : ${_G_HAVE_PLUSEQ_OP="yes"} ;; esac fi # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is # useable or anything else if it does not work. test -z "$_G_HAVE_PLUSEQ_OP" \ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ && _G_HAVE_PLUSEQ_OP=yes if test yes = "$_G_HAVE_PLUSEQ_OP" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_append () { $debug_cmd eval "$1+=\$2" }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_append () { $debug_cmd eval "$1=\$$1\$2" } fi # func_append_quoted VAR VALUE # ---------------------------- # Quote VALUE and append to the end of shell variable VAR, separated # by a space. if test yes = "$_G_HAVE_PLUSEQ_OP"; then eval 'func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1+=\\ \$func_quote_for_eval_result" }' else func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1=\$$1\\ \$func_quote_for_eval_result" } fi # func_append_uniq VAR VALUE # -------------------------- # Append unique VALUE onto the existing contents of VAR, assuming # entries are delimited by the first character of VALUE. For example: # # func_append_uniq options " --another-option option-argument" # # will only append to $options if " --another-option option-argument " # is not already present somewhere in $options already (note spaces at # each end implied by leading space in second argument). func_append_uniq () { $debug_cmd eval _G_current_value='`$ECHO $'$1'`' _G_delim=`expr "$2" : '\(.\)'` case $_G_delim$_G_current_value$_G_delim in *"$2$_G_delim"*) ;; *) func_append "$@" ;; esac } # func_arith TERM... # ------------------ # Set func_arith_result to the result of evaluating TERMs. test -z "$_G_HAVE_ARITH_OP" \ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ && _G_HAVE_ARITH_OP=yes if test yes = "$_G_HAVE_ARITH_OP"; then eval 'func_arith () { $debug_cmd func_arith_result=$(( $* )) }' else func_arith () { $debug_cmd func_arith_result=`expr "$@"` } fi # func_basename FILE # ------------------ # Set func_basename_result to FILE with everything up to and including # the last / stripped. if test yes = "$_G_HAVE_XSI_OPS"; then # If this shell supports suffix pattern removal, then use it to avoid # forking. Hide the definitions single quotes in case the shell chokes # on unsupported syntax... _b='func_basename_result=${1##*/}' _d='case $1 in */*) func_dirname_result=${1%/*}$2 ;; * ) func_dirname_result=$3 ;; esac' else # ...otherwise fall back to using sed. _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` if test "X$func_dirname_result" = "X$1"; then func_dirname_result=$3 else func_append func_dirname_result "$2" fi' fi eval 'func_basename () { $debug_cmd '"$_b"' }' # func_dirname FILE APPEND NONDIR_REPLACEMENT # ------------------------------------------- # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. eval 'func_dirname () { $debug_cmd '"$_d"' }' # func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT # -------------------------------------------------------- # Perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () { $debug_cmd '"$_b"' '"$_d"' }' # func_echo ARG... # ---------------- # Echo program name prefixed message. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname: $_G_line" done IFS=$func_echo_IFS } # func_echo_all ARG... # -------------------- # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_echo_infix_1 INFIX ARG... # ------------------------------ # Echo program name, followed by INFIX on the first line, with any # additional lines not showing INFIX. func_echo_infix_1 () { $debug_cmd $require_term_colors _G_infix=$1; shift _G_indent=$_G_infix _G_prefix="$progname: $_G_infix: " _G_message=$* # Strip color escape sequences before counting printable length for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" do test -n "$_G_tc" && { _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` } done _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes func_echo_infix_1_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_infix_1_IFS $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 _G_prefix=$_G_indent done IFS=$func_echo_infix_1_IFS } # func_error ARG... # ----------------- # Echo program name prefixed message to standard error. func_error () { $debug_cmd $require_term_colors func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 } # func_fatal_error ARG... # ----------------------- # Echo program name prefixed message to standard error, and exit. func_fatal_error () { $debug_cmd func_error "$*" exit $EXIT_FAILURE } # func_grep EXPRESSION FILENAME # ----------------------------- # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $debug_cmd $GREP "$1" "$2" >/dev/null 2>&1 } # func_len STRING # --------------- # Set func_len_result to the length of STRING. STRING may not # start with a hyphen. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_len () { $debug_cmd func_len_result=${#1} }' else func_len () { $debug_cmd func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } fi # func_mkdir_p DIRECTORY-PATH # --------------------------- # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { $debug_cmd _G_directory_path=$1 _G_dir_list= if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then # Protect directory names starting with '-' case $_G_directory_path in -*) _G_directory_path=./$_G_directory_path ;; esac # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done case $_G_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` done _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` func_mkdir_p_IFS=$IFS; IFS=: for _G_dir in $_G_dir_list; do IFS=$func_mkdir_p_IFS # mkdir can fail with a 'File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$_G_dir" 2>/dev/null || : done IFS=$func_mkdir_p_IFS # Bail out if we (or some other process) failed to create a directory. test -d "$_G_directory_path" || \ func_fatal_error "Failed to create '$1'" fi } # func_mktempdir [BASENAME] # ------------------------- # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, BASENAME is the basename for that directory. func_mktempdir () { $debug_cmd _G_template=${TMPDIR-/tmp}/${1-$progname} if test : = "$opt_dry_run"; then # Return a directory name, but don't create it in dry-run mode _G_tmpdir=$_G_template-$$ else # If mktemp works, use that first and foremost _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` if test ! -d "$_G_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race _G_tmpdir=$_G_template-${RANDOM-0}$$ func_mktempdir_umask=`umask` umask 0077 $MKDIR "$_G_tmpdir" umask $func_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$_G_tmpdir" || \ func_fatal_error "cannot create temporary directory '$_G_tmpdir'" fi $ECHO "$_G_tmpdir" } # func_normal_abspath PATH # ------------------------ # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. func_normal_abspath () { $debug_cmd # These SED scripts presuppose an absolute path with a trailing slash. _G_pathcar='s|^/\([^/]*\).*$|\1|' _G_pathcdr='s|^/[^/]*||' _G_removedotparts=':dotsl s|/\./|/|g t dotsl s|/\.$|/|' _G_collapseslashes='s|/\{1,\}|/|g' _G_finalslash='s|/*$|/|' # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` while :; do # Processed it all yet? if test / = "$func_normal_abspath_tpath"; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result"; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_notquiet ARG... # -------------------- # Echo program name prefixed message only when not in quiet mode. func_notquiet () { $debug_cmd $opt_quiet || func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_relative_path SRCDIR DSTDIR # -------------------------------- # Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. func_relative_path () { $debug_cmd func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=$func_dirname_result if test -z "$func_relative_path_tlibdir"; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test -n "$func_stripname_result"; then func_append func_relative_path_result "/$func_stripname_result" fi # Normalisation. If bindir is libdir, return '.' else relative path. if test -n "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result" func_relative_path_result=$func_stripname_result fi test -n "$func_relative_path_result" || func_relative_path_result=. : } # func_quote_for_eval ARG... # -------------------------- # Aesthetically quote ARGs to be evaled later. # This function returns two values: # i) func_quote_for_eval_result # double-quoted, suitable for a subsequent eval # ii) func_quote_for_eval_unquoted_result # has all characters that are still active within double # quotes backslashified. func_quote_for_eval () { $debug_cmd func_quote_for_eval_unquoted_result= func_quote_for_eval_result= while test 0 -lt $#; do case $1 in *[\\\`\"\$]*) _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; *) _G_unquoted_arg=$1 ;; esac if test -n "$func_quote_for_eval_unquoted_result"; then func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" else func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" fi case $_G_unquoted_arg in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and variable expansion # for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_quoted_arg=\"$_G_unquoted_arg\" ;; *) _G_quoted_arg=$_G_unquoted_arg ;; esac if test -n "$func_quote_for_eval_result"; then func_append func_quote_for_eval_result " $_G_quoted_arg" else func_append func_quote_for_eval_result "$_G_quoted_arg" fi shift done } # func_quote_for_expand ARG # ------------------------- # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { $debug_cmd case $1 in *[\\\`\"]*) _G_arg=`$ECHO "$1" | $SED \ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; *) _G_arg=$1 ;; esac case $_G_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_arg=\"$_G_arg\" ;; esac func_quote_for_expand_result=$_G_arg } # func_stripname PREFIX SUFFIX NAME # --------------------------------- # strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_stripname () { $debug_cmd # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary variable first. func_stripname_result=$3 func_stripname_result=${func_stripname_result#"$1"} func_stripname_result=${func_stripname_result%"$2"} }' else func_stripname () { $debug_cmd case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; esac } fi # func_show_eval CMD [FAIL_EXP] # ----------------------------- # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} func_quote_for_expand "$_G_cmd" eval "func_notquiet $func_quote_for_expand_result" $opt_dry_run || { eval "$_G_cmd" _G_status=$? if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_show_eval_locale CMD [FAIL_EXP] # ------------------------------------ # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} $opt_quiet || { func_quote_for_expand "$_G_cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || { eval "$_G_user_locale $_G_cmd" _G_status=$? eval "$_G_safe_locale" if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_tr_sh # ---------- # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { $debug_cmd case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_verbose ARG... # ------------------- # Echo program name prefixed message in verbose mode only. func_verbose () { $debug_cmd $opt_verbose && func_echo "$*" : } # func_warn_and_continue ARG... # ----------------------------- # Echo program name prefixed warning message to standard error. func_warn_and_continue () { $debug_cmd $require_term_colors func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 } # func_warning CATEGORY ARG... # ---------------------------- # Echo program name prefixed warning message to standard error. Warning # messages can be filtered according to CATEGORY, where this function # elides messages where CATEGORY is not listed in the global variable # 'opt_warning_types'. func_warning () { $debug_cmd # CATEGORY must be in the warning_categories list! case " $warning_categories " in *" $1 "*) ;; *) func_internal_error "invalid warning category '$1'" ;; esac _G_category=$1 shift case " $opt_warning_types " in *" $_G_category "*) $warning_func ${1+"$@"} ;; esac } # func_sort_ver VER1 VER2 # ----------------------- # 'sort -V' is not generally available. # Note this deviates from the version comparison in automake # in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a # but this should suffice as we won't be specifying old # version formats or redundant trailing .0 in bootstrap.conf. # If we did want full compatibility then we should probably # use m4_version_compare from autoconf. func_sort_ver () { $debug_cmd printf '%s\n%s\n' "$1" "$2" \ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n } # func_lt_ver PREV CURR # --------------------- # Return true if PREV and CURR are in the correct order according to # func_sort_ver, otherwise false. Use it like this: # # func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." func_lt_ver () { $debug_cmd test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: #! /bin/sh # Set a version string for this script. scriptversion=2015-10-07.11; # UTC # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 # Copyright (C) 2010-2015 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. # 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 . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # This file is a library for parsing options in your shell scripts along # with assorted other useful supporting features that you can make use # of too. # # For the simplest scripts you might need only: # # #!/bin/sh # . relative/path/to/funclib.sh # . relative/path/to/options-parser # scriptversion=1.0 # func_options ${1+"$@"} # eval set dummy "$func_options_result"; shift # ...rest of your script... # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file # starting with '# Written by ' and ending with '# warranty; '. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the # '# Written by ' line, like the one at the top of this file. # # The default options also support '--debug', which will turn on shell # execution tracing (see the comment above debug_cmd below for another # use), and '--verbose' and the func_verbose function to allow your script # to display verbose messages only when your user has specified # '--verbose'. # # After sourcing this file, you can plug processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. ## -------------- ## ## Configuration. ## ## -------------- ## # You should override these variables in your script after sourcing this # file so that they reflect the customisations you have added to the # option parser. # The usage line for option parsing errors and the start of '-h' and # '--help' output messages. You can embed shell variables for delayed # expansion at the time the message is displayed, but you will need to # quote other shell meta-characters carefully to prevent them being # expanded when the contents are evaled. usage='$progpath [OPTION]...' # Short help message in response to '-h' and '--help'. Add to this or # override it after sourcing this library to reflect the full set of # options your script accepts. usage_message="\ --debug enable verbose shell tracing -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -v, --verbose verbosely report processing --version print version information and exit -h, --help print short or long help message and exit " # Additional text appended to 'usage_message' in response to '--help'. long_help_message=" Warning categories include: 'all' show all warnings 'none' turn off all the warnings 'error' warnings are treated as fatal errors" # Help message printed before fatal option parsing errors. fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## ## Hook function management. ## ## ------------------------- ## # This section contains functions for adding, removing, and running hooks # to the main code. A hook is just a named list of of function, that can # be run in order later on. # func_hookable FUNC_NAME # ----------------------- # Declare that FUNC_NAME will run hooks added with # 'func_add_hook FUNC_NAME ...'. func_hookable () { $debug_cmd func_append hookable_fns " $1" } # func_add_hook FUNC_NAME HOOK_FUNC # --------------------------------- # Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must # first have been declared "hookable" by a call to 'func_hookable'. func_add_hook () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not accept hook functions." ;; esac eval func_append ${1}_hooks '" $2"' } # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ # Remove HOOK_FUNC from the list of functions called by FUNC_NAME. func_remove_hook () { $debug_cmd eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' } # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. # It is assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. func_run_hooks () { $debug_cmd _G_rc_run_hooks=false case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook funcions.n" ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do if eval $_G_hook '"$@"'; then # store returned options list back into positional # parameters for next 'cmd' execution. eval _G_hook_result=\$${_G_hook}_result eval set dummy "$_G_hook_result"; shift _G_rc_run_hooks=: fi done $_G_rc_run_hooks && func_run_hooks_result=$_G_hook_result } ## --------------- ## ## Option parsing. ## ## --------------- ## # In order to add your own option parsing hooks, you must accept the # full positional parameter list in your hook function, you may remove/edit # any options that you action, and then pass back the remaining unprocessed # options in '_result', escaped suitably for # 'eval'. In this case you also must return $EXIT_SUCCESS to let the # hook's caller know that it should pay attention to # '_result'. Returning $EXIT_FAILURE signalizes that # arguments are left untouched by the hook and therefore caller will ignore the # result variable. # # Like this: # # my_options_prep () # { # $debug_cmd # # # Extend the existing usage message. # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' # # No change in '$@' (ignored completely by this hook). There is # # no need to do the equivalent (but slower) action: # # func_quote_for_eval ${1+"$@"} # # my_options_prep_result=$func_quote_for_eval_result # false # } # func_add_hook func_options_prep my_options_prep # # # my_silent_option () # { # $debug_cmd # # args_changed=false # # # Note that for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in # --silent|-s) opt_silent=: # args_changed=: # ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift # args_changed=: # ;; # *) # Make sure the first unrecognised option "$_G_opt" # # is added back to "$@", we could need that later # # if $args_changed is true. # set dummy "$_G_opt" ${1+"$@"}; shift; break ;; # esac # done # # if $args_changed; then # func_quote_for_eval ${1+"$@"} # my_silent_option_result=$func_quote_for_eval_result # fi # # $args_changed # } # func_add_hook func_parse_options my_silent_option # # # my_option_validation () # { # $debug_cmd # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." # # false # } # func_add_hook func_validate_options my_option_validation # # You'll also need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. # func_options_finish [ARG]... # ---------------------------- # Finishing the option parse loop (call 'func_options' hooks ATM). func_options_finish () { $debug_cmd _G_func_options_finish_exit=false if func_run_hooks func_options ${1+"$@"}; then func_options_finish_result=$func_run_hooks_result _G_func_options_finish_exit=: fi $_G_func_options_finish_exit } # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the # individual implementations for details. func_hookable func_options func_options () { $debug_cmd _G_rc_options=false for my_func in options_prep parse_options validate_options options_finish do if eval func_$my_func '${1+"$@"}'; then eval _G_res_var='$'"func_${my_func}_result" eval set dummy "$_G_res_var" ; shift _G_rc_options=: fi done # Save modified positional parameters for caller. As a top-level # options-parser function we always need to set the 'func_options_result' # variable (regardless the $_G_rc_options value). if $_G_rc_options; then func_options_result=$_G_res_var else func_quote_for_eval ${1+"$@"} func_options_result=$func_quote_for_eval_result fi $_G_rc_options } # func_options_prep [ARG]... # -------------------------- # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and # needs to propagate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before # returning $EXIT_SUCCESS (otherwise $EXIT_FAILURE is returned). func_hookable func_options_prep func_options_prep () { $debug_cmd # Option defaults: opt_verbose=false opt_warning_types= _G_rc_options_prep=false if func_run_hooks func_options_prep ${1+"$@"}; then _G_rc_options_prep=: # save modified positional parameters for caller func_options_prep_result=$func_run_hooks_result fi $_G_rc_options_prep } # func_parse_options [ARG]... # --------------------------- # The main option parsing loop. func_hookable func_parse_options func_parse_options () { $debug_cmd func_parse_options_result= _G_rc_parse_options=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. if func_run_hooks func_parse_options ${1+"$@"}; then eval set dummy "$func_run_hooks_result"; shift _G_rc_parse_options=: fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' func_echo "enabling shell trace mode" $debug_cmd ;; --no-warnings|--no-warning|--no-warn) set dummy --warnings none ${1+"$@"} shift ;; --warnings|--warning|-W) if test $# = 0 && func_missing_arg $_G_opt; then _G_rc_parse_options=: break fi case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above func_append_uniq opt_warning_types " $1" ;; *all) opt_warning_types=$warning_categories ;; *none) opt_warning_types=none warning_func=: ;; *error) opt_warning_types=$warning_categories warning_func=func_fatal_error ;; *) func_fatal_error \ "unsupported warning category: '$1'" ;; esac shift ;; --verbose|-v) opt_verbose=: ;; --version) func_version ;; -\?|-h) func_usage ;; --help) func_help ;; # Separate optargs to long options (plugins may need this): --*=*) func_split_equals "$_G_opt" set dummy "$func_split_equals_lhs" \ "$func_split_equals_rhs" ${1+"$@"} shift ;; # Separate optargs to short options: -W*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "$func_split_short_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-v*|-x*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) _G_rc_parse_options=: ; break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; *) set dummy "$_G_opt" ${1+"$@"}; shift _G_match_parse_options=false break ;; esac $_G_match_parse_options && _G_rc_parse_options=: done if $_G_rc_parse_options; then # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} func_parse_options_result=$func_quote_for_eval_result fi $_G_rc_parse_options } # func_validate_options [ARG]... # ------------------------------ # Perform any sanity checks on option settings and/or unconsumed # arguments. func_hookable func_validate_options func_validate_options () { $debug_cmd _G_rc_validate_options=false # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" if func_run_hooks func_validate_options ${1+"$@"}; then # save modified positional parameters for caller func_validate_options_result=$func_run_hooks_result _G_rc_validate_options=: fi # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE $_G_rc_validate_options } ## ----------------- ## ## Helper functions. ## ## ----------------- ## # This section contains the helper functions used by the rest of the # hookable option parser framework in ascii-betical order. # func_fatal_help ARG... # ---------------------- # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { $debug_cmd eval \$ECHO \""Usage: $usage"\" eval \$ECHO \""$fatal_help"\" func_error ${1+"$@"} exit $EXIT_FAILURE } # func_help # --------- # Echo long help message to standard output and exit. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message" exit 0 } # func_missing_arg ARGNAME # ------------------------ # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $debug_cmd func_error "Missing argument for '$1'." exit_cmd=exit } # func_split_equals STRING # ------------------------ # Set func_split_equals_lhs and func_split_equals_rhs shell variables after # splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_equals () { $debug_cmd func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} test "x$func_split_equals_lhs" = "x$1" \ && func_split_equals_rhs= }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_equals () { $debug_cmd func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= test "x$func_split_equals_lhs" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals # func_split_short_opt SHORTOPT # ----------------------------- # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_short_opt () { $debug_cmd func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"} }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_short_opt () { $debug_cmd func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt # func_usage # ---------- # Echo short help message to standard output and exit. func_usage () { $debug_cmd func_usage_message $ECHO "Run '$progname --help |${PAGER-more}' for full usage" exit 0 } # func_usage_message # ------------------ # Echo short help message to standard output. func_usage_message () { $debug_cmd eval \$ECHO \""Usage: $usage"\" echo $SED -n 's|^# || /^Written by/{ x;p;x } h /^Written by/q' < "$progpath" echo eval \$ECHO \""$usage_message"\" } # func_version # ------------ # Echo version message to standard output and exit. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' /(C)/!b go :more /\./!{ N s|\n# | | b more } :go /^# Written by /,/# warranty; / { s|^# || s|^# *$|| s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| p } /^# Written by / { s|^# || p } /^warranty; /q' < "$progpath" exit $? } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. scriptversion='(GNU libtool) 2.4.6' # func_echo ARG... # ---------------- # Libtool also displays the current mode in messages, so override # funclib.sh func_echo with this custom definition. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" done IFS=$func_echo_IFS } # func_warning ARG... # ------------------- # Libtool warnings are not categorized, so override funclib.sh # func_warning with this simpler definition. func_warning () { $debug_cmd $warning_func ${1+"$@"} } ## ---------------- ## ## Options parsing. ## ## ---------------- ## # Hook in the functions to make sure our own options are parsed during # the option parsing loop. usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --mode=MODE use operation mode MODE --no-warnings equivalent to '-Wnone' --preserve-dup-deps don't remove duplicate dependency libraries --quiet, --silent don't print informational messages --tag=TAG use configuration variables from tag TAG -v, --verbose print more informational messages than default --version print version information -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. When passed as first option, '--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. Try '$progname --help --mode=MODE' for a more detailed description of MODE. When reporting a bug, please describe a test case to reproduce it and include the following information: host-triplet: $host shell: $SHELL compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) version: $progname $scriptversion Debian-2.4.6-15 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . GNU libtool home page: . General help using GNU software: ." exit 0 } # func_lo2o OBJECT-NAME # --------------------- # Transform OBJECT-NAME from a '.lo' suffix to the platform specific # object suffix. lo2o=s/\\.lo\$/.$objext/ o2lo=s/\\.$objext\$/.lo/ if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_lo2o () { case $1 in *.lo) func_lo2o_result=${1%.lo}.$objext ;; * ) func_lo2o_result=$1 ;; esac }' # func_xform LIBOBJ-OR-SOURCE # --------------------------- # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) # suffix to a '.lo' libtool-object suffix. eval 'func_xform () { func_xform_result=${1%.*}.lo }' else # ...otherwise fall back to using sed. func_lo2o () { func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` } func_xform () { func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` } fi # func_fatal_configuration ARG... # ------------------------------- # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func__fatal_error ${1+"$@"} \ "See the $PACKAGE documentation for more information." \ "Fatal configuration error." } # func_config # ----------- # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # ------------- # Display the features supported by this script. func_features () { echo "host: $host" if test yes = "$build_libtool_libs"; then echo "enable shared libraries" else echo "disable shared libraries" fi if test yes = "$build_old_libs"; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag TAGNAME # ----------------------- # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname=$1 re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf=/$re_begincf/,/$re_endcf/p # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # ------------------------ # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # libtool_options_prep [ARG]... # ----------------------------- # Preparation for options parsed by libtool. libtool_options_prep () { $debug_mode # Option defaults: opt_config=false opt_dlopen= opt_dry_run=false opt_help=false opt_mode= opt_preserve_dup_deps=false opt_quiet=false nonopt= preserve_args= _G_rc_lt_options_prep=: # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; *) _G_rc_lt_options_prep=false ;; esac if $_G_rc_lt_options_prep; then # Pass back the list of options. func_quote_for_eval ${1+"$@"} libtool_options_prep_result=$func_quote_for_eval_result fi $_G_rc_lt_options_prep } func_add_hook func_options_prep libtool_options_prep # libtool_parse_options [ARG]... # --------------------------------- # Provide handling for libtool specific options. libtool_parse_options () { $debug_cmd _G_rc_lt_parse_options=false # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do _G_match_lt_parse_options=: _G_opt=$1 shift case $_G_opt in --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) func_config ;; --dlopen|-dlopen) opt_dlopen="${opt_dlopen+$opt_dlopen }$1" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) func_features ;; --finish) set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $_G_opt && break opt_mode=$1 case $1 in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $_G_opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" ;; --no-warnings|--no-warning|--no-warn) opt_warning=false func_append preserve_args " $_G_opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $_G_opt" ;; --silent|--quiet) opt_quiet=: opt_verbose=false func_append preserve_args " $_G_opt" ;; --tag) test $# = 0 && func_missing_arg $_G_opt && break opt_tag=$1 func_append preserve_args " $_G_opt $1" func_enable_tag "$1" shift ;; --verbose|-v) opt_quiet=false opt_verbose=: func_append preserve_args " $_G_opt" ;; # An option not handled by this hook function: *) set dummy "$_G_opt" ${1+"$@"} ; shift _G_match_lt_parse_options=false break ;; esac $_G_match_lt_parse_options && _G_rc_lt_parse_options=: done if $_G_rc_lt_parse_options; then # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} libtool_parse_options_result=$func_quote_for_eval_result fi $_G_rc_lt_parse_options } func_add_hook func_parse_options libtool_parse_options # libtool_validate_options [ARG]... # --------------------------------- # Perform any sanity checks on option settings and/or unconsumed # arguments. libtool_validate_options () { # save first non-option argument if test 0 -lt $#; then nonopt=$1 shift fi # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" case $host in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match test yes != "$build_libtool_libs" \ && test yes != "$build_old_libs" \ && func_fatal_configuration "not configured to build any kind of library" # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test execute != "$opt_mode"; then func_error "unrecognized option '-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help=$help help="Try '$progname --help --mode=$opt_mode' for more information." } # Pass back the unparsed argument list func_quote_for_eval ${1+"$@"} libtool_validate_options_result=$func_quote_for_eval_result } func_add_hook func_validate_options libtool_validate_options # Process options as early as possible so that --help and --version # can return quickly. func_options ${1+"$@"} eval set dummy "$func_options_result"; shift ## ----------- ## ## Main. ## ## ----------- ## magic='%%%MAGIC variable%%%' magic_exe='%%%MAGIC EXE variable%%%' # Global variables. extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # func_generated_by_libtool # True iff stdin has been generated by Libtool. This function is only # a basic sanity check; it will hardly flush out determined imposters. func_generated_by_libtool_p () { $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p } # func_lalib_unsafe_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if 'file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case $lalib_p_line in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test yes = "$lalib_p" } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { test -f "$1" && $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $debug_cmd save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # 'FILE.' does not work on cygwin managed mounts. func_source () { $debug_cmd case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case $lt_sysroot:$1 in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result='='$func_stripname_result ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $debug_cmd if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with '--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=$1 if test yes = "$build_libtool_libs"; then write_lobj=\'$2\' else write_lobj=none fi if test yes = "$build_old_libs"; then write_oldobj=\'$3\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $debug_cmd # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result= if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result"; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $debug_cmd if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $debug_cmd # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $debug_cmd if test -z "$2" && test -n "$1"; then func_error "Could not determine host file name corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result=$1 fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $debug_cmd if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " '$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result=$3 fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $debug_cmd case $4 in $1 ) func_to_host_path_result=$3$func_to_host_path_result ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via '$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $debug_cmd $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $debug_cmd case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result=$1 } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result=$func_convert_core_msys_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result=$func_convert_core_file_wine_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via '$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $debug_cmd if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd=func_convert_path_$func_stripname_result fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $debug_cmd func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result=$1 } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_msys_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_path_wine_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_dll_def_p FILE # True iff FILE is a Windows DLL '.def' file. # Keep in sync with _LT_DLL_DEF_P in libtool.m4 func_dll_def_p () { $debug_cmd func_dll_def_p_tmp=`$SED -n \ -e 's/^[ ]*//' \ -e '/^\(;.*\)*$/d' \ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ -e q \ "$1"` test DEF = "$func_dll_def_p_tmp" } # func_mode_compile arg... func_mode_compile () { $debug_cmd # Get the compilation command and the source file. base_compile= srcfile=$nonopt # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg=$arg arg_mode=normal ;; target ) libobj=$arg arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify '-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs=$IFS; IFS=, for arg in $args; do IFS=$save_ifs func_append_quoted lastarg "$arg" done IFS=$save_ifs func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg=$srcfile srcfile=$arg ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with '-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj=$func_basename_result } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from '$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test yes = "$build_libtool_libs" \ || func_fatal_configuration "cannot build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name '$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname=$func_basename_result xdir=$func_dirname_result lobj=$xdir$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test yes = "$build_old_libs"; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test no = "$compiler_c_o"; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext lockfile=$output_obj.lock else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test yes = "$need_locks"; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test warn = "$need_locks"; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test no != "$pic_mode"; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test yes = "$suppress_opt"; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test yes = "$build_old_libs"; then if test yes != "$pic_mode"; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test yes = "$compiler_c_o"; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test no != "$need_locks"; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test compile = "$opt_mode" && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a '.o' file suitable for static linking -static only build a '.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a 'standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix '.c' with the library object suffix, '.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to '-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the '--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the 'install' or 'cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE use a list of object files found in FILE to specify objects -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with '-') are ignored. Every other argument is treated as a filename. Files ending in '.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in '.la', then a libtool library is created, only library objects ('.lo' files) may be specified, and '-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created using 'ar' and 'ranlib', or on Windows using 'lib'. If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode '$opt_mode'" ;; esac echo $ECHO "Try '$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test : = "$opt_help"; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | $SED -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | $SED '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $debug_cmd # The first argument is the command name. cmd=$nonopt test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "'$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "'$file' was not linked with '-export-dynamic'" continue fi func_dirname "$file" "" "." dir=$func_dirname_result if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir=$func_dirname_result ;; *) func_warning "'-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir=$absdir # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic=$magic # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file=$progdir/$program elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file=$progdir/$program fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if $opt_dry_run; then # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS else if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd=\$cmd$args fi } test execute = "$opt_mode" && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $debug_cmd libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "'$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument '$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and '=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_quiet && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the '-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the '$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the '$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the '$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test finish = "$opt_mode" && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $debug_cmd # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=false stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=: ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test X-m = "X$prev" && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the '$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=: if $isdir; then destdir=$dest destname= else func_dirname_and_basename "$dest" "" "." destdir=$func_dirname_result destname=$func_basename_result # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "'$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "'$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir=$func_dirname_result func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking '$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname=$1 shift srcname=$realname test -n "$relink_command" && srcname=${realname}T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme=$stripme case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= ;; esac ;; os2*) case $realname in *_dll.a) tstripme= ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try 'ln -sf' first, because the 'ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib=$destdir/$realname func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name=$func_basename_result instname=$dir/${name}i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest=$destfile destfile= ;; *) func_fatal_help "cannot copy a libtool object to '$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test yes = "$build_old_libs"; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext= case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=.exe fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script '$wrapper'" finalize=: for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` if test -n "$libdir" && test ! -f "$libfile"; then func_warning "'$lib' has not been installed in '$libdir'" finalize=false fi done relink_command= func_source "$wrapper" outputname= if test no = "$fast_install" && test -n "$relink_command"; then $opt_dry_run || { if $finalize; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file=$func_basename_result outputname=$tmpdir/$file # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_quiet || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink '$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file=$outputname else func_warning "cannot relink '$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name=$func_basename_result # Set up the ranlib parameters. oldlib=$destdir/$name func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run '$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test install = "$opt_mode" && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $debug_cmd my_outputname=$1 my_originator=$2 my_pic_p=${3-false} my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms=${my_outputname}S.c else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist=$output_objdir/$my_outputname.nm func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* External symbol declarations for the compiler. */\ " if test yes = "$dlself"; then func_verbose "generating symbol list for '$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from '$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols=$output_objdir/$outputname.exp $opt_dry_run || { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from '$dlprefile'" func_basename "$dlprefile" name=$func_basename_result case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename= if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname"; then func_basename "$dlprefile_dlname" dlprefile_dlbasename=$func_basename_result else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename"; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi func_show_eval '$RM "${nlist}I"' if test -n "$global_symbol_to_import"; then eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[];\ " if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ static void lt_syminit(void) { LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; for (; symbol->name; ++symbol) {" $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" echo >> "$output_objdir/$my_dlsyms" "\ } }" fi echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = { {\"$my_originator\", (void *) 0}," if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ {\"@INIT@\", (void *) <_syminit}," fi case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) $my_pic_p && pic_flag_for_symtable=" $pic_flag" ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for '$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $debug_cmd win32_libid_type=unknown win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || func_cygming_gnu_implib_p "$1" then win32_nmres=import else win32_nmres= fi ;; *) func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s|.*|import| p q } }'` ;; esac case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $debug_cmd sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $debug_cmd match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive that possess that section. Heuristic: eliminate # all those that have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $debug_cmd if func_cygming_gnu_implib_p "$1"; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1"; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result= fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $debug_cmd f_ex_an_ar_dir=$1; shift f_ex_an_ar_oldlib=$1 if test yes = "$lock_old_archive_extraction"; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test yes = "$lock_old_archive_extraction"; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $debug_cmd my_gentop=$1; shift my_oldlibs=${1+"$@"} my_oldobjs= my_xlib= my_xabs= my_xdir= for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib=$func_basename_result my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir=$my_gentop/$my_xlib_u func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` func_basename "$darwin_archive" darwin_base_archive=$func_basename_result darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches; do func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" cd "unfat-$$/$darwin_base_archive-$darwin_arch" func_extract_an_archive "`pwd`" "$darwin_base_archive" cd "$darwin_curdir" $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result=$my_oldobjs } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs 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 BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ that is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options that match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test yes = "$fast_install"; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else \$ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined other_platform || defined ... */ #endif /* portability defines, excluding path handling macros */ #if defined _MSC_VER # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC #elif defined __MINGW32__ # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined __CYGWIN__ # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined other platforms ... */ #endif #if defined PATH_MAX # define LT_PATHMAX PATH_MAX #elif defined MAXPATHLEN # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ defined __OS2__ # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free (stale); stale = 0; } \ } while (0) #if defined LT_DEBUGWRAPPER static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; size_t tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined HAVE_DOS_BASED_FILE_SYSTEM if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined HAVE_DOS_BASED_FILE_SYSTEM } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = (size_t) (q - p); p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (STREQ (str, pat)) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else size_t len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { size_t orig_value_len = strlen (orig_value); size_t add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ size_t len = strlen (new_value); while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[--len] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \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" #define SHELL_SPACE_CHARS " \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" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $debug_cmd case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_suncc_cstd_abi # !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! # Several compiler flags select an ABI that is incompatible with the # Cstd library. Avoid specifying it if any are in CXXFLAGS. func_suncc_cstd_abi () { $debug_cmd case " $compile_command " in *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) suncc_use_cstd_abi=no ;; *) suncc_use_cstd_abi=yes ;; esac } # func_mode_link arg... func_mode_link () { $debug_cmd case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll that has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= os2dllname= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=false prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module=$wl-single_module func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test yes != "$build_libtool_libs" \ && func_fatal_configuration "cannot build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg=$1 shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir=$arg prev= continue ;; dlfiles|dlprefiles) $preload || { # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=: } case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test no = "$dlself"; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test dlprefiles = "$prev"; then dlself=yes elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test dlfiles = "$prev"; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols=$arg test -f "$arg" \ || func_fatal_error "symbol file '$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex=$arg prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir=$arg prev= continue ;; mllvm) # Clang does not use LLVM to link, so we can simply discard any # '-mllvm $arg' options when doing the link step. prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result if test none != "$pic_object"; then # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object fi # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file '$arg' does not exist" fi arg=$save_arg prev= continue ;; os2dllname) os2dllname=$arg prev= continue ;; precious_regex) precious_files_regex=$arg prev= continue ;; release) release=-$arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test rpath = "$prev"; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds=$arg prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg=$arg case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "'-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test X-export-symbols = "X$arg"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between '-L' and '$1'" else func_fatal_error "need path for '-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of '$dir'" dir=$absdir ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test X-lc = "X$arg" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test X-lc = "X$arg" && continue ;; esac elif test X-lc_r = "X$arg"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -mllvm) prev=mllvm continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module=$wl-multi_module continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "'-no-install' is ignored for $host" func_warning "assuming '-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -os2dllname) prev=os2dllname continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # -fstack-protector* stack protector flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -specs=* GCC specs files # -stdlib=* select c++ std lib with clang # -fsanitize=* Clang/GCC memory and address sanitizer # -fuse-ld=* Linker select flags for GCC # -static-* direct GCC to link specific libraries statically # -fcilkplus Cilk Plus language extension features for C/C++ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; -Z*) if test os2 = "`expr $host : '.*\(os2\)'`"; then # OS/2 uses -Zxxx to specify OS/2-specific options compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case $arg in -Zlinker | -Zstack) prev=xcompiler ;; esac continue else # Otherwise treat like 'Some other compiler flag' below func_quote_for_eval "$arg" arg=$func_quote_for_eval_result fi ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result test none = "$pic_object" || { # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object } # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test dlfiles = "$prev"; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test dlprefiles = "$prev"; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the '$prevarg' option requires an argument" if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname=$func_basename_result libobjs_save=$libobjs if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" # Definition is injected by LT_CONFIG during libtool generation. func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" func_dirname "$output" "/" "" output_objdir=$func_dirname_result$objdir func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test lib = "$linkmode"; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=false newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test lib,link = "$linkmode,$pass"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs=$tmp_deplibs fi if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass"; then libs=$deplibs deplibs= fi if test prog = "$linkmode"; then case $pass in dlopen) libs=$dlfiles ;; dlpreopen) libs=$dlprefiles ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test lib,dlpreopen = "$linkmode,$pass"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs=$dlprefiles fi if test dlopen = "$pass"; then # Collect dlpreopened libraries save_deplibs=$deplibs deplibs= fi for deplib in $libs; do lib= found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test lib != "$linkmode" && test prog != "$linkmode"; then func_warning "'-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test lib = "$linkmode"; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib=$searchdir/lib$name$search_ext if test -f "$lib"; then if test .la = "$search_ext"; then found=: else found=false fi break 2 fi done done if $found; then # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll=$l done if test "X$ll" = "X$old_library"; then # only static version available found=false func_dirname "$lib" "" "." ladir=$func_dirname_result lib=$ladir/$old_library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi else # deplib doesn't seem to be a libtool library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l *.ltframework) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test conv = "$pass" && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi if test scan = "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "'-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test link = "$pass"; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=false case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=: fi ;; pass_all) valid_a_lib=: ;; esac if $valid_a_lib; then echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" else echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." fi ;; esac continue ;; prog) if test link != "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test conv = "$pass"; then deplibs="$deplib $deplibs" elif test prog = "$linkmode"; then if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=: continue ;; esac # case $deplib $found || test -f "$lib" \ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "'$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir=$func_dirname_result dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass" || { test prog != "$linkmode" && test lib != "$linkmode"; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test conv = "$pass"; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for '$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test prog != "$linkmode" && test lib != "$linkmode"; then func_fatal_error "'$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test yes = "$prefer_static_libs" || test built,no = "$prefer_static_libs,$installed"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib=$l done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for '$lib'" fi # This library was specified with -dlopen. if test dlopen = "$pass"; then test -z "$libdir" \ && func_fatal_error "cannot -dlopen a convenience library: '$lib'" if test -z "$dlname" || test yes != "$dlopen_support" || test no = "$build_libtool_libs" then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of '$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir=$ladir fi ;; esac func_basename "$lib" laname=$func_basename_result # Find the relevant object directory and library name. if test yes = "$installed"; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library '$lib' was moved." dir=$ladir absdir=$abs_ladir libdir=$abs_ladir else dir=$lt_sysroot$libdir absdir=$lt_sysroot$libdir fi test yes = "$hardcode_automatic" && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir=$ladir absdir=$abs_ladir # Remove this search path later func_append notinst_path " $abs_ladir" else dir=$ladir/$objdir absdir=$abs_ladir/$objdir # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test dlpreopen = "$pass"; then if test -z "$libdir" && test prog = "$linkmode"; then func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" fi case $host in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test lib = "$linkmode"; then deplibs="$dir/$old_library $deplibs" elif test prog,link = "$linkmode,$pass"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test prog = "$linkmode" && test link != "$pass"; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=false if test no != "$link_all_deplibs" || test -z "$library_names" || test no = "$build_libtool_libs"; then linkalldeplibs=: fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if $linkalldeplibs; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test prog,link = "$linkmode,$pass"; then if test -n "$library_names" && { { test no = "$prefer_static_libs" || test built,yes = "$prefer_static_libs,$installed"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then # Make sure the rpath contains only unique directories. case $temp_rpath: in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if $alldeplibs && { test pass_all = "$deplibs_check_method" || { test yes = "$build_libtool_libs" && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test built = "$use_static_libs" && test yes = "$installed"; then use_static_libs=no fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc* | *os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test no = "$installed"; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule= for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule=$dlpremoduletest break fi done if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test lib = "$linkmode" && test yes = "$hardcode_into_libs"; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname=$1 shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname=$dlname elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc* | *os2*) func_arith $current - $age major=$func_arith_result versuffix=-$major ;; esac eval soname=\"$soname_spec\" else soname=$realname fi # Make a new name for the extract_expsyms_cmds to use soroot=$soname func_basename "$soroot" soname=$func_basename_result func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from '$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for '$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test prog = "$linkmode" || test relink != "$opt_mode"; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test no = "$hardcode_direct"; then add=$dir/$linklib case $host in *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; *-*-sysv4*uw2*) add_dir=-L$dir ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir=-L$dir ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we cannot # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library"; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add=$dir/$old_library fi elif test -n "$old_library"; then add=$dir/$old_library fi fi esac elif test no = "$hardcode_minus_L"; then case $host in *-*-sunos*) add_shlibpath=$dir ;; esac add_dir=-L$dir add=-l$name elif test no = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; relink) if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$dir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$absdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name elif test yes = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; *) lib_linked=no ;; esac if test yes != "$lib_linked"; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test prog = "$linkmode"; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test yes != "$hardcode_direct" && test yes != "$hardcode_minus_L" && test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test prog = "$linkmode" || test relink = "$opt_mode"; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$libdir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$libdir add=-l$name elif test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add=-l$name elif test yes = "$hardcode_automatic"; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib"; then add=$inst_prefix_dir$libdir/$linklib else add=$libdir/$linklib fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir=-L$libdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name fi if test prog = "$linkmode"; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test prog = "$linkmode"; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test unsupported != "$hardcode_direct"; then test -n "$old_library" && linklib=$old_library compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test yes = "$build_libtool_libs"; then # Not a shared library if test pass_all != "$deplibs_check_method"; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system cannot link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test yes = "$module"; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test lib = "$linkmode"; then if test -n "$dependency_libs" && { test yes != "$hardcode_into_libs" || test yes = "$build_old_libs" || test yes = "$link_static"; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs=$temp_deplibs fi func_append newlib_search_path " $absdir" # Link against this library test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test no != "$link_all_deplibs"; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path=$deplib ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of '$dir'" absdir=$dir fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names"; then for tmp in $deplibrary_names; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl"; then depdepl=$absdir/$objdir/$depdepl darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" path= fi fi ;; *) path=-L$absdir/$objdir ;; esac else eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "'$deplib' seems to be moved" path=-L$absdir fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test link = "$pass"; then if test prog = "$linkmode"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs=$newdependency_libs if test dlpreopen = "$pass"; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test dlopen != "$pass"; then test conv = "$pass" || { # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= } if test prog,link = "$linkmode,$pass"; then vars="compile_deplibs finalize_deplibs" else vars=deplibs fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Add Sun CC postdeps if required: test CXX = "$tagname" && { case $host_os in linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; solaris*) func_cc_basename "$CC" case $func_cc_basename_result in CC* | sunCC*) func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; esac } # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i= ;; esac if test -n "$i"; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test prog = "$linkmode"; then dlfiles=$newdlfiles fi if test prog = "$linkmode" || test lib = "$linkmode"; then dlprefiles=$newdlprefiles fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "'-R' is ignored for archives" test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "'-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "'-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs=$output func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form 'libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test no = "$module" \ && func_fatal_help "libtool library '$output' must begin with 'lib'" if test no != "$need_lib_prefix"; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test pass_all != "$deplibs_check_method"; then func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test no = "$dlself" \ || func_warning "'-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test 1 -lt "$#" \ && func_warning "ignoring multiple '-rpath's for a libtool library" install_libdir=$1 oldlibs= if test -z "$rpath"; then if test yes = "$build_libtool_libs"; then # Building a libtool convenience library. # Some compilers have problems with a '.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "'-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs=$IFS; IFS=: set dummy $vinfo 0 0 0 shift IFS=$save_ifs test -n "$7" && \ func_fatal_help "too many parameters to '-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major=$1 number_minor=$2 number_revision=$3 # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # that has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|freebsd-elf|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; freebsd-aout|qnx|sunos) current=$number_major revision=$number_minor age=0 ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_minor lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type '$version_type'" ;; esac ;; no) current=$1 revision=$2 age=$3 ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT '$current' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION '$revision' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE '$age' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE '$age' is greater than the current interface number '$current'" func_fatal_error "'$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" # On Darwin other compilers case $CC in nagfor*) verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" ;; *) verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; esac ;; freebsd-aout) major=.$current versuffix=.$current.$revision ;; freebsd-elf) func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; irix | nonstopux) if test no = "$lt_irix_increment"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring=$verstring_prefix$major.$revision # Add in all the interfaces that we are compatible with. loop=$revision while test 0 -ne "$loop"; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring_prefix$major.$iface:$verstring done # Before this point, $major must not contain '.'. major=.$major versuffix=$major.$revision ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=.$current.$age.$revision verstring=$current.$age.$revision # Add in all the interfaces that we are compatible with. loop=$age while test 0 -ne "$loop"; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring:$iface.0 done # Make executables depend on our current version. func_append verstring ":$current.0" ;; qnx) major=.$current versuffix=.$current ;; sco) major=.$current versuffix=.$current ;; sunos) major=.$current versuffix=.$current.$revision ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 file systems. func_arith $current - $age major=$func_arith_result versuffix=-$major ;; *) func_fatal_configuration "unknown library version type '$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring=0.0 ;; esac if test no = "$need_version"; then versuffix= else versuffix=.0.0 fi fi # Remove version info from name if versioning should be avoided if test yes,no = "$avoid_version,$need_version"; then major= versuffix= verstring= fi # Check to see if the archive will have undefined symbols. if test yes = "$allow_undefined"; then if test unsupported = "$allow_undefined_flag"; then if test yes = "$build_old_libs"; then func_warning "undefined symbols not allowed in $host shared libraries; building static only" build_libtool_libs=no else func_fatal_error "can't build $host shared library unless -no-undefined is specified" fi fi else # Don't allow undefined symbols. allow_undefined_flag=$no_undefined_flag fi fi func_generate_dlsyms "$libname" "$libname" : func_append libobjs " $symfileobj" test " " = "$libobjs" && libobjs= if test relink != "$opt_mode"; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) if test -n "$precious_files_regex"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles=$dlfiles dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles=$dlprefiles dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test yes = "$build_libtool_libs"; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test yes = "$build_libtool_need_lc"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release= versuffix= major= newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib=$potent_lib while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | $SED 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib= ;; esac fi if test -n "$a_deplib"; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib=$potent_lib # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs= tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test yes = "$allow_libtool_libs_with_static_runtimes"; then for i in $predeps $postdeps; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test none = "$deplibs_check_method"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test yes = "$droppeddeps"; then if test yes = "$module"; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test no = "$allow_undefined"; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs=$new_libs # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test yes = "$build_libtool_libs"; then # Remove $wl instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test yes = "$hardcode_into_libs"; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath=$finalize_rpath test relink = "$opt_mode" || rpath=$compile_rpath$rpath for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath=$finalize_shlibpath test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname=$1 shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname=$realname fi if test -z "$dlname"; then dlname=$soname fi lib=$output_objdir/$realname linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols=$output_objdir/$libname.uexp func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile func_dll_def_p "$export_symbols" || { # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols=$export_symbols export_symbols= always_export_symbols=yes } fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs=$IFS; IFS='~' for cmd1 in $cmds; do IFS=$save_ifs # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test yes = "$try_normal_branch" \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=$output_objdir/$output_la.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS=$save_ifs if test -n "$export_symbols_regex" && test : != "$skipped_export"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test : != "$skipped_export" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs=$tmp_deplibs if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test yes = "$compiler_needs_object" && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test : != "$skipped_export" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then output=$output_objdir/$output_la.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then output=$output_objdir/$output_la.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test yes = "$compiler_needs_object"; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-$k.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test -z "$objlist" || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test 1 -eq "$k"; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-$k.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-$k.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi ${skipped_export-false} && { func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi } test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs=$IFS; IFS='~' for cmd in $concat_cmds; do IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi ${skipped_export-false} && { if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi } libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs=$IFS; IFS='~' for cmd in $cmds; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs # Restore the uninstalled library and exit if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test yes = "$module" || test yes = "$export_dynamic"; then # On all known operating systems, these are identical. dlname=$soname fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "'-R' is ignored for objects" test -n "$vinfo" && \ func_warning "'-version-info' is ignored for objects" test -n "$release" && \ func_warning "'-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object '$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj=$output ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # if reload_cmds runs $LD directly, get rid of -Wl from # whole_archive_flag_spec and hope we can get by with turning comma # into space. case $reload_cmds in *\$LD[\ \$]*) wl= ;; esac if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags else gentop=$output_objdir/${obj}x func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test yes = "$build_libtool_libs" || libobjs=$non_pic_objects # Create the old-style object. reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs output=$obj func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi test yes = "$build_libtool_libs" || { if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS } if test -n "$pic_flag" || test default != "$pic_mode"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output=$libobj func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "'-version-info' is ignored for programs" test -n "$release" && \ func_warning "'-release' is ignored for programs" $preload \ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test CXX = "$tagname"; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " $wl-bind_at_load" func_append finalize_command " $wl-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs=$new_libs func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath=$rpath rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath=$rpath if test -n "$libobjs" && test yes = "$build_old_libs"; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" false # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=: case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=false ;; *cygwin* | *mingw* ) test yes = "$build_libtool_libs" || wrappers_required=false ;; *) if test no = "$need_relink" || test yes != "$build_libtool_libs"; then wrappers_required=false fi ;; esac $wrappers_required || { # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command=$compile_command$compile_rpath # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.$objext"; then func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' fi exit $exit_status } if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test yes = "$no_install"; then # We don't need to create a wrapper script. link_command=$compile_var$compile_command$compile_rpath # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi case $hardcode_action,$fast_install in relink,*) # Fast installation is not supported link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath func_warning "this platform does not like uninstalled shared libraries" func_warning "'$output' will be relinked during installation" ;; *,yes) link_command=$finalize_var$compile_command$finalize_rpath relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` ;; *,no) link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath ;; *,needless) link_command=$finalize_var$compile_command$finalize_rpath relink_command= ;; esac # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource=$output_path/$objdir/lt-$output_name.c cwrapper=$output_path/$output_name.exe $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host"; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do case $build_libtool_libs in convenience) oldobjs="$libobjs_save $symfileobj" addlibs=$convenience build_libtool_libs=no ;; module) oldobjs=$libobjs_save addlibs=$old_convenience build_libtool_libs=no ;; *) oldobjs="$old_deplibs $non_pic_objects" $preload && test -f "$symfileobj" \ && func_append oldobjs " $symfileobj" addlibs=$old_convenience ;; esac if test -n "$addlibs"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase=$func_basename_result case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj"; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test -z "$oldobjs"; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test yes = "$build_old_libs" && old_library=$libname.$libext func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test yes = "$hardcode_automatic"; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test yes = "$installed"; then if test -z "$install_libdir"; then break fi output=$output_objdir/${outputname}i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name=$func_basename_result func_resolve_sysroot "$deplib" eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs=$newdependency_libs newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles=$newdlprefiles else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles=$newdlprefiles fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test -n "$bindir"; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result/$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that cannot go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test no,yes = "$installed,$need_relink"; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } if test link = "$opt_mode" || test relink = "$opt_mode"; then func_mode_link ${1+"$@"} fi # func_mode_uninstall arg... func_mode_uninstall () { $debug_cmd RM=$nonopt files= rmforce=false exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic for arg do case $arg in -f) func_append RM " $arg"; rmforce=: ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir=$func_dirname_result if test . = "$dir"; then odir=$objdir else odir=$dir/$objdir fi func_basename "$file" name=$func_basename_result test uninstall = "$opt_mode" && odir=$dir # Remember odir for removal later, being careful to avoid duplicates if test clean = "$opt_mode"; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif $rmforce; then continue fi rmfiles=$file case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case $opt_mode in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test none != "$pic_object"; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test none != "$non_pic_object"; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test clean = "$opt_mode"; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.$objext" if test yes = "$fast_install" && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name"; then func_append rmfiles " $odir/lt-$noexename.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the $objdir's in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then func_mode_uninstall ${1+"$@"} fi test -z "$opt_mode" && { help=$generic_help func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode '$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # where we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: nut-2.8.3/MAINTAINERS0000644000200500020050000000416614777767434010775 00000000000000In the tradition of stealing ideas for top-level files from the Linux kernel tree, here is the NUT MAINTAINERS file. This file is intended to help patch contributors route their changes to the right people. Note: just because something isn't listed in here doesn't mean it's not being maintained. It just means that the maintainer hasn't sent me a patch to update this file yet. Note 2: there are always other people who work on a project beyond those who are listed here. Omission from this list should not be taken as a slight. Those who are listed below are merely volunteering to be the "lightning rods" for patches to certain parts of the tree. Fields ====== P: Person M: Mail patches to this address W: Web address S: Status: Supported = someone is paid to do this Maintained = someone keeps it running (add others as necessary) In the case of drivers, "maintained" should only be used if you have access to the hardware in question for testing. Drivers ======= P: Russell Kroll M: rkroll@exploits.org S: Maintained: apcsmart, belkin, bestups, cyberpower, dummycons, fentonups, driver core (main.c), upsdrvctl P: Arnaud Quette M: aquette.dev@gmail.com M: ArnaudQuette@eaton.com S: Maintained or Supported: dummy-ups, usbhid-ups, mge-shut mge-utalk, snmp-ups, ... P: Fabio Di Niro M: blaxwan@users.sourceforge.net S: Maintained: metasys P: Kirill Smelkov M: kirr@mns.spb.ru S: Maintained: al175 Packaging ========= P: Nigel Metheringham M: Nigel.Metheringham@dev.InTechnology.co.uk S: Maintained: nut.spec.in (for Red Hat RPM builds) P: Arnaud Quette M: aquette@debian.org S: Maintained: Official Debian packages P: Greg Troxel M: gdt@lexort.com S: Maintained: pkgsrc (sysutils/ups-nut) CI, tests and recipes ===================== P: Evgeny "Jim" Klimov M: jimklimov+nut@gmail.com S: Maintained or Supported: numerous CI recipes, tests and OS integration S: scripts: NDE (NUT Driver Enumerator), NIT (NUT Integration Test suite), S: Jenkins-Dynamatrix, automake/autoconf/m4 scripting, asciidoc documentation. Everything else =============== No other categories have been created yet. nut-2.8.3/config.guess0000755000200500020050000012637315001555010011563 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2018 Free Software Foundation, Inc. timestamp='2018-02-24' # 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; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -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-2018 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'`" # If ldd exists, use it to detect musl libc. if command -v ldd >/dev/null && \ ldd --version 2>&1 | grep -q ^musl then LIBC=musl fi ;; 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=`(uname -p 2>/dev/null || \ "/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 ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine="${arch}${endian}"-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) and ABI. case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; 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 # Determine ABI tags. case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; 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/[-_].*//' | cut -d. -f1,2` ;; 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}${abi}" 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 ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" exit ;; *:MidnightBSD:*:*) echo "$UNAME_MACHINE"-unknown-midnightbsd"$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 ;; *:Sortix:*:*) echo "$UNAME_MACHINE"-unknown-sortix exit ;; *:Redox:*:*) echo "$UNAME_MACHINE"-unknown-redox exit ;; mips:OSF1:*.*) echo mips-dec-osf1 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 ;; 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/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` 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:4.4BSD:*) 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) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" 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*: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 ;; i*:UWIN*:*) echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-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 "[:upper:]" "[:lower:]"``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 ;; e2k:Linux:*:*) echo "$UNAME_MACHINE"-unknown-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 ;; k1om: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; } ;; mips64el:Linux:*:*) echo "$UNAME_MACHINE"-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 ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo "$UNAME_MACHINE"-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:*:*) if objdump -f /bin/sh | grep -q elf32-x86-64; then echo "$UNAME_MACHINE"-pc-linux-"$LIBC"x32 else echo "$UNAME_MACHINE"-pc-linux-"$LIBC" fi 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.*:*) 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 configure 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 ;; SX-ACE:SUPER-UX:*:*) echo sxace-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 # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc 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 ;; NSV-*:NONSTOP_KERNEL:*:*) echo nsv-tandem-nsk"$UNAME_RELEASE" exit ;; NSX-*:NONSTOP_KERNEL:*:*) echo nsx-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 ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac echo "$0: unable to guess system type" >&2 case "$UNAME_MACHINE:$UNAME_SYSTEM" in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&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-functions 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nut-2.8.3/m4/0000755000200500020050000000000015001555410007633 500000000000000nut-2.8.3/m4/ltoptions.m40000644000200500020050000003426215001555004012056 00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 8 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option '$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl 'shared' nor 'disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the 'shared' and # 'disable-shared' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the 'static' and # 'disable-static' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the 'fast-install' # and 'disable-fast-install' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac], [pic_mode=m4_default([$1], [default])]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) nut-2.8.3/m4/nut_check_os.m40000644000200500020050000001160614553676503012507 00000000000000dnl Check for the exact system name and type. This is only used at the moment dnl to determine the packaging rule to be used through the OS_NAME variable. dnl Derived from dist.m4 - OpenSS7 (Ditributed under the GNU GPL v2) dnl Copyright (c) 2001-2006 OpenSS7 Corporation dnl Copyright (c) 1997-2000 Brian F. G. Bidulock AC_DEFUN_ONCE([NUT_OS_FUNCTIONS], [ os_get_name() { case "$[1]" in (*CentOS*|*CENTOS*) echo 'centos' ;; (*Lineox*|*LINEOX*) echo 'lineox' ;; (*White?Box*|*WHITE?BOX*) echo 'whitebox' ;; (*Fedora*|*FEDORA*) echo 'fedora' ;; (*Mandrake*|*Mandriva*|*MANDRAKE*|*MANDRIVA*) echo 'mandriva' ;; (*Red?Hat*|*RED?HAT*) echo 'redhat' ;; (*SuSE*|*SUSE*|*Novell*|*NOVELL*) echo 'suse' ;; (*Debian*|*DEBIAN*) echo 'debian' ;; (*Ubuntu*|*UBUNTU*) echo 'ubuntu' ;; (*Gentoo*|*gentoo*) echo 'gentoo' ;; # FIXME: *BSD, Solaris, HPUX, Aix, ... (*) # fallback for other systems case "${host_cpu}-${host_os}" in *-aix*) echo 'aix' ;; *-freebsd*) echo 'freebsd' ;; *-darwin*) echo 'darwin' ;; *solaris*) echo 'esyscmd(uname -sp)' ;; *-hpux*) echo 'hpux' ;; esac esac } # only list special cases. os_get_target() { case "$[1]" in # some may fall under generic-rpm (centos|lineox|whitebox|fedora|redhat) echo 'redhat' ;; (suse) echo 'opensuse' ;; (ubuntu) echo 'debian' ;; (*) echo '$[1]' ;; # FIXME: *BSD, Solaris, HPUX, Aix, ... esac } ])# _OS_FUNCTIONS AC_DEFUN([NUT_CHECK_OS], [ m4_pattern_allow([^PKG_TARGET$]) # Look for all possible source of OS name resolution # 1) we look for a LSB release info file eval "dist_search_path=\" /etc/lsb-release\"" dist_search_path=$(echo "$dist_search_path" | sed -e 's|\||g;s|//|/|g') for dist_file in $dist_search_path do if test -f "$dist_file" then dist_cv_build_lsb_file="$dist_file" break fi done if test -z "$dist_cv_build_lsb_file" ; then dist_cv_build_lsb_file='no' fi # 2) we look at specific release info file eval "dist_search_path=\" /etc/gentoo-release /etc/centos-release /etc/lineox-release /etc/whitebox-release /etc/fedora-release /etc/mandrake-release /etc/mandriva-release /etc/redhat-release /etc/SuSE-release /etc/debian_version\"" dist_search_path=$(echo "$dist_search_path" | sed -e 's|\||g;s|//|/|g') for dist_file in $dist_search_path do if test -f "$dist_file" then dist_cv_build_rel_file="$dist_file" break fi done if test -z "$dist_cv_build_rel_file" ; then dist_cv_build_rel_file='no' fi # 3) we try the generic issue info file eval "dist_search_path=\" /etc/issue /etc/issue.net\"" dist_search_path=$(echo "$dist_search_path" | sed -e 's|\||g;s|//|/|g') for dist_file in $dist_search_path do if test -f "$dist_file" then dist_cv_build_issue_file="$dist_file" break fi done if test -z "$dist_cv_build_issue_file" ; then dist_cv_build_issue_file='no' fi # Now we parse these content to search for the OS name AC_REQUIRE([NUT_OS_FUNCTIONS]) AC_CACHE_CHECK([for host system name], [dist_cv_build_flavor], [dnl if test -z "$dist_cv_build_flavor" -a ":${dist_cv_build_rel_file:-no}" != :no ; then if test `echo "$dist_cv_build_rel_file" | sed -e 's|.*/||'` != 'debian_version' ; then dist_cv_build_flavor=$(os_get_name "$(cat $dist_cv_build_rel_file)") fi fi if test -z "$dist_cv_build_flavor" -a ":${dist_cv_build_lsb_file:-no}" != :no ; then . "$dist_cv_build_lsb_file" dist_cv_build_flavor=$(os_get_name "${DISTRIB_DESCRIPTION:-unknown}") if test -z "$dist_cv_build_flavor" ; then dist_cv_build_flavor=$(echo "$DISTRIB_ID" | tr [[:upper:]] [[:lower:]] | sed -e 's|[[[:space:]]]*||g;s|linux||g') fi fi if test -z "$dist_cv_build_flavor" -a ":${dist_cv_build_issue_file:-no}" != :no ; then dist_cv_build_flavor=$(os_get_name "$(cat $dist_cv_build_issue_file | grep 'Linux\|Fedora\|Ubuntu' | head -1)") fi # do debian after lsb and issue for Ubuntu if test -z "$dist_cv_build_flavor" -a ":${dist_cv_build_rel_file:-no}" != :no ; then if test `echo "$dist_cv_build_rel_file" | sed -e 's|.*/||'` = 'debian_version' ; then dist_cv_build_flavor='debian' fi fi # FIXME if test -z "$dist_cv_build_flavor" ; then dist_cv_build_flavor=$(os_get_name "$(${CC-cc} $CFLAGS -v 2>&1 | grep 'gcc version')") fi # save the result if test -n "$dist_cv_build_flavor" ; then OS_NAME=$dist_cv_build_flavor PKG_TARGET=$(os_get_target "$dist_cv_build_flavor") fi ]) ])# NUT_CHECK_OS dnl checking for OS information file {/etc/lsb-release, /etc/xxx_version, /etc/issue, ...) dnl Checking for host system name dnl get the base type (linux, ...) from uname, dnl then check the exact linux type?! dnl FIXME: consider cross pf target dnl detect build env (pbuilder, .rpm, ...) nut-2.8.3/m4/nut_compiler_family.m40000644000200500020050000003250114777767434014115 00000000000000dnl detect if current compiler is clang or gcc (or...) AC_DEFUN([NUT_COMPILER_FAMILY], [ if test -z "${nut_compiler_family_seen}"; then nut_compiler_family_seen=yes CC_VERSION_FULL="`LANG=C LC_ALL=C $CC --version 2>&1`" || CC_VERSION_FULL="" CXX_VERSION_FULL="`LANG=C LC_ALL=C $CXX --version 2>&1`" || CXX_VERSION_FULL="" CPP_VERSION_FULL="`LANG=C LC_ALL=C $CPP --version 2>&1`" || CPP_VERSION_FULL="" CC_VERSION="" CXX_VERSION="" CPP_VERSION="" AC_CACHE_CHECK([if CC compiler family is GCC], [nut_cv_GCC], [AS_IF([test -n "$CC" && test -n "$CC_VERSION_FULL"], [AS_IF([echo "${CC_VERSION_FULL}" | grep 'Free Software Foundation' > /dev/null], [nut_cv_GCC=yes],[nut_cv_GCC=no])], [AC_MSG_ERROR([CC is not set])] )]) AC_CACHE_CHECK([if CXX compiler family is GCC], [nut_cv_GXX], [AS_IF([test -n "$CXX" && test -n "$CXX_VERSION_FULL"], [AS_IF([echo "${CXX_VERSION_FULL}" | grep 'Free Software Foundation' > /dev/null], [nut_cv_GXX=yes],[nut_cv_GXX=no])], [AC_MSG_ERROR([CXX is not set])] )]) AC_CACHE_CHECK([if CPP preprocessor family is GCC], [nut_cv_GPP], [AS_IF([test -n "$CPP" && test -n "$CPP_VERSION_FULL"], [AS_IF([echo "${CPP_VERSION_FULL}" | grep 'Free Software Foundation' > /dev/null], [nut_cv_GPP=yes],[nut_cv_GPP=no])], [AC_MSG_ERROR([CPP is not set])] )]) AS_IF([test "x$GCC" = "x" && test "$nut_cv_GCC" = yes], [GCC=yes CC_VERSION="`echo "${CC_VERSION_FULL}" | grep -i gcc | head -1`" \ && test -n "${CC_VERSION}" || CC_VERSION="" ]) AS_IF([test "x$GXX" = "x" && test "$nut_cv_GXX" = yes], [GXX=yes CXX_VERSION="`echo "${CXX_VERSION_FULL}" | grep -i -E 'g++|gcc' | head -1`" \ && test -n "${CXX_VERSION}" || CXX_VERSION="" ]) AS_IF([test "x$GPP" = "x" && test "$nut_cv_GPP" = yes], [GPP=yes CPP_VERSION="`echo "${CPP_VERSION_FULL}" | grep -i -E 'cpp|gcc' | head -1`" \ && test -n "${CPP_VERSION}" || CPP_VERSION="" ]) AC_CACHE_CHECK([if CC compiler family is clang], [nut_cv_CLANGCC], [AS_IF([test -n "$CC" && test -n "$CC_VERSION_FULL"], [AS_IF([echo "${CC_VERSION_FULL}" | grep -E '(clang version|Apple LLVM version .*clang-)' > /dev/null], [nut_cv_CLANGCC=yes],[nut_cv_CLANGCC=no])], [AC_MSG_ERROR([CC is not set])] )]) AC_CACHE_CHECK([if CXX compiler family is clang], [nut_cv_CLANGXX], [AS_IF([test -n "$CXX" && test -n "$CXX_VERSION_FULL"], [AS_IF([echo "${CXX_VERSION_FULL}" | grep -E '(clang version|Apple LLVM version .*clang-)' > /dev/null], [nut_cv_CLANGXX=yes],[nut_cv_CLANGXX=no])], [AC_MSG_ERROR([CXX is not set])] )]) AC_CACHE_CHECK([if CPP preprocessor family is clang], [nut_cv_CLANGPP], [AS_IF([test -n "$CPP" && test -n "$CPP_VERSION_FULL"], [AS_IF([echo "${CPP_VERSION_FULL}" | grep -E '(clang version|Apple LLVM version .*clang-)' > /dev/null], [nut_cv_CLANGPP=yes],[nut_cv_CLANGPP=no])], [AC_MSG_ERROR([CPP is not set])] )]) AS_IF([test "x$CLANGCC" = "x" && test "$nut_cv_CLANGCC" = yes], [CLANGCC=yes CC_VERSION="`echo "${CC_VERSION_FULL}" | grep -v "Dir:" | tr '\n' ';' | sed -e 's, *;,;,g' -e 's,;$,,' -e 's,;,; ,g'`" \ && test -n "${CC_VERSION}" || CC_VERSION="" ]) AS_IF([test "x$CLANGXX" = "x" && test "$nut_cv_CLANGXX" = yes], [CLANGXX=yes CXX_VERSION="`echo "${CXX_VERSION_FULL}" | grep -v "Dir:" | tr '\n' ';' | sed -e 's, *;,;,g' -e 's,;$,,' -e 's,;,; ,g'`" \ && test -n "${CXX_VERSION}" || CXX_VERSION="" ]) AS_IF([test "x$CLANGPP" = "x" && test "$nut_cv_CLANGPP" = yes], [CLANGPP=yes CPP_VERSION="`echo "${CPP_VERSION_FULL}" | grep -v "Dir:" | tr '\n' ';' | sed -e 's, *;,;,g' -e 's,;$,,' -e 's,;,; ,g'`" \ && test -n "${CPP_VERSION}" || CPP_VERSION="" ]) AS_IF([test "x$CC_VERSION" = x], [CC_VERSION="`echo "${CC_VERSION_FULL}" | head -1`"]) AS_IF([test "x$CXX_VERSION" = x], [CXX_VERSION="`echo "${CXX_VERSION_FULL}" | head -1`"]) AS_IF([test "x$CPP_VERSION" = x], [CPP_VERSION="`echo "${CPP_VERSION_FULL}" | head -1`"]) fi ]) AC_DEFUN([NUT_CHECK_COMPILE_FLAG], [ dnl Note: with this line uncommented, builds report dnl sed: 0: conftest.c: No such file or directory dnl so seemingly try to parse the method without args: dnl### AC_REQUIRE([AX_RUN_OR_LINK_IFELSE]) dnl Note: per https://stackoverflow.com/questions/52557417/how-to-check-support-compile-flag-in-autoconf-for-clang dnl the -Werror below is needed to detect "warnings" about unsupported options dnl NOTE: this option should not be passed via the fourth argument of the macro, dnl or it ends up in the flags too, possibly during the "pop"; have to use the dnl GOOD_FLAG instead :\ COMPILERFLAG="$1" dnl We also try to run an actual build since tools called from that might dnl complain if they are forwarded unknown flags accepted by the front-end. NUT_SAVED_CFLAGS="$CFLAGS" NUT_SAVED_CXXFLAGS="$CXXFLAGS" AC_MSG_NOTICE([Starting check compile flag for '${COMPILERFLAG}'; now CFLAGS='${CFLAGS}' and CXXFLAGS='${CXXFLAGS}']) AC_LANG_PUSH([C]) GOOD_FLAG=no AX_CHECK_COMPILE_FLAG([${COMPILERFLAG}], [CFLAGS="-Werror $NUT_SAVED_CFLAGS ${COMPILERFLAG}" AC_MSG_CHECKING([whether the flag '${COMPILERFLAG}' is still supported in CC linker mode]) AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [GOOD_FLAG=yes],[]) AC_MSG_RESULT([${GOOD_FLAG}]) ], [], []) AC_LANG_POP([C]) AS_IF([test x"${GOOD_FLAG}" = xyes], [CFLAGS="$NUT_SAVED_CFLAGS ${COMPILERFLAG}"], [CFLAGS="$NUT_SAVED_CFLAGS"] ) AC_MSG_NOTICE([${GOOD_FLAG} for C '${COMPILERFLAG}'; now CFLAGS=${CFLAGS}]) AC_LANG_PUSH([C++]) GOOD_FLAG=no AX_CHECK_COMPILE_FLAG([${COMPILERFLAG}], [CXXFLAGS="-Werror $NUT_SAVED_CXXFLAGS ${COMPILERFLAG}" AC_MSG_CHECKING([whether the flag '${COMPILERFLAG}' is still supported in CXX linker mode]) AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [GOOD_FLAG=yes],[]) AC_MSG_RESULT([${GOOD_FLAG}]) ], [], []) AC_LANG_POP([C++]) AS_IF([test x"${GOOD_FLAG}" = xyes], [CXXFLAGS="$NUT_SAVED_CXXFLAGS ${COMPILERFLAG}"], [CXXFLAGS="$NUT_SAVED_CXXFLAGS"] ) AC_MSG_NOTICE([${GOOD_FLAG} for C++ '${COMPILERFLAG}'; now CXXFLAGS=${CXXFLAGS}]) unset NUT_SAVED_CXXFLAGS unset NUT_SAVED_CFLAGS unset GOOD_FLAG ]) AC_DEFUN([NUT_COMPILER_FAMILY_FLAGS], [ AC_MSG_NOTICE([Detecting support for additional compiler flags]) dnl -Qunused-arguments: dnl Do not die due to `clang: error: argument unused during compilation: '-I .'` dnl -Wno-unknown-warning-option: Do not die (on older clang releases) due to dnl error: unknown warning option '-Wno-double-promotion'; did you mean dnl '-Wno-documentation'? [-Werror,-Wunknown-warning-option] dnl -fcolor-diagnostics: help find where bugs are in the wall of text (clang) dnl -fdiagnostics-color=ARG: help find where bugs are in the wall of text (gcc) dnl First check for this to avoid failing on unused include paths etc: NUT_CHECK_COMPILE_FLAG([-Qunused-arguments]) m4_foreach_w([TESTCOMPILERFLAG], [ -Wno-reserved-identifier ], [ NUT_CHECK_COMPILE_FLAG([TESTCOMPILERFLAG]) ]) dnl Note: each m4_foreach_w arg must be named uniquely dnl Note: Seems -fcolor-diagnostics is clang-only and sometimes dnl gcc blindly accepts it in test and fails to use later. AS_IF([test x"${nut_enable_Wcolor}" = xyes], [ m4_foreach_w([TESTCOMPILERFLAG_COLOR], [ -fdiagnostics-color=always ], [ NUT_CHECK_COMPILE_FLAG([TESTCOMPILERFLAG_COLOR]) ]) ], [AC_MSG_NOTICE([NOT checking for options to request colorized compiler output (pass --enable-Wcolor for that)])]) dnl Last check for this to avoid accepting anything regardless of support. dnl NOTE that some toolkit versions accept this option blindly and without dnl really supporting it (but not erroring out on it, either): dnl cc1: note: unrecognized command-line option '-Wno-unknown-warning-option' dnl may have been intended to silence earlier diagnostics NUT_CHECK_COMPILE_FLAG([-Wno-unknown-warning-option]) dnl # Older "brute-forced" settings: dnl AS_IF([test "x$CLANGCC" = xyes], [CFLAGS="$CFLAGS -Wno-unknown-warning-option"]) dnl AS_IF([test "x$CLANGXX" = xyes], [CXXFLAGS="$CXXFLAGS -Wno-unknown-warning-option"]) dnl # Despite the internet lore, practical GCC versions seen so far dnl # (4.x-10.x) do not know of this CLI option, with varied results dnl # from "cc1: note: unrecognized command-line option '-Wno-unknown-warning' dnl # may have been intended to silence earlier diagnostics" dnl # to "cc1: error: unrecognized command line option '-Wno-unknown-warning' dnl # [-Werror]"... so we do not pass it by default: dnl AS_IF([test "x$GCC" = xyes], [CFLAGS="$CFLAGS -Wno-unknown-warning"]) dnl AS_IF([test "x$GXX" = xyes], [CXXFLAGS="$CXXFLAGS -Wno-unknown-warning"]) dnl # There should be no need to include standard system paths (and possibly dnl # confuse the compiler assumptions - along with its provided headers)... dnl # ideally; in practice however cppunit, net-snmp, openssl-3 and some dnl # system include files do cause grief to picky compiler settings (more dnl # so from third party packages shipped via /usr/local/... namespace); dnl # see also e.g. nut_check_libopenssl.m4 for component-specific locations: AS_IF([test "x$cross_compiling" != xyes], [ AS_IF([test "x$CLANGCC" = xyes -o "x$GCC" = xyes], [ dnl # CFLAGS="-isystem /usr/include $CFLAGS" AS_IF([test -d /usr/local/include], [CFLAGS="-isystem /usr/local/include $CFLAGS"]) AS_IF([test -d /usr/pkg/include], [CFLAGS="-isystem /usr/pkg/include $CFLAGS"]) ]) AS_IF([test "x$CLANGXX" = xyes -o "x$GXX" = xyes], [ dnl # CXXFLAGS="-isystem /usr/include $CXXFLAGS" AS_IF([test -d /usr/local/include], [CXXFLAGS="-isystem /usr/local/include $CXXFLAGS"]) AS_IF([test -d /usr/pkg/include], [CXXFLAGS="-isystem /usr/pkg/include $CXXFLAGS"]) ]) ]) dnl # Default to avoid noisy warnings on older compilers dnl # (gcc-4.x, clang-3.x) due to their preference of dnl # ANSI C (C89/C90) out of the box. While NUT codebase dnl # currently can build in that mode, reliability of dnl # results is uncertain - third-party and/or system dnl # headers and libs seemingly no longer care for C90 dnl # on modern systems, and we have no recent data from dnl # truly legacy systems which have no choice. dnl # Some distributions and platforms also have problems dnl # building in "strict C" mode, so for the GNU-compatible dnl # compilers we default to the GNU C/C++ dialects. AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes], [AS_CASE(["${CFLAGS}"], [*"-std="*|*"-ansi"*], [], [AC_LANG_PUSH([C]) AX_CHECK_COMPILE_FLAG([-std=gnu99], [AC_MSG_NOTICE([Defaulting C standard support to GNU C99 on a GCC or CLANG compatible compiler]) CFLAGS="$CFLAGS -std=gnu99" ], [], [-Werror]) AC_LANG_POP([C]) ]) ]) dnl # Note: this might upset some very old compilers dnl # but then by default we wouldn't build C++ parts AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes], [AS_CASE(["${CXXFLAGS}"], [*"-std="*|*"-ansi"*], [], [AC_LANG_PUSH([C++]) AX_CHECK_COMPILE_FLAG([-std=gnu++11], [AC_MSG_NOTICE([Defaulting C++ standard support to GNU C++11 on a GCC or CLANG compatible compiler]) CXXFLAGS="$CXXFLAGS -std=gnu++11" ], [], [-Werror]) AC_LANG_POP([C++]) ]) ]) ]) AC_DEFUN([NUT_COMPILER_FAMILY_FLAGS_DEFAULT_STANDARD], [ dnl # Default to avoid noisy warnings on older compilers dnl # (gcc-4.x, clang-3.x) due to their preference of dnl # ANSI C (C89/C90) out of the box. While NUT codebase dnl # currently can build in that mode, reliability of dnl # results is uncertain - third-party and/or system dnl # headers and libs seemingly no longer care for C90 dnl # on modern systems, and we have no recent data from dnl # truly legacy systems which have no choice. dnl # Some distributions and platforms also have problems dnl # building in "strict C" mode, so for the GNU-compatible dnl # compilers we default to the GNU C/C++ dialects. AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes], [AS_CASE(["${CFLAGS}"], [*"-std="*|*"-ansi"*], [], [AC_LANG_PUSH([C]) AX_CHECK_COMPILE_FLAG([-std=gnu99], [AC_MSG_NOTICE([Defaulting C standard support to GNU C99 on a GCC or CLANG compatible compiler]) CFLAGS="$CFLAGS -std=gnu99" ], [], [-Werror]) AC_LANG_POP([C]) ]) ]) dnl # Note: this might upset some very old compilers dnl # but then by default we wouldn't build C++ parts AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes], [AS_CASE(["${CXXFLAGS}"], [*"-std="*|*"-ansi"*], [], [AC_LANG_PUSH([C++]) AX_CHECK_COMPILE_FLAG([-std=gnu++11], [AC_MSG_NOTICE([Defaulting C++ standard support to GNU C++11 on a GCC or CLANG compatible compiler]) CXXFLAGS="$CXXFLAGS -std=gnu++11" ], [], [-Werror]) AC_LANG_POP([C++]) ]) ]) ]) nut-2.8.3/m4/nut_check_libneon.m40000644000200500020050000000654414777767434013535 00000000000000dnl Check for LIBNEON compiler flags. On success, set nut_have_neon="yes" dnl and set LIBNEON_CFLAGS and LIBNEON_LIBS. On failure, set dnl nut_have_neon="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBNEON], [ if test -z "${nut_have_neon_seen}"; then nut_have_neon_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [dnl See which version of the neon library (if any) is installed dnl FIXME : Support detection of cflags/ldflags below by legacy dnl discovery if pkgconfig is not there AC_MSG_CHECKING(for libneon version via pkg-config (0.25.0 minimum required)) NEON_VERSION="`$PKG_CONFIG --silence-errors --modversion neon 2>/dev/null`" if test "$?" != "0" -o -z "${NEON_VERSION}"; then NEON_VERSION="none" fi AC_MSG_RESULT(${NEON_VERSION} found) ], [NEON_VERSION="none" AC_MSG_NOTICE([can not check libneon settings via pkg-config]) ] ) AC_MSG_CHECKING(for libneon cflags) AC_ARG_WITH(neon-includes, AS_HELP_STRING([@<:@--with-neon-includes=CFLAGS@:>@], [include flags for the neon library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-neon-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], [ AS_IF([test x"$have_PKG_CONFIG" = xyes], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags neon 2>/dev/null`" \ || depCFLAGS="-I/usr/include/neon -I/usr/local/include/neon"], [depCFLAGS="-I/usr/include/neon -I/usr/local/include/neon"] )] ) AC_MSG_RESULT([${CFLAGS}]) AC_MSG_CHECKING(for libneon ldflags) AC_ARG_WITH(neon-libs, AS_HELP_STRING([@<:@--with-neon-libs=LIBS@:>@], [linker flags for the neon library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-neon-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], [ AS_IF([test x"$have_PKG_CONFIG" = xyes], [depLIBS="`$PKG_CONFIG --silence-errors --libs neon 2>/dev/null`" \ || depLIBS="-lneon"], [depLIBS="-lneon"] )] ) AC_MSG_RESULT([${depLIBS}]) dnl check if neon is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(ne_xmlreq.h, [nut_have_neon=yes], [nut_have_neon=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(ne_xml_dispatch_request, [], [nut_have_neon=no]) if test "${nut_have_neon}" = "yes"; then dnl Check for connect timeout support in library (optional) AC_CHECK_FUNCS(ne_set_connect_timeout ne_sock_connect_timeout) LIBNEON_CFLAGS="${depCFLAGS}" LIBNEON_LIBS="${depLIBS}" dnl Help ltdl if we can (nut-scanner etc.) for TOKEN in $depLIBS ; do AS_CASE(["${TOKEN}"], [-l*neon*], [ AX_REALPATH_LIB([${TOKEN}], [SOPATH_LIBNEON], []) AS_IF([test -n "${SOPATH_LIBNEON}" && test -s "${SOPATH_LIBNEON}"], [ AC_DEFINE_UNQUOTED([SOPATH_LIBNEON],["${SOPATH_LIBNEON}"],[Path to dynamic library on build system]) SOFILE_LIBNEON="`basename "$SOPATH_LIBNEON"`" AC_DEFINE_UNQUOTED([SOFILE_LIBNEON],["${SOFILE_LIBNEON}"],[Base file name of dynamic library on build system]) break ]) ] ) done unset TOKEN fi unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_check_libgd.m40000644000200500020050000001455514777767434013171 00000000000000dnl Check for LIBGD compiler flags. On success, set nut_have_libgd="yes" dnl and set LIBGD_CFLAGS and LIBGD_LDFLAGS. On failure, set dnl nut_have_libgd="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBGD], [ if test -z "${nut_have_libgd_seen}"; then nut_have_libgd_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) CFLAGS_ORIG="${CFLAGS}" LDFLAGS_ORIG="${LDFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LDFLAGS="" LIBS="" depCFLAGS="" depLDFLAGS="" depLIBS="" AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) LIBGD (before): CFLAGS_ORIG="${CFLAGS_ORIG}" CXXFLAGS_ORIG="${CXXFLAGS_ORIG}" CPPFLAGS_ORIG="${CPPFLAGS_ORIG}" LDFLAGS_ORIG="${LDFLAGS_ORIG}" LIBS_ORIG="${LIBS_ORIG}"]) ]) AS_IF([test x"$have_PKG_CONFIG" = xyes], [AC_MSG_CHECKING(for gd version via pkg-config) GD_VERSION="`$PKG_CONFIG --silence-errors --modversion gdlib 2>/dev/null`" if test "$?" != "0" -o -z "${GD_VERSION}"; then GD_VERSION="none" fi AC_MSG_RESULT(${GD_VERSION} found) ], [GD_VERSION="none" AC_MSG_NOTICE([can not check libgd settings via pkg-config]) ] ) AS_IF([test x"$GD_VERSION" != xnone], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags gdlib 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs gdlib 2>/dev/null`" ], [dnl Initial defaults. These are only used if gdlib-config is dnl unusable and the user fails to pass better values in --with dnl arguments depCFLAGS="" depLDFLAGS="-L/usr/X11R6/lib" depLIBS="-lgd -lpng -lz -ljpeg -lfreetype -lm -lXpm -lX11" dnl By default seek in PATH AC_PATH_PROGS([GDLIB_CONFIG], [gdlib-config], [none]) AC_ARG_WITH(gdlib-config, AS_HELP_STRING([@<:@--with-gdlib-config=/path/to/gdlib-config@:>@], [path to program that reports GDLIB configuration]), [ case "${withval}" in "") ;; yes|no) AC_MSG_ERROR(invalid option --with(out)-gdlib-config - see docs/configure.txt) ;; *) GDLIB_CONFIG="${withval}" ;; esac ]) AS_IF([test x"$GDLIB_CONFIG" != xnone], [AC_MSG_CHECKING(for gd version via ${GDLIB_CONFIG}) GD_VERSION="`${GDLIB_CONFIG} --version 2>/dev/null`" if test "$?" != "0" -o -z "${GD_VERSION}"; then GD_VERSION="none" fi AC_MSG_RESULT(${GD_VERSION} found) ], [GD_VERSION="none"] ) case "${GD_VERSION}" in none) ;; 2.0.5 | 2.0.6 | 2.0.7) AC_MSG_WARN([[gd ${GD_VERSION} detected, unable to use ${GDLIB_CONFIG} script]]) AC_MSG_WARN([[If gd detection fails, upgrade gd or use --with-gd-includes and --with-gd-libs]]) ;; *) depCFLAGS="`${GDLIB_CONFIG} --includes 2>/dev/null`" depLDFLAGS="`${GDLIB_CONFIG} --ldflags 2>/dev/null`" depLIBS="`${GDLIB_CONFIG} --libs 2>/dev/null`" ;; esac ] ) dnl Now allow overriding gd settings if the user knows best AC_MSG_CHECKING(for gd include flags) AC_ARG_WITH(gd-includes, AS_HELP_STRING([@<:@--with-gd-includes=CFLAGS@:>@], [include flags for the gd library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-gd-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for gd library flags) AC_ARG_WITH(gd-libs, AS_HELP_STRING([@<:@--with-gd-libs=LDFLAGS@:>@], [linker flags for the gd library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-gd-libs - see docs/configure.txt) ;; *) depLDFLAGS="${withval}" depLIBS="" ;; esac ], []) AC_MSG_RESULT([${depLDFLAGS} ${depLIBS}]) dnl check if gd is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LDFLAGS="${LDFLAGS_ORIG} ${depLDFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(gd.h gdfontmb.h, [nut_have_libgd=yes], [nut_have_libgd=no], [AC_INCLUDES_DEFAULT]) AC_SEARCH_LIBS(gdImagePng, gd, [], [ dnl If using pkg-config, query additionally for Libs.private dnl to pull -L/usr/X11R6/lib or whatever current OS wants AC_MSG_CHECKING([for more gd library flags]) AS_IF([test -n "${with_gd_libs}" || test x"$have_PKG_CONFIG" != xyes], [nut_have_libgd=no], [ depLIBS_PRIVATE="`$PKG_CONFIG --silence-errors --libs gdlib --static 2>/dev/null`" AS_IF([test -z "${depLIBS_PRIVATE}"], [nut_have_libgd=no], [ AC_MSG_CHECKING([with gdlib.pc Libs.private]) depLDFLAGS="$depLDFLAGS $depLIBS_PRIVATE" unset ac_cv_search_gdImagePng LDFLAGS="${LDFLAGS_ORIG} ${depLDFLAGS}" AC_SEARCH_LIBS(gdImagePng, gd, [nut_have_libgd=yes], [nut_have_libgd=no]) ]) unset depLIBS_PRIVATE dnl At least mingw 32-bit builds of the DLL seem to not dnl tell the linker how to get from GD to PNG lib AS_IF([test x"$nut_have_libgd" = xno], [ AC_MSG_CHECKING([with explicit -lpng in the loop]) depLDFLAGS="$depLDFLAGS -lgd" unset ac_cv_search_gdImagePng LDFLAGS="${LDFLAGS_ORIG} ${depLDFLAGS}" AC_SEARCH_LIBS(gdImagePng, png png16, [nut_have_libgd=yes], [nut_have_libgd=no]) ]) ]) ]) dnl Collect possibly updated dependencies after AC SEARCH LIBS: AS_IF([test x"${LIBS}" != x"${LIBS_ORIG} ${depLIBS}"], [ AS_IF([test x = x"${LIBS_ORIG}"], [depLIBS="$LIBS"], [ depLIBS="`echo "$LIBS" | sed -e 's|'"${LIBS_ORIG}"'| |' -e 's|^ *||' -e 's| *$||'`" ]) ]) if test "${nut_have_libgd}" = "yes"; then AC_MSG_CHECKING([whether we can build, link and/or run a program with libgd]) AC_LANG_PUSH([C]) AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([ #include #include #include ], [ FILE *tmpf = tmpfile(); gdImagePtr im = gdImageCreate(64, 128); int back_color = gdImageColorAllocate(im, 255, 128, 32); int scale_num_color = gdImageColorAllocate(im, 0, 128, 128); gdImageFilledRectangle(im, 0, 0, 64, 128, back_color); gdImageColorTransparent(im, back_color); /* this may invoke fontconfig/freetype or equivalen dependencies of libgd: */ gdImageString(im, gdFontMediumBold, 4, 16, (unsigned char *)"Test Label", scale_num_color); gdImagePng(im, tmpf ? tmpf : stderr); gdImageDestroy(im); ] )], [], [nut_have_libgd=no]) AC_LANG_POP([C]) AC_MSG_RESULT([${nut_have_libgd}]) fi if test "${nut_have_libgd}" = "yes"; then AC_DEFINE(HAVE_LIBGD, 1, [Define if you have Boutell's libgd installed]) LIBGD_CFLAGS="${depCFLAGS}" LIBGD_LDFLAGS="${depLDFLAGS} ${depLIBS}" fi unset depCFLAGS unset depLDFLAGS unset depLIBS dnl put back the original versions CFLAGS="${CFLAGS_ORIG}" LDFLAGS="${LDFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/ax_c_pragmas.m40000644000200500020050000020053114777767434012500 00000000000000dnl Check for current compiler support of specific pragmas we use, dnl e.g. diagnostics management to keep warnings quiet sometimes AC_DEFUN([AX_C_PRAGMAS], [ if test -z "${nut_have_ax_c_pragmas_seen}"; then nut_have_ax_c_pragmas_seen="yes" CFLAGS_SAVED="${CFLAGS}" CXXFLAGS_SAVED="${CXXFLAGS}" dnl ### To be sure, bolt the language AC_LANG_PUSH([C]) dnl # This is expected to fail builds with unknown pragma names on GCC or CLANG at least AS_IF([test "${CLANG}" = "yes"], [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-pragmas -Werror=unknown-warning-option" CXXFLAGS="${CXXFLAGS_SAVED} -Werror=pragmas -Werror=unknown-pragmas -Werror=unknown-warning-option"], [AS_IF([test "${GCC}" = "yes"], dnl ### Despite the docs, this dies with lack of (apparently) support for dnl ### -Wunknown-warning(-options) on all GCC versions I tried (v5-v10) dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning"], [CFLAGS="${CFLAGS_SAVED} -Wall -Wextra -Werror" CXXFLAGS="${CXXFLAGS_SAVED} -Wall -Wextra -Werror"], [CFLAGS="${CFLAGS_SAVED} -Wall -Wextra -Werror" CXXFLAGS="${CXXFLAGS_SAVED} -Wall -Wextra -Werror"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic push and pop (outside functions)], [ax_cv__pragma__gcc__diags_push_pop_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[ #pragma GCC diagnostic push #pragma GCC diagnostic pop ]], [])], [ax_cv__pragma__gcc__diags_push_pop_besidefunc=yes], [ax_cv__pragma__gcc__diags_push_pop_besidefunc=no] )] ) AC_CACHE_CHECK([for pragma clang diagnostic push and pop (outside functions)], [ax_cv__pragma__clang__diags_push_pop_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[ #ifdef __clang__ #endif #pragma clang diagnostic push #pragma clang diagnostic pop ]], [])], [ax_cv__pragma__clang__diags_push_pop_besidefunc=yes], [ax_cv__pragma__clang__diags_push_pop_besidefunc=no] )] ) dnl # Currently our code uses these pragmas as close to lines that cause dnl # questions from linters as possible. GCC before 4.5 did not allow dnl # for diag pragmas inside function bodies, but also did not complain dnl # about messy code as new compilers do. For completeness, we support dnl # the possibility of defining larger-scoped pragmas around whole dnl # function bodies. In practice, we don't currently do that so in dnl # most cases the shorter names (without _INSIDEFUNC) are used with dnl # that implied meaning. AC_CACHE_CHECK([for pragma GCC diagnostic push and pop (inside functions)], [ax_cv__pragma__gcc__diags_push_pop_insidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic push #pragma GCC diagnostic pop } ]], [])], [ax_cv__pragma__gcc__diags_push_pop_insidefunc=yes], [ax_cv__pragma__gcc__diags_push_pop_insidefunc=no] )] ) AC_CACHE_CHECK([for pragma clang diagnostic push and pop (inside functions)], [ax_cv__pragma__clang__diags_push_pop_insidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #ifdef __clang__ #endif #pragma clang diagnostic push #pragma clang diagnostic pop } ]], [])], [ax_cv__pragma__clang__diags_push_pop_insidefunc=yes], [ax_cv__pragma__clang__diags_push_pop_insidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_push_pop_insidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic push and pop inside function bodies]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_push_pop_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic push and pop outside function bodies]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_push_pop_besidefunc" = "yes" && test "$ax_cv__pragma__gcc__diags_push_pop_insidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP], 1, [define if your compiler has #pragma GCC diagnostic push and pop]) ]) AS_IF([test "$ax_cv__pragma__clang__diags_push_pop_insidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP_INSIDEFUNC], 1, [define if your compiler has #pragma clang diagnostic push and pop inside function bodies]) ]) AS_IF([test "$ax_cv__pragma__clang__diags_push_pop_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP_BESIDEFUNC], 1, [define if your compiler has #pragma clang diagnostic push and pop outside function bodies]) ]) AS_IF([test "$ax_cv__pragma__clang__diags_push_pop_besidefunc" = "yes" && test "$ax_cv__pragma__clang__diags_push_pop_insidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP], 1, [define if your compiler has #pragma clang diagnostic push and pop]) ]) dnl Test for some clang-specific pragma support: primarily useful for older dnl clang (3.x) releases, so polluting NUT codebase only when unavoidable. dnl In most cases, GCC pragmas are usable by both; in a few others, direct dnl use of `#ifdef __clang__` suffices. AS_IF([test "${CLANG}" = "yes"], [ AC_CACHE_CHECK([for pragma CLANG diagnostic ignored "-Wdeprecated-declarations"], [ax_cv__pragma__clang__diags_ignored_deprecated_declarations], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma clang diagnostic ignored "-Wdeprecated-declarations" } ]], [])], [ax_cv__pragma__clang__diags_ignored_deprecated_declarations=yes], [ax_cv__pragma__clang__diags_ignored_deprecated_declarations=no] )] ) AS_IF([test "$ax_cv__pragma__clang__diags_ignored_deprecated_declarations" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS], 1, [define if your compiler has #pragma clang diagnostic ignored "-Wdeprecated-declarations"]) ]) AC_CACHE_CHECK([for pragma CLANG diagnostic ignored "-Wdeprecated-declarations" (outside functions)], [ax_cv__pragma__clang__diags_ignored_deprecated_declarations_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma clang diagnostic ignored "-Wdeprecated-declarations"]], [])], [ax_cv__pragma__clang__diags_ignored_deprecated_declarations_besidefunc=yes], [ax_cv__pragma__clang__diags_ignored_deprecated_declarations_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__clang__diags_ignored_deprecated_declarations_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS_BESIDEFUNC], 1, [define if your compiler has #pragma clang diagnostic ignored "-Wdeprecated-declarations" (outside functions)]) ]) AC_CACHE_CHECK([for pragma CLANG diagnostic ignored "-Wunreachable-code-return"], [ax_cv__pragma__clang__diags_ignored_unreachable_code_return], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma clang diagnostic ignored "-Wunreachable-code-return" } ]], [])], [ax_cv__pragma__clang__diags_ignored_unreachable_code_return=yes], [ax_cv__pragma__clang__diags_ignored_unreachable_code_return=no] )] ) AS_IF([test "$ax_cv__pragma__clang__diags_ignored_unreachable_code_return" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN], 1, [define if your compiler has #pragma clang diagnostic ignored "-Wunreachable-code-return"]) ]) AC_CACHE_CHECK([for pragma CLANG diagnostic ignored "-Wunreachable-code-return" (outside functions)], [ax_cv__pragma__clang__diags_ignored_unreachable_code_return_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma clang diagnostic ignored "-Wunreachable-code-return"]], [])], [ax_cv__pragma__clang__diags_ignored_unreachable_code_return_besidefunc=yes], [ax_cv__pragma__clang__diags_ignored_unreachable_code_return_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__clang__diags_ignored_unreachable_code_return_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN_BESIDEFUNC], 1, [define if your compiler has #pragma clang diagnostic ignored "-Wunreachable-code-return" (outside functions)]) ]) ]) dnl Special pragma support testing for clang dnl Test common pragmas for GCC (and compatible) compilers AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wpedantic"], [ax_cv__pragma__gcc__diags_ignored_pedantic], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wpedantic" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_pedantic=yes], [ax_cv__pragma__gcc__diags_ignored_pedantic=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_pedantic" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_PEDANTIC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wpedantic"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wpedantic" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_pedantic_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wpedantic"]], [])], [ax_cv__pragma__gcc__diags_ignored_pedantic_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_pedantic_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_pedantic_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_PEDANTIC_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wpedantic" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wunused-function"], [ax_cv__pragma__gcc__diags_ignored_unused_function], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wunused-function" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_unused_function=yes], [ax_cv__pragma__gcc__diags_ignored_unused_function=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unused_function" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNUSED_FUNCTION], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunused-function"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wunused-parameter"], [ax_cv__pragma__gcc__diags_ignored_unused_parameter], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wunused-parameter" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_unused_parameter=yes], [ax_cv__pragma__gcc__diags_ignored_unused_parameter=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unused_parameter" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNUSED_PARAMETER], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunused-parameter"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wdeprecated-declarations"], [ax_cv__pragma__gcc__diags_ignored_deprecated_declarations], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wdeprecated-declarations" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_deprecated_declarations=yes], [ax_cv__pragma__gcc__diags_ignored_deprecated_declarations=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_deprecated_declarations" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wdeprecated-declarations"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-nonliteral"], [ax_cv__pragma__gcc__diags_ignored_format_nonliteral], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wformat-nonliteral" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_format_nonliteral=yes], [ax_cv__pragma__gcc__diags_ignored_format_nonliteral=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_nonliteral" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-nonliteral"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-nonliteral" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_format_nonliteral_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wformat-nonliteral"]], [])], [ax_cv__pragma__gcc__diags_ignored_format_nonliteral_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_format_nonliteral_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_nonliteral_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-nonliteral" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-security"], [ax_cv__pragma__gcc__diags_ignored_format_security], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wformat-security" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_format_security=yes], [ax_cv__pragma__gcc__diags_ignored_format_security=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_security" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-security"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-security" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_format_security_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wformat-security"]], [])], [ax_cv__pragma__gcc__diags_ignored_format_security_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_format_security_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_security_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-security" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-truncation"], [ax_cv__pragma__gcc__diags_ignored_format_truncation], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wformat-truncation" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_format_truncation=yes], [ax_cv__pragma__gcc__diags_ignored_format_truncation=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_truncation" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-truncation"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-truncation" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_format_truncation_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wformat-truncation"]], [])], [ax_cv__pragma__gcc__diags_ignored_format_truncation_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_format_truncation_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_truncation_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-truncation" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wstringop-truncation"], [ax_cv__pragma__gcc__diags_ignored_stringop_truncation], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wstringop-truncation" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_stringop_truncation=yes], [ax_cv__pragma__gcc__diags_ignored_stringop_truncation=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_stringop_truncation" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRINGOP_TRUNCATION], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wstringop-truncation"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wstringop-truncation" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_stringop_truncation_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wstringop-truncation"]], [])], [ax_cv__pragma__gcc__diags_ignored_stringop_truncation_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_stringop_truncation_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_stringop_truncation_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRINGOP_TRUNCATION_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wstringop-truncation" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtype-limits"], [ax_cv__pragma__gcc__diags_ignored_type_limits], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wtype-limits" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_type_limits=yes], [ax_cv__pragma__gcc__diags_ignored_type_limits=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_type_limits" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtype-limits"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtype-limits" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_type_limits_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wtype-limits"]], [])], [ax_cv__pragma__gcc__diags_ignored_type_limits_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_type_limits_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_type_limits_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtype-limits" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Warray-bounds"], [ax_cv__pragma__gcc__diags_ignored_array_bounds], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Warray-bounds" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_array_bounds=yes], [ax_cv__pragma__gcc__diags_ignored_array_bounds=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_array_bounds" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ARRAY_BOUNDS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Warray-bounds"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Warray-bounds" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_array_bounds_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Warray-bounds"]], [])], [ax_cv__pragma__gcc__diags_ignored_array_bounds_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_array_bounds_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_array_bounds_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ARRAY_BOUNDS_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Warray-bounds" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtautological-type-limit-compare"], [ax_cv__pragma__gcc__diags_ignored_tautological_type_limit_compare], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_tautological_type_limit_compare=yes], [ax_cv__pragma__gcc__diags_ignored_tautological_type_limit_compare=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_tautological_type_limit_compare" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-type-limit-compare"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_tautological_type_limit_compare_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wtautological-type-limit-compare"]], [])], [ax_cv__pragma__gcc__diags_ignored_tautological_type_limit_compare_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_tautological_type_limit_compare_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_tautological_type_limit_compare_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"], [ax_cv__pragma__gcc__diags_ignored_tautological_constant_out_of_range_compare], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_tautological_constant_out_of_range_compare=yes], [ax_cv__pragma__gcc__diags_ignored_tautological_constant_out_of_range_compare=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_tautological_constant_out_of_range_compare" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_tautological_constant_out_of_range_compare_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare"]], [])], [ax_cv__pragma__gcc__diags_ignored_tautological_constant_out_of_range_compare_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_tautological_constant_out_of_range_compare_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_tautological_constant_out_of_range_compare_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare"], [ax_cv__pragma__gcc__diags_ignored_tautological_unsigned_zero_compare], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_tautological_unsigned_zero_compare=yes], [ax_cv__pragma__gcc__diags_ignored_tautological_unsigned_zero_compare=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_tautological_unsigned_zero_compare" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_tautological_unsigned_zero_compare_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare"]], [])], [ax_cv__pragma__gcc__diags_ignored_tautological_unsigned_zero_compare_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_tautological_unsigned_zero_compare_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_tautological_unsigned_zero_compare_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtautological-compare"], [ax_cv__pragma__gcc__diags_ignored_tautological_compare], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wtautological-compare" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_tautological_compare=yes], [ax_cv__pragma__gcc__diags_ignored_tautological_compare=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_tautological_compare" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-compare"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wtautological-compare" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_tautological_compare_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wtautological-compare"]], [])], [ax_cv__pragma__gcc__diags_ignored_tautological_compare_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_tautological_compare_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_tautological_compare_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-compare" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wsign-compare"], [ax_cv__pragma__gcc__diags_ignored_sign_compare], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wsign-compare" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_sign_compare=yes], [ax_cv__pragma__gcc__diags_ignored_sign_compare=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_sign_compare" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_COMPARE], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wsign-compare"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wsign-compare" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_sign_compare_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wsign-compare"]], [])], [ax_cv__pragma__gcc__diags_ignored_sign_compare_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_sign_compare_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_sign_compare_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_COMPARE_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wsign-compare" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wsign-conversion"], [ax_cv__pragma__gcc__diags_ignored_sign_conversion], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wsign-conversion" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_sign_conversion=yes], [ax_cv__pragma__gcc__diags_ignored_sign_conversion=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_sign_conversion" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_CONVERSION], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wsign-conversion"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wsign-conversion" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_sign_conversion_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wsign-conversion"]], [])], [ax_cv__pragma__gcc__diags_ignored_sign_conversion_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_sign_conversion_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_sign_conversion_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_CONVERSION_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wsign-conversion" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wunreachable-code-break"], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_break], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wunreachable-code-break" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_break=yes], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_break=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code_break" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-break"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wunreachable-code-break" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_break_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wunreachable-code-break"]], [])], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_break_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_break_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code_break_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-break" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wunreachable-code-return"], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_return], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wunreachable-code-return" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_return=yes], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_return=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code_return" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-return"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wunreachable-code-return" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_return_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wunreachable-code-return"]], [])], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_return_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_return_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code_return_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-return" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wunreachable-code"], [ax_cv__pragma__gcc__diags_ignored_unreachable_code], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wunreachable-code" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_unreachable_code=yes], [ax_cv__pragma__gcc__diags_ignored_unreachable_code=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wunreachable-code" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wunreachable-code"]], [])], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_unreachable_code_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-overflow"], [ax_cv__pragma__gcc__diags_ignored_format_overflow], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wformat-overflow" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_format_overflow=yes], [ax_cv__pragma__gcc__diags_ignored_format_overflow=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_overflow" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-overflow"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-overflow" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_format_overflow_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wformat-overflow"]], [])], [ax_cv__pragma__gcc__diags_ignored_format_overflow_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_format_overflow_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_overflow_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-overflow" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wcovered-switch-default"], [ax_cv__pragma__gcc__diags_ignored_covered_switch_default], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wcovered-switch-default" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_covered_switch_default=yes], [ax_cv__pragma__gcc__diags_ignored_covered_switch_default=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_covered_switch_default" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcovered-switch-default"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wcovered-switch-default" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_covered_switch_default_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wcovered-switch-default"]], [])], [ax_cv__pragma__gcc__diags_ignored_covered_switch_default_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_covered_switch_default_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_covered_switch_default_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcovered-switch-default" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wextra-semi-stmt"], [ax_cv__pragma__gcc__diags_ignored_extra_semi_stmt], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wextra-semi-stmt" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_extra_semi_stmt=yes], [ax_cv__pragma__gcc__diags_ignored_extra_semi_stmt=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_extra_semi_stmt" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wextra-semi-stmt"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wextra-semi-stmt" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_extra_semi_stmt_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wextra-semi-stmt"]], [])], [ax_cv__pragma__gcc__diags_ignored_extra_semi_stmt_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_extra_semi_stmt_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_extra_semi_stmt_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wextra-semi-stmt" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Waddress"], [ax_cv__pragma__gcc__diags_ignored_address], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Waddress" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_address=yes], [ax_cv__pragma__gcc__diags_ignored_address=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_address" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ADDRESS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Waddress"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Waddress" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_address_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Waddress"]], [])], [ax_cv__pragma__gcc__diags_ignored_address_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_address_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_address_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ADDRESS_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Waddress" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wcast-align"], [ax_cv__pragma__gcc__diags_ignored_cast_align], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wcast-align" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_cast_align=yes], [ax_cv__pragma__gcc__diags_ignored_cast_align=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cast_align" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcast-align"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wcast-align" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_cast_align_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wcast-align"]], [])], [ax_cv__pragma__gcc__diags_ignored_cast_align_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_cast_align_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cast_align_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcast-align" (outside functions)]) ]) dnl https://reviews.llvm.org/D134831 AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wcast-function-type-strict"], [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wcast-function-type-strict" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict=yes], [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcast-function-type-strict"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wcast-function-type-strict" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wcast-function-type-strict"]], [])], [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cast_function_type_strict_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wcast-function-type-strict" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wstrict-prototypes"], [ax_cv__pragma__gcc__diags_ignored_strict_prototypes], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wstrict-prototypes" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_strict_prototypes=yes], [ax_cv__pragma__gcc__diags_ignored_strict_prototypes=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_strict_prototypes" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wstrict-prototypes"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wstrict-prototypes" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_strict_prototypes_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wstrict-prototypes"]], [])], [ax_cv__pragma__gcc__diags_ignored_strict_prototypes_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_strict_prototypes_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_strict_prototypes_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wstrict-prototypes" (outside functions)]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wassign-enum"], [ax_cv__pragma__gcc__diags_ignored_assign_enum], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wassign-enum" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_assign_enum=yes], [ax_cv__pragma__gcc__diags_ignored_assign_enum=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_assign_enum" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wassign-enum"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wassign-enum" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_assign_enum_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wassign-enum"]], [])], [ax_cv__pragma__gcc__diags_ignored_assign_enum_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_assign_enum_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_assign_enum_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wassign-enum" (outside functions)]) ]) AC_LANG_POP([C]) dnl ### Series of tests for C++ specific pragmas AC_LANG_PUSH([C++]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic=yes], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_PEDANTIC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"]], [])], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_PEDANTIC_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wc++98-compat"], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wc++98-compat" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat=yes], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat"]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wc++98-compat" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wc++98-compat"]], [])], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wmaybe-uninitialized"], [ax_cv__pragma__gcc__diags_ignored_maybe_uninitialized], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_maybe_uninitialized=yes], [ax_cv__pragma__gcc__diags_ignored_maybe_uninitialized=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_maybe_uninitialized" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_MAYBE_UNINITIALIZED], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wmaybe-uninitialized" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_maybe_uninitialized_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"]], [])], [ax_cv__pragma__gcc__diags_ignored_maybe_uninitialized_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_maybe_uninitialized_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_maybe_uninitialized_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_MAYBE_UNINITIALIZED_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wglobal-constructors"], [ax_cv__pragma__gcc__diags_ignored_global_constructors], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wglobal-constructors" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_global_constructors=yes], [ax_cv__pragma__gcc__diags_ignored_global_constructors=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_global_constructors" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wglobal-constructors"]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wglobal-constructors" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_global_constructors_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wglobal-constructors"]], [])], [ax_cv__pragma__gcc__diags_ignored_global_constructors_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_global_constructors_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_global_constructors_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wglobal-constructors" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wexit-time-destructors"], [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-Wexit-time-destructors" } ]], [])], [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors=yes], [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_exit_time_destructors" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wexit-time-destructors"]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wexit-time-destructors" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wexit-time-destructors"]], [])], [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_exit_time_destructors_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wexit-time-destructors" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wsuggest-override" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_suggest_override_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wsuggest-override"]], [])], [ax_cv__pragma__gcc__diags_ignored_suggest_override_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_suggest_override_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_suggest_override_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wsuggest-override" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wsuggest-destructor-override" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_suggest_destructor_override_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wsuggest-destructor-override"]], [])], [ax_cv__pragma__gcc__diags_ignored_suggest_destructor_override_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_suggest_destructor_override_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_suggest_destructor_override_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wsuggest-destructor-override" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wweak-vtables" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_weak_vtables_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wweak-vtables"]], [])], [ax_cv__pragma__gcc__diags_ignored_weak_vtables_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_weak_vtables_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_weak_vtables_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wweak-vtables" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_deprecated_dynamic_exception_spec_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec"]], [])], [ax_cv__pragma__gcc__diags_ignored_deprecated_dynamic_exception_spec_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_deprecated_dynamic_exception_spec_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_deprecated_dynamic_exception_spec_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wextra-semi" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_extra_semi_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wextra-semi"]], [])], [ax_cv__pragma__gcc__diags_ignored_extra_semi_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_extra_semi_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_extra_semi_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wextra-semi" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wold-style-cast" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_old_style_cast_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wold-style-cast"]], [])], [ax_cv__pragma__gcc__diags_ignored_old_style_cast_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_old_style_cast_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_old_style_cast_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wold-style-cast" (outside functions)]) ]) AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" (outside functions)], [ax_cv__pragma__gcc__diags_ignored_zero_as_null_pointer_constant_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"]], [])], [ax_cv__pragma__gcc__diags_ignored_zero_as_null_pointer_constant_besidefunc=yes], [ax_cv__pragma__gcc__diags_ignored_zero_as_null_pointer_constant_besidefunc=no] )] ) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_zero_as_null_pointer_constant_besidefunc" = "yes"],[ AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ZERO_AS_NULL_POINTER_CONSTANT_BESIDEFUNC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" (outside functions)]) ]) AC_LANG_POP([C++]) dnl # Meta-macros for simpler use-cases where we pick dnl # equivalent-effect macros for different compiler versions AS_IF([test "$ax_cv__pragma__gcc__diags_push_pop_insidefunc" = "yes"],[ AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_security" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_format_nonliteral" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-nonliteral" or "-Wformat-security" and for push-pop support]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_truncation" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_stringop_truncation" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-truncation" or "-Werror=stringop-truncation" and for push-pop support]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code_break" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wunreachable-code(-break)" and for push-pop support]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wc++98-compat(-pedantic)" and for push-pop support]) ]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_push_pop_besidefunc" = "yes"],[ AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_security" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_format_nonliteral" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL_BESIDEFUNC], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-nonliteral" or "-Wformat-security" and for push-pop support (outside function bodies)]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_truncation" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_stringop_truncation" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION_BESIDEFUNC], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-truncation" or "-Werror=stringop-truncation" and for push-pop support (outside function bodies)]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code_break" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BESIDEFUNC], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wunreachable-code(-break)" and for push-pop support (outside function bodies)]) ]) AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_BESIDEFUNC], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wc++98-compat(-pedantic)" and for push-pop support (outside function bodies)]) ]) ]) dnl ### Sanity check if the CLI options actually work: AC_CACHE_CHECK([for pragma BOGUSforTest], [ax_cv__pragma__bogus], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma BOGUSforTest } ]], [])], [ax_cv__pragma__bogus=yes], [ax_cv__pragma__bogus=no] )] ) AC_CACHE_CHECK([for pragma BOGUSforTest (outside functions)], [ax_cv__pragma__bogus_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma BOGUSforTest]], [])], [ax_cv__pragma__bogus_besidefunc=yes], [ax_cv__pragma__bogus_besidefunc=no] )] ) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-WBOGUSforTest"], [ax_cv__pragma__bogus_diag], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[void func(void) { #pragma GCC diagnostic ignored "-WBOGUSforTest" } ]], [])], [ax_cv__pragma__bogus_diag=yes], [ax_cv__pragma__bogus_diag=no] )] ) AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-WBOGUSforTest" (outside functions)], [ax_cv__pragma__bogus_diag_besidefunc], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-WBOGUSforTest"]], [])], [ax_cv__pragma__bogus_diag_besidefunc=yes], [ax_cv__pragma__bogus_diag_besidefunc=no] )] ) AS_IF([test "${ax_cv__pragma__bogus}" != "no"], [AC_MSG_WARN([A bogus test that was expected to fail did not! ax_cv__pragma__bogus=$ax_cv__pragma__bogus (not 'no')])]) AS_IF([test "${ax_cv__pragma__bogus_besidefunc}" != "no"], [AC_MSG_WARN([A bogus test that was expected to fail did not! ax_cv__pragma__bogus_besidefunc=$ax_cv__pragma__bogus_besidefunc (not 'no')])]) AS_IF([test "${ax_cv__pragma__bogus_diag}" != "no"], [AC_MSG_WARN([A bogus test that was expected to fail did not! ax_cv__pragma__bogus_diag=$ax_cv__pragma__bogus_diag (not 'no')])]) AS_IF([test "${ax_cv__pragma__bogus_diag_besidefunc}" != "no"], [AC_MSG_WARN([A bogus test that was expected to fail did not! ax_cv__pragma__bogus_diag_besidefunc=$ax_cv__pragma__bogus_diag_besidefunc (not 'no')])]) CFLAGS="${CFLAGS_SAVED}" CXXFLAGS="${CXXFLAGS_SAVED}" fi ]) AC_DEFUN([AX_C_PRINTF_STRING_NULL], [ dnl The following code crashes on some libc implementations (e.g. Solaris 8) dnl TODO: We may need to update NUT codebase to use NUT_STRARG() macro more dnl often and consistently, or find a way to tweak upsdebugx() etc. varargs. if test -z "${nut_have_ax_c_printf_string_null_seen}"; then nut_have_ax_c_printf_string_null_seen="yes" AC_REQUIRE([AX_RUN_OR_LINK_IFELSE])dnl dnl Here we do not care if the compiler formally complains about dnl undefined behavior of printf("%s", NULL) as long as it works dnl in practice (compiler or libc implement a sane fallback): myWARN_CFLAGS="" AS_IF([test "${GCC}" = "yes" || test "${CLANGCC}" = "yes"], [myWARN_CFLAGS="-Wno-format-truncation -Wno-format-overflow"]) dnl ### To be sure, bolt the language AC_LANG_PUSH([C]) AC_CACHE_CHECK([for practical support to printf("%s", NULL)], [ax_cv__printf_string_null], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([dnl #include #include ], [[ char buf[128]; char *s = NULL; /* The following line may issue pedantic static analysis warnings (ignored); * it may also crash (segfault) during a run on some systems - hence the test. */ int res = snprintf(buf, sizeof(buf), "%s", s); buf[sizeof(buf)-1] = '\0'; if (res < 0) { fprintf(stderr, "FAILED to snprintf() a variable NULL string argument\n"); return 1; } if (buf[0] == '\0') { fprintf(stderr, "RETURNED empty string from snprintf() with a variable NULL string argument\n"); return 0; } if (strstr(buf, "null") == NULL) { fprintf(stderr, "RETURNED some string from snprintf() with a variable NULL string argument: '%s'\n", buf); return 0; } fprintf(stderr, "SUCCESS: RETURNED a string that contains something like 'null' from snprintf() with a variable NULL string argument: '%s'\n", buf); res = printf("%s", NULL); if (res < 0) { fprintf(stderr, "FAILED to printf() an explicit NULL string argument (to stdout)\n"); return 1; } return 0; ]])], [ax_cv__printf_string_null=yes ], [ax_cv__printf_string_null=no ], [${myWARN_CFLAGS}] )] ) unset myWARN_CFLAGS NUT_ARG_ENABLE([NUT_STRARG-always], [Enable NUT_STRARG macro to handle NULL string printing even if system libraries seem to support it natively], [auto]) dnl gcc-13.2.0 and gcc-13.3.0 were seen to complain about dnl alleged formatting string overflow (seems like a false dnl positive in that case). Require the full macro there dnl by default. AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CC_VERSION='$CC_VERSION']) ]) AS_IF([test x"$nut_enable_NUT_STRARG_always" = xauto], [ nut_enable_NUT_STRARG_always=no AS_IF([test "${CLANGCC}" = "yes"], [ true dnl no-op at the moment dnl AS_CASE(["$CC_VERSION"], dnl [*" "18.*], [nut_enable_NUT_STRARG_always=yes] dnl ) ],[ AS_IF([test "${GCC}" = "yes"], [ AS_CASE(["$CC_VERSION"], [*" "13.*], [nut_enable_NUT_STRARG_always=yes] ) ]) ]) AS_IF([test x"$nut_enable_NUT_STRARG_always" = xyes], [AC_MSG_NOTICE([Automatically enabled NUT_STRARG-always due to compiler version used])]) ]) AS_IF([test "$ax_cv__printf_string_null" = "yes" && test x"$nut_enable_NUT_STRARG_always" != xyes],[ AM_CONDITIONAL([REQUIRE_NUT_STRARG], [false]) AC_DEFINE([REQUIRE_NUT_STRARG], [0], [Define to 0 if your libc can printf("%s", NULL) sanely, or to 1 if your libc requires workarounds to print NULL values.]) ],[ AM_CONDITIONAL([REQUIRE_NUT_STRARG], [true]) AC_DEFINE([REQUIRE_NUT_STRARG], [1], [Define to 0 if your libc can printf("%s", NULL) sanely, or to 1 if your libc requires workarounds to print NULL values.]) AC_MSG_WARN([Your C library requires workarounds to print NULL values; if something crashes with a segmentation fault (especially during verbose debug) - that may be why]) ]) AC_LANG_POP([C]) fi ]) nut-2.8.3/m4/libtool.m40000644000200500020050000112677115001555004011477 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 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. # GNU Libtool 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool 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 . ]) # serial 58 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from 'configure', and 'config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # 'config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain=$ac_aux_dir/ltmain.sh ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the 'libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to 'config.status' so that its # declaration there will have the same value as in 'configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags='_LT_TAGS'dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into 'config.status', and then the shell code to quote escape them in # for loops in 'config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # '#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test 0 = "$lt_write_fail" && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $[#] do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try '$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try '$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS=$save_LDFLAGS ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[912]]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[[012]][[,.]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*|11.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test yes = "$lt_cv_ld_force_load"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], [ if test yes != "$lt_cv_apple_cc_single_mod"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script that will find a shell with a builtin # printf (that we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case $ECHO in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot if not specified).])], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([$with_sysroot]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and where our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cr} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS ]) if test yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n "$lt_cv_sys_max_cmd_len"; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes = "$cross_compiling"; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen=shl_load], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen=dlopen], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) ]) ]) ]) ]) ]) ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links=nottested if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test no = "$hard_links"; then AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", [Define to the sub-directory where libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$1"; then lt_cv_path_MAGIC_CMD=$ac_dir/"$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac]) MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program that can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi]) if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM=-lm) ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test yes = "$GCC"; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([nm_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test yes = "$GCC"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS=$save_LDFLAGS]) if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi _LT_TAGVAR(link_all_deplibs, $1)=no else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; osf3*) if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test yes,yes = "$GCC,$enable_shared"; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC=$CC AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report what library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC=$lt_save_CC ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(GCC, $1)=$GXX _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)=$p else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)=$p else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test no = "$F77"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_F77"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$G77 _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_F77" AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test no = "$FC"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_FC"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_FC" AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code=$lt_simple_compile_test_code # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f "$lt_ac_sed" && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test 10 -lt "$lt_ac_count" && break lt_ac_count=`expr $lt_ac_count + 1` if test "$lt_ac_count" -gt "$lt_ac_max"; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS nut-2.8.3/m4/nut_check_bool.m40000644000200500020050000006045014777767434013036 00000000000000dnl # For the sake of portability, check if the system offers a "bool" or a dnl # "bool_t" type, and "true"/"false" values for it, and try to determine dnl # how exactly these are spelled and implemented. For consumers in the dnl # codebase, this plays along with "includes/nut_bool.h" header. dnl # Ideally the just exists and provides reasonable types and dnl # values (all lower-case), per the standard, which we would just alias dnl # as "nut_bool_t" and use. dnl # See also https://en.cppreference.com/w/cpp/header/cstdbool for more dnl # info about what should be available where per standard approach. dnl # Copyright (C) 2024 by Jim Klimov AC_DEFUN([NUT_CHECK_BOOL], [ if test -z "${nut_check_bool_seen}"; then nut_check_bool_seen="yes" AC_MSG_NOTICE([Checking below whether bool types are provided by system headers and how]) AC_LANG_PUSH([C++]) AC_CHECK_HEADERS_ONCE([cstdbool]) AC_LANG_POP([C++]) AC_LANG_PUSH([C]) dnl # Check for existing definition of boolean type (should be stdbool.h, but...) AC_CHECK_HEADERS_ONCE([stdbool.h]) myINCLUDE_STDBOOL=" #ifdef HAVE_STDBOOL_H # include #endif " dnl # Below we would check for C99 built-in "_Bool", and for "bool", dnl # "boolean" and/or "bool_t" type names with various spellings dnl # that may come from headers like FOUND__BOOL_TYPE="" FOUND__BOOL_IMPLEM_STR="" dnl # _bool HAVE__BOOL_TYPE_LOWERCASE=false dnl # _BOOL HAVE__BOOL_TYPE_UPPERCASE=false dnl # _Bool HAVE__BOOL_TYPE_CAMELCASE=false FOUND_BOOL_TYPE="" FOUND_BOOL_IMPLEM_STR="" dnl # bool HAVE_BOOL_TYPE_LOWERCASE=false dnl # BOOL HAVE_BOOL_TYPE_UPPERCASE=false dnl # Bool HAVE_BOOL_TYPE_CAMELCASE=false FOUND_BOOLEAN_TYPE="" FOUND_BOOLEAN_IMPLEM_STR="" dnl # boolean HAVE_BOOLEAN_TYPE_LOWERCASE=false dnl # BOOLEAN HAVE_BOOLEAN_TYPE_UPPERCASE=false dnl # Boolean HAVE_BOOLEAN_TYPE_CAMELCASE=false FOUND_BOOL_T_TYPE="" FOUND_BOOL_T_IMPLEM_STR="" dnl # bool_t HAVE_BOOL_T_TYPE_LOWERCASE=false dnl # BOOL_T HAVE_BOOL_T_TYPE_UPPERCASE=false dnl # Bool_t? HAVE_BOOL_T_TYPE_CAMELCASE=false FOUND__BOOL_VALUE_TRUE="" FOUND__BOOL_VALUE_FALSE="" dnl # true/false HAVE__BOOL_VALUE_LOWERCASE=false dnl # TRUE/FALSE HAVE__BOOL_VALUE_UPPERCASE=false dnl # True/False HAVE__BOOL_VALUE_CAMELCASE=false FOUND_BOOL_VALUE_TRUE="" FOUND_BOOL_VALUE_FALSE="" HAVE_BOOL_VALUE_LOWERCASE=false HAVE_BOOL_VALUE_UPPERCASE=false HAVE_BOOL_VALUE_CAMELCASE=false FOUND_BOOLEAN_VALUE_TRUE="" FOUND_BOOLEAN_VALUE_FALSE="" HAVE_BOOLEAN_VALUE_LOWERCASE=false HAVE_BOOLEAN_VALUE_UPPERCASE=false HAVE_BOOLEAN_VALUE_CAMELCASE=false FOUND_BOOL_T_VALUE_TRUE="" FOUND_BOOL_T_VALUE_FALSE="" HAVE_BOOL_T_VALUE_LOWERCASE=false HAVE_BOOL_T_VALUE_UPPERCASE=false HAVE_BOOL_T_VALUE_CAMELCASE=false HAVE__BOOL_IMPLEM_MACRO=false HAVE__BOOL_IMPLEM_INT=false HAVE__BOOL_IMPLEM_ENUM=false HAVE_BOOL_IMPLEM_MACRO=false HAVE_BOOL_IMPLEM_INT=false HAVE_BOOL_IMPLEM_ENUM=false HAVE_BOOLEAN_IMPLEM_MACRO=false HAVE_BOOLEAN_IMPLEM_INT=false HAVE_BOOLEAN_IMPLEM_ENUM=false HAVE_BOOL_T_IMPLEM_MACRO=false HAVE_BOOL_T_IMPLEM_INT=false HAVE_BOOL_T_IMPLEM_ENUM=false AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [_bool b])], [HAVE__BOOL_TYPE_LOWERCASE=true; FOUND__BOOL_TYPE="_bool"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [_BOOL b])], [HAVE__BOOL_TYPE_UPPERCASE=true; FOUND__BOOL_TYPE="_BOOL"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [_Bool b])], [HAVE__BOOL_TYPE_CAMELCASE=true; FOUND__BOOL_TYPE="_Bool"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [bool b])], [HAVE_BOOL_TYPE_LOWERCASE=true; FOUND_BOOL_TYPE="bool"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [BOOL b])], [HAVE_BOOL_TYPE_UPPERCASE=true; FOUND_BOOL_TYPE="BOOL"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [Bool b])], [HAVE_BOOL_TYPE_CAMELCASE=true; FOUND_BOOL_TYPE="Bool"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [boolean b])], [HAVE_BOOLEAN_TYPE_LOWERCASE=true; FOUND_BOOLEAN_TYPE="boolean"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [BOOLEAN b])], [HAVE_BOOLEAN_TYPE_UPPERCASE=true; FOUND_BOOLEAN_TYPE="BOOLEAN"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [Boolean b])], [HAVE_BOOLEAN_TYPE_CAMELCASE=true; FOUND_BOOLEAN_TYPE="Boolean"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [bool_t b])], [HAVE_BOOL_T_TYPE_LOWERCASE=true; FOUND_BOOL_T_TYPE="bool_t"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [BOOL_T b])], [HAVE_BOOL_T_TYPE_UPPERCASE=true; FOUND_BOOL_T_TYPE="BOOL_T"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [Bool_t b])], [HAVE_BOOL_T_TYPE_CAMELCASE=true; FOUND_BOOL_T_TYPE="Bool_t"]) AS_IF([test x"${FOUND__BOOL_TYPE}" != x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND__BOOL_TYPE} bT = true, bF = false])], [HAVE__BOOL_VALUE_LOWERCASE=true; FOUND__BOOL_VALUE_TRUE="true"; FOUND__BOOL_VALUE_FALSE="false"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND__BOOL_TYPE} bT = TRUE, bF = FALSE])], [HAVE__BOOL_VALUE_UPPERCASE=true; FOUND__BOOL_VALUE_TRUE="TRUE"; FOUND__BOOL_VALUE_FALSE="FALSE"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND__BOOL_TYPE} bT = True, bF = False])], [HAVE__BOOL_VALUE_CAMELCASE=true; FOUND__BOOL_VALUE_TRUE="True"; FOUND__BOOL_VALUE_FALSE="False"]) ]) AS_IF([test x"${FOUND_BOOL_TYPE}" != x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_TYPE} bT = true, bF = false])], [HAVE_BOOL_VALUE_LOWERCASE=true; FOUND_BOOL_VALUE_TRUE="true"; FOUND_BOOL_VALUE_FALSE="false"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_TYPE} bT = TRUE, bF = FALSE])], [HAVE_BOOL_VALUE_UPPERCASE=true; FOUND_BOOL_VALUE_TRUE="TRUE"; FOUND_BOOL_VALUE_FALSE="FALSE"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_TYPE} bT = True, bF = False])], [HAVE_BOOL_VALUE_CAMELCASE=true; FOUND_BOOL_VALUE_TRUE="True"; FOUND_BOOL_VALUE_FALSE="False"]) ]) AS_IF([test x"${FOUND_BOOLEAN_TYPE}" != x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOLEAN_TYPE} bT = true, bF = false])], [HAVE_BOOLEAN_VALUE_LOWERCASE=true; FOUND_BOOLEAN_VALUE_TRUE="true"; FOUND_BOOL_VALUE_FALSE="false"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOLEAN_TYPE} bT = TRUE, bF = FALSE])], [HAVE_BOOLEAN_VALUE_UPPERCASE=true; FOUND_BOOLEAN_VALUE_TRUE="TRUE"; FOUND_BOOL_VALUE_FALSE="FALSE"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOLEAN_TYPE} bT = True, bF = False])], [HAVE_BOOLEAN_VALUE_CAMELCASE=true; FOUND_BOOLEAN_VALUE_TRUE="True"; FOUND_BOOL_VALUE_FALSE="False"]) ]) AS_IF([test x"${FOUND_BOOL_T_TYPE}" != x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_T_TYPE} b = true, bF = false])], [HAVE_BOOL_T_VALUE_LOWERCASE=true; FOUND_BOOL_T_VALUE_TRUE="true"; FOUND_BOOL_T_VALUE_FALSE="false"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_T_TYPE} b = TRUE, bF = FALSE])], [HAVE_BOOL_T_VALUE_UPPERCASE=true; FOUND_BOOL_T_VALUE_TRUE="TRUE"; FOUND_BOOL_T_VALUE_FALSE="FALSE"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [${FOUND_BOOL_T_TYPE} b = True, bF = False])], [HAVE_BOOL_T_VALUE_CAMELCASE=true; FOUND_BOOL_T_VALUE_TRUE="True"; FOUND_BOOL_T_VALUE_FALSE="False"]) ]) dnl # FIXME: Some more diligent checks for signed/unsigned int/char/... dnl # type details? e.g. via sizeof, assignment to negatives, etc. AS_IF([test x"${FOUND__BOOL_TYPE}" = x && test x"${FOUND_BOOL_TYPE}" = x && test x"${FOUND_BOOLEAN_TYPE}" = x && test x"${FOUND_BOOL_T_TYPE}" = x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [int bT = true, bF = false])], [FOUND_BOOL_TYPE="int"; HAVE_BOOL_VALUE_LOWERCASE=true; FOUND_BOOL_VALUE_TRUE="true"; FOUND_BOOL_VALUE_FALSE="false"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [int bT = TRUE, bF = FALSE])], [FOUND_BOOL_TYPE="int"; HAVE_BOOL_VALUE_UPPERCASE=true; FOUND_BOOL_VALUE_TRUE="TRUE"; FOUND_BOOL_VALUE_FALSE="FALSE"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [int bT = True, bF = False])], [FOUND_BOOL_TYPE="int"; HAVE_BOOL_VALUE_CAMELCASE=true; FOUND_BOOL_VALUE_TRUE="True"; FOUND_BOOL_VALUE_FALSE="False"]) ]) dnl # Assume there are only 3 implementation options we can discern here dnl #################################################################### AS_IF([test x"${FOUND__BOOL_TYPE}" != x && test x"${FOUND__BOOL_VALUE_TRUE}" != x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ #ifndef ${FOUND__BOOL_VALUE_TRUE} #error "${FOUND__BOOL_VALUE_TRUE} is not a macro #endif #ifndef ${FOUND__BOOL_VALUE_FALSE} #error "${FOUND__BOOL_VALUE_FALSE} is not a macro #endif ])], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ ${FOUND__BOOL_TYPE} bT = ${FOUND__BOOL_VALUE_TRUE}; bT = 42 ])], [HAVE__BOOL_IMPLEM_INT=true; FOUND__BOOL_IMPLEM="number"], [HAVE__BOOL_IMPLEM_ENUM=true; FOUND__BOOL_IMPLEM="enum"]) ], [HAVE__BOOL_IMPLEM_MACRO=true; FOUND__BOOL_IMPLEM="macro"]) dnl # Final check AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ ${FOUND__BOOL_TYPE} b = ${FOUND__BOOL_VALUE_TRUE}; int ret = 0; if (!(!b == ${FOUND__BOOL_VALUE_FALSE})) ret = 1; if (!(b != ${FOUND__BOOL_VALUE_FALSE})) ret = 2; if (!(!b != ${FOUND__BOOL_VALUE_TRUE})) ret = 3; if (!b) ret = 4; if (ret) return ret /* no ";return 0;" here - autoconf adds one */ ])], [ dnl # All tests passed, remember this AC_MSG_NOTICE([Detected a semantically usable "_Bool"-like type name ${FOUND__BOOL_TYPE} implemented as ${FOUND__BOOL_IMPLEM} with boolean values '${FOUND__BOOL_VALUE_TRUE}' and '${FOUND__BOOL_VALUE_FALSE}']) AC_DEFINE_UNQUOTED([FOUND__BOOL_TYPE], [${FOUND__BOOL_TYPE}], [C spelling of _Bool type]) AC_DEFINE_UNQUOTED([FOUND__BOOL_IMPLEM_STR], ["${FOUND__BOOL_IMPLEM}"], [String spelling of _Bool type implementation]) AC_DEFINE_UNQUOTED([FOUND__BOOL_VALUE_TRUE], [${FOUND__BOOL_VALUE_TRUE}], [C spelling of _Bool type true value]) AC_DEFINE_UNQUOTED([FOUND__BOOL_VALUE_FALSE], [${FOUND__BOOL_VALUE_FALSE}], [C spelling of _Bool type false value]) AS_IF([${HAVE__BOOL_TYPE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_TYPE_LOWERCASE], [1], [Name of ${FOUND__BOOL_TYPE} is defined as lower-case token])]) AS_IF([${HAVE__BOOL_TYPE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_TYPE_UPPERCASE], [1], [Name of ${FOUND__BOOL_TYPE} is defined as upper-case token])]) AS_IF([${HAVE__BOOL_TYPE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_TYPE_CAMELCASE], [1], [Name of ${FOUND__BOOL_TYPE} is defined as camel-case token])]) AS_IF([${HAVE__BOOL_VALUE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_VALUE_LOWERCASE], [1], [Boolean values of ${FOUND__BOOL_TYPE} are defined as lower-case tokens])]) AS_IF([${HAVE__BOOL_VALUE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_VALUE_UPPERCASE], [1], [Boolean values of ${FOUND__BOOL_TYPE} are defined as upper-case tokens])]) AS_IF([${HAVE__BOOL_VALUE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_VALUE_CAMELCASE], [1], [Boolean values of ${FOUND__BOOL_TYPE} are defined as camel-case tokens])]) AS_IF([${HAVE__BOOL_IMPLEM_INT}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_IMPLEM_INT], [1], [Boolean type ${FOUND__BOOL_TYPE} is defined as a general-purpose number type (int)])]) AS_IF([${HAVE__BOOL_IMPLEM_ENUM}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_IMPLEM_ENUM], [1], [Boolean type ${FOUND__BOOL_TYPE} is defined as an enum with specific values allowed])]) AS_IF([${HAVE__BOOL_IMPLEM_MACRO}], [AC_DEFINE_UNQUOTED([HAVE__BOOL_IMPLEM_MACRO], [1], [Boolean values of ${FOUND__BOOL_TYPE} are defined as a preprocessor macro (type/implem is questionable)])]) ], [AC_MSG_NOTICE([Detected a "_Bool"-like type name ${FOUND__BOOL_TYPE}, but it was not semantically usable])]) ], [AC_MSG_NOTICE([A "_Bool"-like type name or its useful values were not detected])]) dnl #################################################################### AS_IF([test x"${FOUND_BOOL_TYPE}" != x && test x"${FOUND_BOOL_VALUE_TRUE}" != x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ #ifndef ${FOUND_BOOL_VALUE_TRUE} #error "${FOUND_BOOL_VALUE_TRUE} is not a macro #endif #ifndef ${FOUND_BOOL_VALUE_FALSE} #error "${FOUND_BOOL_VALUE_FALSE} is not a macro #endif ])], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ ${FOUND_BOOL_TYPE} bT = ${FOUND_BOOL_VALUE_TRUE}; bT = 42 ])], [HAVE_BOOL_IMPLEM_INT=true; FOUND_BOOL_IMPLEM="number"], [HAVE_BOOL_IMPLEM_ENUM=true; FOUND_BOOL_IMPLEM="enum"]) ], [HAVE_BOOL_IMPLEM_MACRO=true; FOUND_BOOL_IMPLEM="macro"]) dnl # Final check AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ ${FOUND_BOOL_TYPE} b = ${FOUND_BOOL_VALUE_TRUE}; int ret = 0; if (!(!b == ${FOUND_BOOL_VALUE_FALSE})) ret = 1; if (!(b != ${FOUND_BOOL_VALUE_FALSE})) ret = 2; if (!(!b != ${FOUND_BOOL_VALUE_TRUE})) ret = 3; if (!b) ret = 4; if (ret) return ret /* no ";return 0;" here - autoconf adds one */ ])], [ dnl # All tests passed, remember this AC_MSG_NOTICE([Detected a semantically usable "bool"-like type name ${FOUND_BOOL_TYPE} implemented as ${FOUND_BOOL_IMPLEM} with boolean values '${FOUND_BOOL_VALUE_TRUE}' and '${FOUND_BOOL_VALUE_FALSE}']) AC_DEFINE_UNQUOTED([FOUND_BOOL_TYPE], [${FOUND_BOOL_TYPE}], [C spelling of bool type]) AC_DEFINE_UNQUOTED([FOUND_BOOL_IMPLEM_STR], ["${FOUND_BOOL_IMPLEM}"], [String spelling of bool type implementation]) AC_DEFINE_UNQUOTED([FOUND_BOOL_VALUE_TRUE], [${FOUND_BOOL_VALUE_TRUE}], [C spelling of bool type true value]) AC_DEFINE_UNQUOTED([FOUND_BOOL_VALUE_FALSE], [${FOUND_BOOL_VALUE_FALSE}], [C spelling of bool type false value]) AS_IF([${HAVE_BOOL_TYPE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_TYPE_LOWERCASE], [1], [Name of ${FOUND_BOOL_TYPE} is defined as lower-case token])]) AS_IF([${HAVE_BOOL_TYPE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_TYPE_UPPERCASE], [1], [Name of ${FOUND_BOOL_TYPE} is defined as upper-case token])]) AS_IF([${HAVE_BOOL_TYPE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_TYPE_CAMELCASE], [1], [Name of ${FOUND_BOOL_TYPE} is defined as camel-case token])]) AS_IF([${HAVE_BOOL_VALUE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_VALUE_LOWERCASE], [1], [Boolean values of ${FOUND_BOOL_TYPE} are defined as lower-case tokens])]) AS_IF([${HAVE_BOOL_VALUE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_VALUE_UPPERCASE], [1], [Boolean values of ${FOUND_BOOL_TYPE} are defined as upper-case tokens])]) AS_IF([${HAVE_BOOL_VALUE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_VALUE_CAMELCASE], [1], [Boolean values of ${FOUND_BOOL_TYPE} are defined as camel-case tokens])]) AS_IF([${HAVE_BOOL_IMPLEM_INT}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_IMPLEM_INT], [1], [Boolean type ${FOUND_BOOL_TYPE} is defined as a general-purpose number type (int)])]) AS_IF([${HAVE_BOOL_IMPLEM_ENUM}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_IMPLEM_ENUM], [1], [Boolean type ${FOUND_BOOL_TYPE} is defined as an enum with specific values allowed])]) AS_IF([${HAVE_BOOL_IMPLEM_MACRO}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_IMPLEM_MACRO], [1], [Boolean values of ${FOUND_BOOL_TYPE} are defined as a preprocessor macro (type/implem is questionable)])]) ], [AC_MSG_NOTICE([Detected a "bool"-like type name ${FOUND_BOOL_TYPE}, but it was not semantically usable])]) ], [AC_MSG_NOTICE([A "bool"-like type name or its useful values were not detected])]) dnl #################################################################### AS_IF([test x"${FOUND_BOOLEAN_TYPE}" != x && test x"${FOUND_BOOLEAN_VALUE_TRUE}" != x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ #ifndef ${FOUND_BOOLEAN_VALUE_TRUE} #error "${FOUND_BOOLEAN_VALUE_TRUE} is not a macro #endif #ifndef ${FOUND_BOOLEAN_VALUE_FALSE} #error "${FOUND_BOOLEAN_VALUE_FALSE} is not a macro #endif ])], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ ${FOUND_BOOLEAN_TYPE} bT = ${FOUND_BOOLEAN_VALUE_TRUE}; bT = 42 ])], [HAVE_BOOLEAN_IMPLEM_INT=true; FOUND_BOOLEAN_IMPLEM="number"], [HAVE_BOOLEAN_IMPLEM_ENUM=true; FOUND_BOOLEAN_IMPLEM="enum"]) ], [HAVE_BOOLEAN_IMPLEM_MACRO=true; FOUND_BOOLEAN_IMPLEM="macro"]) dnl # Final check AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ ${FOUND_BOOLEAN_TYPE} b = ${FOUND_BOOLEAN_VALUE_TRUE}; int ret = 0; if (!(!b == ${FOUND_BOOLEAN_VALUE_FALSE})) ret = 1; if (!(b != ${FOUND_BOOLEAN_VALUE_FALSE})) ret = 2; if (!(!b != ${FOUND_BOOLEAN_VALUE_TRUE})) ret = 3; if (!b) ret = 4; if (ret) return ret /* no ";return 0;" here - autoconf adds one */ ])], [ dnl # All tests passed, remember this AC_MSG_NOTICE([Detected a semantically usable "boolean"-like type name ${FOUND_BOOLEAN_TYPE} implemented as ${FOUND_BOOLEAN_IMPLEM} with boolean values '${FOUND_BOOLEAN_VALUE_TRUE}' and '${FOUND_BOOL_VALUE_FALSE}']) AC_DEFINE_UNQUOTED([FOUND_BOOLEAN_TYPE], [${FOUND_BOOLEAN_TYPE}], [C spelling of boolean type]) AC_DEFINE_UNQUOTED([FOUND_BOOLEAN_IMPLEM_STR], ["${FOUND_BOOLEAN_IMPLEM}"], [String spelling of boolean type implementation]) AC_DEFINE_UNQUOTED([FOUND_BOOLEAN_VALUE_TRUE], [${FOUND_BOOLEAN_VALUE_TRUE}], [C spelling of boolean type true value]) AC_DEFINE_UNQUOTED([FOUND_BOOLEAN_VALUE_FALSE], [${FOUND_BOOLEAN_VALUE_FALSE}], [C spelling of boolean type false value]) AS_IF([${HAVE_BOOLEAN_TYPE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_TYPE_LOWERCASE], [1], [Name of ${FOUND_BOOLEAN_TYPE} is defined as lower-case token])]) AS_IF([${HAVE_BOOLEAN_TYPE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_TYPE_UPPERCASE], [1], [Name of ${FOUND_BOOLEAN_TYPE} is defined as upper-case token])]) AS_IF([${HAVE_BOOLEAN_TYPE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_TYPE_CAMELCASE], [1], [Name of ${FOUND_BOOLEAN_TYPE} is defined as camel-case token])]) AS_IF([${HAVE_BOOLEAN_VALUE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_VALUE_LOWERCASE], [1], [Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as lower-case tokens])]) AS_IF([${HAVE_BOOLEAN_VALUE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_VALUE_UPPERCASE], [1], [Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as upper-case tokens])]) AS_IF([${HAVE_BOOLEAN_VALUE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_VALUE_CAMELCASE], [1], [Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as camel-case tokens])]) AS_IF([${HAVE_BOOLEAN_IMPLEM_INT}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_IMPLEM_INT], [1], [Boolean type ${FOUND_BOOLEAN_TYPE} is defined as a general-purpose number type (int)])]) AS_IF([${HAVE_BOOLEAN_IMPLEM_ENUM}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_IMPLEM_ENUM], [1], [Boolean type ${FOUND_BOOLEAN_TYPE} is defined as an enum with specific values allowed])]) AS_IF([${HAVE_BOOLEAN_IMPLEM_MACRO}], [AC_DEFINE_UNQUOTED([HAVE_BOOLEAN_IMPLEM_MACRO], [1], [Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as a preprocessor macro (type/implem is questionable)])]) ], [AC_MSG_NOTICE([Detected a "boolean"-like type name ${FOUND_BOOLEAN_TYPE}, but it was not semantically usable])]) ], [AC_MSG_NOTICE([A "boolean"-like type name or its useful values were not detected])]) dnl #################################################################### AS_IF([test x"${FOUND_BOOL_T_TYPE}" != x && test x"${FOUND_BOOL_T_VALUE_TRUE}" != x], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ #ifndef ${FOUND_BOOL_T_VALUE_TRUE} #error "${FOUND_BOOL_T_VALUE_TRUE} is not a macro #endif ])], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_T_STDBOOL}], [ ${FOUND_BOOL_T_TYPE} bT = ${FOUND_BOOL_T_VALUE_TRUE}; bT = 42 ])], [HAVE_BOOL_T_IMPLEM_INT=true; FOUND_BOOL_T_IMPLEM="number"], [HAVE_BOOL_T_IMPLEM_ENUM=true; FOUND_BOOL_T_IMPLEM="enum"]) ], [HAVE_BOOL_T_IMPLEM_MACRO=true; FOUND_BOOL_T_IMPLEM="macro"]) dnl # Final check AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([${myINCLUDE_STDBOOL}], [ ${FOUND_BOOL_T_TYPE} b = ${FOUND_BOOL_T_VALUE_TRUE}; int ret = 0; if (!(!b == ${FOUND_BOOL_T_VALUE_FALSE})) ret = 1; if (!(b != ${FOUND_BOOL_T_VALUE_FALSE})) ret = 2; if (!(!b != ${FOUND_BOOL_T_VALUE_TRUE})) ret = 3; if (!b) ret = 4; if (ret) return ret /* no ";return 0;" here - autoconf adds one */ ])], [ dnl # All tests passed, remember this AC_MSG_NOTICE([Detected a semantically usable "bool_t"-like type name ${FOUND_BOOL_T_TYPE} implemented as ${FOUND_BOOL_T_IMPLEM} with boolean values '${FOUND_BOOL_T_VALUE_TRUE}' and '${FOUND_BOOL_T_VALUE_FALSE}']) AC_DEFINE_UNQUOTED([FOUND_BOOL_T_TYPE], [${FOUND_BOOL_T_TYPE}], [C spelling of bool_t type]) AC_DEFINE_UNQUOTED([FOUND_BOOL_T_IMPLEM_STR], ["${FOUND_BOOL_T_IMPLEM}"], [String spelling of bool_t type implementation]) AC_DEFINE_UNQUOTED([FOUND_BOOL_T_VALUE_TRUE], [${FOUND_BOOL_T_VALUE_TRUE}], [C spelling of bool_t type true value]) AC_DEFINE_UNQUOTED([FOUND_BOOL_T_VALUE_FALSE], [${FOUND_BOOL_T_VALUE_FALSE}], [C spelling of bool_t type false value]) AS_IF([${HAVE_BOOL_T_TYPE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_TYPE_LOWERCASE], [1], [Name of ${FOUND_BOOL_T_TYPE} is defined as lower-case token])]) AS_IF([${HAVE_BOOL_T_TYPE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_TYPE_UPPERCASE], [1], [Name of ${FOUND_BOOL_T_TYPE} is defined as upper-case token])]) AS_IF([${HAVE_BOOL_T_TYPE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_TYPE_CAMELCASE], [1], [Name of ${FOUND_BOOL_T_TYPE} is defined as camel-case token])]) AS_IF([${HAVE_BOOL_T_VALUE_LOWERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_VALUE_LOWERCASE], [1], [Boolean values of ${FOUND_BOOL_T_TYPE} are defined as lower-case tokens])]) AS_IF([${HAVE_BOOL_T_VALUE_UPPERCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_VALUE_UPPERCASE], [1], [Boolean values of ${FOUND_BOOL_T_TYPE} are defined as upper-case tokens])]) AS_IF([${HAVE_BOOL_T_VALUE_CAMELCASE}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_VALUE_CAMELCASE], [1], [Boolean values of ${FOUND_BOOL_T_TYPE} are defined as camel-case tokens])]) AS_IF([${HAVE_BOOL_T_IMPLEM_INT}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_IMPLEM_INT], [1], [Boolean type ${FOUND_BOOL_T_TYPE} is defined as a general-purpose number type (int)])]) AS_IF([${HAVE_BOOL_T_IMPLEM_ENUM}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_IMPLEM_ENUM], [1], [Boolean type ${FOUND_BOOL_T_TYPE} is defined as an enum with specific values allowed])]) AS_IF([${HAVE_BOOL_T_IMPLEM_MACRO}], [AC_DEFINE_UNQUOTED([HAVE_BOOL_T_IMPLEM_MACRO], [1], [Boolean values of ${FOUND_BOOL_T_TYPE} are defined as a preprocessor macro (type/implem is questionable)])]) ], [AC_MSG_NOTICE([Detected a "bool_t"-like type name ${FOUND_BOOL_T_TYPE}, but it was not semantically usable])]) ], [AC_MSG_NOTICE([A "bool_t"-like type name or its useful values were not detected])]) dnl #################################################################### AC_LANG_POP([C]) fi ]) nut-2.8.3/m4/nut_check_libwrap.m40000644000200500020050000000336014777767434013540 00000000000000dnl Check for LIBWRAP compiler flags. On success, set nut_have_libwrap="yes" dnl and set LIBWRAP_CFLAGS and LIBWRAP_LIBS. On failure, set dnl nut_have_libwrap="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBWRAP], [ if test -z "${nut_have_libwrap_seen}"; then nut_have_libwrap_seen=yes dnl save LIBS LIBS_ORIG="${LIBS}" dnl Do not neuter LIBS here, we check it below right away depLIBS="" AC_CHECK_HEADERS(tcpd.h, [nut_have_libwrap=yes], [nut_have_libwrap=no], [AC_INCLUDES_DEFAULT]) AC_SEARCH_LIBS(yp_get_default_domain, nsl, [], [nut_have_libwrap=no]) dnl The line below does not work on Solaris 10. dnl AC_SEARCH_LIBS(request_init, wrap, [], [nut_have_libwrap=no]) dnl Collect possibly updated dependencies after AC SEARCH LIBS: AS_IF([test x"${LIBS}" != x"${LIBS_ORIG}"], [ AS_IF([test x = x"${LIBS_ORIG}"], [depLIBS="$LIBS"], [ depLIBS="`echo "$LIBS" | sed -e 's|'"${LIBS_ORIG}"'| |' -e 's|^ *||' -e 's| *$||'`" ]) ]) AC_MSG_CHECKING(for library containing request_init) AC_LANG_PUSH([C]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include int allow_severity = 0, deny_severity = 0; ]], [[ request_init(0); ]])], [ AC_MSG_RESULT(none required) ], [ depLIBS="${depLIBS} -lwrap" LIBS="${LIBS_ORIG} ${depLIBS}" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include int allow_severity = 0, deny_severity = 0; ]], [[ request_init(0); ]])], [ AC_MSG_RESULT(-lwrap) ], [ AC_MSG_RESULT(no) nut_have_libwrap=no ]) ]) AC_LANG_POP([C]) if test "${nut_have_libwrap}" = "yes"; then AC_DEFINE(HAVE_WRAP, 1, [Define to enable libwrap support]) LIBWRAP_CFLAGS="" LIBWRAP_LIBS="${depLIBS}" fi unset depLIBS dnl restore original LIBS LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/ltversion.m40000644000200500020050000000127315001555004012044 00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 4179 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.6]) m4_define([LT_PACKAGE_REVISION], [2.4.6]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.6' macro_revision='2.4.6' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) nut-2.8.3/m4/nut_func_getnameinfo_argtypes.m40000644000200500020050000000657614777534446016177 00000000000000dnl This code was lifted and adapted for NUT from cURL project: dnl https://github.com/curl/curl/blob/e3657644d695373e9cf9ab9b4f1571afda7fd041/acinclude.m4#L228 dnl NUT_FUNC_GETNAMEINFO_ARGTYPES dnl ------------------------------------------------- dnl Check the type to be passed to five of the arguments dnl of getnameinfo function, and define those types in dnl macros GETNAMEINFO_TYPE_ARG1, GETNAMEINFO_TYPE_ARG2, dnl GETNAMEINFO_TYPE_ARG46 (4 and 6) and GETNAMEINFO_TYPE_ARG7. dnl As seen from the loop, these vary a lot between OSes... dnl Order of attempts in the loop below was updated to first dnl try and quickly match current X/Open definition at dnl https://pubs.opengroup.org/onlinepubs/9699919799/functions/getnameinfo.html dnl for modern conforming OSes. AC_DEFUN([NUT_FUNC_GETNAMEINFO_ARGTYPES], [ AC_REQUIRE([NUT_CHECK_HEADER_WS2TCPIP])dnl AC_REQUIRE([NUT_TYPE_SOCKLEN_T])dnl AC_CHECK_HEADERS(sys/types.h sys/socket.h netdb.h) AC_LANG_PUSH([C]) AC_CACHE_CHECK([types of arguments for getnameinfo], [nut_cv_func_getnameinfo_args], [ nut_cv_func_getnameinfo_args="unknown" for gni_arg1 in 'const struct sockaddr *' 'struct sockaddr *' 'void *'; do for gni_arg2 in 'socklen_t' 'size_t' 'int'; do for gni_arg46 in 'socklen_t' 'size_t' 'int' 'unsigned int' 'DWORD'; do for gni_arg7 in 'int' 'unsigned int'; do AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([ #undef inline #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # if (!defined(_WIN32_WINNT)) || (_WIN32_WINNT < 0x0501) # undef _WIN32_WINNT # define _WIN32_WINNT 0x0501 # endif # include # ifdef HAVE_WINSOCK2_H # include # ifdef HAVE_WS2TCPIP_H # include # endif # endif # define GNICALLCONV WSAAPI #else # ifdef HAVE_SYS_TYPES_H # include # endif # ifdef HAVE_SYS_SOCKET_H # include # endif # ifdef HAVE_NETDB_H # include # endif # define GNICALLCONV #endif extern int GNICALLCONV getnameinfo($gni_arg1, $gni_arg2, char *, $gni_arg46, char *, $gni_arg46, $gni_arg7); ],[ $gni_arg2 salen=0; $gni_arg46 hostlen=0; $gni_arg46 servlen=0; $gni_arg7 flags=0; int res = getnameinfo(0, salen, 0, hostlen, 0, servlen, flags); ]) ],[ nut_cv_func_getnameinfo_args="$gni_arg1,$gni_arg2,$gni_arg46,$gni_arg7" break 4 ]) done done done done ]) AC_LANG_POP([C]) if test "$nut_cv_func_getnameinfo_args" = "unknown"; then AC_MSG_WARN([Cannot find proper types to use for getnameinfo args]) else gni_prev_IFS=$IFS; IFS=',' set dummy `echo "$nut_cv_func_getnameinfo_args" | sed 's/\*/\*/g'` IFS=$gni_prev_IFS shift AC_DEFINE_UNQUOTED(GETNAMEINFO_TYPE_ARG1, $[1], [Define to the type of arg 1 for getnameinfo.]) AC_DEFINE_UNQUOTED(GETNAMEINFO_TYPE_ARG2, $[2], [Define to the type of arg 2 for getnameinfo.]) AC_DEFINE_UNQUOTED(GETNAMEINFO_TYPE_ARG46, $[3], [Define to the type of args 4 and 6 for getnameinfo.]) AC_DEFINE_UNQUOTED(GETNAMEINFO_TYPE_ARG7, $[4], [Define to the type of arg 7 for getnameinfo.]) fi ]) nut-2.8.3/m4/ax_realpath.m40000644000200500020050000002076014777534446012343 00000000000000dnl Resolve given path (if we can), for filenames that may be symlinks, dnl or in a relative directory, or where directories are symlinks... dnl Copyright (C) 2023 by Jim Klimov dnl Licensed under the terms of GPLv2 or newer. dnl Calling script is welcome to pre-detect external REALPATH implementation, dnl otherwise shell implementation would be used (hopefully capable enough): dnl AC_CHECK_PROGS([REALPATH], [realpath], []) AC_DEFUN([AX_REALPATH_SHELL_ONELEVEL], [ dnl # resolve links - #1 value (not quoted by caller) or some its dnl # ancestor directory may be a symlink; save into varname #2. dnl # In case of problems return #1 and set non-zero RESOLVE_ERROR. dnl # We recurse backwards from original name to root "/" dnl # (or abort mid-way). AS_IF([test x"$1" = x], [AC_MSG_ERROR([Bad call to REALPATH_SHELL_ONELEVEL macro (arg1)])]) AS_IF([test x"$2" = x], [AC_MSG_ERROR([Bad call to REALPATH_SHELL_ONELEVEL macro (arg2)])]) AS_IF([test x"$RESOLVE_ERROR" = x], [RESOLVE_ERROR=0]) AS_IF([test x"$RESOLVE_ERROR" != x0 || test x"$1" = x/], [dnl Quick bail out $2="$1" ], [ dnl # Code below was adapted from Apache Tomcat startup.sh TGT="$1" while test -h "$TGT" ; do LS_OUT="`ls -ld "$TGT"`" || { RESOLVE_ERROR=$? ; break ; } LINK="`expr "$LS_OUT" : '.*-> \(.*\)$'`" || { RESOLVE_ERROR=$? ; break ; } if expr "$LINK" : '/.*' > /dev/null; then TGT="$LINK" else TGT="`dirname "$TGT"`/$LINK" fi done if test "$RESOLVE_ERROR" = 0 ; then TGTDIR="`dirname "$TGT"`" && \ TGTDIR="`cd "$TGTDIR" && pwd`" || { TGTDIR="`dirname "$TGT"`" || \ RESOLVE_ERROR=$? ; } if test "$RESOLVE_ERROR" = 0 ; then while test -h "$TGTDIR" ; do LS_OUT="`ls -ld "$TGTDIR"`" || { RESOLVE_ERROR=$? ; break ; } LINK="`expr "$LS_OUT" : '.*-> \(.*\)$'`" || { RESOLVE_ERROR=$? ; break ; } if expr "$LINK" : '/.*' > /dev/null; then TGTDIR="$LINK" else PARENTDIR="`dirname "$TGTDIR"`" case "$PARENTDIR" in /) TGTDIR="/$LINK" ; break ;; *) TGTDIR="$PARENTDIR/$LINK" ;; esac fi done fi fi if test "$RESOLVE_ERROR" = 0 ; then $2="$TGTDIR/`basename "$TGT"`" else $2="$1" fi unset TGT TGTDIR PARENTDIR unset LS_OUT LINK ]) ]) AC_DEFUN([AX_REALPATH_SHELL_RECURSIVE], [ dnl Autoconf/m4 is not really friendly for recursive functions dnl so we have to do it like a loop. Sanity-checking is in the dnl helper method above and will abort the script upon problems. dnl The RESOLVE_ERROR is provided and unset by caller. RESOLVE_PREFIX="$1" RESOLVE_SUFFIX="" while \ test x"$RESOLVE_PREFIX" != x \ && test x"$RESOLVE_PREFIX" != x/ \ && test x"$RESOLVE_ERROR" = x0 \ ; do dnl In case of non-fatal resolve error, value in RESOLVE_PREFIX dnl should remain unchanged, and a RESOLVE_ERROR flag raised. dnl Note that the recursion would technically re-check the last dnl seen object (the parent directory), but should quickly move dnl on since it is not a symlink anymore. So not too ineffecient. AX_REALPATH_SHELL_ONELEVEL([$RESOLVE_PREFIX], [RESOLVE_PREFIX]) if test x"$RESOLVE_ERROR" = x0 ; then dnl Recurse to check the (grand)parent dir (if any) if test -n "$RESOLVE_SUFFIX" ; then RESOLVE_SUFFIX="`basename "$RESOLVE_PREFIX"`/$RESOLVE_SUFFIX" else RESOLVE_SUFFIX="`basename "$RESOLVE_PREFIX"`" fi RESOLVE_PREFIX="`dirname "$RESOLVE_PREFIX"`" else dnl Bail out, keep latest answer break fi done if test -n "$RESOLVE_SUFFIX" ; then if test x"$RESOLVE_PREFIX" = x ; then RESOLVE_PREFIX="/" fi if test x"$RESOLVE_PREFIX" = x/ ; then $2="/$RESOLVE_SUFFIX" else $2="$RESOLVE_PREFIX/$RESOLVE_SUFFIX" fi else $2="$RESOLVE_PREFIX" fi unset RESOLVE_PREFIX RESOLVE_SUFFIX ]) AC_DEFUN([AX_REALPATH], [ dnl # resolve links - #1 value (not quoted by caller) dnl # or its directory may be a softlink dnl # save into varname #2 AS_IF([test x"$1" = x], [AC_MSG_ERROR([Bad call to REALPATH macro (arg1)])]) AS_IF([test x"$2" = x], [AC_MSG_ERROR([Bad call to REALPATH macro (arg2)])]) AC_MSG_CHECKING([for "real path" of '$1']) REALPRG="" AS_IF([test -n "$REALPATH"], [ REALPRG="`${REALPATH} "$1"`" ]) AS_IF([test -z "$REALPRG"], [ RESOLVE_ERROR=0 dnl Note: not all "test" implementations have "-e", so got fallbacks: AS_IF([test -e "$1" || test -f "$1" || test -s "$1" || test -d "$1" || test -L "$1" || test -h "$1" || test -c "$1" || test -b "$1" || test -p "$1"], [], [ AC_MSG_WARN([Path name '$1' not found (absent or access to ancestor directories denied)]) dnl We can still try to resolve, e.g. to find dnl the real location an absent file would be in dnl RESOLVE_ERROR=1 ]) AX_REALPATH_SHELL_RECURSIVE([$1], [REALPRG]) ]) AS_IF([test -n "$REALPRG"], [ AS_IF([test x"$REALPRG" = x"$1"], [AC_MSG_RESULT(['$REALPRG'])], [AC_MSG_RESULT(['$REALPRG' (differs from input)])] ) $2="$REALPRG" ], [ dnl Indent due to newline from warning and/or tool errors above AC_MSG_RESULT([...failed to resolve, keeping original: '$1']) $2="$1" ]) unset REALPRG RESOLVE_ERROR ]) AC_DEFUN([UNITTEST_AX_REALPATH_EXPECT], [ AX_REALPATH([$1], [TMPNAME]) AS_IF([test x"$TMPNAME" != x"$2"], [AC_MSG_WARN([>>> Got: '$TMPNAME' (should be '$2')])]) ]) AC_DEFUN([UNITTEST_AX_REALPATH], [ AC_MSG_NOTICE([======= starting UNITTEST for REALPATH macro]) AC_MSG_NOTICE([=== Testing macro for realpath; .../q/x are directories, qwe is a file inside, and .../Q is a symlink to .../q]) TESTDIR="`mktemp -d`" && test -d "$TESTDIR" && test -w "$TESTDIR" || TESTDIR="/tmp" rm -rf "$TESTDIR"/q ; mkdir -p "$TESTDIR"/q/x ; echo qwe > "$TESTDIR"/q/x/qwe ; ln -fs q "$TESTDIR"/Q dnl Do not quote TESTDIR in macro calls below, shell quotes are added in implem AC_MSG_NOTICE([=======]) UNITTEST_AX_REALPATH_EXPECT([$TESTDIR/q/x], [$TESTDIR/q/x]) UNITTEST_AX_REALPATH_EXPECT([$TESTDIR/Q/x], [$TESTDIR/q/x]) UNITTEST_AX_REALPATH_EXPECT([$TESTDIR/Q/x/qwe], [$TESTDIR/q/x/qwe]) AC_MSG_NOTICE([=======]) AC_MSG_NOTICE([=== Should not have access to next file (does not exist) in a readable dir]) UNITTEST_AX_REALPATH_EXPECT([$TESTDIR/q/x/absent], [$TESTDIR/q/x/absent]) AC_MSG_NOTICE([=======]) AC_MSG_NOTICE([=== Should not have access to next file (does not exist) in a SYMLINK to readable dir]) UNITTEST_AX_REALPATH_EXPECT([$TESTDIR/Q/x/absent], [$TESTDIR/q/x/absent]) AC_MSG_NOTICE([=======]) AC_MSG_NOTICE([=== Present and visible or not, unless this is (behind) a symlink it should remain the same path]) UNITTEST_AX_REALPATH_EXPECT([/etc/nut/ups.conf], [/etc/nut/ups.conf]) AC_MSG_NOTICE([=======]) AC_MSG_NOTICE([=== Should be a shell interpreter here (if procfs is supported on the platform)]) AX_REALPATH([/proc/$$/exe], [TMPNAME]) AC_MSG_NOTICE([>>> Got: '$TMPNAME']) AC_MSG_NOTICE([=======]) AC_MSG_NOTICE([=== Should be an stdin socket here (if procfs is supported on the platform)]) AX_REALPATH([/proc/$$/fd/1], [TMPNAME]) AC_MSG_NOTICE([>>> Got: '$TMPNAME']) AC_MSG_NOTICE([=======]) AC_MSG_NOTICE([=== Should not have access to next SYMLINK (reading link content is forbidden, if procfs is supported on the platform and if not root)]) UNITTEST_AX_REALPATH_EXPECT([/proc/1/exe], [/proc/1/exe]) AC_MSG_NOTICE([=======]) AC_MSG_NOTICE([=== Should not have access to next dir (don't know if file exists, if procfs is supported on the platform and if not root)]) UNITTEST_AX_REALPATH_EXPECT([/proc/1/fd/1], [/proc/1/fd/1]) AC_MSG_NOTICE([======= end of UNITTEST for REALPATH macro]) AS_IF([test x"$TESTDIR" = x"/tmp"], [rm -rf "$TESTDIR/q" "$TESTDIR/Q"], [rm -rf "$TESTDIR"]) ]) nut-2.8.3/m4/nut_check_libnss.m40000644000200500020050000000745614777767434013404 00000000000000dnl Check for Mozilla NSS (LIBNSS) compiler flags. On success, set dnl nut_have_libnss="yes" and nut_ssl_lib="Mozilla NSS", and define WITH_SSL, dnl WITH_NSS, LIBSSL_CFLAGS and LIBSSL_LIBS. On failure, set nut_have_libnss="no". dnl This macro can be run multiple times, but will do the checking only once. AC_DEFUN([NUT_CHECK_LIBNSS], [ if test -z "${nut_have_libnss_seen}"; then nut_have_libnss_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" REQUIRES_ORIG="${REQUIRES}" CFLAGS="" LIBS="" REQUIRES="" depCFLAGS="" depLIBS="" depREQUIRES="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [AC_MSG_CHECKING(for Mozilla NSS version via pkg-config) NSS_VERSION="`$PKG_CONFIG --silence-errors --modversion nss 2>/dev/null`" if test "$?" != "0" -o -z "${NSS_VERSION}"; then NSS_VERSION="none" fi AC_MSG_RESULT(${NSS_VERSION} found) ], [NSS_VERSION="none" AC_MSG_NOTICE([can not check libnss settings via pkg-config]) ] ) AS_IF([test x"$NSS_VERSION" != xnone], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags nss 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs nss 2>/dev/null`" depREQUIRES="nss" ], [depCFLAGS="" depLIBS="-lnss3 -lnssutil3 -lsmime3 -lssl3 -lplds4 -lplc4 -lnspr4" depREQUIRES="nss" ] ) dnl allow overriding NSS settings if the user knows best AC_MSG_CHECKING(for Mozilla NSS cflags) AC_ARG_WITH(nss-includes, AS_HELP_STRING([@<:@--with-nss-includes=CFLAGS@:>@], [include flags for the Mozilla NSS library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-nss-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for Mozilla NSS ldflags) AC_ARG_WITH(nss-libs, AS_HELP_STRING([@<:@--with-nss-libs=LIBS@:>@], [linker flags for the Mozilla NSS library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-nss-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depLIBS}]) dnl check if NSS is usable: we need both the runtime and headers dnl NOTE that caller may have to specify PKG_CONFIG_PATH including dnl their bitness variant if it is not prioritized in their default dnl setting built in by OS distribution; the .../pkgconfig/nss.pc dnl tends to specify the libdir which is CPU Arch dependent. CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" REQUIRES="${REQUIRES_ORIG} ${depREQUIRES}" AC_CHECK_FUNCS(NSS_Init, [nut_have_libnss=yes], [nut_have_libnss=no]) dnl libc6 also provides an nss.h file, so also check for ssl.h AC_CHECK_HEADERS([nss.h ssl.h], [], [nut_have_libnss=no], [AC_INCLUDES_DEFAULT]) if test "${nut_have_libnss}" = "yes"; then nut_with_ssl="yes" nut_ssl_lib="(Mozilla NSS)" AC_DEFINE(WITH_SSL, 1, [Define to enable SSL support]) AC_DEFINE(WITH_NSS, 1, [Define to enable SSL support using Mozilla NSS]) LIBSSL_CFLAGS="${depCFLAGS}" LIBSSL_LIBS="${depLIBS}" LIBSSL_REQUIRES="${depREQUIRES}" dnl # See tools/nut-scanner/Makefile.am dnl # FIXME: Handle "-R /path" tokens, are they anywhere? LIBSSL_LDFLAGS_RPATH="" for TOKEN in ${LIBSSL_LIBS} ; do case "$TOKEN" in -R*) LIBSSL_LDFLAGS_RPATH="$LIBSSL_LDFLAGS_RPATH $TOKEN" dnl ### LIBSSL_LDFLAGS_RPATH="$LIBSSL_LDFLAGS_RPATH -Wl,runpath,`echo $TOKEN | sed 's,^-R *,,'`" LIBSSL_LDFLAGS_RPATH="$LIBSSL_LDFLAGS_RPATH -Wl,-rpath,`echo $TOKEN | sed 's,^-R *,,'`" ;; esac done dnl if test x"$LIBSSL_LDFLAGS_RPATH" != x ; then dnl LIBSSL_LDFLAGS_RPATH="--enable-new-dtags $LIBSSL_LDFLAGS_RPATH" dnl fi fi unset depCFLAGS unset depLIBS unset depREQUIRES dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" REQUIRES="${REQUIRES_ORIG}" fi ]) nut-2.8.3/m4/nut_check_libopenssl.m40000644000200500020050000001004214777767434014245 00000000000000dnl Check for OpenSSL (LIBOPENSSL) compiler flags. On success, set dnl nut_have_openssl="yes" and nut_ssl_lib="OpenSSL", and define WITH_SSL, dnl WITH_OPENSSL, LIBSSL_CFLAGS and LIBSSL_LIBS. On failure, set dnl nut_have_libssl="no". dnl This macro can be run multiple times, but will do the checking only once. AC_DEFUN([NUT_CHECK_LIBOPENSSL], [ if test -z "${nut_have_libopenssl_seen}"; then nut_have_libopenssl_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" REQUIRES_ORIG="${REQUIRES}" CFLAGS="" LIBS="" REQUIRES="" depCFLAGS="" depLIBS="" depREQUIRES="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [AC_MSG_CHECKING(for OpenSSL version via pkg-config) OPENSSL_VERSION="`$PKG_CONFIG --silence-errors --modversion openssl 2>/dev/null`" if test "$?" != "0" -o -z "${OPENSSL_VERSION}"; then OPENSSL_VERSION="none" fi AC_MSG_RESULT(${OPENSSL_VERSION} found) ], [OPENSSL_VERSION="none" AC_MSG_NOTICE([can not check OpenSSL settings via pkg-config]) ] ) AS_IF([test x"$OPENSSL_VERSION" != xnone], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags openssl 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs openssl 2>/dev/null`" depREQUIRES="openssl" ], [depCFLAGS="" depLIBS="-lssl -lcrypto" depREQUIRES="openssl" ] ) dnl allow overriding OpenSSL settings if the user knows best AC_MSG_CHECKING(for OpenSSL cflags) AC_ARG_WITH(openssl-includes, AS_HELP_STRING([@<:@--with-openssl-includes=CFLAGS@:>@], [include flags for the OpenSSL library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-openssl-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for OpenSSL ldflags) AC_ARG_WITH(openssl-libs, AS_HELP_STRING([@<:@--with-openssl-libs=LIBS@:>@], [linker flags for the OpenSSL library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-openssl-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depLIBS}]) dnl check if openssl is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" REQUIRES="${REQUIRES_ORIG} ${depREQUIRES}" AC_CHECK_HEADERS(openssl/ssl.h, [nut_have_openssl=yes], [nut_have_openssl=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(SSL_CTX_new, [], [nut_have_openssl=no]) if test "${nut_have_openssl}" = "yes"; then nut_with_ssl="yes" nut_ssl_lib="(OpenSSL)" AC_DEFINE(WITH_SSL, 1, [Define to enable SSL support]) AC_DEFINE(WITH_OPENSSL, 1, [Define to enable SSL support using OpenSSL]) dnl # Repeat some tricks from nut_compiler_family.m4 AS_IF([test "x$cross_compiling" != xyes], [ AS_IF([test "x$CLANGCC" = xyes -o "x$GCC" = xyes], [ dnl # This was hit on OmniOS Extra packaging repo dnl /usr/ssl-3/include/openssl/safestack.h:205:1: dnl error: cast from 'sk_OPENSSL_STRING_freefunc' dnl (aka 'void (*)(char *)') to 'OPENSSL_sk_freefunc' dnl (aka 'void (*)(void *)') converts to incompatible dnl function type [-Werror,-Wcast-function-type-strict] dnl # Below: Pick out -I... args of the depCFLAGS dnl # to check locations that actually matter for dnl # the build addCFLAGS="" for TOKEN in ${depCFLAGS} ; do case "${TOKEN}" in -I*) TOKENDIR="`echo "$TOKEN" | sed 's,^-I,,'`" case " ${CFLAGS} ${addCFLAGS} " in *" -isystem $TOKENDIR "*) ;; *) addCFLAGS="${addCFLAGS} -isystem $TOKENDIR" ;; esac ;; esac done test -z "${addCFLAGS}" || depCFLAGS="${depCFLAGS} ${addCFLAGS}" unset addCFLAGS ]) ]) LIBSSL_CFLAGS="${depCFLAGS}" LIBSSL_LIBS="${depLIBS}" LIBSSL_REQUIRES="${depREQUIRES}" dnl # See tools/nut-scanner/Makefile.am and also dnl # nut_check_libnss.m4 if there are custom RPATHs LIBSSL_LDFLAGS_RPATH="" fi unset depCFLAGS unset depLIBS unset depREQUIRES dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" REQUIRES="${REQUIRES_ORIG}" fi ]) nut-2.8.3/m4/ax_compare_version.m40000644000200500020050000001465214553676503013732 00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_compare_version.html # =========================================================================== # # SYNOPSIS # # AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # # DESCRIPTION # # This macro compares two version strings. Due to the various number of # minor-version numbers that can exist, and the fact that string # comparisons are not compatible with numeric comparisons, this is not # necessarily trivial to do in a autoconf script. This macro makes doing # these comparisons easy. # # The six basic comparisons are available, as well as checking equality # limited to a certain number of minor-version levels. # # The operator OP determines what type of comparison to do, and can be one # of: # # eq - equal (test A == B) # ne - not equal (test A != B) # le - less than or equal (test A <= B) # ge - greater than or equal (test A >= B) # lt - less than (test A < B) # gt - greater than (test A > B) # # Additionally, the eq and ne operator can have a number after it to limit # the test to that number of minor versions. # # eq0 - equal up to the length of the shorter version # ne0 - not equal up to the length of the shorter version # eqN - equal up to N sub-version levels # neN - not equal up to N sub-version levels # # When the condition is true, shell commands ACTION-IF-TRUE are run, # otherwise shell commands ACTION-IF-FALSE are run. The environment # variable 'ax_compare_version' is always set to either 'true' or 'false' # as well. # # Examples: # # AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) # AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) # # would both be true. # # AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) # AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) # # would both be false. # # AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) # # would be true because it is only comparing two minor versions. # # AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) # # would be true because it is only comparing the lesser number of minor # versions of the two values. # # Note: The characters that separate the version numbers do not matter. An # empty string is the same as version 0. OP is evaluated by autoconf, not # configure, so must be a string, not a variable. # # The author would like to acknowledge Guido Draheim whose advice about # the m4_case and m4_ifvaln functions make this macro only include the # portions necessary to perform the specific comparison specified by the # OP argument in the final configure script. # # LICENSE # # Copyright (c) 2008 Tim Toolan # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 11 dnl ######################################################################### AC_DEFUN([AX_COMPARE_VERSION], [ AC_REQUIRE([AC_PROG_AWK]) # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. AS_VAR_PUSHDEF([A],[ax_compare_version_A]) A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` AS_VAR_PUSHDEF([B],[ax_compare_version_B]) B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary dnl # then the first line is used to determine if the condition is true. dnl # The sed right after the echo is to remove any indented white space. m4_case(m4_tolower($2), [lt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [gt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [le],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` ], [ge],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` ],[ dnl Split the operator from the subversion count if present. m4_bmatch(m4_substr($2,2), [0],[ # A count of zero means use the length of the shorter version. # Determine the number of characters in A and B. ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` # Set A to no more than B's length and B to no more than A's length. A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` ], [[0-9]+],[ # A count greater than zero means use only that many subversions A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` ], [.+],[ AC_WARNING( [illegal OP numeric parameter: $2]) ],[]) # Pad zeros at end of numbers to make same length. ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" B="$B`echo $A | sed 's/./0/g'`" A="$ax_compare_version_tmp_A" # Check for equality or inequality as necessary. m4_case(m4_tolower(m4_substr($2,0,2)), [eq],[ test "x$A" = "x$B" && ax_compare_version=true ], [ne],[ test "x$A" != "x$B" && ax_compare_version=true ],[ AC_WARNING([illegal OP parameter: $2]) ]) ]) AS_VAR_POPDEF([A])dnl AS_VAR_POPDEF([B])dnl dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. if test "$ax_compare_version" = "true" ; then m4_ifvaln([$4],[$4],[:])dnl m4_ifvaln([$5],[else $5])dnl fi ]) dnl AX_COMPARE_VERSION nut-2.8.3/m4/nut_check_aspell.m40000644000200500020050000002035114777767434013357 00000000000000dnl Check for tools used in spell-checking of documentation source files. dnl On success, set nut_have_aspell="yes" (meaning we can do at least some dnl documentation checks) and lots of automake macros and configure vars. dnl On failure, set nut_have_aspell="no" (meaning we can't run the checks). dnl This macro can be run multiple times, but will do the checking only once. AC_DEFUN([NUT_CHECK_ASPELL], [ if test -z "${nut_have_aspell_seen}"; then nut_have_aspell_seen=yes dnl # Note: this is just a known-working version on NUT CI platforms: dnl # Legacy baselines (CentOS 7, OpenBSD 6.5): dnl # @(#) International Ispell Version 3.1.20 (but really Aspell 0.60.6.1) dnl # More recent distros (as of 2022-2023): dnl # @(#) International Ispell Version 3.1.20 (but really Aspell 0.60.8) ASPELL_MIN_VERSION="0.60.6" dnl check for spell checking deps AC_PATH_PROGS([ASPELL], [aspell]) dnl Some builds of aspell (e.g. in mingw) claim they do not know mode "tex" dnl even though they can list it as a built-in filter and files exist. dnl It seems that specifying the path helps in those cases. ASPELL_FILTER_LIB_PATH="none" ASPELL_FILTER_SHARE_PATH="none" dnl Location of "tex.amf" may be shifted, especially if binary filters dnl are involved (happens in some platform packages but not others). ASPELL_FILTER_TEX_PATH="none" if test -n "${ASPELL}" ; then dnl # e.g.: @(#) International Ispell Version 3.1.20 (but really Aspell 0.60.8) AC_MSG_CHECKING([for aspell version]) ASPELL_VERSION="`LANG=C LC_ALL=C ${ASPELL} --version 2>/dev/null | sed -e 's,^.*@<:@Aa@:>@spell \(@<:@0-9.@:>@*\),\1,' -e 's,@<:@^0-9.@:>@.*,,'`" || ASPELL_VERSION="none" AC_MSG_RESULT([${ASPELL_VERSION}]) ASPELL_VERSION_MINMAJ="`echo "${ASPELL_VERSION}" | sed 's,\.@<:@0-9@:>@@<:@0-9@:>@*$,,'`" dnl FIXME: Some systems have more complicated layouts, e.g. dnl /usr/lib/amd64/aspell-0.60/tex-filter.so dnl /usr/lib/aspell-0.60/tex-filter.so dnl which require matching of the `aspell` binary architecture dnl with the module. We currently avoid the hassle thanks to a dnl fallback to built-in paths below if this initial guesswork dnl failed. This may need some more-direct addressing later. AC_MSG_CHECKING([for aspell "lib" filtering resources directory]) ASPELL_BINDIR="`dirname "$ASPELL"`" if test -d "${ASPELL_BINDIR}/../lib" ; then if test x"${ASPELL_VERSION}" != x"none" && test -d "${ASPELL_BINDIR}/../lib/aspell-${ASPELL_VERSION}" ; then ASPELL_FILTER_LIB_PATH="`cd "${ASPELL_BINDIR}/../lib/aspell-${ASPELL_VERSION}" && pwd`" \ || ASPELL_FILTER_LIB_PATH="${ASPELL_BINDIR}/../lib/aspell-${ASPELL_VERSION}" else if test x"${ASPELL_VERSION_MINMAJ}" != x"none" && test -d "${ASPELL_BINDIR}/../lib/aspell-${ASPELL_VERSION_MINMAJ}" ; then ASPELL_FILTER_LIB_PATH="`cd "${ASPELL_BINDIR}/../lib/aspell-${ASPELL_VERSION_MINMAJ}" && pwd`" \ || ASPELL_FILTER_LIB_PATH="${ASPELL_BINDIR}/../lib/aspell-${ASPELL_VERSION_MINMAJ}" else if test -d "${ASPELL_BINDIR}/../lib/aspell" ; then ASPELL_FILTER_LIB_PATH="`cd "${ASPELL_BINDIR}/../lib/aspell" && pwd`" \ || ASPELL_FILTER_LIB_PATH="${ASPELL_BINDIR}/../lib/aspell" fi fi fi fi AC_MSG_RESULT([${ASPELL_FILTER_LIB_PATH}]) AC_MSG_CHECKING([for aspell "share" filtering resources directory]) ASPELL_BINDIR="`dirname "$ASPELL"`" if test -d "${ASPELL_BINDIR}/../share" ; then if test x"${ASPELL_VERSION}" != x"none" && test -d "${ASPELL_BINDIR}/../share/aspell-${ASPELL_VERSION}" ; then ASPELL_FILTER_SHARE_PATH="`cd "${ASPELL_BINDIR}/../share/aspell-${ASPELL_VERSION}" && pwd`" \ || ASPELL_FILTER_SHARE_PATH="${ASPELL_BINDIR}/../share/aspell-${ASPELL_VERSION}" else if test x"${ASPELL_VERSION_MINMAJ}" != x"none" && test -d "${ASPELL_BINDIR}/../share/aspell-${ASPELL_VERSION_MINMAJ}" ; then ASPELL_FILTER_SHARE_PATH="`cd "${ASPELL_BINDIR}/../share/aspell-${ASPELL_VERSION_MINMAJ}" && pwd`" \ || ASPELL_FILTER_SHARE_PATH="${ASPELL_BINDIR}/../share/aspell-${ASPELL_VERSION_MINMAJ}" else if test -d "${ASPELL_BINDIR}/../share/aspell" ; then ASPELL_FILTER_SHARE_PATH="`cd "${ASPELL_BINDIR}/../share/aspell" && pwd`" \ || ASPELL_FILTER_SHARE_PATH="${ASPELL_BINDIR}/../share/aspell" fi fi fi fi AC_MSG_RESULT([${ASPELL_FILTER_SHARE_PATH}]) AC_MSG_CHECKING([for aspell "tex" filtering resources directory]) dnl # May be in a platform-dependent subdir (e.g. Debian Linux) dnl # or not (e.g. MinGW/MSYS2, OpenIndiana): if test -d "${ASPELL_FILTER_LIB_PATH}" ; then ASPELL_FILTER_TEX_PATH="`find "${ASPELL_FILTER_LIB_PATH}" -name "tex.amf"`" \ && test x"${ASPELL_FILTER_TEX_PATH}" != x \ && ASPELL_FILTER_TEX_PATH="`dirname "${ASPELL_FILTER_TEX_PATH}"`" \ && test -d "${ASPELL_FILTER_TEX_PATH}" \ || ASPELL_FILTER_TEX_PATH="none" fi dnl # Fallback (e.g. on FreeBSD): if test x"${ASPELL_FILTER_TEX_PATH}" = xnone \ && test -d "${ASPELL_FILTER_SHARE_PATH}" ; then ASPELL_FILTER_TEX_PATH="`find "${ASPELL_FILTER_SHARE_PATH}" -name "tex.amf"`" \ && test x"${ASPELL_FILTER_TEX_PATH}" != x \ && ASPELL_FILTER_TEX_PATH="`dirname "${ASPELL_FILTER_TEX_PATH}"`" \ && test -d "${ASPELL_FILTER_TEX_PATH}" \ || ASPELL_FILTER_TEX_PATH="none" fi AC_MSG_RESULT([${ASPELL_FILTER_TEX_PATH}]) fi AC_MSG_CHECKING([if aspell version can do our documentation spell checks (minimum required ${ASPELL_MIN_VERSION})]) AX_COMPARE_VERSION([${ASPELL_VERSION}], [ge], [${ASPELL_MIN_VERSION}], [ AC_MSG_RESULT(yes) AC_MSG_CHECKING([if detected aspell configuration works]) dnl Roughly following docs/Makefile.am setup for "make spellcheck": ASPELL_NUT_TEXMODE_ARGS="-t" AS_IF([test -n "$ASPELL_FILTER_TEX_PATH" -a -d "$ASPELL_FILTER_TEX_PATH"], [ASPELL_NUT_TEXMODE_ARGS="--filter-path='${ASPELL_FILTER_TEX_PATH}' ${ASPELL_NUT_TEXMODE_ARGS}"]) ASPELL_NUT_COMMON_ARGS="-d en -a" dnl Using "eval" to handle quotes, in case of funny paths out0="`LANG=C; LC_ALL=C; export LANG; export LC_ALL; ( set -x; echo test | eval ${ASPELL} ${ASPELL_NUT_TEXMODE_ARGS} ${ASPELL_NUT_COMMON_ARGS} ) 2>&1`"; res0=$? AS_IF([test x"$res0" != x0], [ AC_MSG_NOTICE([FAILED CMD: ${ASPELL} ${ASPELL_NUT_TEXMODE_ARGS} ${ASPELL_NUT_COMMON_ARGS}]) AC_MSG_NOTICE([aspell result ($res0) and output: $out0]) ]) AS_CASE([$out0], [*ELFCLASS*|*"wrong ELF class"*], [ dnl Retry without the filter path, we must have caught a wrong one dnl and *most* platforms do serve a trustworthy built-in after all: AC_MSG_RESULT(no) AC_MSG_CHECKING([if detected aspell configuration works with built-in paths (tweaked one finds wrong binary modules)]) ASPELL_NUT_TEXMODE_ARGS="-t" out0="`LANG=C; LC_ALL=C; export LANG; export LC_ALL; ( set -x; echo test | eval ${ASPELL} ${ASPELL_NUT_TEXMODE_ARGS} ${ASPELL_NUT_COMMON_ARGS} ) 2>&1`"; res0=$? AS_IF([test x"$res0" = x0], [ASPELL_FILTER_TEX_PATH=""], [ AC_MSG_NOTICE([FAILED CMD: ${ASPELL} ${ASPELL_NUT_TEXMODE_ARGS} ${ASPELL_NUT_COMMON_ARGS}]) AC_MSG_NOTICE([aspell result ($res0) and output: $out0]) ]) ] ) out1="`echo test | eval ${ASPELL} ${ASPELL_NUT_TEXMODE_ARGS} ${ASPELL_NUT_COMMON_ARGS} | grep test`"; res1=$? out2="`echo qwer | eval ${ASPELL} ${ASPELL_NUT_TEXMODE_ARGS} ${ASPELL_NUT_COMMON_ARGS} | grep qwer`"; res2=$? AS_IF([test x"$out1" = x -a x"$out2" != x], [ AC_MSG_RESULT(yes) nut_have_aspell="yes" ], [ AC_MSG_RESULT(no) AC_MSG_NOTICE([aspell result ($res1) for 'test' (should be empty): $out1]) AC_MSG_NOTICE([aspell result ($res2) for 'qwer' (should have suggestions): $out2]) nut_have_aspell="no" ]) ], [ AC_MSG_RESULT(no) nut_have_aspell="no" ]) AM_CONDITIONAL([HAVE_ASPELL_FILTER_LIB_PATH], [test -d "$ASPELL_FILTER_LIB_PATH"]) AC_SUBST(ASPELL_FILTER_LIB_PATH) AM_CONDITIONAL([HAVE_ASPELL_FILTER_SHARE_PATH], [test -d "$ASPELL_FILTER_SHARE_PATH"]) AC_SUBST(ASPELL_FILTER_SHARE_PATH) AM_CONDITIONAL([HAVE_ASPELL_FILTER_TEX_PATH], [test -d "$ASPELL_FILTER_TEX_PATH"]) AC_SUBST(ASPELL_FILTER_TEX_PATH) dnl Notes: we also keep HAVE_ASPELL for implicit targets, such as dnl addition to "make check" target dnl ### AM_CONDITIONAL([HAVE_ASPELL], [test -n "$ASPELL"]) AM_CONDITIONAL([HAVE_ASPELL], [test "${nut_have_aspell}" = "yes"]) AC_MSG_CHECKING([if we have all the tools mandatory for documentation spell checks]) AC_MSG_RESULT([${nut_have_aspell}]) fi ]) nut-2.8.3/m4/nut_check_libgpiod.m40000644000200500020050000001030714777767434013670 00000000000000dnl Check for LIBGPIO compiler flags. On success, set nut_have_gpio="yes" dnl and set LIBGPIO_CFLAGS and LIBGPIO_LIBS. On failure, set dnl nut_have_gpio="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBGPIO], [ if test -z "${nut_have_gpio_seen}"; then nut_have_gpio_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" # Store implementation (if any) to be reported by configure.ac: nut_gpio_lib="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [dnl See which version of the gpiod library (if any) is installed dnl FIXME : Support detection of cflags/ldflags below by legacy dnl discovery if pkgconfig is not there AC_MSG_CHECKING(for libgpiod version via pkg-config (1.0.0 minimum required)) GPIO_VERSION="`$PKG_CONFIG --silence-errors --modversion libgpiod 2>/dev/null`" if test "$?" != "0" -o -z "${GPIO_VERSION}"; then GPIO_VERSION="none" else nut_gpio_lib="libgpiod" fi AC_MSG_RESULT(${GPIO_VERSION} found) ], [GPIO_VERSION="none" AC_MSG_NOTICE([can not check libgpiod settings via pkg-config]) ] ) AC_MSG_CHECKING(for libgpiod cflags) AC_ARG_WITH(gpio-includes, AS_HELP_STRING([@<:@--with-gpio-includes=CFLAGS@:>@], [include flags for the gpiod library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-gpio-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], [ AS_IF([test x"$have_PKG_CONFIG" = xyes], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags libgpiod 2>/dev/null`" \ || depCFLAGS="-I/usr/include -I/usr/local/include"], [depCFLAGS="-I/usr/include -I/usr/local/include"] )] ) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for libgpiod ldflags) AC_ARG_WITH(gpio-libs, AS_HELP_STRING([@<:@--with-gpio-libs=LIBS@:>@], [linker flags for the gpiod library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-gpio-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], [ AS_IF([test x"$have_PKG_CONFIG" = xyes], [depLIBS="`$PKG_CONFIG --silence-errors --libs libgpiod 2>/dev/null`" \ || depLIBS="-lgpiod"], [depLIBS="-lgpiod"] )] ) AC_MSG_RESULT([${depLIBS}]) dnl check if gpiod is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(gpiod.h, [nut_have_gpio=yes], [nut_have_gpio=no], [AC_INCLUDES_DEFAULT]) AS_IF([test x"${nut_have_gpio}" = xyes], [AC_CHECK_FUNCS(gpiod_chip_close, [], [nut_have_gpio=no])]) AS_IF([test x"${nut_have_gpio}" = xyes], [ AS_CASE(["${GPIO_VERSION}"], [2.*], [AC_CHECK_FUNCS(gpiod_chip_open, [nut_gpio_lib="libgpiod"], [nut_have_gpio=no])], [1.*], [AC_CHECK_FUNCS(gpiod_chip_open_by_name, [nut_gpio_lib="libgpiod"], [nut_have_gpio=no])], [AC_CHECK_FUNCS(gpiod_chip_open_by_name, [ nut_gpio_lib="libgpiod" AS_IF([test x"${GPIO_VERSION}" = xnone], [GPIO_VERSION="1.x"]) ], [ AC_CHECK_FUNCS(gpiod_chip_open, [ nut_gpio_lib="libgpiod" AS_IF([test x"${GPIO_VERSION}" = xnone], [GPIO_VERSION="2.x"]) ])] )] ) ]) if test "${nut_have_gpio}" = "yes"; then LIBGPIO_CFLAGS="${depCFLAGS}" LIBGPIO_LIBS="${depLIBS}" dnl Normally this would be in library headers, but they do not seem forthcoming AS_CASE([${GPIO_VERSION}], [2.*], [ AC_DEFINE(WITH_LIBGPIO_VERSION, 0x00020000, [Define libgpio C API version generation]) AC_DEFINE_UNQUOTED(WITH_LIBGPIO_VERSION_STR, ["0x00020000"], [Define libgpio C API version generation as string]) ], [1.*], [ AC_DEFINE(WITH_LIBGPIO_VERSION, 0x00010000, [Define libgpio C API version generation]) AC_DEFINE_UNQUOTED(WITH_LIBGPIO_VERSION_STR, ["0x00010000"], [Define libgpio C API version generation as string]) ] ) else dnl FIXME: Report "none" here? nut_gpio_lib="" AC_DEFINE(WITH_LIBGPIO_VERSION, 0x00000000, [Define libgpio C API version generation]) AC_DEFINE_UNQUOTED(WITH_LIBGPIO_VERSION_STR, ["0x00000000"], [Define libgpio C API version generation as string]) fi unset CFLAGS unset LIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_type_socklen_t.m40000644000200500020050000001053514777534446013762 00000000000000dnl Check for socklen_t: historically on BSD it is an int, and in dnl POSIX 1g it is a type of its own, but some platforms use different dnl types for the argument to getsockopt, getpeername, etc.: dnl HP-UX 10.20, IRIX 6.5, Interix 3.5, BeOS. dnl So we have to test to find something that will work. dnl Copyright (C) 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Albert Chin, Windows fixes from Simon Josefsson. dnl On mingw32, socklen_t is in ws2tcpip.h ('int'), so we try to find dnl it there first. That file is included by gnulib sys_socket.in.h, which dnl all users of this module should include. Cygwin must not include dnl ws2tcpip.h. dnl This code gets around. This instance came from gnulib trunk (21 Oct. 2010). AC_DEFUN([NUT_TYPE_SOCKLEN_T], [ NUT_PREREQ_SYS_H_SOCKET AC_REQUIRE([NUT_CHECK_HEADER_WS2TCPIP])dnl dnl # TOTHINK: Are and mutually exclusive? dnl # Some projects test for both, based on ifdef results; we declare dnl # those in NUT_PREREQ_SYS_H_SOCKET however as either one or another HEADERS_SOCKLEN_T=' #undef inline #ifdef HAVE_WINDOWS_H # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # if (!defined(_WIN32_WINNT)) || (_WIN32_WINNT < 0x0501) # undef _WIN32_WINNT # define _WIN32_WINNT 0x0501 # endif # include # ifdef HAVE_WINSOCK2_H # include # ifdef HAVE_WS2TCPIP_H # include # endif # endif # define GNICALLCONV WSAAPI # define GNICALLLINK WINSOCK_API_LINKAGE #else # ifdef HAVE_SYS_TYPES_H # include # endif # ifdef HAVE_SYS_SOCKET_H # include # endif # ifdef HAVE_NETDB_H # include # endif # define GNICALLCONV # define GNICALLLINK #endif ' AC_CHECK_TYPE([socklen_t], ,[ AC_MSG_CHECKING([for socklen_t equivalent]) AC_CACHE_VAL([nut_cv_socklen_t_equiv], [# Systems have either "struct sockaddr *" or # "void *" as the second argument to getpeername AC_LANG_PUSH([C]) nut_cv_socklen_t_equiv= for arg1 in "int" "SOCKET"; do for arg2 in "struct sockaddr" void; do for arg3 in int size_t unsigned long "unsigned long" "unsigned int" "long int" "unsigned long int"; do AC_COMPILE_IFELSE([AC_LANG_PROGRAM([${HEADERS_SOCKLEN_T} GNICALLLINK int GNICALLCONV getpeername ($arg1, $arg2 *, $arg3 *); ],[ $arg3 len; getpeername(0, 0, &len); ])], [ nut_cv_socklen_t_equiv="$arg3" break ]) if test x"$nut_cv_socklen_t_equiv" != "x" ; then break ; fi done if test x"$nut_cv_socklen_t_equiv" != "x" ; then break ; fi done if test x"$nut_cv_socklen_t_equiv" != "x" ; then break ; fi done AC_LANG_POP([C]) if test "x$nut_cv_socklen_t_equiv" = x; then AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) fi ]) AC_MSG_RESULT($nut_cv_socklen_t_equiv) AC_DEFINE_UNQUOTED(socklen_t, $nut_cv_socklen_t_equiv, [type to use in place of socklen_t if not defined])], [${HEADERS_SOCKLEN_T}]) ]) AC_DEFUN([NUT_PREREQ_SYS_H_SOCKET], [ dnl Check prerequisites of the replacement. AC_CHECK_HEADERS_ONCE([sys/socket.h]) if test $ac_cv_header_sys_socket_h = yes; then HAVE_SYS_SOCKET_H=1 HAVE_WS2TCPIP_H=0 HAVE_WINSOCK2_H=0 else HAVE_SYS_SOCKET_H=0 dnl We cannot use AC_CHECK_HEADERS_ONCE here, because that would make dnl the check for those headers unconditional; yet cygwin reports dnl that the headers are present but cannot be compiled (since on dnl cygwin, all socket information should come from sys/socket.h). AC_CHECK_HEADERS([ws2tcpip.h]) if test $ac_cv_header_ws2tcpip_h = yes; then HAVE_WS2TCPIP_H=1 else HAVE_WS2TCPIP_H=0 fi AC_CHECK_HEADERS([winsock2.h]) if test "$ac_cv_header_winsock2_h" = yes; then HAVE_WINSOCK2_H=1 else HAVE_WINSOCK2_H=0 fi fi AC_SUBST([HAVE_WINSOCK2_H]) AC_SUBST([HAVE_SYS_SOCKET_H]) AC_SUBST([HAVE_WS2TCPIP_H]) ]) nut-2.8.3/m4/nut_check_libavahi.m40000644000200500020050000000754414777767434013667 00000000000000dnl Check for LIBAVAHI compiler flags. On success, set nut_have_avahi="yes" dnl and set LIBAVAHI_CFLAGS and LIBAVAHI_LIBS. On failure, set dnl nut_have_avahi="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBAVAHI], [ if test -z "${nut_have_avahi_seen}"; then nut_have_avahi_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [dnl See which version of the avahi library (if any) is installed AC_MSG_CHECKING(for avahi-core version via pkg-config (0.6.30 minimum required)) AVAHI_CORE_VERSION="`$PKG_CONFIG --silence-errors --modversion avahi-core 2>/dev/null`" if test "$?" != "0" -o -z "${AVAHI_CORE_VERSION}"; then AVAHI_CORE_VERSION="none" fi AC_MSG_RESULT(${AVAHI_CORE_VERSION} found) AC_MSG_CHECKING(for avahi-client version via pkg-config (0.6.30 minimum required)) AVAHI_CLIENT_VERSION="`$PKG_CONFIG --silence-errors --modversion avahi-client 2>/dev/null`" if test "$?" != "0" -o -z "${AVAHI_CLIENT_VERSION}"; then AVAHI_CLIENT_VERSION="none" fi AC_MSG_RESULT(${AVAHI_CLIENT_VERSION} found) ], [AC_MSG_NOTICE([can not check avahi settings via pkg-config])] ) AC_MSG_CHECKING(for avahi cflags) AC_ARG_WITH(avahi-includes, AS_HELP_STRING([@<:@--with-avahi-includes=CFLAGS@:>@], [include flags for the avahi library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-avahi-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], [ AS_IF([test x"$have_PKG_CONFIG" = xyes], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags avahi-core avahi-client 2>/dev/null`" \ || depCFLAGS="-I/usr/local/include -I/usr/include -L/usr/local/lib -L/usr/lib"], [depCFLAGS="-I/usr/local/include -I/usr/include -L/usr/local/lib -L/usr/lib"] )] ) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for avahi ldflags) AC_ARG_WITH(avahi-libs, AS_HELP_STRING([@<:@--with-avahi-libs=LIBS@:>@], [linker flags for the avahi library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-avahi-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], [ AS_IF([test x"$have_PKG_CONFIG" = xyes], [depLIBS="`$PKG_CONFIG --silence-errors --libs avahi-core avahi-client 2>/dev/null`" \ || depLIBS="-lavahi-core -lavahi-client"], [depLIBS="-lavahi-core -lavahi-client"] )] ) AC_MSG_RESULT([${depLIBS}]) dnl check if avahi-core is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(avahi-common/malloc.h, [nut_have_avahi=yes], [nut_have_avahi=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(avahi_free, [], [nut_have_avahi=no]) if test "${nut_have_avahi}" = "yes"; then dnl check if avahi-client is usable AC_CHECK_HEADERS(avahi-client/client.h, [nut_have_avahi=yes], [nut_have_avahi=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(avahi_client_new, [], [nut_have_avahi=no]) if test "${nut_have_avahi}" = "yes"; then LIBAVAHI_CFLAGS="${depCFLAGS}" LIBAVAHI_LIBS="${depLIBS}" fi dnl Help ltdl if we can (nut-scanner etc.) for TOKEN in $depLIBS ; do AS_CASE(["${TOKEN}"], [-l*avahi*client*], [ AX_REALPATH_LIB([${TOKEN}], [SOPATH_LIBAVAHI], []) AS_IF([test -n "${SOPATH_LIBAVAHI}" && test -s "${SOPATH_LIBAVAHI}"], [ AC_DEFINE_UNQUOTED([SOPATH_LIBAVAHI],["${SOPATH_LIBAVAHI}"],[Path to dynamic library on build system]) SOFILE_LIBAVAHI="`basename "$SOPATH_LIBAVAHI"`" AC_DEFINE_UNQUOTED([SOFILE_LIBAVAHI],["${SOFILE_LIBAVAHI}"],[Base file name of dynamic library on build system]) break ]) ] ) done unset TOKEN fi unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_check_asciidoc.m40000644000200500020050000001203614777733634013651 00000000000000dnl Check for tools used in generation of documentation final-format files dnl such as the basically required MAN, and optional HTML (single or chunked). dnl On success, set nut_have_asciidoc="yes" (meaning we can do at least some dnl documentation generation) and lots of automake macros and configure vars. dnl On failure, set nut_have_asciidoc="no" (meaning we can't generate even a dnl manpage, which is a requirement for proceeding to the other formats). dnl This macro can be run multiple times, but will do the checking only once. dnl Also note that this routine currently only checks the basic presence (and dnl versions) of the required software; the configure script has additional dnl functional checks (ability to build doc files) based on --with-doc request dnl so as to not waste time on doc-types not requested by maintainer, and done dnl in ways more intimate to NUT (using its tracked docs). AC_DEFUN([NUT_CHECK_ASCIIDOC], [ if test -z "${nut_have_asciidoc_seen}"; then nut_have_asciidoc_seen=yes dnl # Note: this is typically same for both asciidoc and a2x: dnl # most systems nowadays (2023) have both at 8.6.3 or newer. dnl # Slackware 15 has asciidoc-8.1.0 and a2x-1.0.0 served in dnl # a side-project repository... ASCIIDOC_MIN_VERSION="8.1.0" A2X_MIN_VERSION="1.0.0" dnl # Note: this is checked in the configure script if PDF is of interest at all DBLATEX_MIN_VERSION="0.2.5" AC_PATH_PROGS([ASCIIDOC], [asciidoc]) if test -n "${ASCIIDOC}"; then AC_MSG_CHECKING([for asciiDoc version]) ASCIIDOC_VERSION="`${ASCIIDOC} --version 2>/dev/null`" dnl strip 'asciidoc ' from version string ASCIIDOC_VERSION="${ASCIIDOC_VERSION##* }" AC_MSG_RESULT(${ASCIIDOC_VERSION} found) fi AM_CONDITIONAL([MANUALUPDATE], [test -n "${ASCIIDOC}"]) AC_PATH_PROGS([A2X], [a2x]) if test -n "${A2X}"; then AC_MSG_CHECKING([for a2x version]) A2X_VERSION="`${A2X} --version 2>/dev/null`" dnl strip 'a2x ' from version string A2X_VERSION="${A2X_VERSION##* }" AC_MSG_RESULT(${A2X_VERSION} found) fi AC_PATH_PROGS([DBLATEX], [dblatex]) if test -n "${DBLATEX}"; then AC_MSG_CHECKING([for dblatex version]) DBLATEX_VERSION="`${DBLATEX} --version 2>/dev/null`" dnl strip 'dblatex version ' from version string DBLATEX_VERSION="${DBLATEX_VERSION##* }" AC_MSG_RESULT(${DBLATEX_VERSION} found) fi AC_PATH_PROGS([XSLTPROC], [xsltproc]) if test -n "${XSLTPROC}"; then AC_MSG_CHECKING([for xsltproc version]) XSLTPROC_VERSION="`${XSLTPROC} --version 2>/dev/null`" dnl strip 'xsltproc version ' from version string XSLTPROC_VERSION="${XSLTPROC_VERSION##* }" AC_MSG_RESULT(${XSLTPROC_VERSION} found) fi AC_PATH_PROGS([XMLLINT], [xmllint]) if test -n "${XMLLINT}"; then AC_MSG_CHECKING([for xmllint version]) XMLLINT_VERSION="`${XMLLINT} --version 2>/dev/null`" dnl strip 'xmllint version ' from version string XMLLINT_VERSION="${XMLLINT_VERSION##* }" if test -z "${XMLLINT_VERSION}" ; then dnl Some releases also report what flags they were compiled with as dnl part of the version info, so the last-line match finds nothing. dnl Also some builds return version data to stderr. XMLLINT_VERSION="`${XMLLINT} --version 2>&1 | grep version`" XMLLINT_VERSION="${XMLLINT_VERSION##* }" fi AC_MSG_RESULT(${XMLLINT_VERSION} found) fi AC_PATH_PROGS([SOURCE_HIGHLIGHT], [source-highlight]) AM_CONDITIONAL([HAVE_SOURCE_HIGHLIGHT], [test -n "$SOURCE_HIGHLIGHT"]) dnl Note that a common "nut_have_asciidoc" variable is in fact a flag dnl that we have several tools needed for the documentation generation dnl TODO? Rename the script variable and makefile flags to reflect this? AC_MSG_CHECKING([if asciidoc version can build manpages (minimum required ${ASCIIDOC_MIN_VERSION})]) AX_COMPARE_VERSION([${ASCIIDOC_VERSION}], [ge], [${ASCIIDOC_MIN_VERSION}], [ AC_MSG_RESULT(yes) nut_have_asciidoc="yes" ], [ AC_MSG_RESULT(no) nut_have_asciidoc="no" ]) AC_MSG_CHECKING([if a2x version can build manpages (minimum required ${A2X_MIN_VERSION})]) AX_COMPARE_VERSION([${A2X_VERSION}], [ge], [${A2X_MIN_VERSION}], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) nut_have_asciidoc="no" ]) dnl TODO: test for docbook-xsl files (maybe build a test man page?) dnl https://github.com/networkupstools/nut/issues/162 AC_MSG_CHECKING([if xsltproc is present (mandatory for man page regeneration)]) if test -n "${XSLTPROC}"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) nut_have_asciidoc="no" fi AC_MSG_CHECKING([if xmllint is present (mandatory for man page regeneration)]) if test -n "${XMLLINT}"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) nut_have_asciidoc="no" fi dnl Notes: we also keep HAVE_ASCIIDOC for implicit targets, such as manpage dnl building AM_CONDITIONAL([HAVE_ASCIIDOC], [test "${nut_have_asciidoc}" = "yes"]) AC_MSG_CHECKING([if we have all the tools mandatory for man page regeneration]) AC_MSG_RESULT([${nut_have_asciidoc}]) AC_MSG_CHECKING([if source-highlight is present (preferable for documentation generation)]) if test -n "${SOURCE_HIGHLIGHT}"; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi fi ]) nut-2.8.3/m4/nut_check_libpowerman.m40000644000200500020050000000651014777767434014417 00000000000000dnl Check for LIBPOWERMAN compiler flags. On success, set nut_have_libpowerman="yes" dnl and set LIBPOWERMAN_CFLAGS and LIBPOWERMAN_LIBS. On failure, set dnl nut_have_libpowerman="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBPOWERMAN], [ if test -z "${nut_have_libpowerman_seen}"; then nut_have_libpowerman_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [AC_MSG_CHECKING([for LLNC libpowerman version via pkg-config]) POWERMAN_VERSION="`$PKG_CONFIG --silence-errors --modversion libpowerman 2>/dev/null`" dnl Unlike other pkg-config enabled projects we use, dnl libpowerman (at least on Debian) delivers an empty dnl "Version:" tag in /usr/lib/pkgconfig/libpowerman.pc dnl (and it is the only file in that dir, others going dnl to /usr/lib/x86_64-linux-gnu/pkgconfig/ or similar dnl for other architectures). Empty is not an error here! if test "$?" != "0" ; then # -o -z "${POWERMAN_VERSION}"; then POWERMAN_VERSION="none" fi AC_MSG_RESULT(['${POWERMAN_VERSION}' found]) ], [POWERMAN_VERSION="none" AC_MSG_NOTICE([can not check LLNC libpowerman settings via pkg-config]) ] ) AS_IF([test x"$POWERMAN_VERSION" != xnone], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags libpowerman 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs libpowerman 2>/dev/null`" ], [depCFLAGS="" depLIBS="" ] ) AC_MSG_CHECKING([for libpowerman cflags]) AC_ARG_WITH(powerman-includes, AS_HELP_STRING([@<:@--with-powerman-includes=CFLAGS@:>@], [include flags for the libpowerman library]), [ case "${withval}" in yes|no) AC_MSG_ERROR([invalid option --with(out)-powerman-includes - see docs/configure.txt]) ;; *) depCFLAGS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for libpowerman libs) AC_ARG_WITH(powerman-libs, AS_HELP_STRING([@<:@--with-powerman-libs=LIBS@:>@], [linker flags for the libpowerman library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-powerman-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depLIBS}]) dnl check if libpowerman is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(libpowerman.h, [nut_have_libpowerman=yes], [nut_have_libpowerman=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(pm_connect, [], [ dnl Some systems may just have libpowerman in their dnl standard paths, but not the pkg-config data AS_IF([test "${nut_have_libpowerman}" = "yes" && test "$POWERMAN_VERSION" = "none" && test -z "$LIBS"], [AC_MSG_CHECKING([if libpowerman is just present in path]) depLIBS="-L/usr/lib -L/usr/local/lib -lpowerman" unset ac_cv_func_pm_connect || true LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_FUNCS(pm_connect, [], [nut_have_libpowerman=no]) AC_MSG_RESULT([${nut_have_libpowerman}]) ], [nut_have_libpowerman=no] )] ) if test "${nut_have_libpowerman}" = "yes"; then LIBPOWERMAN_CFLAGS="${depCFLAGS}" LIBPOWERMAN_LIBS="${depLIBS}" fi unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_check_libfreeipmi.m40000644000200500020050000001170314777767434014367 00000000000000dnl Check for FreeIPMI (LIBFREEIPMI) compiler flags. On success, set dnl nut_have_freeipmi="yes" and nut_ipmi_lib="FreeIPMI", and define WITH_IPMI, dnl WITH_FREEIPMI, LIBIPMI_CFLAGS and LIBIPMI_LIBS. On failure, set dnl nut_have_freeipmi="no". dnl This macro can be run multiple times, but will do the checking only once. AC_DEFUN([NUT_CHECK_LIBFREEIPMI], [ if test -z "${nut_have_libfreeipmi_seen}"; then nut_have_libfreeipmi_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [dnl pkg-config support requires Freeipmi 1.0.5, released on Thu Jun 30 2011 dnl but NUT should only require 0.8.5 (for nut-scanner) and 1.0.1 (for dnl nut-ipmipsu) (comment from upstream Al Chu) AC_MSG_CHECKING(for FreeIPMI version via pkg-config) FREEIPMI_VERSION="`$PKG_CONFIG --silence-errors --modversion libfreeipmi 2>/dev/null`" if test "$?" != "0" -o -z "${FREEIPMI_VERSION}"; then FREEIPMI_VERSION="none" fi AC_MSG_RESULT(${FREEIPMI_VERSION} found) ], [FREEIPMI_VERSION="none" AC_MSG_NOTICE([can not check FreeIPMI settings via pkg-config]) ] ) AS_IF([test x"$FREEIPMI_VERSION" != xnone], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags libfreeipmi libipmimonitoring 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs libfreeipmi libipmimonitoring 2>/dev/null`" ], [depCFLAGS="" depLIBS="-lfreeipmi -lipmimonitoring" ] ) dnl allow overriding FreeIPMI settings if the user knows best AC_MSG_CHECKING(for FreeIPMI cflags) AC_ARG_WITH(freeipmi-includes, AS_HELP_STRING([@<:@--with-freeipmi-includes=CFLAGS@:>@], [include flags for the FreeIPMI library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-freeipmi-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for FreeIPMI ldflags) AC_ARG_WITH(freeipmi-libs, AS_HELP_STRING([@<:@--with-freeipmi-libs=LIBS@:>@], [linker flags for the FreeIPMI library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-freeipmi-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depLIBS}]) dnl check if freeipmi is usable with our current flags CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(freeipmi/freeipmi.h, [nut_have_freeipmi=yes], [nut_have_freeipmi=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS(ipmi_monitoring.h, [], [nut_have_freeipmi=no], [AC_INCLUDES_DEFAULT]) AC_SEARCH_LIBS([ipmi_ctx_create], [freeipmi], [], [nut_have_freeipmi=no]) dnl when version cannot be tested (prior to 1.0.5, with no pkg-config) dnl we have to check for some specific functions AC_SEARCH_LIBS([ipmi_ctx_find_inband], [freeipmi], [], [nut_have_freeipmi=no]) AC_SEARCH_LIBS([ipmi_monitoring_init], [ipmimonitoring], [nut_have_freeipmi_monitoring=yes], [nut_have_freeipmi_monitoring=no]) AC_SEARCH_LIBS([ipmi_monitoring_sensor_read_record_id], [ipmimonitoring], [], [nut_have_freeipmi_monitoring=no]) dnl Check for FreeIPMI 1.1.X / 1.2.X which implies API changes! AC_SEARCH_LIBS([ipmi_sdr_cache_ctx_destroy], [freeipmi], [nut_have_freeipmi_11x_12x=no], []) AC_SEARCH_LIBS([ipmi_sdr_ctx_destroy], [freeipmi], [nut_have_freeipmi_11x_12x=yes], [nut_have_freeipmi_11x_12x=no]) dnl Collect possibly updated dependencies after AC SEARCH LIBS: AS_IF([test x"${LIBS}" != x"${LIBS_ORIG} ${depLIBS}"], [ AS_IF([test x = x"${LIBS_ORIG}"], [depLIBS="$LIBS"], [ depLIBS="`echo "$LIBS" | sed -e 's|'"${LIBS_ORIG}"'| |' -e 's|^ *||' -e 's| *$||'`" ]) ]) if test "${nut_have_freeipmi}" = "yes"; then nut_with_ipmi="yes" nut_ipmi_lib="(FreeIPMI)" nut_have_libipmi="yes" AC_DEFINE(HAVE_FREEIPMI, 1, [Define if FreeIPMI support is available]) LIBIPMI_CFLAGS="${depCFLAGS}" LIBIPMI_LIBS="${depLIBS}" dnl Help ltdl if we can (nut-scanner etc.) for TOKEN in $depLIBS ; do AS_CASE(["${TOKEN}"], [-l*ipmi*], [ AX_REALPATH_LIB([${TOKEN}], [SOPATH_LIBFREEIPMI], []) AS_IF([test -n "${SOPATH_LIBFREEIPMI}" && test -s "${SOPATH_LIBFREEIPMI}"], [ AC_DEFINE_UNQUOTED([SOPATH_LIBFREEIPMI],["${SOPATH_LIBFREEIPMI}"],[Path to dynamic library on build system]) SOFILE_LIBFREEIPMI="`basename "$SOPATH_LIBFREEIPMI"`" AC_DEFINE_UNQUOTED([SOFILE_LIBFREEIPMI],["${SOFILE_LIBFREEIPMI}"],[Base file name of dynamic library on build system]) break ]) ] ) done unset TOKEN fi if test "${nut_have_freeipmi_11x_12x}" = "yes"; then AC_DEFINE(HAVE_FREEIPMI_11X_12X, 1, [Define if FreeIPMI 1.1.X / 1.2.X support is available]) fi if test "${nut_have_freeipmi_monitoring}" = "yes"; then AC_DEFINE(HAVE_FREEIPMI_MONITORING, 1, [Define if FreeIPMI monitoring support is available]) fi unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_arg_with.m40000644000200500020050000000147014777534446012542 00000000000000dnl simplified declaration of some feature options dnl Working With External Software (might name a variant or other contextual arg) dnl https://www.gnu.org/software/autoconf/manual/autoconf-2.66/html_node/External-Software.html#External-Software AC_DEFUN([NUT_ARG_WITH], [ AC_ARG_WITH($1, AS_HELP_STRING([--with-$1], [$2 ($3)]), [[nut_with_]m4_translit($1, [-], [_])="${withval}"], [[nut_with_]m4_translit($1, [-], [_])="$3"] ) ]) dnl Enable a feature (might name a variant), or yes/no dnl https://www.gnu.org/software/autoconf/manual/autoconf-2.66/html_node/Package-Options.html AC_DEFUN([NUT_ARG_ENABLE], [ AC_ARG_ENABLE($1, AS_HELP_STRING([--enable-$1], [$2 ($3)]), [[nut_enable_]m4_translit($1, [-], [_])="${enableval}"], [[nut_enable_]m4_translit($1, [-], [_])="$3"] ) ]) nut-2.8.3/m4/ax_c___attribute__.m40000644000200500020050000001155214777534446013643 00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_c___attribute__.html # # Downloaded into the Network UPS Tools (NUT) codebase from # http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_c___attribute__.m4 # as of 2020-11-20 and adapted for attribute supports we needed # =========================================================================== # # SYNOPSIS # # AX_C___ATTRIBUTE__ # # DESCRIPTION # # Provides a test for the compiler support of __attribute__ extensions. # Defines HAVE___ATTRIBUTE__ if it is found. # Also in particular defines # HAVE___ATTRIBUTE__UNUSED_ARG # HAVE___ATTRIBUTE__UNUSED_FUNC # HAVE___ATTRIBUTE__NORETURN # if support for respective values and use-cases of interest for NUT # codebase is found. # # LICENSE # # Copyright (c) 2008 Stepan Kasal # Copyright (c) 2008 Christian Haggstrom # Copyright (c) 2008 Ryan McCabe # Copyright (c) 2020 Jim Klimov # # 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, 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 9 AC_DEFUN([AX_C___ATTRIBUTE__], [ AC_LANG_PUSH([C]) AC_CACHE_CHECK([for __attribute__((unused)) for function arguments], [ax_cv___attribute__unused_arg], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include static void foo( int); static void foo(__attribute__ ((unused)) int i) { return; } ]], [foo(1);])], [ax_cv___attribute__unused_arg=yes], [ax_cv___attribute__unused_arg=no] ) ]) AC_CACHE_CHECK([for __attribute__((unused)) for functions], [ax_cv___attribute__unused_func], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include static void foo(void) __attribute__ ((unused)); static void foo(void) { return; } ]], [])], [ax_cv___attribute__unused_func=yes], [ax_cv___attribute__unused_func=no] ) ]) AC_CACHE_CHECK([for __attribute__((noreturn))], [ax_cv___attribute__noreturn], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include static void foo(void) __attribute__ ((noreturn)); static void foo(void) { exit(1); } ]], [foo();])], [ax_cv___attribute__noreturn=yes], [ax_cv___attribute__noreturn=no] ) ]) AC_LANG_POP([C]) AC_CACHE_CHECK([for at least some __attribute__ support], [ax_cv___attribute__], [if test "$ax_cv___attribute__unused_arg" = "yes" \ || test "$ax_cv___attribute__unused_func" = "yes" \ || test "$ax_cv___attribute__noreturn" = "yes" \ ; then dnl # Some values did not error, support for keyword itself exists ax_cv___attribute__=yes else dnl # At least none of the options we are interested in work... ax_cv___attribute__=no fi ]) if test "$ax_cv___attribute__unused_arg" = "yes"; then AC_DEFINE([HAVE___ATTRIBUTE__UNUSED_ARG], 1, [define if your compiler has __attribute__((unused)) for function arguments]) fi if test "$ax_cv___attribute__unused_func" = "yes"; then AC_DEFINE([HAVE___ATTRIBUTE__UNUSED_FUNC], 1, [define if your compiler has __attribute__((unused)) for functions]) fi if test "$ax_cv___attribute__noreturn" = "yes"; then AC_DEFINE([HAVE___ATTRIBUTE__NORETURN], 1, [define if your compiler has __attribute__((noreturn))]) fi if test "$ax_cv___attribute__" = "yes"; then AC_DEFINE([HAVE___ATTRIBUTE__], 1, [define if your compiler has __attribute__]) fi ]) nut-2.8.3/m4/ax_realpath_lib.m40000644000200500020050000003131314777767434013172 00000000000000dnl Resolve real path (if we can) to a library file that would be used dnl by gcc/clang compatible toolkit. Relies on AX_REALPATH macro and dnl may benefit from a REALPATH envvar pointing to a command-line tool dnl (otherwise m4/shell implementation gets used), and NUT_COMPILER_FAMILY. dnl Copyright (C) 2024 by Jim Klimov dnl Licensed under the terms of GPLv2 or newer. dnl Calling script is welcome to pre-detect external REALPATH implementation, dnl otherwise shell implementation would be used (hopefully capable enough): dnl AC_CHECK_PROGS([REALPATH], [realpath], []) AC_DEFUN([AX_REALPATH_LIB_PREREQ], [ if test -z "${nut_ax_realpath_lib_prereq_seen}"; then nut_ax_realpath_lib_prereq_seen=yes AC_REQUIRE([NUT_COMPILER_FAMILY])dnl AC_REQUIRE([AX_REALPATH])dnl AS_CASE(["${target_os}"], [*mingw*], [ AS_IF([test x"${DLLTOOL-}" = x], [AC_CHECK_TOOLS([DLLTOOL], [dlltool dlltool.exe], [false])]) AS_IF([test x"${OBJDUMP-}" = x], [AC_CHECK_TOOLS([OBJDUMP], [objdump objdump.exe], [false])]) dnl # Assuming mingw (sourceware) x86_64-w64-mingw32-ld or similar AS_IF([test x"${LD-}" = x], [AC_CHECK_TOOLS([LD], [ld ld.exe], [false])]) ], [*darwin*], [ dnl # Can be a non-GNU ld AS_IF([test x"${LD-}" = x], [AC_CHECK_TOOLS([LD], [ld], [false])]) ] ) fi ]) AC_DEFUN([AX_REALPATH_LIB], [ dnl # resolve libname - #1 value (not quoted by caller) if we can; dnl # save into varname #2. dnl # In case of problems return #3 (optional, defaults to empty). AC_REQUIRE([AX_REALPATH_LIB_PREREQ])dnl AS_IF([test x"$1" = x], [AC_MSG_ERROR([Bad call to REALPATH_LIB macro (arg1)])]) AS_IF([test x"$2" = x], [AC_MSG_ERROR([Bad call to REALPATH_LIB macro (arg2)])]) AS_IF([test "x$GCC" = xyes -o "x$CLANGCC" = xyes], [ myLIBNAME="$1" AS_CASE(["${myLIBNAME}"], [-l*], [myLIBNAME="`echo "$myLIBNAME" | sed 's/^-l/lib/'`"] ) dnl # Primarily we care to know dynamically linked (shared object) dnl # files, so inject the extension to the presumed base name AS_CASE(["${myLIBNAME}"], [*.so*|*.a|*.o|*.lo|*.la|*.dll|*.dll.a|*.lib|*.dylib|*.sl], [], [ AS_CASE(["${target_os}"], [*mingw*], [myLIBNAME="${myLIBNAME}.dll"], [*darwin*], [myLIBNAME="${myLIBNAME}.dylib"], [*hpux*|*hp?ux*], [ dnl # See detailed comments in nut_platform.h myLIBNAME="${myLIBNAME}.sl" ],[myLIBNAME="${myLIBNAME}.so"]) ] ) AS_CASE(["${myLIBNAME}"], [lib*], [ dnl Alas, the portable solution with sed is to avoid dnl parentheses and pipe chars, got too many different dnl ways to escape them in the wild myLIBNAME_LD="`echo "$myLIBNAME" | sed -e 's/^lib/-l/' -e 's/\.dll$//' -e 's/\.dll\.a$//' -e 's/\.a$//' -e 's/\.o$//' -e 's/\.la$//' -e 's/\.lo$//' -e 's/\.lib$//' -e 's/\.dylib$//' -e 's/\.so\..*$//' -e 's/\.so//' -e 's/\.sl\..*$//' -e 's/\.sl//'`" ], [myLIBNAME_LD="-l$myLIBNAME"] dnl best-effort... ) AC_MSG_CHECKING([for real path to $1 (re-parsed as ${myLIBNAME} likely file name / ${myLIBNAME_LD} linker arg)]) myLIBPATH="" AS_CASE(["${target_os}"], [*mingw*], [ AS_IF([test x"${LD}" != x -a x"${LD}" != xfalse -a x"${DLLTOOL}" != x -a x"${DLLTOOL}" != xfalse], [ dnl Expected output (Linux mingw cross-build) ends like: dnl ================================================== dnl x86_64-w64-mingw32-ld: mode i386pep dnl attempt to open /usr/x86_64-w64-mingw32/lib/libnetsnmp.dll.a succeeded dnl /usr/x86_64-w64-mingw32/lib/libnetsnmp.dll.a dnl ...which we then resolve with dlltool into a libnetsnmp-40.dll dnl and finally find one in /usr/x86_64-w64-mingw32/bin/libnetsnmp-40.dll dnl (note the version number embedded into base name). { myLIBPATH="`$LD --verbose -Bdynamic ${myLIBNAME_LD} | grep -wi dll | tail -1`" \ && test -n "${myLIBPATH}" && test -s "${myLIBPATH}" ; } \ || { myLIBPATH="`$LD $LDFLAGS $LIBS --verbose -Bdynamic ${myLIBNAME_LD} | grep -wi dll | tail -1`" \ && test -n "${myLIBPATH}" && test -s "${myLIBPATH}" ; } \ || myLIBPATH="" dnl Resolve dynamic library "internal" name from its stub, if needed AS_CASE(["${myLIBPATH}"], [*.dll.a], [ myLIBPATH="`$DLLTOOL -I "${myLIBPATH}"`" || myLIBPATH="" ] ) dnl Internal name may be just that, with no path info AS_CASE(["${myLIBPATH}"], [*/*], [], [ for D in \ "/usr/${target}/bin" \ "/usr/${target}/lib" \ "${MSYSTEM_PREFIX}/bin" \ "${MSYSTEM_PREFIX}/lib" \ "${MINGW_PREFIX}/bin" \ "${MINGW_PREFIX}/lib" \ `${CC} --print-search-dirs 2>/dev/null | grep libraries: | sed 's,^@<:@^=@:>@*=,:,' | sed 's,\(@<:@:;@:>@\)\(@<:@A-Z@:>@\):/,:/\2/,g' | tr ':' '\n'` \ ; do dnl NOTE: Here we check myLIBPATH detected above, dnl in fallback below we would retry with a myLIBNAME if test -s "$D/${myLIBPATH}" 2>/dev/null ; then myLIBPATH="$D/${myLIBPATH}" break fi done unset D ] ) ]) ], [ dnl # POSIX/MacOS builds { myLIBPATH="`${CC} --print-file-name="$myLIBNAME"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || { myLIBPATH="`${CC} $CFLAGS --print-file-name="$myLIBNAME"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || { myLIBPATH="`${CC} $CFLAGS $LDFLAGS $LIBS --print-file-name="$myLIBNAME"`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || myLIBPATH="" ] ) AS_IF([test -z "${myLIBPATH}"], [ for TOKEN in $CFLAGS $LDFLAGS $LIBS ; do D="" case "$TOKEN" in -R*|-L*) D="`echo "$TOKEN" | sed 's,^-[RL],,'`" ;; -Wl,-R*) D="`echo "$TOKEN" | sed 's,^-Wl\,-R,,'`" ;; -Wl,-rpath,*) D="`echo "$TOKEN" | sed 's,^-Wl\,-rpath\,,,'`" ;; esac if test -z "$D" || ! test -d "$D" ; then continue ; fi if test -s "$D/${myLIBNAME}" 2>/dev/null ; then myLIBPATH="$D/${myLIBNAME}" break fi done unset D ]) AS_IF([test -z "${myLIBPATH}"], [ for D in \ "/usr/${target}/bin" \ "/usr/${target}/lib" \ `${CC} --print-search-dirs 2>/dev/null | grep libraries: | sed 's,^@<:@^=@:>@*=,:,' | sed 's,\(@<:@:;@:>@\)\(@<:@A-Z@:>@\):/,:/\2/,g' | tr ':' '\n'` \ ; do if test -s "$D/${myLIBNAME}" 2>/dev/null ; then myLIBPATH="$D/${myLIBNAME}" break fi done unset D ]) AS_IF([test -z "${myLIBPATH}" && test x"${LD}" != x -a x"${LD}" != xfalse], [ AS_CASE(["${target_os}"], [*darwin*], [ dnl Try MacOS-style LD as fallback; expecting strings like dnl ld: warning: /usr/local/lib/libneon.dylib, ignoring unexpected dylib file my_uname_m="`uname -m`" { myLIBPATH="`${LD} -dynamic -r -arch "${target_cpu}" -search_dylibs_first "${myLIBNAME_LD}" 2>&1 | grep -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || { myLIBPATH="`${LD} $LDFLAGS -dynamic -r -arch "${target_cpu}" -search_dylibs_first "${myLIBNAME_LD}" 2>&1 | grep -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || { myLIBPATH="`${LD} $LDFLAGS $LIBS -dynamic -r -arch "${target_cpu}" -search_dylibs_first "${myLIBNAME_LD}" 2>&1 | grep -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || if test x"${target_cpu}" != x"${my_uname_m}" ; then { myLIBPATH="`${LD} -dynamic -r -arch "${my_uname_m}" -search_dylibs_first "${myLIBNAME_LD}" 2>&1 | grep -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || { myLIBPATH="`${LD} $LDFLAGS -dynamic -r -arch "${my_uname_m}" -search_dylibs_first "${myLIBNAME_LD}" 2>&1 | grep -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || { myLIBPATH="`${LD} $LDFLAGS $LIBS -dynamic -r -arch "${my_uname_m}" -search_dylibs_first "${myLIBNAME_LD}" 2>&1 | grep -w dylib | sed 's/^@<:@^\/@:>@*\(\/.*\.dylib\),.*$/\1/'`" && test -n "$myLIBPATH" && test -s "$myLIBPATH" ; } \ || myLIBPATH="" else myLIBPATH="" fi rm -f a.out 2>/dev/null || true unset my_uname_m ] ) ]) AS_IF([test -n "${myLIBPATH}" && test -s "${myLIBPATH}"], [ AC_MSG_RESULT([initially '${myLIBPATH}']) AC_MSG_CHECKING([whether the file is a "GNU ld script" and not a binary]) AS_IF([LANG=C LC_ALL=C file "${myLIBPATH}" | grep -Ei '(ascii|text)' && grep -w GROUP "${myLIBPATH}" >/dev/null], [ # dnl e.g. # cat /usr/lib/x86_64-linux-gnu/libusb.so # dnl /* GNU ld script. */ # dnl GROUP ( /lib/x86_64-linux-gnu/libusb-0.1.so.4.4.4 ) # dnl Note that spaces around parentheses vary, more keywords # dnl may be present in a group (e.g. AS_NEEDED), and comment # dnl strings are inconsistent (useless to match by). AC_MSG_RESULT([yes, iterate further]) myLIBPATH_LDSCRIPT="`grep -w GROUP "${myLIBPATH}" | sed 's,^.*GROUP *( *\(/@<:@^ @:>@*\.so@<:@^ @:>@*\)@<:@^0-9a-zA-Z_.-@:>@.*$,\1,'`" AS_IF([test -n "${myLIBPATH_LDSCRIPT}" && test -s "${myLIBPATH_LDSCRIPT}"], [ AC_MSG_NOTICE([will dig into ${myLIBPATH_LDSCRIPT}]) dnl # See detailed comments just below myLIBPATH_REAL="${myLIBPATH_LDSCRIPT}" AX_REALPATH([${myLIBPATH_LDSCRIPT}], [myLIBPATH_REAL]) ], [ AC_MSG_NOTICE([could not determine a further path name, will use what we have]) dnl # See detailed comments just below myLIBPATH_REAL="${myLIBPATH}" AX_REALPATH([${myLIBPATH}], [myLIBPATH_REAL]) ]) ],[ AC_MSG_RESULT([no, seems like a normal binary]) dnl # Resolving the directory location is a nice bonus dnl # (usually the paths are relative to toolkit and ugly, dnl # though maybe arguably portable with regard to symlinks). dnl # The primary goal is to resolve the actual library file dnl # name like "libnetsnmp.so.1.2.3", so we can preferentially dnl # try to dlopen() it on a system with a packaged footprint dnl # that does not serve short (developer-friendly) links like dnl # "libnetsnmp.so". myLIBPATH_REAL="${myLIBPATH}" AX_REALPATH([${myLIBPATH}], [myLIBPATH_REAL]) ]) AC_MSG_RESULT(${myLIBPATH_REAL}) $2="${myLIBPATH_REAL}" ],[ AC_MSG_RESULT([not found]) $2="$3" ]) ], [AC_MSG_WARN([Compiler not detected as GCC/CLANG-compatible, skipping REALPATH_LIB($1)]) $2="$3" ]) ]) nut-2.8.3/m4/nut_check_pkgconfig.m40000644000200500020050000001133614777767434014051 00000000000000dnl Check for LIBPOWERMAN compiler flags. On success, set nut_have_libpowerman="yes" dnl and set LIBPOWERMAN_CFLAGS and LIBPOWERMAN_LIBS. On failure, set dnl nut_have_libpowerman="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_PKGCONFIG], [ AS_IF([test -z "${nut_have_pkg_config_seen}"], [ nut_have_pkg_config_seen=yes dnl Note that PKG_CONFIG may be a filename, path, dnl or either with args - so no quoting here AC_MSG_CHECKING([whether usable PKG_CONFIG was already detected by autoconf]) AS_IF([test -n "${PKG_CONFIG-}" && test x"${PKG_CONFIG-}" != x"false" && $PKG_CONFIG --help 2>&1 | grep -E '(--cflags|--libs)' >/dev/null], [AC_MSG_RESULT([yes: ${PKG_CONFIG}]) have_PKG_CONFIG=yes ], [AC_MSG_RESULT([no]) PKG_CONFIG=false have_PKG_CONFIG=no ] ) AS_IF([test x"${PKG_CONFIG-}" = x"false"], [dnl Some systems have older autotools without direct macro support for PKG_CONF* have_PKG_CONFIG=yes AC_PATH_PROG(dummy_PKG_CONFIG, pkg-config) AC_ARG_WITH(pkg-config, AS_HELP_STRING([--with-pkg-config=/path/to/pkg-config], [path to program that reports development package configuration]), [ case "${withval}" in "") ;; yes|no) AC_MSG_ERROR(invalid option --with(out)-pkg-config - see docs/configure.txt) ;; *) dummy_PKG_CONFIG="${withval}" ;; esac ]) AC_MSG_CHECKING([whether usable PKG_CONFIG is present in PATH or was set by caller]) AS_IF([test x"$dummy_PKG_CONFIG" = xno || test -z "$dummy_PKG_CONFIG"], [AC_MSG_RESULT([no]) PKG_CONFIG=false have_PKG_CONFIG=no ], [AS_IF([$dummy_PKG_CONFIG --help 2>&1 | grep -E '(--cflags|--libs)' >/dev/null], [AC_MSG_RESULT([yes: ${dummy_PKG_CONFIG}]) have_PKG_CONFIG=yes PKG_CONFIG="$dummy_PKG_CONFIG" ], [AC_MSG_RESULT([no]) PKG_CONFIG=false have_PKG_CONFIG=no ] )] )] ) have_PKG_CONFIG_MACROS=no AS_IF([test x"$have_PKG_CONFIG" = xyes], [AC_MSG_NOTICE([checking for autoconf macro support of pkg-config (${PKG_CONFIG})]) dummy_RES=0 ifdef([PKG_PROG_PKG_CONFIG], [], [dummy_RES=1]) ifdef([PKG_CHECK_MODULES], [], [dummy_RES=2]) AS_IF([test "${dummy_RES}" = 0], [AC_MSG_NOTICE([checking for autoconf macro support of pkg-config module checker]) dnl The m4 macro below may be not defined if pkg-config package is not dnl installed. Use of ifdef (here and below for e.g. CPPUNIT check) dnl allows to avoid shell syntax errors in generated configure script dnl by defining a dummy macro in-place. ifdef([PKG_CHECK_MODULES], [], [AC_DEFUN([PKG_CHECK_MODULES], [false])]) PKG_CHECK_MODULES([dummy_PKG_CONFIG], [pkg-config], [have_PKG_CONFIG_MACROS=yes]) ] )] ) AS_IF([test x"$have_PKG_CONFIG" = xno], [AC_MSG_WARN([pkg-config program is needed to look for further dependencies (will be skipped)]) PKG_CONFIG="false" ], [AS_IF([test x"$have_PKG_CONFIG_MACROS" = xno], [AC_MSG_WARN([pkg-config macros are needed to look for further dependencies, but in some cases pkg-config program can be used directly])]) AC_MSG_CHECKING([for pkg-config envvar PKG_CONFIG_PATH (if passed to configure script or exported in shell session)]) AC_MSG_RESULT([${PKG_CONFIG_PATH}]) AC_MSG_CHECKING([for pkg-config reported pc_path]) myPKG_CONFIG_PC_PATH="`pkg-config --variable pc_path pkg-config`" || myPKG_CONFIG_PC_PATH="" AC_MSG_RESULT([${myPKG_CONFIG_PC_PATH}]) dnl # The piece below is inspired by https://github.com/wxWidgets/wxWidgets/commit/7899850496ba2707c41cc534b51d14ac5b9fdbba dnl When cross-compiling for another system from Linux, don't use .pc files on dnl the build system, they are at best useless and can be harmful (e.g. they dnl may define options inappropriate for the cross-build, resulting in the dnl failure of all the subsequent tests). dnl dnl However do use .pc files for the host libraries that can be found by the dnl host-specific pkg-config if it was found by PKG_PROG_PKG_CONFIG above. AS_IF([test x"$build" != x"$host"], [ AS_CASE(["$PKG_CONFIG"], [*/"$host"-pkg-config], [], [AC_MSG_WARN([Not using native pkg-config when cross-compiling.]) dnl pkg.m4 forbids the use of PKG_XXX, so undo it here dnl to avoid autoconf errors. m4_pattern_allow([PKG_CONFIG_LIBDIR]) dnl If pkg-config libdir is already defined, we suppose that dnl callers know what they're doing and leave it alone, but dnl if not, set it to a path in which no .pc files will be found. AS_IF([test x"$PKG_CONFIG_LIBDIR" = x], [ AC_MSG_WARN([Exporting a hack PKG_CONFIG_LIBDIR to avoid search for .pc files in host paths]) PKG_CONFIG_LIBDIR=/dev/null export PKG_CONFIG_LIBDIR ]) ]) ]) ] ) ]) dnl if nut_have_pkg_config_seen ]) nut-2.8.3/m4/ax_check_compile_flag.m40000644000200500020050000000535214777534446014321 00000000000000# =========================================================================== # https://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. # # NOTE: This implementation was extended with check for compiler complaints # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # Copyright (c) 2022 Jim Klimov # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 6 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [ dnl UPDATE: As tested on CentOS 6, its "autoconf-2.63-5.1.el6.noarch" also suffices. AC_PREREQ(2.63) dnl #AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF 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()])], [dnl Toolkit per se did not return an error code; but did it complain? dnl Below are a few strings typical for some versions of GCC and CLANG dnl This relies on AC_COMPILE_IFELSE implementation retaining conftest.err AS_IF([grep -E '(unrecognized.* option|did you mean|unknown argument:)' < conftest.err >/dev/null 2>/dev/null], [AS_VAR_SET(CACHEVAR,[no])],dnl Hit a complaint, flag is not supported after all [AS_VAR_SET(CACHEVAR,[yes])])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_VAR_IF(CACHEVAR,yes, [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS nut-2.8.3/m4/nut_check_cppcheck.m40000644000200500020050000000220414553676503013640 00000000000000dnl Check for "cppcheck" analysis tools AC_DEFUN([NUT_CHECK_CPPCHECK], [ if test -z "${nut_have_cppcheck_seen}"; then dnl NOTE: Did not really investigate suitable CPPCHECK_MIN_VERSION dnl values, just using current available as the baseline; maybe dnl older releases are also okay (if someone proves so). dnl The oldest available on the NUT CI build farm was 1.6 that worked. nut_have_cppcheck_seen=yes CPPCHECK_MIN_VERSION="1.0" AC_PATH_PROGS([CPPCHECK], [cppcheck]) if test -n "${CPPCHECK}"; then AC_MSG_CHECKING([for cppcheck version]) CPPCHECK_VERSION="`${CPPCHECK} --version 2>/dev/null`" dnl strip 'cppcheck ' from version string CPPCHECK_VERSION="${CPPCHECK_VERSION##* }" AC_MSG_RESULT(${CPPCHECK_VERSION} found) fi AC_MSG_CHECKING([if cppcheck version is okay (minimum required ${CPPCHECK_MIN_VERSION})]) AX_COMPARE_VERSION([${CPPCHECK_VERSION}], [ge], [${CPPCHECK_MIN_VERSION}], [ AC_MSG_RESULT(yes) nut_have_cppcheck="yes" ], [ AC_MSG_RESULT(no) nut_have_cppcheck="no" ]) dnl Notes: we also keep HAVE_CPPCHECK for implicit targets AM_CONDITIONAL([HAVE_CPPCHECK], [test "${nut_have_cppcheck}" = "yes"]) fi ]) nut-2.8.3/m4/nut_check_socketlib.m40000644000200500020050000000261114777534446014050 00000000000000dnl Copyright (C) 2008-2010 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl NUT_CHECK_SOCKETLIB dnl Determines the library to use for socket functions. dnl Sets and AC_SUBSTs NETLIBS. dnl This code comes from gnulib trunk (4 Nov. 2010). AC_DEFUN([NUT_CHECK_SOCKETLIB], [ NUT_PREREQ_SYS_H_SOCKET dnl for HAVE_WINSOCK2_H NETLIBS= if test $HAVE_WINSOCK2_H = 1; then dnl Native Windows API (not Cygwin). AC_CACHE_CHECK([if we need to call WSAStartup in winsock2.h and -lws2_32], [nut_cv_func_wsastartup], [ nut_save_LIBS="$LIBS" LIBS="$LIBS -lws2_32" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_WINSOCK2_H # include #endif]], [[ WORD wVersionRequested = MAKEWORD(1, 1); WSADATA wsaData; int err = WSAStartup(wVersionRequested, &wsaData); WSACleanup ();]])], nut_cv_func_wsastartup=yes, nut_cv_func_wsastartup=no) LIBS="$nut_save_LIBS" ]) if test "$nut_cv_func_wsastartup" = "yes"; then AC_DEFINE([WINDOWS_SOCKETS], [1], [Define if WSAStartup is needed.]) NETLIBS='-lws2_32' fi fi AC_SUBST([NETLIBS]) AM_CONDITIONAL([HAVE_WINDOWS_SOCKETS], [test "$nut_cv_func_wsastartup" = "yes"]) ]) nut-2.8.3/m4/nut_check_libregex.m40000644000200500020050000000675714777767434013716 00000000000000dnl Check for LIBREGEX (and, if found, fill 'nut_usb_lib' with its dnl approximate version) and its compiler flags. On success, set dnl nut_have_libusb="yes" and set LIBREGEX_CFLAGS and LIBREGEX_LIBS. On failure, set dnl nut_have_libusb="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBREGEX], [ if test -z "${nut_have_libregex_seen}"; then nut_have_libregex_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" REQUIRES_ORIG="${REQUIRES}" CFLAGS="" LIBS="" REQUIRES="" depCFLAGS="" depLIBS="" depREQUIRES="" dnl Actually did not see it in any systems' pkg-config info... dnl Part of standard footprint? LIBREGEX_MODULE="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [AC_MSG_CHECKING(for libregex version via pkg-config) LIBREGEX_VERSION="`$PKG_CONFIG --silence-errors --modversion regex 2>/dev/null`" if test "$?" != "0" -o -z "${LIBREGEX_VERSION}"; then LIBREGEX_VERSION="`$PKG_CONFIG --silence-errors --modversion libregex 2>/dev/null`" if test "$?" != "0" -o -z "${LIBREGEX_VERSION}"; then LIBREGEX_VERSION="none" else LIBREGEX_MODULE="libregex" fi else LIBREGEX_MODULE="regex" fi AC_MSG_RESULT(${LIBREGEX_VERSION} found) ], [LIBREGEX_VERSION="none" AC_MSG_NOTICE([can not check libregex settings via pkg-config]) ] ) AS_IF([test x"$LIBREGEX_VERSION" != xnone && test x"$LIBREGEX_MODULE" != x], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags "${LIBREGEX_MODULE}" 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs "${LIBREGEX_MODULE}" 2>/dev/null`" depREQUIRES="${LIBREGEX_MODULE}" ], [depCFLAGS="" depLIBS="" depREQUIRES="" ] ) dnl Check if libregex is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" REQUIRES="${REQUIRES_ORIG} ${depREQUIRES}" AC_LANG_PUSH([C]) dnl # With USB we can match desired devices by regex dnl # (and currently have no other use for the library); dnl # however we may have some general regex helper dnl # methods built into libcommon (may become useful dnl # elsewhere) - so need to know if we may and should. dnl # Maybe already involved in NUT for Windows builds... nut_have_regex=no AC_CHECK_HEADER([regex.h], [AC_DEFINE([HAVE_REGEX_H], [1], [Define to 1 if you have .])]) AC_CHECK_DECLS([regexec, regcomp], [nut_have_regex=yes], [], [#ifdef HAVE_REGEX_H # include #endif ]) AS_IF([test x"${nut_have_regex}" = xyes], [ nut_have_regex=no AC_SEARCH_LIBS([regcomp], [regex], [ AC_SEARCH_LIBS([regcomp], [regex], [nut_have_regex=yes]) ]) ]) dnl Collect possibly updated dependencies after AC SEARCH LIBS: AS_IF([test x"${LIBS}" != x"${LIBS_ORIG} ${depLIBS}"], [ AS_IF([test x = x"${LIBS_ORIG}"], [depLIBS="$LIBS"], [ depLIBS="`echo "$LIBS" | sed -e 's|'"${LIBS_ORIG}"'| |' -e 's|^ *||' -e 's| *$||'`" ]) ]) AS_IF([test x"${nut_have_regex}" = xyes], [ LIBREGEX_CFLAGS="${depCFLAGS}" LIBREGEX_LIBS="${depLIBS}" AC_DEFINE(HAVE_LIBREGEX, 1, [Define to 1 for build where we can support general regex matching.]) ], [ LIBREGEX_CFLAGS="" LIBREGEX_LIBS="" AC_DEFINE(HAVE_LIBREGEX, 0, [Define to 1 for build where we can support general regex matching.]) ]) AM_CONDITIONAL(HAVE_LIBREGEX, test x"${nut_have_regex}" = xyes) AC_LANG_POP([C]) unset depCFLAGS unset depLIBS unset depREQUIRES dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/ax_run_or_link_ifelse.m40000644000200500020050000000317114777534446014410 00000000000000dnl By default, AC_RUN_IFELSE() fails if it detects cross-compilation dnl but it provides the fourth argument to customize the handling. dnl In our case, we would fall back to trying just to link then - dnl the result would not be as relevant regarding run-time behavior dnl of the code, but at least we would know that API and ABI are ok. dnl Here the fourth and fifth arguments can be used to pass custom dnl CFLAGS and CXXFLAGS options (e.g. warnings to cover or ignore), dnl respectively. For the test to succeed, the build/link must pass dnl without warnings. dnl Per original /usr/share/autoconf/autoconf/general.m4 which makes dnl a similar wrapper: dnl # AC_TRY_RUN(PROGRAM, dnl # [ACTION-IF-TRUE], [ACTION-IF-FALSE], dnl # [ACTION-IF-CROSS-COMPILING = RUNTIME-ERROR]) dnl # ------------------------------------------------------- AC_DEFUN([AX_RUN_OR_LINK_IFELSE], [ myCFLAGS="$CFLAGS" myCXXFLAGS="$CXXFLAGS" AS_IF([test "${GCC}" = "yes" || test "${CLANGCC}" = "yes"], [ CFLAGS="$myCFLAGS -Werror -Werror=implicit-function-declaration $4" dnl # cc1plus: error: '-Werror=' argument '-Werror=implicit-function-declaration' is not valid for C++ [-Werror] CXXFLAGS="$myCXXFLAGS -Werror $5" ], [ dnl # Don't know what to complain about for unknown compilers dnl # FIXME: Presume here they have at least a "-Werror" option CFLAGS="$myCFLAGS -Werror $4" CXXFLAGS="$myCXXFLAGS -Werror $5" ]) AC_RUN_IFELSE([$1], [$2], [$3], [ AC_MSG_WARN([Current build is a cross-build, so not running test binaries, just linking them]) AC_LINK_IFELSE([$1], [$2], [$3]) ] ) CFLAGS="$myCFLAGS" CXXFLAGS="$myCXXFLAGS" ]) nut-2.8.3/m4/lt~obsolete.m40000644000200500020050000001377415001555004012402 00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software # Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) nut-2.8.3/m4/nut_check_python.m40000644000200500020050000005311414777767434013423 00000000000000dnl Check for python binary program names per language version dnl to embed into scripts and Make rules AC_DEFUN([NUT_CHECK_PYTHON_DEFAULT], [ dnl Check for all present variants and pick the default PYTHON AC_REQUIRE([NUT_CHECK_PYTHON]) AC_REQUIRE([NUT_CHECK_PYTHON2]) AC_REQUIRE([NUT_CHECK_PYTHON3]) AS_IF([test x"$PYTHON2" = xno], [PYTHON2=""]) AS_IF([test x"$PYTHON3" = xno], [PYTHON3=""]) AS_IF([test x"$PYTHON" = xno], [PYTHON=""]) AS_IF([test x"$PYTHON" = x], [ AC_MSG_CHECKING([which python version to use by default]) dnl Last hit wins (py3) AS_IF([test x"$PYTHON2" != x], [PYTHON="$PYTHON2"]) AS_IF([test x"$PYTHON3" != x], [PYTHON="$PYTHON3"]) AS_IF([test x"$PYTHON" = x], [AC_MSG_RESULT([none])], [AC_MSG_RESULT([$PYTHON]) AC_MSG_WARN([A python program name was not specified during configuration, will default to '$PYTHON' (derived from --with-python2 or --with-python3 setting)]) ]) ]) AS_IF([test -z "${PYTHON3}" && test x"${nut_with_python3}" = xyes], [ AC_MSG_ERROR([A python3 interpreter was required but not found or validated]) ]) AS_IF([test -z "${PYTHON2}" && test x"${nut_with_python2}" = xyes], [ AC_MSG_ERROR([A python2 interpreter was required but not found or validated]) ]) AS_IF([test -z "${PYTHON}" && test x"${nut_with_python}" = xyes], [ AC_MSG_ERROR([A python interpreter was required but not found or validated]) ]) ]) dnl Note: this checks for default/un-versioned python version dnl as the --with-python=SHEBANG_PATH setting into the PYTHON dnl variable; it may be further tweaked by NUT_CHECK_PYTHON_DEFAULT AC_DEFUN([NUT_CHECK_PYTHON], [ AS_IF([test -z "${nut_with_python}"], [ NUT_ARG_WITH([python], [Use a particular program name of the python interpeter], [auto]) PYTHON="" PYTHON_SITE_PACKAGES="" PYTHON_VERSION_REPORT="" PYTHON_VERSION_INFO_REPORT="" PYTHON_SYSPATH_REPORT="" AS_CASE([${nut_with_python}], [auto|yes|""], [AC_CHECK_PROGS([PYTHON], [python python3 python2], [_python_runtime])], [no], [PYTHON="no"], [PYTHON="${nut_with_python}"] ) dnl Default to calling a basename from PATH, only use a specific full pathname dnl if provided by the caller: AS_CASE([${PYTHON}], [_python_runtime], [ PYTHON="/usr/bin/env python" AC_MSG_WARN([A python program name was not detected during configuration, will default to '$PYTHON' (scripts will fail if that is not in PATH at run time)])], [no], [], [/*" "*" "*], [ AC_MSG_WARN([A python program name is not a single token (was specified with more than one argument?), so shebangs can be not reliable]) ], [/*], [], [*" "*" "*], [ AC_MSG_WARN([A python program name is not a single token (was specified with more than one argument?), so shebangs can be not reliable]) PYTHON="/usr/bin/env ${PYTHON}" ], [*" "*], [ AC_MSG_WARN([A python program name is not a single token (was specified with an argument?), so /usr/bin/env shebangs can be not reliable]) PYTHON="/usr/bin/env ${PYTHON}" ], [*], [ dnl Note: no "realpath" here, see comment below myPYTHON="`command -v "${PYTHON}" 2>/dev/null`" && test -n "${myPYTHON}" && test -x "${myPYTHON}" \ && PYTHON="${myPYTHON}" \ || PYTHON="/usr/bin/env ${PYTHON}" unset myPYTHON ] ) dnl Note: requesting e.g. "--with-python=python3" is valid, dnl but would likely use a symlink that changes over time - dnl and if `env` gets used, can resolve according to PATH dnl (by default we try to bolt pathname here if resolvable, dnl but do not unwrap the chain of symlinks like we do for dnl versioned "--with-python2/3" due to their site-packages). dnl For some use-cases, this lack of constraints may be dnl deliberately desired; for others it is a "caveat emptor!" AS_CASE(["${PYTHON}"], [*2.*|*3.*|no], [], [AC_MSG_WARN([A python program name without a specific version number was requested (may be a symlink prone to change over time): ${PYTHON}])]) AS_CASE(["${PYTHON}"], [/usr/bin/env*], [AC_MSG_WARN([A python program will be resolved from PATH at run-time (PyNUT module may be not found if installed into site-packages of a specific version): ${PYTHON}])]) AS_IF([test -n "${PYTHON}" && test "${PYTHON}" != "no"], [ AS_IF([test x"`$PYTHON -c 'import sys; print (sys.version_info >= (2, 6))'`" = xTrue], [PYTHON_VERSION_INFO_REPORT=" (`$PYTHON -c 'import sys; print (sys.version_info)'`)"], [AC_MSG_WARN([Version reported by ${PYTHON} was not suitable as python]) PYTHON=no]) ]) dnl Unfulfilled "yes" is re-tested in NUT_CHECK_PYTHON_DEFAULT AS_IF([test -z "${PYTHON}" || test "${PYTHON}" = "no"], [ AS_CASE([${nut_with_python}], [auto|yes|no|""], [], [AC_MSG_ERROR([A python interpreter was required but not found or validated: ${nut_with_python}])]) ]) AC_MSG_CHECKING([python interpeter to call]) AC_MSG_RESULT([${PYTHON}${PYTHON_VERSION_INFO_REPORT}]) AC_SUBST([PYTHON], [${PYTHON}]) AM_CONDITIONAL([HAVE_PYTHON], [test -n "${PYTHON}" && test "${PYTHON}" != "no"]) AS_IF([test -n "${PYTHON}" && test "${PYTHON}" != "no"], [ AC_MSG_CHECKING([python build sys.version]) dnl Can have extra lines about compiler used, etc. PYTHON_VERSION_REPORT="`${PYTHON} -c 'import sys; print(sys.version);' | tr '\n' ' '`" \ || PYTHON_VERSION_REPORT="" AC_MSG_RESULT([${PYTHON_VERSION_REPORT}]) AC_MSG_CHECKING([python sys.path used to search for modules]) PYTHON_SYSPATH_REPORT="`${PYTHON} -c 'import sys; print(sys.path);'`" \ || PYTHON_SYSPATH_REPORT="" AC_MSG_RESULT([${PYTHON_SYSPATH_REPORT}]) export PYTHON AC_CACHE_CHECK([python site-packages location], [nut_cv_PYTHON_SITE_PACKAGES], [ dnl sysconfig introduced in python3.2 AS_IF([test x"`${PYTHON} -c 'import sys; print (sys.version_info >= (3, 2))'`" = xTrue], [nut_cv_PYTHON_SITE_PACKAGES="`${PYTHON} -c 'import sysconfig; print(sysconfig.get_path("purelib"))'`"], [nut_cv_PYTHON_SITE_PACKAGES="`${PYTHON} -c 'import site; print(site.getsitepackages().pop(0))'`"]) AS_CASE(["$nut_cv_PYTHON_SITE_PACKAGES"], [*:*], [ dnl Note: on Windows MSYS2 this embeds "C:/msys64/mingw..." into the string [nut#1584] nut_cv_PYTHON_SITE_PACKAGES="`cd "$nut_cv_PYTHON_SITE_PACKAGES" && pwd`" ] ) ]) ]) AC_SUBST([PYTHON_SITE_PACKAGES], [${nut_cv_PYTHON_SITE_PACKAGES}]) AM_CONDITIONAL([HAVE_PYTHON_SITE_PACKAGES], [test x"${PYTHON_SITE_PACKAGES}" != "x"]) ]) ]) AC_DEFUN([NUT_CHECK_PYTHON2], [ AS_IF([test -z "${nut_with_python2}"], [ NUT_ARG_WITH([python2], [Use a particular program name of the python2 interpeter for code that needs that version and is not compatible with python3], [auto]) PYTHON2="" PYTHON2_SITE_PACKAGES="" PYTHON2_VERSION_REPORT="" PYTHON2_VERSION_INFO_REPORT="" PYTHON2_SYSPATH_REPORT="" AS_CASE([${nut_with_python2}], [auto|yes|""], [ dnl Cross check --with-python results: AS_CASE(["${PYTHON_VERSION_INFO_REPORT}"], [*major=2,*], [ PYTHON2="`${PYTHON} -c 'import sys; print(sys.executable);' 2>/dev/null`" && test -n "${PYTHON2}" || PYTHON2="${PYTHON}" PYTHON2="`realpath "${PYTHON2}" 2>/dev/null`" && test -n "${PYTHON2}" || { PYTHON2="${PYTHON}" PYTHON_CONFIG="`command -v "${PYTHON}-config" 2>/dev/null`" || PYTHON_CONFIG="" if test -n "${PYTHON_CONFIG}" ; then mySHEBANG_SCRIPT="`${PYTHON_CONFIG} --config-dir 2>/dev/null`/python-config.py" \ || mySHEBANG_SCRIPT="${PYTHON_CONFIG}" if test -f "${mySHEBANG_SCRIPT}" ; then mySHEBANG="`head -1 "${mySHEBANG_SCRIPT}" | grep -E '^#!'`" || mySHEBANG="" if test -n "${mySHEBANG}" ; then PYTHON2="`echo "${mySHEBANG}" | sed 's,^#! *,,'`" \ && test -n "${PYTHON2}" || PYTHON2="${PYTHON}" fi fi fi unset mySHEBANG_SCRIPT unset mySHEBANG unset PYTHON_CONFIG } dnl Only accept fully qualified names that refer to expected dnl python version or quietly fall back to search below: AS_CASE(["${PYTHON2}"], [/usr/bin/env*], [PYTHON2=""], [/*py*2.*], [AC_MSG_WARN([A python2 program name was not specified during configuration, will default to '$PYTHON2' (derived from --with-python setting which has a suitable version)])], [/*py*2*], [AC_MSG_WARN([A python2 program name was not specified during configuration, will default to '$PYTHON2' (derived from --with-python setting which has a suitable version, but without a specific version number - so may be a symlink prone to change over time)])], [PYTHON2=""]) ]) AS_IF([test x"${PYTHON2}" = x], [ AC_CHECK_PROGS([PYTHON2], [python2 python2.7 python-2.7 python], [_python2_runtime]) ]) ], [no], [PYTHON2="no"], [PYTHON2="${nut_with_python2}"] ) dnl Default to calling a basename from PATH, only use a specific full pathname dnl if provided by the caller: AS_CASE([${PYTHON2}], [_python2_runtime], [ PYTHON2="/usr/bin/env python2" AC_MSG_WARN([A python2 program name was not detected during configuration, will default to '$PYTHON2' (scripts will fail if that is not in PATH at run time)]) ], [no], [], [/*" "*" "*], [ AC_MSG_WARN([A python2 program name is not a single token (was specified with more than one argument?), so shebangs can be not reliable]) ], [/*], [], [*" "*" "*], [ AC_MSG_WARN([A python2 program name is not a single token (was specified with more than one argument?), so shebangs can be not reliable]) PYTHON2="/usr/bin/env ${PYTHON2}" ], [*" "*], [ AC_MSG_WARN([A python2 program name is not a single token (was specified with an argument?), so /usr/bin/env shebangs can be not reliable]) PYTHON2="/usr/bin/env ${PYTHON2}" ], [*], [ myPYTHON="`command -v "${PYTHON2}" 2>/dev/null`" && test -n "${myPYTHON}" && test -x "${myPYTHON}" \ && PYTHON2="${myPYTHON}" \ || PYTHON2="/usr/bin/env ${PYTHON2}" unset myPYTHON ] ) AS_IF([test -n "${PYTHON2}" && test "${PYTHON2}" != "no"], [ AS_IF([test x"`$PYTHON2 -c 'import sys; print (sys.version_info >= (2, 6) and sys.version_info < (3, 0))'`" = xTrue], [PYTHON2_VERSION_INFO_REPORT=" (`$PYTHON2 -c 'import sys; print (sys.version_info)'`)"], [AC_MSG_WARN([Version reported by ${PYTHON2} was not suitable as python2]) PYTHON2=no]) ]) dnl Unfulfilled "yes" is re-tested in NUT_CHECK_PYTHON_DEFAULT AS_IF([test -z "${PYTHON2}" || test "${PYTHON2}" = "no"], [ AS_CASE([${nut_with_python2}], [auto|yes|no|""], [], [AC_MSG_ERROR([A python2 interpreter was required but not found or validated: ${nut_with_python2}])]) ]) AC_MSG_CHECKING([python2 interpeter to call]) AC_MSG_RESULT([${PYTHON2}${PYTHON2_VERSION_INFO_REPORT}]) AC_SUBST([PYTHON2], [${PYTHON2}]) AM_CONDITIONAL([HAVE_PYTHON2], [test -n "${PYTHON2}" && test "${PYTHON2}" != "no"]) AS_IF([test -n "${PYTHON2}" && test "${PYTHON2}" != "no"], [ AC_MSG_CHECKING([python2 build sys.version]) dnl Can have extra lines about compiler used, etc. PYTHON2_VERSION_REPORT="`${PYTHON2} -c 'import sys; print(sys.version);' | tr '\n' ' '`" \ || PYTHON2_VERSION_REPORT="" AC_MSG_RESULT([${PYTHON2_VERSION_REPORT}]) AC_MSG_CHECKING([python2 sys.path used to search for modules]) PYTHON2_SYSPATH_REPORT="`${PYTHON2} -c 'import sys; print(sys.path);'`" \ || PYTHON2_SYSPATH_REPORT="" AC_MSG_RESULT([${PYTHON2_SYSPATH_REPORT}]) export PYTHON2 AC_CACHE_CHECK([python2 site-packages location], [nut_cv_PYTHON2_SITE_PACKAGES], [ nut_cv_PYTHON2_SITE_PACKAGES="`${PYTHON2} -c 'import site; print(site.getsitepackages().pop(0))'`" AS_CASE(["$nut_cv_PYTHON2_SITE_PACKAGES"], [*:*], [ dnl Note: on Windows MSYS2 this embeds "C:/msys64/mingw..." into the string [nut#1584] nut_cv_PYTHON2_SITE_PACKAGES="`cd "$nut_cv_PYTHON2_SITE_PACKAGES" && pwd`" ] ) ]) ]) AC_SUBST([PYTHON2_SITE_PACKAGES], [${nut_cv_PYTHON2_SITE_PACKAGES}]) AM_CONDITIONAL([HAVE_PYTHON2_SITE_PACKAGES], [test x"${PYTHON2_SITE_PACKAGES}" != "x"]) ]) ]) AC_DEFUN([NUT_CHECK_PYTHON3], [ AS_IF([test -z "${nut_with_python3}"], [ NUT_ARG_WITH([python3], [Use a particular program name of the python3 interpeter for code that needs that version and is not compatible with python2], [auto]) PYTHON3="" PYTHON3_SITE_PACKAGES="" PYTHON3_VERSION_REPORT="" PYTHON3_VERSION_INFO_REPORT="" PYTHON3_SYSPATH_REPORT="" AS_CASE([${nut_with_python3}], [auto|yes|""], [ dnl Cross check --with-python results: AS_CASE(["${PYTHON_VERSION_INFO_REPORT}"], [*major=3,*], [ PYTHON3="`${PYTHON} -c 'import sys; print(sys.executable);' 2>/dev/null`" && test -n "${PYTHON3}" || PYTHON3="${PYTHON}" PYTHON3="`realpath "${PYTHON3}" 2>/dev/null`" && test -n "${PYTHON3}" || { PYTHON3="${PYTHON}" PYTHON_CONFIG="`command -v "${PYTHON}-config" 2>/dev/null`" || PYTHON_CONFIG="" if test -n "${PYTHON_CONFIG}" ; then mySHEBANG_SCRIPT="`${PYTHON_CONFIG} --config-dir 2>/dev/null`/python-config.py" \ || mySHEBANG_SCRIPT="${PYTHON_CONFIG}" if test -f "${mySHEBANG_SCRIPT}" ; then mySHEBANG="`head -1 "${mySHEBANG_SCRIPT}" | grep -E '^#!'`" || mySHEBANG="" if test -n "${mySHEBANG}" ; then PYTHON3="`echo "${mySHEBANG}" | sed 's,^#! *,,'`" \ && test -n "${PYTHON3}" || PYTHON3="${PYTHON}" fi fi fi unset mySHEBANG_SCRIPT unset mySHEBANG unset PYTHON_CONFIG } dnl Only accept fully qualified names that refer to expected dnl python version or quietly fall back to search below: AS_CASE(["${PYTHON3}"], [/usr/bin/env*], [PYTHON3=""], [/*py*3.*], [AC_MSG_WARN([A python3 program name was not specified during configuration, will default to '$PYTHON3' (derived from --with-python setting which has a suitable version)])], [/*py*3*], [AC_MSG_WARN([A python3 program name was not specified during configuration, will default to '$PYTHON3' (derived from --with-python setting which has a suitable version, but without a specific version number - so may be a symlink prone to change over time)])], [PYTHON3=""]) ]) AS_IF([test x"${PYTHON3}" = x], [ AC_CHECK_PROGS([PYTHON3], [python3 python3.14 python-3.14 python3.13 python-3.13 python3.12 python-3.12 python3.11 python-3.11 python3.10 python-3.10 python3.9 python-3.9 python3.7 python-3.7 python3.6 python-3.6 python3.5 python-3.5 python], [_python3_runtime]) ]) ], [no], [PYTHON3="no"], [PYTHON3="${nut_with_python3}"] ) dnl Default to calling a basename from PATH, only use a specific full pathname dnl if provided by the caller: AS_CASE([${PYTHON3}], [_python3_runtime], [ PYTHON3="/usr/bin/env python3" AC_MSG_WARN([A python3 program name was not detected during configuration, will default to '$PYTHON3' (scripts will fail if that is not in PATH at run time)]) ], [no], [], [/*" "*" "*], [ AC_MSG_WARN([A python3 program name is not a single token (was specified with more than one argument?), so shebangs can be not reliable]) ], [/*], [], [*" "*" "*], [ AC_MSG_WARN([A python3 program name is not a single token (was specified with more than one argument?), so shebangs can be not reliable]) PYTHON3="/usr/bin/env ${PYTHON3}" ], [*" "*], [ AC_MSG_WARN([A python3 program name is not a single token (was specified with an argument?), so /usr/bin/env shebangs can be not reliable]) PYTHON3="/usr/bin/env ${PYTHON3}" ], [*], [ myPYTHON="`command -v "${PYTHON3}" 2>/dev/null`" && test -n "${myPYTHON}" && test -x "${myPYTHON}" \ && PYTHON3="${myPYTHON}" \ || PYTHON3="/usr/bin/env ${PYTHON3}" unset myPYTHON ] ) AS_IF([test -n "${PYTHON3}" && test "${PYTHON3}" != "no"], [ AS_IF([test x"`$PYTHON3 -c 'import sys; print (sys.version_info >= (3, 0))'`" = xTrue], [PYTHON3_VERSION_INFO_REPORT=" (`$PYTHON3 -c 'import sys; print (sys.version_info)'`)"], [AC_MSG_WARN([Version reported by ${PYTHON3} was not suitable as python3]) PYTHON3=no]) ]) dnl Unfulfilled "yes" is re-tested in NUT_CHECK_PYTHON_DEFAULT AS_IF([test -z "${PYTHON3}" || test "${PYTHON3}" = "no"], [ AS_CASE([${nut_with_python3}], [auto|yes|no|""], [], [AC_MSG_ERROR([A python3 interpreter was required but not found or validated: ${nut_with_python3}])]) ]) AC_MSG_CHECKING([python3 interpeter to call]) AC_MSG_RESULT([${PYTHON3}${PYTHON3_VERSION_INFO_REPORT}]) AC_SUBST([PYTHON3], [${PYTHON3}]) AM_CONDITIONAL([HAVE_PYTHON3], [test -n "${PYTHON3}" && test "${PYTHON3}" != "no"]) AS_IF([test -n "${PYTHON3}" && test "${PYTHON3}" != "no"], [ AC_MSG_CHECKING([python3 build sys.version]) dnl Can have extra lines about compiler used, etc. PYTHON3_VERSION_REPORT="`${PYTHON3} -c 'import sys; print(sys.version);' | tr '\n' ' '`" \ || PYTHON3_VERSION_REPORT="" AC_MSG_RESULT([${PYTHON3_VERSION_REPORT}]) AC_MSG_CHECKING([python3 sys.path used to search for modules]) PYTHON3_SYSPATH_REPORT="`${PYTHON3} -c 'import sys; print(sys.path);'`" \ || PYTHON3_SYSPATH_REPORT="" AC_MSG_RESULT([${PYTHON3_SYSPATH_REPORT}]) export PYTHON3 AC_CACHE_CHECK([python3 site-packages location], [nut_cv_PYTHON3_SITE_PACKAGES], [ dnl sysconfig introduced in python3.2 AS_IF([test x"`${PYTHON3} -c 'import sys; print (sys.version_info >= (3, 2))'`" = xTrue], [nut_cv_PYTHON3_SITE_PACKAGES="`${PYTHON3} -c 'import sysconfig; print(sysconfig.get_path("purelib"))'`"], [nut_cv_PYTHON3_SITE_PACKAGES="`${PYTHON3} -c 'import site; print(site.getsitepackages().pop(0))'`"]) AS_CASE(["$nut_cv_PYTHON3_SITE_PACKAGES"], [*:*], [ dnl Note: on Windows MSYS2 this embeds "C:/msys64/mingw..." into the string [nut#1584] nut_cv_PYTHON3_SITE_PACKAGES="`cd "$nut_cv_PYTHON3_SITE_PACKAGES" && pwd`" ] ) ]) ]) AC_SUBST([PYTHON3_SITE_PACKAGES], [${nut_cv_PYTHON3_SITE_PACKAGES}]) AM_CONDITIONAL([HAVE_PYTHON3_SITE_PACKAGES], [test x"${PYTHON3_SITE_PACKAGES}" != "x"]) ]) ]) nut-2.8.3/m4/nut_check_headers_windows.m40000644000200500020050000001546714777767434015300 00000000000000dnl This code was lifted and adapted for NUT from cURL project: dnl https://github.com/curl/curl/blob/83245d9ff352b742753cff1216781ff041e4e987/acinclude.m4#L172 dnl https://github.com/curl/curl/blob/83245d9ff352b742753cff1216781ff041e4e987/acinclude.m4#L207 dnl https://github.com/curl/curl/blob/83245d9ff352b742753cff1216781ff041e4e987/acinclude.m4#L238 dnl https://github.com/curl/curl/blob/83245d9ff352b742753cff1216781ff041e4e987/acinclude.m4#L275 dnl https://github.com/curl/curl/blob/83245d9ff352b742753cff1216781ff041e4e987/acinclude.m4#L312 dnl NUT_CHECK_HEADER_WINDOWS dnl ------------------------------------------------- dnl Check for compilable and valid windows.h header AC_DEFUN([NUT_CHECK_HEADER_WINDOWS], [ AC_CACHE_CHECK([for windows.h], [nut_cv_header_windows_h], [ AC_LANG_PUSH([C]) TESTPROG_H=' #undef inline #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include ' TESTPROG_C=' #if defined(__CYGWIN__) || defined(__CEGCC__) HAVE_WINDOWS_H shall not be defined. #else int dummy=2*WINVER; #endif ' AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([$TESTPROG_H], [$TESTPROG_C]) ],[ nut_cv_header_windows_h="yes" ],[ dnl Try extending default search path as relevant for e.g. MSYS2 dnl (though there this should be compiler built-in default): SAVED_CFLAGS="$CFLAGS" CFLAGS="-I/usr/include/w32api $CFLAGS" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([$TESTPROG_H], [$TESTPROG_C]) ],[ nut_cv_header_windows_h="yes" ],[ nut_cv_header_windows_h="no" CFLAGS="$SAVED_CFLAGS" ]) ]) AC_LANG_POP([C]) ]) case "$nut_cv_header_windows_h" in yes) AC_DEFINE_UNQUOTED(HAVE_WINDOWS_H, 1, [Define to 1 if you have the windows.h header file.]) ;; esac AM_CONDITIONAL(HAVE_WINDOWS_H, test "x$nut_cv_header_windows_h" = xyes) ]) dnl NUT_CHECK_NATIVE_WINDOWS dnl ------------------------------------------------- dnl Check if building a native Windows target AC_DEFUN([NUT_CHECK_NATIVE_WINDOWS], [ AC_REQUIRE([NUT_CHECK_HEADER_WINDOWS])dnl AC_CACHE_CHECK([whether build target is a native Windows one], [nut_cv_native_windows], [ if test "$nut_cv_header_windows_h" = "no"; then nut_cv_native_windows="no" else AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ ]],[[ #if defined(__MINGW32__) || defined(__MINGW32CE__) || \ (defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))) int dummy=1; #else Not a native Windows build target. #endif ]]) ],[ nut_cv_native_windows="yes" ],[ nut_cv_native_windows="no" ]) AC_LANG_POP([C]) fi ]) AM_CONDITIONAL(DOING_NATIVE_WINDOWS, test "x$nut_cv_native_windows" = xyes) ]) dnl NUT_CHECK_HEADER_WINSOCK dnl ------------------------------------------------- dnl Check for compilable and valid winsock.h header AC_DEFUN([NUT_CHECK_HEADER_WINSOCK], [ AC_REQUIRE([NUT_CHECK_HEADER_WINDOWS])dnl AC_CACHE_CHECK([for winsock.h], [nut_cv_header_winsock_h], [ AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #undef inline #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include ]],[[ #if defined(__CYGWIN__) || defined(__CEGCC__) HAVE_WINSOCK_H shall not be defined. #else int dummy=WSACleanup(); #endif ]]) ],[ nut_cv_header_winsock_h="yes" ],[ nut_cv_header_winsock_h="no" ]) AC_LANG_POP([C]) ]) case "$nut_cv_header_winsock_h" in yes) AC_DEFINE_UNQUOTED(HAVE_WINSOCK_H, 1, [Define to 1 if you have the winsock.h header file.]) ;; esac AM_CONDITIONAL(HAVE_WINSOCK_H, test "x$nut_cv_header_winsock_h" = xyes) ]) dnl NUT_CHECK_HEADER_WINSOCK2 dnl ------------------------------------------------- dnl Check for compilable and valid winsock2.h header AC_DEFUN([NUT_CHECK_HEADER_WINSOCK2], [ AC_REQUIRE([NUT_CHECK_HEADER_WINDOWS])dnl AC_CACHE_CHECK([for winsock2.h], [nut_cv_header_winsock2_h], [ AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #undef inline #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include ]],[[ #if defined(__CYGWIN__) || defined(__CEGCC__) || defined(__MINGW32CE__) HAVE_WINSOCK2_H shall not be defined. #else int dummy=2*IPPROTO_ESP; #endif ]]) ],[ nut_cv_header_winsock2_h="yes" ],[ nut_cv_header_winsock2_h="no" ]) AC_LANG_POP([C]) ]) case "$nut_cv_header_winsock2_h" in yes) AC_DEFINE_UNQUOTED(HAVE_WINSOCK2_H, 1, [Define to 1 if you have the winsock2.h header file.]) ;; esac AM_CONDITIONAL(HAVE_WINSOCK2_H, test "x$nut_cv_header_winsock2_h" = xyes) ]) dnl NUT_CHECK_HEADER_WS2TCPIP dnl ------------------------------------------------- dnl Check for compilable and valid ws2tcpip.h header AC_DEFUN([NUT_CHECK_HEADER_WS2TCPIP], [ AC_REQUIRE([NUT_CHECK_HEADER_WINSOCK2])dnl AC_CACHE_CHECK([for ws2tcpip.h], [nut_cv_header_ws2tcpip_h], [ AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #undef inline #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include ]],[[ #if defined(__CYGWIN__) || defined(__CEGCC__) || defined(__MINGW32CE__) HAVE_WS2TCPIP_H shall not be defined. #else int dummy=2*IP_PKTINFO; #endif ]]) ],[ nut_cv_header_ws2tcpip_h="yes" ],[ nut_cv_header_ws2tcpip_h="no" ]) AC_LANG_POP([C]) ]) case "$nut_cv_header_ws2tcpip_h" in yes) AC_DEFINE_UNQUOTED(HAVE_WS2TCPIP_H, 1, [Define to 1 if you have the ws2tcpip.h header file.]) ;; esac AM_CONDITIONAL(HAVE_WS2TCPIP_H, test "x$nut_cv_header_ws2tcpip_h" = xyes) ]) dnl NUT_CHECK_HEADER_IPHLPAPI dnl ------------------------------------------------- dnl Check for compilable and valid iphlpapi.h header AC_DEFUN([NUT_CHECK_HEADER_IPHLPAPI], [ AC_REQUIRE([NUT_CHECK_HEADER_WINSOCK2])dnl AC_CACHE_CHECK([for iphlpapi.h], [nut_cv_header_iphlpapi_h], [ AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #undef inline #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include ]],[[ PIP_ADAPTER_ADDRESSES pAddresses = NULL; IP_ADAPTER_PREFIX *pPrefix = NULL; PIP_ADAPTER_INFO pAdapter = NULL; ]]) ],[ nut_cv_header_iphlpapi_h="yes" ],[ nut_cv_header_iphlpapi_h="no" ]) AC_LANG_POP([C]) ]) AS_CASE([$nut_cv_header_iphlpapi_h], [yes], [ AC_DEFINE_UNQUOTED(HAVE_IPHLPAPI_H, 1, [Define to 1 if you have the iphlpapi.h header file.]) ] ) AM_CONDITIONAL(HAVE_IPHLPAPI_H, test "x$nut_cv_header_iphlpapi_h" = xyes) ]) nut-2.8.3/m4/nut_check_libsystemd.m40000644000200500020050000001174014777767434014260 00000000000000dnl Check for LIBSYSTEMD compiler flags. On success, set nut_have_libsystemd="yes" dnl and set LIBSYSTEMD_CFLAGS and LIBSYSTEMD_LIBS. On failure, set dnl nut_have_libsystemd="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBSYSTEMD], [ if test -z "${nut_have_libsystemd_seen}"; then nut_have_libsystemd_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" SYSTEMD_VERSION="none" AC_CHECK_TOOL(SYSTEMCTL, systemctl, none) AS_IF([test x"$have_PKG_CONFIG" = xyes], [dnl See which version of the systemd library (if any) is installed dnl FIXME : Support detection of cflags/ldflags below by legacy dnl discovery if pkgconfig is not there AC_MSG_CHECKING(for libsystemd version via pkg-config) SYSTEMD_VERSION="`$PKG_CONFIG --silence-errors --modversion libsystemd 2>/dev/null`" AS_IF([test "$?" != "0" -o -z "${SYSTEMD_VERSION}"], [ SYSTEMD_VERSION="none" ]) AC_MSG_RESULT(${SYSTEMD_VERSION} found) ] ) AS_IF([test x"${SYSTEMD_VERSION}" = xnone], [ AS_IF([test x"${SYSTEMCTL}" != xnone], [ AC_MSG_CHECKING(for libsystemd version via systemctl) dnl NOTE: Unlike the configure.ac file, in a "pure" dnl m4 script like this one, we have to escape the dnl dollar-number references (in awk below) lest they dnl get seen as m4 function positional parameters. SYSTEMD_VERSION="`LANG=C LC_ALL=C ${SYSTEMCTL} --version | grep -E '^systemd@<:@ \t@:>@*@<:@0-9@:>@@<:@0-9@:>@*' | awk '{print ''$''2}'`" \ && test -n "${SYSTEMD_VERSION}" \ || SYSTEMD_VERSION="none" AC_MSG_RESULT(${SYSTEMD_VERSION} found) ]) ] ) AS_IF([test x"${SYSTEMD_VERSION}" = xnone], [ AC_MSG_NOTICE([can not check libsystemd settings via pkg-config nor systemctl]) ]) AC_MSG_CHECKING(for libsystemd cflags) AC_ARG_WITH(libsystemd-includes, AS_HELP_STRING([@<:@--with-libsystemd-includes=CFLAGS@:>@], [include flags for the systemd library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-libsystemd-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], [ dnl Not specifying a default include path here, dnl headers are referenced by relative directory dnl and these should be in OS location usually. AS_IF([test x"$have_PKG_CONFIG" = xyes], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags libsystemd 2>/dev/null`" \ || depCFLAGS=""], [depCFLAGS=""] )] ) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for libsystemd ldflags) AC_ARG_WITH(libsystemd-libs, AS_HELP_STRING([@<:@--with-libsystemd-libs=LIBS@:>@], [linker flags for the systemd library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-libsystemd-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], [ AS_IF([test x"$have_PKG_CONFIG" = xyes], [depLIBS="`$PKG_CONFIG --silence-errors --libs libsystemd 2>/dev/null`" \ || depLIBS="-lsystemd"], [depLIBS="-lsystemd"] )] ) AC_MSG_RESULT([${depLIBS}]) dnl check if libsystemd is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(systemd/sd-daemon.h, [nut_have_libsystemd=yes], [nut_have_libsystemd=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(sd_notify, [], [nut_have_libsystemd=no]) nut_have_libsystemd_inhibitor=no AS_IF([test x"${nut_have_libsystemd}" = x"yes"], [ dnl Check for additional feature support in library (optional) AC_CHECK_FUNCS(sd_booted sd_watchdog_enabled sd_notify_barrier) LIBSYSTEMD_CFLAGS="${depCFLAGS}" LIBSYSTEMD_LIBS="${depLIBS}" dnl Since systemd 183: https://systemd.io/INHIBITOR_LOCKS/ dnl ...or 221: https://www.freedesktop.org/software/systemd/man/latest/sd_bus_call_method.html dnl and some bits even later (e.g. message container reading) AS_IF([test "$SYSTEMD_VERSION" -ge 221], [ nut_have_libsystemd_inhibitor=yes AC_CHECK_HEADERS(systemd/sd-bus.h, [], [nut_have_libsystemd_inhibitor=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS([sd_bus_call_method sd_bus_message_read_basic sd_bus_open_system sd_bus_default_system sd_bus_get_property_trivial], [], [nut_have_libsystemd_inhibitor=no]) dnl NOTE: In practice we use "p"-suffixed sd_bus_flush_close_unrefp dnl and sd_bus_message_unrefp methods prepared by a macro in sd-bus.h AC_CHECK_FUNCS([sd_bus_flush_close_unref sd_bus_message_unref sd_bus_error_free], [], [nut_have_libsystemd_inhibitor=no]) dnl Optional methods: nicer with them, can do without AC_CHECK_FUNCS([sd_bus_open_system_with_description sd_bus_set_description]) dnl For inhibitor per se, we do not have to read containers: dnl AC_CHECK_FUNCS([sd_bus_message_enter_container sd_bus_message_exit_container]) ]) AC_MSG_CHECKING(for libsystemd inhibitor interface support) AC_MSG_RESULT([${nut_have_libsystemd_inhibitor}]) ]) unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_check_libusb.m40000644000200500020050000004223714777767434013366 00000000000000dnl Check for LIBUSB 1.0 or 0.1 (and, if found, fill 'nut_usb_lib' with its dnl approximate version) and its compiler flags. On success, set dnl nut_have_libusb="yes" and set LIBUSB_CFLAGS and LIBUSB_LIBS. On failure, set dnl nut_have_libusb="no". This macro can be run multiple times, but will dnl do the checking only once. dnl By default, if both libusb 1.0 and libusb 0.1 are available and appear to be dnl usable, libusb 1.0 takes precedence. dnl An optional argument with value 'libusb-1.0' or 'libusb-0.1' can be used to dnl restrict checks to a specific version. AC_DEFUN([NUT_CHECK_LIBUSB], [ if test -z "${nut_have_libusb_seen}"; then nut_have_libusb_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl Our USB matching relies on regex abilities AC_REQUIRE([NUT_CHECK_LIBREGEX]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" dnl Magic-format string to hold chosen libusb version and its config-source nut_usb_lib="" dnl TOTHINK: What if there are more than 0.1 and 1.0 to juggle? dnl TODO? Add libusb-compat (1.0 code with 0.1's API) to the mix? AS_IF([test x"$have_PKG_CONFIG" = xyes], [AC_MSG_CHECKING([for libusb-1.0 version via pkg-config]) LIBUSB_1_0_VERSION="`$PKG_CONFIG --silence-errors --modversion libusb-1.0 2>/dev/null`" \ && test -n "${LIBUSB_1_0_VERSION}" \ || LIBUSB_1_0_VERSION="none" AC_MSG_RESULT([${LIBUSB_1_0_VERSION} found]) AC_MSG_CHECKING([for libusb(-0.1) version via pkg-config]) LIBUSB_0_1_VERSION="`$PKG_CONFIG --silence-errors --modversion libusb 2>/dev/null`" \ && test -n "${LIBUSB_0_1_VERSION}" \ || LIBUSB_0_1_VERSION="none" AC_MSG_RESULT([${LIBUSB_0_1_VERSION} found]) ], [LIBUSB_0_1_VERSION="none" LIBUSB_1_0_VERSION="none" AC_MSG_NOTICE([can not check libusb settings via pkg-config]) ] ) dnl Note: it seems the script was only shipped for libusb-0.1 dnl So we don't separate into LIBUSB_0_1_CONFIG and LIBUSB_1_0_CONFIG AC_PATH_PROGS([LIBUSB_CONFIG], [libusb-config], [none]) AC_ARG_WITH(libusb-config, AS_HELP_STRING([@<:@--with-libusb-config=/path/to/libusb-config@:>@], [path to program that reports LibUSB configuration]), dnl ...for LibUSB-0.1 [ AS_CASE(["${withval}"], [""], [], dnl empty arg [yes|no], [ dnl MAYBE bump preference of script over pkg-config? AC_MSG_ERROR([invalid option --with(out)-libusb-config - see docs/configure.txt]) ], [dnl default LIBUSB_CONFIG="${withval}" ] ) ] ) AS_IF([test x"${LIBUSB_CONFIG}" != xnone], [AC_MSG_CHECKING([via ${LIBUSB_CONFIG}]) LIBUSB_CONFIG_VERSION="`$LIBUSB_CONFIG --version 2>/dev/null`" \ && test -n "${LIBUSB_CONFIG_VERSION}" \ || LIBUSB_CONFIG_VERSION="none" AC_MSG_RESULT([${LIBUSB_CONFIG_VERSION} found]) ], [LIBUSB_CONFIG_VERSION="none"] ) dnl By default, prefer newest available, and if anything is known dnl to pkg-config, prefer that. Otherwise, fall back to script data: AS_IF([test x"${LIBUSB_1_0_VERSION}" != xnone], [LIBUSB_VERSION="${LIBUSB_1_0_VERSION}" nut_usb_lib="(libusb-1.0)" dnl ...except on Windows, where we support libusb-0.1(-compat) dnl better so far (allow manual specification though, to let dnl someone finally develop the on-par support), see also dnl https://github.com/networkupstools/nut/issues/1507 dnl Note this may upset detection of libmodbus RTU USB support. AS_IF([test x"${LIBUSB_0_1_VERSION}" != xnone], [ AS_CASE(["${target_os}"], [*mingw*], [ AS_IF([test x"$build" = x"$host"], [ AS_IF([test "${nut_with_modbus_and_usb}" = "yes"], [ AC_MSG_NOTICE(["Normally" mingw/MSYS2 native builds prefer libusb-0.1(-compat) over libusb-1.0 if both are available, but you requested --with-modbus+usb so preferring libusb-1.0 in this build]) ], [ AC_MSG_NOTICE([mingw/MSYS2 native builds prefer libusb-0.1(-compat) over libusb-1.0 if both are available until https://github.com/networkupstools/nut/issues/1507 is solved]) LIBUSB_VERSION="${LIBUSB_0_1_VERSION}" nut_usb_lib="(libusb-0.1)" ]) ],[ AC_MSG_NOTICE([mingw cross-builds prefer libusb-1.0 over libusb-0.1(-compat) if both are available]) ]) ]) ] ) ], [AS_IF([test x"${LIBUSB_0_1_VERSION}" != xnone], [LIBUSB_VERSION="${LIBUSB_0_1_VERSION}" nut_usb_lib="(libusb-0.1)" ], [LIBUSB_VERSION="${LIBUSB_CONFIG_VERSION}" AS_IF([test x"${LIBUSB_CONFIG_VERSION}" != xnone], [dnl TODO: This assumes 0.1; check for 1.0+ somehow? nut_usb_lib="(libusb-0.1-config)"], [nut_usb_lib=""] )] )] ) dnl Pick up the default or caller-provided choice here from dnl NUT_ARG_WITH(usb, ...) in the main configure.ac script AC_MSG_CHECKING([for libusb preferred version]) AS_CASE(["${nut_with_usb}"], [auto], [], dnl Use preference picked above [yes], [], dnl Use preference from above, fail in the end if none found [no], [], dnl Try to find, report in the end if that is discarded; TODO: not waste time? [libusb-1.0|1.0], [ dnl NOTE: Assuming there is no libusb-config-1.0 or similar script, never saw one AS_IF([test x"${LIBUSB_1_0_VERSION}" = xnone], [AC_MSG_ERROR([option --with-usb=${withval} was required, but this library version was not detected]) ]) LIBUSB_VERSION="${LIBUSB_1_0_VERSION}" nut_usb_lib="(libusb-1.0)" ], [libusb-0.1|0.1], [ AS_IF([test x"${LIBUSB_0_1_VERSION}" = xnone \ && test x"${LIBUSB_CONFIG_VERSION}" = xnone], [AC_MSG_ERROR([option --with-usb=${withval} was required, but this library version was not detected]) ]) AS_IF([test x"${LIBUSB_0_1_VERSION}" != xnone], [LIBUSB_VERSION="${LIBUSB_0_1_VERSION}" nut_usb_lib="(libusb-0.1)" ], [LIBUSB_VERSION="${LIBUSB_CONFIG_VERSION}" nut_usb_lib="(libusb-0.1-config)" ]) ], [dnl default AC_MSG_ERROR([invalid option value --with-usb=${withval} - see docs/configure.txt]) ] ) AC_MSG_RESULT([${LIBUSB_VERSION} ${nut_usb_lib}]) AS_IF([test x"${LIBUSB_1_0_VERSION}" != xnone && test x"${nut_usb_lib}" != x"(libusb-1.0)" ], [AC_MSG_NOTICE([libusb-1.0 support was detected, but another was chosen ${nut_usb_lib}])] ) dnl FIXME? Detect and report all CFLAGS/LIBS that we can, dnl and *then* pick one set of values to use? AS_CASE([${nut_usb_lib}], ["(libusb-1.0)"], [ depCFLAGS="`$PKG_CONFIG --silence-errors --cflags libusb-1.0 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs libusb-1.0 2>/dev/null`" ], ["(libusb-0.1)"], [ depCFLAGS="`$PKG_CONFIG --silence-errors --cflags libusb 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs libusb 2>/dev/null`" ], ["(libusb-0.1-config)"], [ depCFLAGS="`$LIBUSB_CONFIG --cflags 2>/dev/null`" depLIBS="`$LIBUSB_CONFIG --libs 2>/dev/null`" ], [dnl default, for other versions or "none" AC_MSG_WARN([Defaulting libusb configuration]) LIBUSB_VERSION="none" depCFLAGS="" depLIBS="-lusb" ] ) dnl check optional user-provided values for cflags/ldflags dnl and publish what we end up using AC_MSG_CHECKING(for libusb cflags) AC_ARG_WITH(usb-includes, AS_HELP_STRING([@<:@--with-usb-includes=CFLAGS@:>@], [include flags for the libusb library]), [ AS_CASE(["${withval}"], [yes|no], [ AC_MSG_ERROR(invalid option --with(out)-usb-includes - see docs/configure.txt) ], [dnl default depCFLAGS="${withval}" ] ) ], []) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for libusb ldflags) AC_ARG_WITH(usb-libs, AS_HELP_STRING([@<:@--with-usb-libs=LIBS@:>@], [linker flags for the libusb library]), [ AS_CASE(["${withval}"], [yes|no], [ AC_MSG_ERROR(invalid option --with(out)-usb-libs - see docs/configure.txt) ], [dnl default depLIBS="${withval}" ] ) ], []) AC_MSG_RESULT([${depLIBS}]) dnl TODO: Consult chosen nut_usb_lib value and/or nut_with_usb argument dnl (with "auto" we may use a 0.1 if present and working while a 1.0 is dnl present but useless) dnl Check if libusb is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_LANG_PUSH([C]) if test -n "${LIBUSB_VERSION}"; then dnl Test specifically for libusb-1.0 via pkg-config, else fall back below test -n "$PKG_CONFIG" \ && test x"${nut_usb_lib}" = x"(libusb-1.0)" \ && $PKG_CONFIG --silence-errors --atleast-version=1.0 libusb-1.0 2>/dev/null if test "$?" = "0"; then dnl libusb 1.0: libusb_set_auto_detach_kernel_driver AC_CHECK_HEADERS(libusb.h, [nut_have_libusb=yes], [nut_have_libusb=no], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(libusb_init, [], [nut_have_libusb=no]) AC_CHECK_FUNCS(libusb_strerror, [], [nut_have_libusb=no; nut_have_libusb_strerror=no]) if test "${nut_have_libusb_strerror}" = "no"; then AC_MSG_WARN([libusb_strerror() not found; install libusbx to use libusb 1.0 API. See https://github.com/networkupstools/nut/issues/509]) fi if test "${nut_have_libusb}" = "yes"; then dnl This function is fairly old, but check for it anyway: AC_CHECK_FUNCS(libusb_kernel_driver_active) dnl Check for libusb "force driver unbind" availability AC_CHECK_FUNCS(libusb_set_auto_detach_kernel_driver) dnl libusb 1.0: libusb_detach_kernel_driver dnl FreeBSD 10.1-10.3 have this, but not libusb_set_auto_detach_kernel_driver AC_CHECK_FUNCS(libusb_detach_kernel_driver) AC_CHECK_FUNCS(libusb_detach_kernel_driver_np) dnl From libusb-0.1 - check these to have valid config.h definitions dnl Note: confusingly, FreeBSD does find both as defined dnl (despite being spread across usb.h and libusb.h), dnl so our source code has to care :\ AC_CHECK_FUNCS(usb_detach_kernel_driver_np) fi else dnl libusb 0.1, or missing pkg-config : AC_CHECK_HEADERS(usb.h, [nut_have_libusb=yes], [ nut_have_libusb=no dnl Per https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/ dnl this project (used among alternatives in MSYS2/MinGW builds) dnl uses a different include filename to avoid conflict with dnl a WDK header: AS_CASE(["${target_os}"], [*mingw*], [ AC_MSG_NOTICE([try alternate header name for mingw builds with libusb-win32]) AC_CHECK_HEADERS(lusb0_usb.h, [ nut_usb_lib="(libusb-0.1)" nut_have_libusb=yes ], [], [AC_INCLUDES_DEFAULT]) ]) ], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(usb_init, [], [ dnl Some systems may just have libusb in their standard dnl paths, but not the pkg-config or libusb-config data AS_IF([test "${nut_have_libusb}" = "yes" && test "$LIBUSB_VERSION" = "none" && test -z "$LIBS" -o x"$LIBS" = x"-lusb" ], [AC_MSG_CHECKING([if libusb is just present in path]) depLIBS="-L/usr/lib -L/usr/local/lib -lusb" dnl TODO: Detect bitness for trying /mingw32 or /usr/$ARCH as well? dnl This currently caters to mingw-w64-x86_64-libusb-win32 of MSYS2: AS_CASE(["${target_os}"], [*mingw*], [depLIBS="-L/mingw64/lib $depLIBS"]) unset ac_cv_func_usb_init || true LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_FUNCS(usb_init, [], [ AC_MSG_CHECKING([if libusb0 is just present in path]) depLIBS="$depLIBS"0 unset ac_cv_func_usb_init || true LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_FUNCS(usb_init, [nut_usb_lib="(libusb-0.1)"], [nut_have_libusb=no]) ]) AC_MSG_RESULT([${nut_have_libusb}]) ], [nut_have_libusb=no] )] ) dnl Check for libusb "force driver unbind" availability if test "${nut_have_libusb}" = "yes"; then AC_CHECK_FUNCS(usb_detach_kernel_driver_np) dnl From libusb-1.0 - check these to have valid config.h definitions AC_CHECK_FUNCS(libusb_kernel_driver_active) AC_CHECK_FUNCS(libusb_set_auto_detach_kernel_driver) AC_CHECK_FUNCS(libusb_detach_kernel_driver) AC_CHECK_FUNCS(libusb_detach_kernel_driver_np) fi fi else nut_have_libusb=no fi nut_with_usb_busport=no AS_IF([test "${nut_have_libusb}" = "yes"], [ dnl ---------------------------------------------------------------------- dnl additional USB-related checks dnl Solaris 10/11 USB handling (need librt and libusb runtime path) dnl Should we check for `uname -o == illumos` to avoid legacy here? dnl Or better yet, perform some active capability tests for need of dnl workarounds or not? e.g. OpenIndiana should include a capable dnl version of libusb-1.0.23+ tailored with NUT tests in mind... dnl HPUX, since v11, needs an explicit activation of pthreads dnl TODO: There are reports about FreeBSD error-code dnl handling in libusb-0.1 port returning "-1" always, dnl instead of differing codes like on other systems. dnl Should we check for that below?.. dnl https://github.com/networkupstools/nut/issues/490 AS_CASE(["${target_os}"], [solaris2.1*], [ AC_MSG_CHECKING([for Solaris 10 / 11 specific configuration for usb drivers]) AC_SEARCH_LIBS(nanosleep, rt) dnl Collect possibly updated dependencies after AC SEARCH LIBS: AS_IF([test x"${LIBS}" != x"${LIBS_ORIG} ${depLIBS}"], [ AS_IF([test x = x"${LIBS_ORIG}"], [depLIBS="$LIBS"], [ depLIBS="`echo "$LIBS" | sed -e 's|'"${LIBS_ORIG}"'| |' -e 's|^ *||' -e 's| *$||'`" ]) ]) depLIBS="-R/usr/sfw/lib ${depLIBS}" dnl FIXME: Sun's libusb doesn't support timeout (so blocks notification) dnl and need to call libusb close upon reconnection dnl TODO: Somehow test for susceptible versions? AC_DEFINE(SUN_LIBUSB, 1, [Define to 1 for Sun version of the libusb.]) SUN_LIBUSB=1 AC_MSG_RESULT([${depLIBS}]) ], [hpux11*], [ depCFLAGS="${depCFLAGS} -lpthread" ] ) CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" dnl AC_MSG_CHECKING([for libusb bus port support]) dnl Per https://github.com/networkupstools/nut/issues/2043#issuecomment-1721856494 : dnl #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102) dnl DEFINE WITH_USB_BUSPORT dnl #endif AC_CHECK_FUNCS(libusb_get_port_number, [nut_with_usb_busport=yes]) ]) AC_LANG_POP([C]) AS_IF([test x"${nut_with_usb_busport}" = xyes], [ AC_DEFINE(WITH_USB_BUSPORT, 1, [Define to 1 for libusb versions where we can support "busport" USB matching value.]) ], [ AC_DEFINE(WITH_USB_BUSPORT, 0, [Define to 1 for libusb versions where we can support "busport" USB matching value.]) ]) AS_IF([test "${nut_have_libusb}" = "yes"], [ LIBUSB_CFLAGS="${depCFLAGS}" LIBUSB_LIBS="${depLIBS}" ], [ AS_CASE(["${nut_with_usb}"], [no|auto], [], [yes|1.0|0.1|libusb-1.0|libusb-0.1], [dnl Explicitly choosing a library implies 'yes' (i.e. fail if not found), not 'auto'. AC_MSG_ERROR([USB drivers requested, but libusb not found.]) ] ) ]) if test "${nut_with_usb}" = "no"; then if test -n "${nut_usb_lib}" && test "${nut_usb_lib}" != none ; then AC_MSG_NOTICE([libusb was detected ${nut_usb_lib}, but a build without USB drivers was requested]) fi nut_usb_lib="" else nut_with_usb="${nut_have_libusb}" fi AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_have_libusb='${nut_have_libusb}']) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_usb='${nut_with_usb}']) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_usb_lib='${nut_usb_lib}']) ]) dnl Note: AC_DEFINE specifies a verbatim "value" so we pre-calculate it! dnl Source code should be careful to use "#if" and not "#ifdef" when dnl checking these values during the build. And both must be defined dnl with some value. AS_IF([test "${nut_with_usb}" = "yes" && test "${nut_usb_lib}" = "(libusb-1.0)"], [AC_DEFINE([WITH_LIBUSB_1_0], [1], [Define to 1 for version 1.0 of the libusb (via pkg-config).]) dnl Help ltdl if we can (nut-scanner etc.) for TOKEN in $depLIBS ; do AS_CASE(["${TOKEN}"], [-l*usb*], [ AX_REALPATH_LIB([${TOKEN}], [SOPATH_LIBUSB1], []) AS_IF([test -n "${SOPATH_LIBUSB1}" && test -s "${SOPATH_LIBUSB1}"], [ AC_DEFINE_UNQUOTED([SOPATH_LIBUSB1],["${SOPATH_LIBUSB1}"],[Path to dynamic library on build system]) SOFILE_LIBUSB1="`basename "$SOPATH_LIBUSB1"`" AC_DEFINE_UNQUOTED([SOFILE_LIBUSB1],["${SOFILE_LIBUSB1}"],[Base file name of dynamic library on build system]) break ]) ] ) done unset TOKEN ], [AC_DEFINE([WITH_LIBUSB_1_0], [0], [Define to 1 for version 1.0 of the libusb (via pkg-config).])] ) AS_IF([test "${nut_with_usb}" = "yes" && test "${nut_usb_lib}" = "(libusb-0.1)" -o "${nut_usb_lib}" = "(libusb-0.1-config)"], [AC_DEFINE([WITH_LIBUSB_0_1], [1], [Define to 1 for version 0.1 of the libusb (via pkg-config or libusb-config).]) dnl Help ltdl if we can (nut-scanner etc.) for TOKEN in $depLIBS ; do AS_CASE(["${TOKEN}"], [-l*usb*], [ AX_REALPATH_LIB([${TOKEN}], [SOPATH_LIBUSB0], []) AS_IF([test -n "${SOPATH_LIBUSB0}" && test -s "${SOPATH_LIBUSB0}"], [ AC_DEFINE_UNQUOTED([SOPATH_LIBUSB0],["${SOPATH_LIBUSB0}"],[Path to dynamic library on build system]) SOFILE_LIBUSB0="`basename "$SOPATH_LIBUSB0"`" AC_DEFINE_UNQUOTED([SOFILE_LIBUSB0],["${SOFILE_LIBUSB0}"],[Base file name of dynamic library on build system]) break ]) ] ) done unset TOKEN ], [AC_DEFINE([WITH_LIBUSB_0_1], [0], [Define to 1 for version 0.1 of the libusb (via pkg-config or libusb-config).])] ) unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_check_libnetsnmp.m40000644000200500020050000003241114777767434014252 00000000000000dnl Check for LIBNETSNMP compiler flags. On success, set dnl nut_have_libnetsnmp="yes" and set LIBNETSNMP_CFLAGS and dnl LIBNETSNMP_LIBS. On failure, set nut_have_libnetsnmp="no". dnl This macro can be run multiple times, but will do the dnl checking only once. AC_DEFUN([NUT_CHECK_LIBNETSNMP], [ if test -z "${nut_have_libnetsnmp_seen}"; then nut_have_libnetsnmp_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) AC_LANG_PUSH([C]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" dnl We prefer to get info from pkg-config (for suitable arch/bitness as dnl specified in args for that mechanism), unless (legacy) a particular dnl --with-net-snmp-config=... was requested. If there is no pkg-config dnl info, we fall back to detecting and running a NET_SNMP_CONFIG as well. dnl By default seek in PATH, but which variant (if several are provided)? AC_CHECK_SIZEOF([void *]) NET_SNMP_CONFIG="none" AS_CASE(["${ac_cv_sizeof_void_p}"], [4],[AC_PATH_PROGS([NET_SNMP_CONFIG], [net-snmp-config-32 net-snmp-config], [none])], [8],[AC_PATH_PROGS([NET_SNMP_CONFIG], [net-snmp-config-64 net-snmp-config], [none])], [AC_PATH_PROGS([NET_SNMP_CONFIG], [net-snmp-config], [none])] ) prefer_NET_SNMP_CONFIG=false AC_ARG_WITH(net-snmp-config, AS_HELP_STRING([@<:@--with-net-snmp-config=/path/to/net-snmp-config@:>@], [path to program that reports Net-SNMP configuration]), [ case "${withval}" in ""|yes) prefer_NET_SNMP_CONFIG=true ;; no) dnl AC_MSG_ERROR(invalid option --with(out)-net-snmp-config - see docs/configure.txt) prefer_NET_SNMP_CONFIG=false ;; *) NET_SNMP_CONFIG="${withval}" prefer_NET_SNMP_CONFIG=true ;; esac ]) if test x"$have_PKG_CONFIG" = xyes && ! "${prefer_NET_SNMP_CONFIG}" ; then AC_MSG_CHECKING(for Net-SNMP version via pkg-config) dnl TODO? Loop over possible/historic pkg names, like dnl netsnmp, net-snmp, ucd-snmp, libsnmp, snmp... SNMP_VERSION="`$PKG_CONFIG --silence-errors --modversion netsnmp 2>/dev/null`" if test "$?" = "0" -a -n "${SNMP_VERSION}" ; then AC_MSG_RESULT(${SNMP_VERSION} found) else AC_MSG_RESULT(none found) prefer_NET_SNMP_CONFIG=true fi fi if test "$NET_SNMP_CONFIG" = none ; then prefer_NET_SNMP_CONFIG=false fi if "${prefer_NET_SNMP_CONFIG}" ; then dnl See which version of the Net-SNMP library (if any) is installed AC_MSG_CHECKING(for Net-SNMP version via ${NET_SNMP_CONFIG}) SNMP_VERSION="`${NET_SNMP_CONFIG} --version 2>/dev/null`" if test "$?" != "0" -o -z "${SNMP_VERSION}"; then SNMP_VERSION="none" prefer_NET_SNMP_CONFIG=false fi AC_MSG_RESULT(${SNMP_VERSION} found) fi if test x"$have_PKG_CONFIG" != xyes && ! "${prefer_NET_SNMP_CONFIG}" ; then AC_MSG_WARN([did not find either net-snmp-config or pkg-config for net-snmp]) fi depCFLAGS_SOURCE="" AC_MSG_CHECKING(for Net-SNMP cflags) AC_ARG_WITH(snmp-includes, AS_HELP_STRING([@<:@--with-snmp-includes=CFLAGS@:>@], [include flags for the Net-SNMP library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-snmp-includes - see docs/configure.txt) ;; *) depCFLAGS_SOURCE="confarg" depCFLAGS="${withval}" ;; esac ], [AS_IF(["${prefer_NET_SNMP_CONFIG}"], [depCFLAGS="`${NET_SNMP_CONFIG} --base-cflags 2>/dev/null`" depCFLAGS_SOURCE="netsnmp-config"], [AS_IF([test x"$have_PKG_CONFIG" = xyes], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags netsnmp 2>/dev/null`" depCFLAGS_SOURCE="pkg-config"], [depCFLAGS_SOURCE="default"] )] )] ) AC_MSG_RESULT([${depCFLAGS} (source: ${depCFLAGS_SOURCE})]) depLIBS_SOURCE="" AC_MSG_CHECKING(for Net-SNMP libs) AC_ARG_WITH(snmp-libs, AS_HELP_STRING([@<:@--with-snmp-libs=LIBS@:>@], [linker flags for the Net-SNMP library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-snmp-libs - see docs/configure.txt) ;; *) depLIBS_SOURCE="confarg" depLIBS="${withval}" ;; esac ], [AS_IF(["${prefer_NET_SNMP_CONFIG}"], [depLIBS="`${NET_SNMP_CONFIG} --libs 2>/dev/null`" depLIBS_SOURCE="netsnmp-config"], [AS_IF([test x"$have_PKG_CONFIG" = xyes], [depLIBS="`$PKG_CONFIG --silence-errors --libs netsnmp 2>/dev/null`" depLIBS_SOURCE="pkg-config"], [depLIBS="-lnetsnmp" depLIBS_SOURCE="default"])] )] ) AC_MSG_RESULT([${depLIBS} (source: ${depLIBS_SOURCE})]) dnl Check if the Net-SNMP library is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" nut_have_libnetsnmp_static=no nut_have_libnetsnmp=no AC_CHECK_HEADERS([net-snmp/net-snmp-config.h], dnl The second header requires the first to be included [AC_CHECK_HEADERS([net-snmp/net-snmp-includes.h], [nut_have_libnetsnmp=yes], [], [AC_INCLUDES_DEFAULT #include ]) ], [], [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS(init_snmp, [], [ dnl Probably is dysfunctional, except one case... nut_have_libnetsnmp=no AS_IF([test x"$depLIBS_SOURCE" = x"pkg-config"], [ AS_CASE(["${target_os}"], [*mingw*], [ AC_MSG_NOTICE([mingw builds of net-snmp might provide only a static library - retrying for that]) depLIBS="`$PKG_CONFIG --silence-errors --libs --static netsnmp 2>/dev/null`" dnl # Some workarouds here, to avoid libtool bailing out like this: dnl # *** Warning: This system cannot link to static lib archive /usr/x86_64-w64-mingw32/lib//libnetsnmp.la. dnl # *** I have the capability to make that library automatically link in when dnl # *** you link to this library. But I can only do this if you have a dnl # *** shared version of the library, which you do not appear to have. dnl # In Makefiles be sure to use _LDFLAGS (not _LIBADD) to smuggle linker dnl # arguments when building "if WITH_SNMP_STATIC" recipe blocks! dnl # For a practical example, see tools/nut-scanner/Makefile.am. depLIBS="`echo " $depLIBS" | sed 's/ -l/ -Wl,-l/g'`" LIBS="${LIBS_ORIG} ${depLIBS}" AS_UNSET([ac_cv_func_init_snmp]) AC_CHECK_FUNCS(init_snmp, [ nut_have_libnetsnmp=yes nut_have_libnetsnmp_static=yes ]) ] ) ]) ]) AS_UNSET([depLIBS_SOURCE]) AS_UNSET([depCFLAGS_SOURCE]) AS_IF([test "${nut_have_libnetsnmp}" = "yes"], [ LIBNETSNMP_CFLAGS="${depCFLAGS}" LIBNETSNMP_LIBS="${depLIBS}" AC_MSG_CHECKING([for defined usmAESPrivProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmAESPrivProtocol; ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmAES128PrivProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmAES128PrivProtocol; ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmAES128PrivProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmAES128PrivProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmDESPrivProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmDESPrivProtocol; #ifdef NETSNMP_DISABLE_DES #error "NETSNMP_DISABLE_DES is defined" #endif ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmDESPrivProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmDESPrivProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmHMAC256SHA384AuthProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmHMAC256SHA384AuthProtocol; #ifndef HAVE_EVP_SHA384 #error "HAVE_EVP_SHA384 is NOT defined" #endif ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMAC256SHA384AuthProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMAC256SHA384AuthProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmHMAC384SHA512AuthProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmHMAC384SHA512AuthProtocol; #ifndef HAVE_EVP_SHA384 #error "HAVE_EVP_SHA384 is NOT defined" #endif ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmHMAC192SHA256AuthProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmHMAC192SHA256AuthProtocol; #ifndef HAVE_EVP_SHA224 #error "HAVE_EVP_SHA224 is NOT defined" #endif ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMAC192SHA256AuthProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMAC192SHA256AuthProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmAES192PrivProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmAES192PrivProtocol; #ifndef NETSNMP_DRAFT_BLUMENTHAL_AES_04 #error "NETSNMP_DRAFT_BLUMENTHAL_AES_04 is NOT defined" #endif ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmAES192PrivProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmAES192PrivProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmAES256PrivProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmAES256PrivProtocol; #ifndef NETSNMP_DRAFT_BLUMENTHAL_AES_04 #error "NETSNMP_DRAFT_BLUMENTHAL_AES_04 is NOT defined" #endif ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmAES256PrivProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmAES256PrivProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmHMACMD5AuthProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmHMACMD5AuthProtocol; #ifdef NETSNMP_DISABLE_MD5 #error "NETSNMP_DISABLE_MD5 is defined" #endif ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMACMD5AuthProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMACMD5AuthProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined usmHMACSHA1AuthProtocol]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include oid * pProto = usmHMACSHA1AuthProtocol; ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMACSHA1AuthProtocol, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_usmHMACSHA1AuthProtocol, 0, [Variable or macro by this name is not resolvable]) ]) AC_MSG_CHECKING([for defined NETSNMP_DRAFT_BLUMENTHAL_AES_04]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include int num = NETSNMP_DRAFT_BLUMENTHAL_AES_04 + 1; /* if defined, NETSNMP_DRAFT_BLUMENTHAL_AES_04 is 1 */ ], [] )], [AC_MSG_RESULT([yes]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04, 1, [Variable or macro by this name is resolvable]) ], [AC_MSG_RESULT([no]) AC_DEFINE_UNQUOTED(NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04, 0, [Variable or macro by this name is not resolvable]) ]) dnl Help ltdl if we can (nut-scanner etc.) for TOKEN in $depLIBS ; do AS_CASE(["${TOKEN}"], [-l*snmp*], [ AX_REALPATH_LIB([${TOKEN}], [SOPATH_LIBNETSNMP], []) AS_IF([test -n "${SOPATH_LIBNETSNMP}" && test -s "${SOPATH_LIBNETSNMP}"], [ AC_DEFINE_UNQUOTED([SOPATH_LIBNETSNMP],["${SOPATH_LIBNETSNMP}"],[Path to dynamic library on build system]) SOFILE_LIBNETSNMP="`basename "$SOPATH_LIBNETSNMP"`" AC_DEFINE_UNQUOTED([SOFILE_LIBNETSNMP],["${SOFILE_LIBNETSNMP}"],[Base file name of dynamic library on build system]) break ]) ] ) done unset TOKEN ]) AC_LANG_POP([C]) unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/ltsugar.m40000644000200500020050000001044015001555004011474 00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59, which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) nut-2.8.3/m4/nut_check_libltdl.m40000644000200500020050000000607714777767434013536 00000000000000dnl Check for LIBLTDL compiler flags. On success, set nut_have_libltdl="yes" dnl and set LIBLTDL_CFLAGS and LIBLTDL_LIBS. On failure, set dnl nut_have_libltdl="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBLTDL], [ if test -z "${nut_have_libltdl_seen}"; then nut_have_libltdl_seen=yes dnl No NUT_CHECK_PKGCONFIG here: (lib)ltdl.pc was not seen on any OS dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" LIBS="" CFLAGS="" depLIBS="" depCFLAGS="" dnl For fallback below: myCFLAGS="" AC_MSG_CHECKING(for libltdl cflags) AC_ARG_WITH(libltdl-includes, AS_HELP_STRING([@<:@--with-libltdl-includes=CFLAGS@:>@], [include flags for the libltdl library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-libltdl-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], [dnl Best-Effort Fallback (LDFLAGS might make more sense for -L..., dnl but other m4's have it so) to use if probe below fails: myCFLAGS="-I/usr/local/include -I/usr/include -L/usr/local/lib -L/usr/lib" ]) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for libltdl ldflags) AC_ARG_WITH(libltdl-libs, AS_HELP_STRING([@<:@--with-libltdl-libs=LIBS@:>@], [linker flags for the libltdl library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-libltdl-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], [])dnl No fallback here - we probe suitable libs below AC_MSG_RESULT([${depLIBS}]) CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(ltdl.h, [nut_have_libltdl=yes], [ dnl Double-check if we stashed include paths to try above AS_IF([test -n "$myCFLAGS"], [ depCFLAGS="$myCFLAGS" AS_UNSET([ac_cv_header_ltdl_h]) CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" AC_CHECK_HEADERS(ltdl.h, [nut_have_libltdl=yes], [nut_have_libltdl=no], [AC_INCLUDES_DEFAULT]) ],[nut_have_libltdl=no] )], [AC_INCLUDES_DEFAULT]) AS_IF([test x"$nut_have_libltdl" = xyes], [ dnl ltdl-number may help find it for MingW DLLs naming AC_SEARCH_LIBS(lt_dlinit, ltdl ltdl-7, [], [ nut_have_libltdl=no AS_IF([test -n "$myCFLAGS" -a x"$myCFLAGS" != x"$CFLAGS"], [ depCFLAGS="$myCFLAGS" dnl No ltdl-7 here, this codepath is unlikely on Windows where that matters: CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" unset ac_cv_search_lt_dlinit AC_SEARCH_LIBS(lt_dlinit, ltdl, [nut_have_libltdl=yes], []) ]) ]) ]) dnl Collect possibly updated dependencies after AC SEARCH LIBS: AS_IF([test x"${LIBS}" != x"${LIBS_ORIG} ${depLIBS}"], [ AS_IF([test x = x"${LIBS_ORIG}"], [depLIBS="$LIBS"], [ depLIBS="`echo "$LIBS" | sed -e 's|'"${LIBS_ORIG}"'| |' -e 's|^ *||' -e 's| *$||'`" ]) ]) AS_IF([test "${nut_have_libltdl}" = "yes"], [ AC_DEFINE(HAVE_LIBLTDL, 1, [Define to enable libltdl support]) LIBLTDL_CFLAGS="${depCFLAGS}" LIBLTDL_LIBS="${depLIBS}" ]) unset myCFLAGS unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_check_libmodbus.m40000644000200500020050000002441215001552635014031 00000000000000dnl Check for LIBMODBUS compiler flags. On success, set nut_have_libmodbus="yes" dnl and set LIBMODBUS_CFLAGS and LIBMODBUS_LIBS. On failure, set dnl nut_have_libmodbus="no". This macro can be run multiple times, but will dnl do the checking only once. AC_DEFUN([NUT_CHECK_LIBMODBUS], [ if test -z "${nut_have_libmodbus_seen}"; then nut_have_libmodbus_seen=yes AC_REQUIRE([NUT_CHECK_PKGCONFIG]) dnl save CFLAGS and LIBS CFLAGS_ORIG="${CFLAGS}" LIBS_ORIG="${LIBS}" CFLAGS="" LIBS="" depCFLAGS="" depLIBS="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [AC_MSG_CHECKING(for libmodbus version via pkg-config) LIBMODBUS_VERSION="`$PKG_CONFIG --silence-errors --modversion libmodbus 2>/dev/null`" if test "$?" != "0" -o -z "${LIBMODBUS_VERSION}"; then LIBMODBUS_VERSION="none" fi AC_MSG_RESULT(${LIBMODBUS_VERSION} found) ], [LIBMODBUS_VERSION="none" AC_MSG_NOTICE([can not check libmodbus settings via pkg-config]) ] ) AS_IF([test x"$LIBMODBUS_VERSION" != xnone], [depCFLAGS="`$PKG_CONFIG --silence-errors --cflags libmodbus 2>/dev/null`" depLIBS="`$PKG_CONFIG --silence-errors --libs libmodbus 2>/dev/null`" ], [depCFLAGS="-I/usr/include/modbus" depLIBS="-lmodbus" ] ) AC_MSG_CHECKING(for libmodbus cflags) AC_ARG_WITH(modbus-includes, AS_HELP_STRING([@<:@--with-modbus-includes=CFLAGS@:>@], [include flags for the libmodbus library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-modbus-includes - see docs/configure.txt) ;; *) depCFLAGS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depCFLAGS}]) AC_MSG_CHECKING(for libmodbus ldflags) AC_ARG_WITH(modbus-libs, AS_HELP_STRING([@<:@--with-modbus-libs=LIBS@:>@], [linker flags for the libmodbus library]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-modbus-libs - see docs/configure.txt) ;; *) depLIBS="${withval}" ;; esac ], []) AC_MSG_RESULT([${depLIBS}]) dnl check if libmodbus is usable CFLAGS="${CFLAGS_ORIG} ${depCFLAGS}" LIBS="${LIBS_ORIG} ${depLIBS}" AC_CHECK_HEADERS(modbus.h, [nut_have_libmodbus=yes], [nut_have_libmodbus=no], [AC_INCLUDES_DEFAULT]) AS_IF([test x"${nut_have_libmodbus}" = xyes ], [ AC_CHECK_FUNCS(modbus_new_tcp, [], [ nut_have_libmodbus=no AC_REQUIRE([NUT_CHECK_SOCKETLIB]) AS_IF([test x"${NETLIBS-}" != x], [ AC_MSG_NOTICE([Retry detection of libmodbus TCP support with NETLIBS]) unset ac_cv_func_modbus_new_tcp LIBS="${LIBS} ${NETLIBS}" AC_CHECK_FUNCS(modbus_new_tcp, [ nut_have_libmodbus=yes depLIBS="${depLIBS} ${NETLIBS}" ], [ AS_IF([test x"${NETLIBS_GETADDRS-}" != x], [ AC_MSG_NOTICE([Retry detection of libmodbus TCP support with NETLIBS and NETLIBS_GETADDRS]) unset ac_cv_func_modbus_new_tcp LIBS="${LIBS} ${NETLIBS_GETADDRS}" AC_CHECK_FUNCS(modbus_new_tcp, [ nut_have_libmodbus=yes depLIBS="${depLIBS} ${NETLIBS} ${NETLIBS_GETADDRS}" ], [nut_have_libmodbus=no]) ]) ]) ]) ]) ]) AS_IF([test x"${nut_have_libmodbus}" = xyes ], [ AC_CHECK_FUNCS(modbus_new_rtu, [], [nut_have_libmodbus=no]) AC_CHECK_FUNCS(modbus_set_byte_timeout, [], [nut_have_libmodbus=no]) AC_CHECK_FUNCS(modbus_set_response_timeout, [], [nut_have_libmodbus=no]) ]) AS_IF([test x"${nut_have_libmodbus}" = xyes ], [ AC_CHECK_FUNCS(modbus_new_rtu_usb, [nut_have_libmodbus_usb=yes], [ nut_have_libmodbus_usb=no AS_IF([test x"${nut_with_usb}" != xno && test x"${nut_with_modbus}" != xno && test x"${nut_have_libmodbus}" = xyes ], [ dnl Retry with LibUSB dependency settings if we dnl know we are not opposed to pulling it in. dnl Static libmodbus builds do not refer to dnl (shared) libusb for example. dnl NOTE: Currently libusb-1.0 is required by dnl libmodbus with rtu_usb additions. By our dnl default, mingw/MSYS2 native builds prefer dnl libusb-0.1(-compat) over libusb-1.0 if dnl both are available - see nut_check_libusb.m4 AC_REQUIRE([NUT_CHECK_LIBUSB]) AC_MSG_NOTICE([Retry detection of libmodbus USB support (may require libusb-1.0 specifically)]) CFLAGS="$CFLAGS $LIBUSB_CFLAGS" LIBS="$LIBS $LIBUSB_LIBS" unset ac_cv_func_modbus_new_rtu_usb AC_CHECK_FUNCS(modbus_new_rtu_usb, [ nut_have_libmodbus_usb=yes depCFLAGS="${depCFLAGS} ${LIBUSB_CFLAGS}" depLIBS="${depLIBS} ${LIBUSB_LIBS}" ], [ AS_IF([test x"${nut_with_usb}" = xyes && test x"${nut_with_modbus}" = xyes && test x"${nut_have_libmodbus}" = xyes ], [ AC_MSG_WARN([Both --with-modbus and --with-usb were requested, and a libmodbus was found, but it seems to not support USB. You may require a custom build per https://github.com/networkupstools/nut/wiki/APC-UPS-with-Modbus-protocol]) ]) ]) ]) ]) ], [ nut_have_libmodbus_usb=no ]) dnl modbus_set_byte_timeout() and modbus_set_response_timeout() dnl in 3.0.x and 3.1.x have different args (since ~2013): the dnl older version used to accept timeout as a struct timeval dnl instead of seconds and microseconds. Detect which we use?.. AS_IF([test x"$nut_have_libmodbus" = xyes], [dnl Do not rely on versions if we can test actual API AX_C_PRAGMAS AC_LANG_PUSH([C]) AC_CACHE_CHECK([types of arguments for modbus_set_byte_timeout], [nut_cv_func_modbus_set_byte_timeout_args], [nut_cv_func_modbus_set_byte_timeout_args="unknown" AC_COMPILE_IFELSE( [dnl Try purely the old API (timeval) AC_LANG_PROGRAM([ #include #include ], [modbus_t *ctx; struct timeval to = (struct timeval){0}; modbus_set_byte_timeout(ctx, &to);]) ], [nut_cv_func_modbus_set_byte_timeout_args="timeval" dnl Try the old API in more detail: check dnl if we can just assign uint32's for new dnl code into timeval fields (exist+numeric)? AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([ #include #include #include ], [modbus_t *ctx; uint32_t to_sec = 10, to_usec = 50; struct timeval to = (struct timeval){0}; /* TODO: Clarify and detect warning names and * so pragmas for signed/unsigned assignment (e.g. * for timeval definitions that have "long" fields) */ #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_COMPARE # pragma GCC diagnostic ignored "-Wsign-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_CONVERSION # pragma GCC diagnostic ignored "-Wsign-conversion" #endif to.tv_sec = to_sec; to.tv_usec = to_usec; modbus_set_byte_timeout(ctx, &to); ]) ], [nut_cv_func_modbus_set_byte_timeout_args="timeval_numeric_fields"]) ], [dnl Try another API variant: new API with dnl fields of struct timeval as numbers dnl (checks they exist, and are compatible dnl numeric types so compiler can convert) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([ #include #include #include ], [modbus_t *ctx; struct timeval to = (struct timeval){0}; /* TODO: Clarify and detect warning names and * so pragmas for signed/unsigned assignment (e.g. * for timeval definitions that have "long" fields) */ #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_COMPARE # pragma GCC diagnostic ignored "-Wsign-compare" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_CONVERSION # pragma GCC diagnostic ignored "-Wsign-conversion" #endif uint32_t to_sec = to.tv_sec, to_usec = to.tv_usec; modbus_set_byte_timeout(ctx, to_sec, to_usec); ]) ], [nut_cv_func_modbus_set_byte_timeout_args="sec_usec_uint32_cast_timeval_fields"], [dnl Try another API variant: new API purely (two uint32's) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([ #include #include ], [modbus_t *ctx; uint32_t to_sec = 0, to_usec = 0; modbus_set_byte_timeout(ctx, to_sec, to_usec);]) ], [nut_cv_func_modbus_set_byte_timeout_args="sec_usec_uint32"]) ]) ]) ]) dnl NOTE: We could add similar tests to above for dnl other time-related methods, but for now keep dnl it simple -- and assume some same approach dnl applies to the same generation of the library. AC_LANG_POP([C]) AC_MSG_RESULT([Found types to use for modbus_set_byte_timeout: ${nut_cv_func_modbus_set_byte_timeout_args}]) dnl NOTE: code should check for having a token name defined e.g.: dnl #ifdef NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32 dnl Alas, we can't pass variables as macro name to AC_DEFINE COMMENT="Define to specify timeout method args approach for libmodbus" AS_CASE(["${nut_cv_func_modbus_set_byte_timeout_args}"], [timeval_numeric_fields], [AC_DEFINE([NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields], 1, [${COMMENT}])], [timeval], [AC_DEFINE([NUT_MODBUS_TIMEOUT_ARG_timeval], 1, [${COMMENT}])], [sec_usec_uint32_cast_timeval_fields], [AC_DEFINE([NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields], 1, [${COMMENT}])], [sec_usec_uint32], [AC_DEFINE([NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32], 1, [${COMMENT}])], [dnl default AC_MSG_WARN([Cannot find proper types to use for modbus_set_byte_timeout]) nut_have_libmodbus=no] ) ]) AS_IF([test x"${nut_have_libmodbus}" = x"yes"], [LIBMODBUS_CFLAGS="${depCFLAGS}" LIBMODBUS_LIBS="${depLIBS}" AS_IF([test x"${nut_have_libmodbus_usb}" = x"yes"], [AC_DEFINE([NUT_MODBUS_HAS_USB], 1, [Define to use libmodbus USB backend])]) dnl The hack below relies on definition of AC LINK IFELSE macro and (GNUish) LDD! dnl FIXME: This may be platform-dependent; check e.g. mingw/WIN32 builds via ${top_srcdir}/scripts/Windows/dllldd.sh? dnl Information ismostly useful for troubleshooting though dnl (cosmetic/messages), so no big fuss if we do not learn it LIBMODBUS_LINKTYPE="unknown" AS_IF([test -n "${LDD}" && test -x "${LDD}"], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([ #include ], [modbus_t *ctx = modbus_new_rtu(NULL, 0, 0, 0, 0); if (ctx) modbus_free(ctx);])], [AS_IF([test -x "conftest$ac_exeext"], [ AS_IF([test -n "`${LDD} "conftest$ac_exeext" | grep "libmodbus"`" 2>/dev/null], [LIBMODBUS_LINKTYPE="dynamic"], [LIBMODBUS_LINKTYPE="static"]) ])]) dnl If not GNU LDD, try other tools? ]) AC_MSG_CHECKING([if libmodbus linking is dynamic or static]) AC_MSG_RESULT([${LIBMODBUS_LINKTYPE}]) AC_DEFINE_UNQUOTED([NUT_MODBUS_LINKTYPE_STR], ["${LIBMODBUS_LINKTYPE}"], [Define to let the libmodbus linking type be known for troubleshooting]) ]) unset depCFLAGS unset depLIBS dnl restore original CFLAGS and LIBS CFLAGS="${CFLAGS_ORIG}" LIBS="${LIBS_ORIG}" fi ]) nut-2.8.3/m4/nut_report_feature.m40000644000200500020050000001666514777767434014005 00000000000000dnl automated feature report at the end of configure script. dnl it also AC_DEFINE() and AM_CONDITIONAL the matching variable. dnl for example, "usb" (--with-usb) will give dnl nut_with_usb and WITH_USB (both macros, and dnl AM_CONDITIONAL) AC_DEFUN([NUT_REPORT_FILE], [ dnl arg#1 = description (summary) dnl arg#2 = value dnl arg#3 = file tag (e.g. number) dnl arg#4 = file title (e.g. "NUT Configuration summary:") AS_IF([test x"${nut_report_feature_flag$3}" = x], [ nut_report_feature_flag$3="1" ac_clean_files="${ac_clean_files} config.nut_report_feature.log.$3" case x"$3" in x1a) echo "$4" echo "$4" | sed 's/./=/g' echo "" ;; x1*) ;; *) echo "" echo "$4" echo "$4" | sed 's/./-/g' echo "" ;; esac > "config.nut_report_feature.log.$3" ]) printf "* %s:\t%s\n" "$1" "$2" >> "config.nut_report_feature.log.$3" ]) AC_DEFUN([NUT_REPORT], [ dnl arg#1 = description (summary) dnl arg#2 = value NUT_REPORT_FILE([$1], [$2], [1a], "NUT Configuration summary:") ]) AC_DEFUN([NUT_REPORT_DRV], [ dnl arg#1 = description (summary) dnl arg#2 = value dnl Title irrelevant here, should not show NUT_REPORT_FILE([$1], [$2], [1b], "NUT Configuration summary:") ]) AC_DEFUN([NUT_REPORT_PRG], [ dnl arg#1 = description (summary) dnl arg#2 = value dnl Title irrelevant here, should not show NUT_REPORT_FILE([$1], [$2], [1c], "NUT Configuration summary:") ]) AC_DEFUN([NUT_REPORT_PATH], [ dnl arg#1 = description (summary) dnl arg#2 = value NUT_REPORT_FILE([$1], [$2], [2], "NUT Paths:") ]) AC_DEFUN([NUT_REPORT_PATH_INTEGRATIONS], [ dnl arg#1 = description (summary) dnl arg#2 = value NUT_REPORT_FILE([$1], [$2], [3], "NUT Paths for third-party integrations:") ]) AC_DEFUN([NUT_REPORT_DRIVER], [ dnl NOTE: Same as feature, just grouped into "1b" file to display after features dnl arg#1 = summary/config.log description dnl arg#2 = test flag ("yes" or not) dnl arg#3 = value dnl arg#4 = autoconf varname dnl arg#5 = longer description (autoconf comment) AC_MSG_CHECKING([whether to $1]) AC_MSG_RESULT([$2 $3]) NUT_REPORT_DRV([$1], [$2 $3]) AM_CONDITIONAL([$4], test "$2" = "yes") AS_IF([test x"$2" = x"yes"], [ AC_DEFINE_UNQUOTED($4, 1, $5) ]) ]) AC_DEFUN([NUT_REPORT_PROGRAM], [ dnl NOTE: Same as feature, just grouped into "1c" file to display last dnl arg#1 = summary/config.log description dnl arg#2 = test flag ("yes" or not) dnl arg#3 = value dnl arg#4 = autoconf varname dnl arg#5 = longer description (autoconf comment) AC_MSG_CHECKING([whether to $1]) AC_MSG_RESULT([$2 $3]) NUT_REPORT_PRG([$1], [$2 $3]) AM_CONDITIONAL([$4], test "$2" = "yes") AS_IF([test x"$2" = x"yes"], [ AC_DEFINE_UNQUOTED($4, 1, $5) ]) ]) AC_DEFUN([NUT_REPORT_FEATURE], [ dnl arg#1 = summary/config.log description dnl arg#2 = test flag ("yes" or not) dnl arg#3 = value dnl arg#4 = autoconf varname dnl arg#5 = longer description (autoconf comment) AC_MSG_CHECKING([whether to $1]) AC_MSG_RESULT([$2 $3]) NUT_REPORT([$1], [$2 $3]) AM_CONDITIONAL([$4], test "$2" = "yes") AS_IF([test x"$2" = x"yes"], [ AC_DEFINE_UNQUOTED($4, 1, $5) ]) ]) AC_DEFUN([NUT_REPORT_SETTING], [ dnl arg#1 = summary/config.log description dnl arg#2 = autoconf varname dnl arg#3 = value dnl arg#4 = longer description (autoconf comment) AC_MSG_CHECKING([setting for $1]) AC_MSG_RESULT([$3]) NUT_REPORT([$1], [$3]) dnl Note: unlike features, settings do not imply an AutoMake toggle AC_DEFINE_UNQUOTED($2, $3, $4) ]) AC_DEFUN([NUT_REPORT_SETTING_PATH], [ dnl arg#1 = summary/config.log description dnl arg#2 = autoconf varname dnl arg#3 = value dnl arg#4 = longer description (autoconf comment) AC_MSG_CHECKING([setting for $1]) AC_MSG_RESULT([$3]) NUT_REPORT_PATH([$1], [$3]) dnl Note: unlike features, settings do not imply an AutoMake toggle AC_DEFINE_UNQUOTED($2, $3, $4) ]) AC_DEFUN([NUT_REPORT_SETTING_PATH_INTEGRATIONS], [ dnl arg#1 = summary/config.log description dnl arg#2 = autoconf varname dnl arg#3 = value dnl arg#4 = longer description (autoconf comment) AC_MSG_CHECKING([setting for $1]) AC_MSG_RESULT([$3]) NUT_REPORT_PATH_INTEGRATIONS([$1], [$3]) dnl Note: unlike features, settings do not imply an AutoMake toggle AC_DEFINE_UNQUOTED($2, $3, $4) ]) AC_DEFUN([NUT_REPORT_TARGET], [ dnl arg#1 = autoconf varname dnl arg#2 = value dnl arg#3 = summary/config.log/autoconf description AC_MSG_CHECKING([$3]) AC_MSG_RESULT([$2]) dnl FIXME: value here is already quoted by caller (for AC_DEFINE_UNQUOTED dnl with multi-token strings). Then quotes are added in NUT_REPORT_FILE() dnl and turn it into multiple single-token strings. So we neuter that here: NUT_REPORT_FILE([$3], ["$2"], [8], "NUT Build/Target system info:") dnl Note: unlike features, target info does not imply an AutoMake toggle AC_DEFINE_UNQUOTED($1, $2, $3) ]) AC_DEFUN([NUT_REPORT_TARGET_WITHOUT_AC_DEFINE], [ dnl arg#1 = autoconf varname dnl arg#2 = value dnl arg#3 = summary/config.log/autoconf description AC_MSG_CHECKING([$3]) AC_MSG_RESULT([$2]) NUT_REPORT_FILE([$3], ["$2"], [8], "NUT Build/Target system info:") dnl Not defining here (e.g. multi-line strings causing bad C markup) ]) AC_DEFUN([NUT_REPORT_COMPILERS], [ (echo "" echo "NUT Compiler settings:" echo "----------------------" echo "" if test x"${nut_with_debuginfo_C}" = x"yes" -o x"${nut_with_debuginfo_CXX}" = x"yes" ; then printf 'NOTE: Settings for ' if test x"${nut_with_debuginfo_C}" = x"yes" ; then printf 'C ' fi if test x"${nut_with_debuginfo_C}${nut_with_debuginfo_CXX}" = x"yesyes" ; then printf 'and ' fi if test x"${nut_with_debuginfo_CXX}" = x"yes" ; then printf 'C++ ' fi printf 'compiler' if test x"${nut_with_debuginfo_C}${nut_with_debuginfo_CXX}" = x"yesyes" ; then printf 's' fi printf ' are adjusted for debugging (and minimal optimizations)\n\n' fi printf '* CC \t: %s\n' "$CC" printf '* CFLAGS \t: %s\n' "$CFLAGS" printf '* CXX \t: %s\n' "$CXX" printf '* CXXFLAGS\t: %s\n' "$CXXFLAGS" printf '* CPP \t: %s\n' "$CPP" printf '* CPPFLAGS\t: %s\n' "$CPPFLAGS" printf '* LD \t: %s\n' "$LD" printf '* LDFLAGS \t: %s\n' "$LDFLAGS" printf '* CONFIG_FLAGS\t: %s\n' "$CONFIG_FLAGS" ) > config.nut_report_feature.log.9 ac_clean_files="${ac_clean_files} config.nut_report_feature.log.9" ]) AC_DEFUN([NUT_PRINT_FEATURE_REPORT], [ dnl By (legacy) default we remove this report file dnl For CI we want to publish its artifact dnl Manageable by "--enable-keep_nut_report_feature" echo "" AS_IF([test x"${nut_enable_keep_nut_report_feature-}" = xyes], [AC_MSG_NOTICE([Will keep config.nut_report_feature.log]) cat config.nut_report_feature.log.* > config.nut_report_feature.log cat config.nut_report_feature.log ], [dnl Remove if exists from old builds ac_clean_files="${ac_clean_files} config.nut_report_feature.log" cat config.nut_report_feature.log.* ]) ]) nut-2.8.3/m4/nut_stash_warnings.m40000644000200500020050000000561614553676503013767 00000000000000dnl Callers like CI or developers can enable various warning flags dnl including those that would be fatal to the configure script dnl itself passing (autotools probing code is rather sloppy by dnl strict standards). These routines try to stash away the warning dnl flags from CFLAGS and CXXFLAGS passed by user, to re-apply in dnl the end of configure script run. AC_DEFUN([NUT_STASH_WARNINGS], [ dnl WARNING: This code assumes that there are no whitespaces dnl inside C*FLAGS values (e.g. no spacey include paths) CFLAGS_STASHED_WARNINGS="" CPPFLAGS_STASHED_WARNINGS="" CXXFLAGS_STASHED_WARNINGS="" AS_IF([test -z "$CFLAGS"],[],[ TMP="" for V in ${CFLAGS} ; do case "$V" in -W*|-*pedantic*) CFLAGS_STASHED_WARNINGS="${CFLAGS_STASHED_WARNINGS} ${V}" ;; *) TMP="${TMP} ${V}" ;; esac done CFLAGS="$TMP" ]) AS_IF([test -n "${CFLAGS_STASHED_WARNINGS}"], [AC_MSG_NOTICE([Stashed CFLAGS warnings to not confuse autotools probes: ${CFLAGS_STASHED_WARNINGS}])]) AS_IF([test -z "$CPPFLAGS"],[],[ TMP="" for V in ${CPPFLAGS} ; do case "$V" in -W*|-*pedantic*) CPPFLAGS_STASHED_WARNINGS="${CPPFLAGS_STASHED_WARNINGS} ${V}" ;; *) TMP="${TMP} ${V}" ;; esac done CPPFLAGS="$TMP" ]) AS_IF([test -n "${CPPFLAGS_STASHED_WARNINGS}"], [AC_MSG_NOTICE([Stashed CPPFLAGS warnings to not confuse autotools probes: ${CPPFLAGS_STASHED_WARNINGS}])]) AS_IF([test -z "$CXXFLAGS"],[],[ TMP="" for V in ${CXXFLAGS} ; do case "$V" in -W*|-*pedantic*) CXXFLAGS_STASHED_WARNINGS="${CXXFLAGS_STASHED_WARNINGS} ${V}" ;; *) TMP="${TMP} ${V}" ;; esac done CXXFLAGS="$TMP" ]) AS_IF([test -n "${CXXFLAGS_STASHED_WARNINGS}"], [AC_MSG_NOTICE([Stashed CXXFLAGS warnings to not confuse autotools probes: ${CXXFLAGS_STASHED_WARNINGS}])]) ]) AC_DEFUN([NUT_POP_WARNINGS], [ AS_IF([test -n "${CFLAGS_STASHED_WARNINGS}"],[ AC_MSG_NOTICE([Applying back the stashed CFLAGS warnings]) CFLAGS="${CFLAGS} ${CFLAGS_STASHED_WARNINGS}" AC_MSG_NOTICE([Ended up with: '${CFLAGS}']) ]) AS_IF([test -n "${CPPFLAGS_STASHED_WARNINGS}"],[ AC_MSG_NOTICE([Applying back the stashed CPPFLAGS warnings]) CPPFLAGS="${CPPFLAGS} ${CPPFLAGS_STASHED_WARNINGS}" AC_MSG_NOTICE([Ended up with: '${CPPFLAGS}']) ]) AS_IF([test -n "${CXXFLAGS_STASHED_WARNINGS}"],[ AC_MSG_NOTICE([Applying back the stashed CXXFLAGS warnings]) CXXFLAGS="${CXXFLAGS} ${CXXFLAGS_STASHED_WARNINGS}" AC_MSG_NOTICE([Ended up with: '${CXXFLAGS}']) ]) ]) nut-2.8.3/Makefile.am0000644000200500020050000020073115001552635011300 00000000000000# top-level Makefile for NUT # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ # include directory for aclocal ACLOCAL_AMFLAGS = -I m4 # Autotools' SUBDIRS (our values are listed below) allow for powerful recursive # recipe automation, with one notable weakness: the dirs are processed in a # loop sequentially, even in parallel builds (each such sub-make is parallel # then). In our case, the HTML/PDF render of ChangeLog can take a minute of # work in "docs" while we are not building anything in other dirs. On the up # side, that approach does allow for dirs with dependencies to get built first # deterministically. For more details search for "am__recursive_targets" in the # generated Makefile. # # The commonly suggested way out of this predicament is to consolidate numerous # Makefile.am recipes into one, which alone properly defines all the needed # interdependecies that are "known" to one instance of the `make` process. # This however loses the ability to quickly e.g. `cd tests && make check`, so # the next layer is to re-introduce Makefiles in sub-directories that define # a few popular targets to perform via the one big top-level Makefile. # # Our approach here is to merge the two solutions: do use SUBDIRS the way # autotools handle them for the hordes of `*-recursive` targets for us, but # define more explicitly the targets for hot code paths (all, check) so that # they can run first for certain different directories (in parallel if asked # to) with "knowledge" of dependencies, and then a bit wastefully maybe re-run # those directories via autotools integration. They should be quick no-ops by # then in the anticipated common use-cases. # # List of source subdirectories to build and distribute, used to spawn automake # (alas sequential) target recipes. The order matters, as several subdirectories # depend on stuff in "common" or tools being built first! SUBDIRS = include common clients conf data drivers tools \ lib scripts server tests docs/man docs # Note: not generated from SUBDIRS, because not all are recursive: SUBDIRS_ALL_RECURSIVE = \ all/include \ all/common \ all/clients \ all/conf \ all-recursive/data \ all-drivers \ all/tools/nut-scanner \ all/tools/nutconf \ all-recursive/tools \ all/lib \ all-recursive/scripts \ all/server \ all/tests/NIT \ all/tests \ all/docs \ all/docs/man \ all-recursive/docs \ all-recursive/tests # Library creation happens in a number of subdirectories, may be optional # (e.g. C++ ones are not built without a suitable compiler and enablement). # List maintenance is aided by this query: # git grep -E 'LTLIBRARIES' '*.am' SUBDIRS_ALL_LIBS_LOCAL = \ all-libs-local/include \ all-libs-local/common \ all-libs-local/clients \ all-libs-local/drivers \ all-libs-local/tests \ all-libs-local/tools \ all-libs-local/tools/nut-scanner # First target often defines default behavior, and in automake is always at least: # all: all-recursive # with maybe custom dependencies of "all:" from a Makefile.am tacked on too # (which used to cause us a lot of headache, building same things twice at # the same time). #all all-recursive all-am-local all-local: all-fanout-maybe all-recursive: all-fanout-maybe # Verbosity for fanout rule tracing; 0/1 (or "default" that may auto-set # to 0 or 1 in some rules below) SUBDIR_MAKE_VERBOSE = default # Run the standard build if going sequential (or with unknown MAKEFLAGS), # or fanout if parallel (presuming GNU/BSD/Sun make at least): all-fanout-maybe: +@if [ x"$(NUT_MAKE_SKIP_FANOUT)" = xtrue ] ; then \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: skip optimization for parallel make - NUT_MAKE_SKIP_FANOUT is set" ; \ fi ; \ exit 0 ; \ fi ; \ case "-$(MAKEFLAGS) $(AM_MAKEFLAGS)" in \ *-j|*-j" "*|*-{j,l}{0,1,2,3,4,5,6,7,8,9}*|*-[jl][0123456789]*|*{-l,--jobs,--load-average,--max-load}" "{-,0,1,2,3,4,5,6,7,8,9}*|*--jobserver*|*--jobs" "[0123456789]*|*--load-average" "[0123456789]*|*--max-load" "[0123456789]*) \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: implement optimization for parallel make as 'make all-fanout-subdirs'" ; \ fi ; \ $(MAKE) $(AM_MAKEFLAGS) all-fanout-subdirs ;; \ *) \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: skip optimization for parallel make - we seem to run sequentially now, seen MAKEFLAGS='$(MAKEFLAGS)' AM_MAKEFLAGS='$(AM_MAKEFLAGS)'" ; \ fi ;; \ esac # We start with a pass to `make all` in `common` dir because our wild recipes # (with other subdirs ensuring the libraries they need have been built) can # sometimes cause parallel compilation and library generation for same files # driven by different make processes that do not know they aim for same goal, # with some "make" implementations... # Just in case we followed up with "make doc", since our wild recipes could end # up writing into same files and so corrupting them (fixes applied, but...) # FIXME: Alas, we still tend to step on our toes when making everything at # once from scratch, so still do benefit from pre-making the libraries: all-fanout-staged: +$(MAKE) $(AM_MAKEFLAGS) all/include +$(MAKE) $(AM_MAKEFLAGS) all/common +$(MAKE) $(AM_MAKEFLAGS) all-fanout-libs +$(MAKE) $(AM_MAKEFLAGS) all-fanout-subdirs all-fanout-subdirs: $(SUBDIRS_ALL_RECURSIVE) all-fanout-libs all-libs-local: $(SUBDIRS_ALL_LIBS_LOCAL) #all all-am-local all-local: # +@cd common && $(MAKE) $(AM_MAKEFLAGS) all # +@$(MAKE) $(AM_MAKEFLAGS) all-recursive # +@$(MAKE) $(AM_MAKEFLAGS) doc # +@$(MAKE) $(AM_MAKEFLAGS) doc bindir = @bindir@ sbindir = @sbindir@ driverexecdir = @driverexecdir@ cgiexecdir = @cgiexecdir@ # Automatically update the libtool script if it becomes out-of-date # See https://www.gnu.org/software/libtool/manual/html_node/LT_005fINIT.html LIBTOOL_DEPS = @LIBTOOL_DEPS@ libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status libtool # COPYING and other autotools-standard files are included automatically # by automake. Note that the INSTALL file is (re-)imposed by autotools # runs and is essentially a manual on configure script general usage, so # NUT's actual installation notes have had to use a different filename. EXTRA_DIST = LICENSE-GPL2 LICENSE-GPL3 LICENSE-DCO MAINTAINERS # Since the renaming of documentation to `*.adoc` extension to help IDE # and GitHub UIs to render the source files in a pretty fashion, we need # to list them: EXTRA_DIST += INSTALL.nut.adoc UPGRADING.adoc TODO.adoc NEWS.adoc README.adoc ci_build.adoc # Tarballs created by `make dist` include the `configure.ac` and `m4/*` sources # but lack NUT magic logic to recreate the `configure` script if someone would # want to adapt it to their autotools or locally fix a tarball-based build. EXTRA_DIST += autogen.sh if KEEP_NUT_REPORT nodist_data_DATA = config.nut_report_feature.log endif KEEP_NUT_REPORT # Not too different from automake generated recursive rules at first sight, # but here we do not loop all subdirs sequentially - instead, a sub-make # (maybe parallel itself and with parallel flags passed) with a certain # target in specified dir is the goal, all as separate targets for this # level's Makefile: SUBDIR_TGT_RULE = ( \ [ x"$${TGT-}" != x ] || TGT="`echo '$@' | awk -F/ '{print $$1}'`" ; \ [ x"$${DIR-}" != x ] || DIR="`echo '$@' | sed 's,^[^/]*/,,'`" ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE STARTING: 'make $$TGT' in $$DIR ..." ; \ fi ; \ cd "$(abs_builddir)/$${DIR}" && \ $(MAKE) $(AM_MAKEFLAGS) $${SUBDIR_TGT_MAKEFLAGS-} "$${TGT}" || { RES=$$?; echo " SUBDIR-MAKE FAILURE: 'make $$TGT' in $$DIR" >&2 ; exit $$RES ; } ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE SUCCESS: 'make $$TGT' in $$DIR" ; \ fi ; \ ) # A way to quickly handle SUBDIRS_ALL_LIBS_LOCAL as dependency for all others # (aka `make all-libs-local` also in root dir). Libs themselves have complex # inter-dependencies which we do not spell out here and let one recipe handle # the intimate details of other directories' deliverables (so far?). Query: # git grep -E '(LTLIBRARIES|\.la([ :'"`printf '\t'`"']|$))' '*.am' ### Delivers: nut_version.h all-libs-local/include: +@$(SUBDIR_TGT_RULE) ### Delivers: libcommon.la libcommonclient.la libcommonstr.la ### Delivers: libparseconf.la libnutconf.la libnutwincompat.la ### Requires-ext: include/nut_version.h ### Requires-int: libparseconf.la libcommonclient.la all-libs-local/common: all-libs-local/include +@$(SUBDIR_TGT_RULE) ### Delivers: libupsclient.la libnutclient.la libnutclientstub.la ### Delivers: libupsclient-version.h ### LIB-Requires-ext: common/libcommonclient.la ### Requires-ext: common/libcommon.la common/libcommonclient.la ### Requires-ext: common/libparseconf.la ### Requires-int: libupsclient.la all-libs-local/clients: all-libs-local/common +@$(SUBDIR_TGT_RULE) ### Delivers: libdummy.la libdummy_serial.la libdummy_upsdrvquery.la ### Delivers: libdummy_mockdrv.la libserial-nutscan.la ### LIB-Requires-ext: common/libcommon.la common/libparseconf.la ### Requires-ext: common/libcommon.la common/libparseconf.la ### Requires-ext: clients/libupsclient.la (dummy-ups only) ### Requires-int: libdummy.la libdummy_upsdrvquery.la ### Requires-int: libdummy_serial.la all-libs-local/drivers: all-libs-local/common +@$(SUBDIR_TGT_RULE) ### Delivers: libdriverstubusb.la ### LIB-Requires-ext: #COMMENTED-AWAY# common/libcommon.la ### Requires-ext: common/libcommon.la common/libnutconf.la ### Requires-ext: clients/libnutclient.la clients/libnutclientstub.la ### Requires-ext: drivers/libdummy_mockdrv.la ### Requires-int: libdriverstubusb.la all-libs-local/tests: all-libs-local/common +@$(SUBDIR_TGT_RULE) ### Delivers: generated sources and/or headers for nut-scanner ### No dependencies: actually runs as part of autogen.sh but may be ### re-run during development when USB or SNMP driver sources change. all-libs-local/tools: +@$(SUBDIR_TGT_RULE) ### Delivers: libnutscan.la ### LIB-Requires-ext: drivers/libserial-nutscan.la ### LIB-Requires-ext: common/libnutwincompat.la common/libcommonstr.la ### HDR-Requires-ext: clients/libupsclient-version.h ### HDR-Requires-ext: nut-scanner/nutscan-snmp.h nut-scanner/nutscan-usb.h ### (generated by nut-scanner-deps/tools aliased as all-libs-local/tools) ### Requires-int: libnutscan.la ### Note: indirectly (ltdl) may use installed libupsclient.so ### however does directly use libupsclient-version.h ### for hints to find it at run-time all-libs-local/tools/nut-scanner: all-libs-local/drivers all-libs-local/common all-libs-local/clients all-libs-local/tools +@$(SUBDIR_TGT_RULE) # Handle all SUBDIRS_ALL_RECURSIVE in a way that dependencies can be specified, # and portably to different make program implementations. Note we may revisit # some dirs via "all-recursive" of a parent after "all" in them first, but it is # expected to be a quick no-op (beneficial overall in parallel make situation). # NOTE: "lib" dir only delivers pkg-config metadata or legacy scripts for any # third-party development to integrate with NUT libs, no library recipes there. all/conf \ all/lib \ .ChangeLog.adoc-parsed.latest/docs \ ChangeLog.adoc-parsed/docs \ all-recursive/data: +@$(SUBDIR_TGT_RULE) all/include: all-libs-local/include +@$(SUBDIR_TGT_RULE) prep-src-docs/docs/man: +@SUBDIR_TGT_MAKEFLAGS='MAINTAINER_DOCS_PREP_MAN_DELAY=3'; export SUBDIR_TGT_MAKEFLAGS; $(SUBDIR_TGT_RULE) prep-src-docs/docs: +@DOCS_NO_MAN=true; export DOCS_NO_MAN; $(SUBDIR_TGT_RULE) all/docs/man: prep-src-docs/docs/man +@$(SUBDIR_TGT_RULE) # Note: we optionally sort of depend on ChangeLog.adoc so it is pre-made and # pre-processed for html/pdf renders (if any are requested), so they surely # do not compete for it to be made by independent "make" processes later on. # BUT we do not want to (re-)build ChangeLog if no (relevant) DOC_BUILD_LIST # types are enabled. MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY = 0 all/docs: prep-src-docs/docs/man +@case "@DOC_BUILD_LIST@" in \ *pdf*|*html-single*|*html-chunked*) \ echo " DOC-CHANGELOG-ASCIIDOC Pre-generate ChangeLog artifacts before the bulk of $@ ..." ; \ MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY="$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" \ export MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY && \ $(MAKE) $(AM_MAKEFLAGS) MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY="$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" ChangeLog.adoc && \ $(MAKE) $(AM_MAKEFLAGS) MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY="$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" .ChangeLog.adoc-parsed.latest/docs && \ echo " DOC-CHANGELOG-ASCIIDOC Pre-generate ChangeLog artifacts before the bulk of $@ : SUCCESS" ;; \ *) ;; \ esac +@$(MAKE) $(AM_MAKEFLAGS) prep-src-docs/docs +@DOCS_NO_MAN=true; export DOCS_NO_MAN; $(SUBDIR_TGT_RULE) all-recursive/docs: all/docs all/docs/man +@$(SUBDIR_TGT_RULE) # Dependencies below are dictated by who needs whose library from another dir # (generated by a sub-make there, so we pre-emptively ensure it exists to avoid # conflicts of several make's writing to same files). Aided by this query: # git grep -E '/[^ ]*\.la([ :]|$)' '*.am' # It does help to spell out all dependencies, even if transitive, to ensure # that the top-level make completes needed (all-libs*) targets before drilling. ### Requires-int: libparseconf.la libcommonclient.la all/common: all/include all-libs-local/common +@$(SUBDIR_TGT_RULE) ### Requires-ext: common/libcommon.la common/libcommonclient.la ### Requires-ext: common/libparseconf.la ### Requires-int: libupsclient.la all/clients: all/common all-libs-local/clients +@$(SUBDIR_TGT_RULE) ### Summary of drivers/ subdir dependencies: ### Requires-ext: common/libcommon.la common/libparseconf.la ### Requires-ext: clients/libupsclient.la (dummy-ups only) ### Requires-int: libdummy.la libdummy_upsdrvquery.la ### Requires-int: libdummy_serial.la # TODO in the future: propagate the knowledge of whether we are building # dummy-ups by default (if only SOME_DRIVERS are requested) from configure.ac, # and so decide if a goal to build it would conflict or not with "all/drivers" # (or alternately if it should be or not be part of "all-drivers", keeping the # current web of definitions in place). Primarily for the benefit of tests/NIT. # NOTE: The dummy-ups driver program relies on both libupsclient (ext) and # libdummy_upsdrvquery.la (int) - and so requires all-libs-local/drivers too. if SOME_DRIVERS # Here we do wholesale subdir all-libs-local at the moment, to # build whichever drivers are enabled (no idea if dummy-ups is # in the default list - FIXME: configure.ac could tell us, so # we could provide it for tests/NIT anyway...) all/drivers: all-libs-local/clients all-libs-local/common all-libs-local/drivers +@$(SUBDIR_TGT_RULE) all-drivers: all/drivers else !SOME_DRIVERS # We build all drivers, let dummy-ups be built with respect for # libupsclient while not blocking other driver builds on that. # NUTSW_DRIVERLIST_DUMMY_UPS acts as an equivalent of DOCS_NO_MAN # in a way, to let other (non dummy-ups) drivers get built in a # separate target with separate dependency trail, then "all-drivers" # should depend on both "dummy-ups" and the rest in so constrained # "all/drivers". This allows to ultimately not order one after another. dummy-ups$(EXEEXT)/drivers: all-libs-local/clients all-libs-local/common all-libs-local/drivers +@$(SUBDIR_TGT_RULE) all/drivers: all/common all-libs-local/drivers +@SUBDIR_TGT_MAKEFLAGS='NUTSW_DRIVERLIST_DUMMY_UPS=dummy'; export SUBDIR_TGT_MAKEFLAGS; $(SUBDIR_TGT_RULE) all-drivers: dummy-ups$(EXEEXT)/drivers all/drivers endif !SOME_DRIVERS ### Requires-ext: common/libcommon.la common/libparseconf.la all/server: all-libs-local/common +@$(SUBDIR_TGT_RULE) ### LIB-Requires-ext: drivers/libserial-nutscan.la ### LIB-Requires-ext: common/libnutwincompat.la common/libcommonstr.la ### Requires-ext: include/nut_version.h ### Requires-ext: clients/libupsclient-version.h ### Requires-int: libnutscan.la all/tools/nut-scanner: all-libs-local/include all-libs-local/common \ all-libs-local/drivers all-libs-local/clients \ all-libs-local/tools/nut-scanner +@$(SUBDIR_TGT_RULE) # only libnutscan is needed for nutconf, # but we do wholesale subdir all-libs-local at the moment... ### Requires-ext: common/libcommon.la common/libnutconf.la ### Requires-ext: tools/nut-scanner/libnutscan.la all/tools/nutconf: all-libs-local/tools/nut-scanner all-libs-local/common +@$(SUBDIR_TGT_RULE) all-recursive/tools: all/tools/nutconf all/tools/nut-scanner +@$(SUBDIR_TGT_RULE) # Prereqs for NIT are runnable upsd, upsc, upsmon, dummy-ups, sample configs... # For the actual "make check-NIT" runs - also python scripts and/or compiled # tests/cppnit (if available). # FIXME: technically of all drivers we need dummy-ups here; # if it is not enabled among SOME_DRIVERS, things can get funny... # But then we should also consider what is enabled by configure and what is not. # Maybe we are doing a quick build not to be tested at all? :-/ all/tests/NIT: all/clients all/server all-drivers all-recursive/tools all-recursive/data +@$(SUBDIR_TGT_RULE) ### LIB-Requires-ext: #COMMENTED-AWAY# common/libcommon.la ### Requires-ext: common/libcommon.la common/libnutconf.la ### Requires-ext: clients/libnutclient.la clients/libnutclientstub.la ### Requires-ext: drivers/libdummy_mockdrv.la ### Requires-int: libdriverstubusb.la all/tests: all-libs-local/tests all-libs-local/drivers all-libs-local/common all-libs-local/clients +@$(SUBDIR_TGT_RULE) all-recursive/tests: all/tests/NIT all/tests +@$(SUBDIR_TGT_RULE) if HAVE_MINGW_RESGEN if HAVE_WINDOWS ### Requires-ext: common/libcommon.la all/scripts/Windows: all-libs-local/common +@$(SUBDIR_TGT_RULE) else !HAVE_WINDOWS all/scripts/Windows: +@$(SUBDIR_TGT_RULE) endif !HAVE_WINDOWS else !HAVE_MINGW_RESGEN all/scripts/Windows: +@$(SUBDIR_TGT_RULE) endif !HAVE_MINGW_RESGEN all-recursive/scripts: all/scripts/Windows +@$(SUBDIR_TGT_RULE) # ---------------------------------------------------------------------- # flags to pass to ./configure when calling "make distcheck" and "make # distcheck-light". Try to check as many features as possible! Also # need to give augeas-lenses-dir, hotplug-dir and udev-dir, and request # PyNUT to be installed near the NUT-Monitor app (if feasible) so that # staged install does not fail. Note that by default PyNUT tries to go # into the system Python site-packages location, and autotools does not # tweak paths not using ${prefix} so `make distcheck` fails for it as # it does not play with a `DESTDIR` either. DISTCHECK_FLAGS = --with-all --with-ssl --with-doc=auto --with-pynut=app --with-nut_monitor=force CXXFLAGS='@NUT_CONFIG_CXXFLAGS@' CFLAGS='@NUT_CONFIG_CFLAGS@' CPPFLAGS='@NUT_CONFIG_CPPFLAGS@' LDFLAGS='@NUT_CONFIG_LDFLAGS@' DISTCHECK_LIGHT_FLAGS = --with-all=auto --with-ssl=auto --with-doc=auto --with-pynut=app --with-nut_monitor=force CXXFLAGS='@NUT_CONFIG_CXXFLAGS@' CFLAGS='@NUT_CONFIG_CFLAGS@' CPPFLAGS='@NUT_CONFIG_CPPFLAGS@' LDFLAGS='@NUT_CONFIG_LDFLAGS@' DISTCHECK_LIGHT_MAN_FLAGS = --with-all=auto --with-ssl=auto --with-doc=man --with-pynut=app --with-nut_monitor=force CXXFLAGS='@NUT_CONFIG_CXXFLAGS@' CFLAGS='@NUT_CONFIG_CFLAGS@' CPPFLAGS='@NUT_CONFIG_CPPFLAGS@' LDFLAGS='@NUT_CONFIG_LDFLAGS@' DISTCHECK_VALGRIND_FLAGS = --with-all=auto --with-ssl=auto --with-doc=skip --with-valgrind CXXFLAGS='@NUT_CONFIG_CXXFLAGS@ -g' CFLAGS='@NUT_CONFIG_CFLAGS@ -g' CPPFLAGS='@NUT_CONFIG_CPPFLAGS@' LDFLAGS='@NUT_CONFIG_LDFLAGS@' --with-pynut=app --with-nut_monitor=force # Note: this rule uses envvar DISTCHECK_FLAGS expanded at run-time DISTCHECK_CONFIGURE_FLAGS = ${DISTCHECK_FLAGS} \ PKG_CONFIG_PATH='@PKG_CONFIG_PATH@' \ --with-systemdsystemunitdir='$${prefix}/lib/systemd/system' \ --with-systemdsystempresetdir='$${prefix}/usr/lib/systemd/system-preset' \ --with-systemdshutdowndir='$${prefix}/lib/systemd/system-shutdown' \ --with-systemdtmpfilesdir='$${prefix}/usr/lib/tmpfiles.d' \ --with-augeas-lenses-dir='$${prefix}/usr/share/augeas/lenses' \ --with-hotplug-dir='$${prefix}/etc/hotplug' \ --with-udev-dir='$${prefix}/etc/udev' \ --with-devd-dir='$${prefix}/etc/devd' \ --with-pynut=app --with-nut_monitor=force # Note: trickery with prefix below is needed to expand it from # DISTCHECK_CONFIGURE_FLAGS defaults defined above in a manner # that is meaningful for sub-make program (gets stripped away # otherwise and breaks custom distchecks). # Helper for CI runs: ensure presence of pre-built man pages # (even if faked where lack and can not build them), so that # the majority of distcheck logic can pass. # See also docs/man/Makefile.am if KNOWN_UNABLE_MANS if DOC_INSTALL_DISTED_MANS distcheck-ci: distcheck dist-ci: dist else !DOC_INSTALL_DISTED_MANS distcheck-ci: distcheck-fake-man dist-ci: dist-fake-man endif !DOC_INSTALL_DISTED_MANS else !KNOWN_UNABLE_MANS if WITH_MANS distcheck-ci: distcheck dist-ci: dist else !WITH_MANS if HAVE_ASCIIDOC distcheck-ci: distcheck dist-ci: dist else !HAVE_ASCIIDOC if DOC_INSTALL_DISTED_MANS distcheck-ci: distcheck dist-ci: dist else !DOC_INSTALL_DISTED_MANS distcheck-ci: distcheck-fake-man dist-ci: dist-fake-man endif !DOC_INSTALL_DISTED_MANS endif !HAVE_ASCIIDOC endif !WITH_MANS endif !KNOWN_UNABLE_MANS # Helper for a number of recipes below that explicitly agree to not require # always real man pages (but require them to dist => distcheck-something) # for CI or developer iterations on environments with incomplete tool kits: distcheck-light-DIST_ALL_PAGES: @echo "Starting $@" >&2 +@cd "$(abs_builddir)/docs/man" && $(MAKE) $(AM_MAKEFLAGS) all +@cd "$(abs_builddir)/docs/man" && $(MAKE) $(AM_MAKEFLAGS) distcheck-light-DIST_ALL_PAGES @echo "Completed $@: preparation of pre-built man pages for dist tarball, possibly faked" >&2 # In some recipes we `configure --with-docs=skip`, so "make dist" should not # hiccup on lack of the page files (nor try to make them); not using simple # distcheck-light-DIST_ALL_PAGES step due to custom logic! distcheck-light-DIST_ALL_PAGES-docs-skipped: @echo "Starting $@" >&2 +@cd $(abs_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) prep-src-docs +@cd $(abs_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) FAKE_PAGES_BUMP_SRC=false distcheck-light-DIST_ALL_PAGES @echo "Completed $@: preparation of pre-built man pages for dist tarball, possibly faked" >&2 # Here we generate man pages (if absent) or fake them # Require other dependencies as usual distcheck does; # be sure to pass through caller's DISTCHECK_FLAGS (if any) distcheck-fake-man: distcheck-light-DIST_ALL_PAGES @echo "Starting $@" >&2 +prefix='$${prefix}'; if test x"$(DISTCHECK_FLAGS)" = x ; then \ $(MAKE) $(AM_MAKEFLAGS) distcheck ; \ else \ $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_FLAGS)" distcheck ; \ fi @echo "Completed $@: strict distcheck, but with possibly faked pre-built man pages" >&2 dist-fake-man: distcheck-light-DIST_ALL_PAGES @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) dist @echo "Completed $@: strict dist, but with possibly faked pre-built man pages" >&2 # Here we allow to skip docs if tools are absent, so "make dist" # should not hiccup on lack of the page files (but MAY make them # if it can); be relaxed toward other dependencies. distcheck-light: distcheck-light-DIST_ALL_PAGES @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_LIGHT_FLAGS)" distcheck @echo "Completed $@: relaxed distcheck, with possibly faked pre-built man pages" >&2 # Require man pages to be built (or fail trying), but not other docs; # be relaxed toward other dependencies. distcheck-light-man: @echo "Starting $@" >&2 +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_LIGHT_MAN_FLAGS)" distcheck @echo "Completed $@: relaxed distcheck, with real man pages" >&2 if HAVE_VALGRIND # Make the check in current build, if possible memcheck: @echo "Starting $@" >&2 @echo "See also scripts/valgrind in NUT sources for a helper tool" +@cd $(builddir)/tests && $(MAKE) $(AM_MAKEFLAGS) -s $@ # Make a distcheck (and check in particular) with enabled valgrind and debug info # Here we skip docs so "make dist" should not hiccup on lack of the page files # (nor try to make them); not using simple distcheck-light-DIST_ALL_PAGES step # due to custom logic! distcheck-valgrind: distcheck-light-DIST_ALL_PAGES-docs-skipped @echo "Starting $@" >&2 @echo "See also scripts/valgrind in NUT sources for a helper tool" +prefix='$${prefix}'; $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_VALGRIND_FLAGS)" distcheck @echo "Completed $@: relaxed distcheck, without man pages ('pre-built' placeholders in dist archive), running tests under valgrind" >&2 else !HAVE_VALGRIND memcheck distcheck-valgrind: @echo "Starting $@" >&2 @echo "See also scripts/valgrind in NUT sources for a helper tool" @echo " SKIP $@ : valgrind was not detected on this system by configure script" >&2 endif !HAVE_VALGRIND # workaround the dist generated files that are also part of the distribution # Note that distcleancheck is disabled for now, while waiting for a proper # solution, that do not break older unix systems #distcleancheck_listfiles = \ # find . -type f -exec sh -c 'test -f $(srcdir)/{} || echo {}' ';' distcleancheck: @: # Quick alias for root dir recipe: realclean: maintainer-clean # Files made by our targets: CLEANFILES = *-spellchecked *.adoc-parsed cppcheck*.xml config.log.inplace-outer DISTCLEANFILES = ChangeLog # Most of the files generated by custom rules in the configure script # or by autogen.sh are cleaned by the Makefile.am in their directories. # Files below are re-created by running `configure` script and may be # wiped by a `make distclean`: DISTCLEANFILES += config.log configure~ #???# configure.ac~ DISTCLEANFILES += include/config.h.in~ # Files made by autotools and common rituals of the configure script, # these are needed to run the configure script itself so are not wiped # by a mere `make distclean`; most of these are copied by autotools # from their installation, or made by `automake` etc. on the system # which generates `configure`; rebuilding NUT after deleting these # requires `autogen.sh` script to be re-run (and tools available): MAINTAINERCLEANFILES = INSTALL MAINTAINERCLEANFILES += aclocal.m4 config.guess config.sub MAINTAINERCLEANFILES += configure MAINTAINERCLEANFILES += depcomp install-sh ltmain.sh test-driver ar-lib MAINTAINERCLEANFILES += m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/lt~obsolete.m4 MAINTAINERCLEANFILES += Makefile.in .dirstamp include/config.h.in # Executed after default rules maintainer-clean-local: $(AM_V_at)rm -f missing || true # Do not let $SUBDIRS/Makefile rules delete their local .deps because # this breaks our ability to clean up (e.g. some common/.../*.Plo files # are included by generated Makefiles from other subdirectories, so they # should be available during their clean-up). Just in case, we make sure # here that their sub-distcleans complete first. distclean-local: +@for DIR in $(SUBDIRS) ; do \ if test -f "$${DIR}/Makefile" ; then \ echo " DISTCLEAN in $${DIR}" >&2 ; \ ( cd "$${DIR}" && $(MAKE) $(AM_MAKEFLAGS) -s distclean ) || exit ; \ fi ; \ done $(AM_V_at)rm -rf .inst tmp autom4te.cache $(AM_V_at)find "$(builddir)" -type d -name '.deps' | while read DIR ; do rm -rf "$${DIR}" ; done # Hook the documentation building and validating recipes # Note: these are optionally available (as determined during configure runs) # Only require SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes for the last entry # (reduce noise for spellcheck-interactive) # Maint: grep -l 'SPELLCHECK_' `git grep -lw spellcheck '*.am'` SPELLCHECK_DIRS_MOST = \ spellcheck/docs \ spellcheck/docs/man \ spellcheck/conf \ spellcheck/data \ spellcheck/data/html \ spellcheck/scripts \ spellcheck/scripts/Solaris \ spellcheck/scripts/Windows \ spellcheck/scripts/devd \ spellcheck/scripts/external_apis \ spellcheck/scripts/hotplug \ spellcheck/scripts/installer \ spellcheck/scripts/python \ spellcheck/scripts/systemd \ spellcheck/scripts/udev \ spellcheck/scripts/upsdrvsvcctl # Same but with an info notice, so runs alone last SPELLCHECK_DIRS_LAST = spellcheck/tests/NIT SPELLCHECK_DIRS = $(SPELLCHECK_DIRS_MOST) $(SPELLCHECK_DIRS_LAST) $(SPELLCHECK_DIRS_MOST): prep-src-docs/docs/man prep-src-docs/docs +@TGT="$(SPELLCHECK_TGT)"; export TGT; $(SUBDIR_TGT_RULE) $(SPELLCHECK_DIRS_LAST): prep-src-docs/docs/man prep-src-docs/docs $(SPELLCHECK_DIRS_MOST) +@SUBDIR_TGT_MAKEFLAGS="SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes"; \ export SUBDIR_TGT_MAKEFLAGS; \ TGT="$(SPELLCHECK_TGT)"; export TGT; \ $(SUBDIR_TGT_RULE) # We want to check all files even if some have errors, so sub-make with "-k": # Tricky TGT to pass sort-of-same rules (and dir list) as spellcheck, # but using the correct make target for this goal: # FIXME: fanned-out recipes tend to fail early despite "make -ks", so for # now we retry with a not-fanned-out attempt to cover most touch-files spellcheck spellcheck-interactive: +@SUBDIR_TGT_MAKEFLAGS="$${SUBDIR_TGT_MAKEFLAGS-} -k -s " ; export SUBDIR_TGT_MAKEFLAGS ; \ if [ x"$(NUT_MAKE_SKIP_FANOUT)" = xtrue ] ; then \ RES=0 ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" != x0 ] ; then \ echo " SUBDIR-MAKE $@: skip optimization for parallel make - NUT_MAKE_SKIP_FANOUT is set" ; \ fi ; \ (cd $(builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) -k -s $(abs_top_builddir)/docs/.prep-src-docs) || RES=$$? ; \ (cd $(builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) -k -s $(abs_top_builddir)/docs/man/.prep-src-docs) || RES=$$? ; \ for D in $(SPELLCHECK_DIRS_MOST) ; do \ D="`echo "$$D" | sed 's,^spellcheck/,,'`" ; \ (cd "$(builddir)/$$D" && $(MAKE) $(AM_MAKEFLAGS) -k -s $@) || RES=$$? ; \ done ; \ for D in $(SPELLCHECK_DIRS_LAST) ; do \ D="`echo "$$D" | sed 's,^spellcheck/,,'`" ; \ (cd "$(builddir)/$$D" && $(MAKE) $(AM_MAKEFLAGS) SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes -k -s $@) || RES=$$? ; \ done ; \ exit $$RES ; \ fi ; \ SUBDIR_MAKE_VERBOSE="$(SUBDIR_MAKE_VERBOSE)" ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" = xdefault ] ; then \ SUBDIR_MAKE_VERBOSE=0 ; \ fi ; \ export SUBDIR_MAKE_VERBOSE ; \ $(MAKE) $(AM_MAKEFLAGS) SPELLCHECK_TGT='$@' SUBDIR_MAKE_VERBOSE="$${SUBDIR_MAKE_VERBOSE}" -k -s $(SPELLCHECK_DIRS) && exit ; \ echo "WARNING: FAILED fanned-out attempt in $@, retrying with NUT_MAKE_SKIP_FANOUT" >&2 ; \ $(MAKE) $(AM_MAKEFLAGS) NUT_MAKE_SKIP_FANOUT=true SPELLCHECK_TGT='$@' -k -s $(SPELLCHECK_DIRS) # Auto-parallel recipe (if current 'make' implementation supports the "-j N" # syntax; the optional MAXPARMAKES may be set in NUT CI farm style builds): spellcheck-quick: +@case " $(MAKEFLAGS) $(AM_MAKEFLAGS)" in \ *"j"*) $(MAKE) $(AM_MAKEFLAGS) -k -s spellcheck && exit ;; \ *) \ if ! [ "$${MAXPARMAKES-}" -gt 1 ] 2>/dev/null ; then \ MAXPARMAKES=8 ; \ fi ; \ $(MAKE) $(AM_MAKEFLAGS) -k -s -j $${MAXPARMAKES} spellcheck \ && exit ;; \ esac # Run auto-parallel recipe, and if something fails - re-run interactively: spellcheck-interactive-quick: +@$(MAKE) $(AM_MAKEFLAGS) -k -s spellcheck-quick && exit ; \ echo "WARNING: in $@: make spellcheck-quick failed, retrying with spellcheck-interactive" >&2 ; \ if [ x"$(SUBDIR_MAKE_VERBOSE)" = xdefault ] ; then \ SUBDIR_MAKE_VERBOSE=1 ; export SUBDIR_MAKE_VERBOSE ; \ fi ; \ $(MAKE) $(AM_MAKEFLAGS) -k -s spellcheck-interactive # Note: the "all-docs" and "check-docs" targets may require tools not # found by `configure` script (and so avoided by conventional recipes) # such as PDF generators, so it should only be called at developer's # discretion, choice and risk. The "check-man" targets covers source # texts, man pages and HTML rendering of man pages, as enabled by tools. doc spellcheck-sortdict spellcheck-report-dict-usage \ all-docs check-docs \ man all-man man-man check-man check-man-man html-man all-html: +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) -s $(abs_top_builddir)/docs/.prep-src-docs +cd $(abs_top_builddir)/docs/man && $(MAKE) $(AM_MAKEFLAGS) -s $(abs_top_builddir)/docs/man/.prep-src-docs +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) $@ INSTALL.nut UPGRADING NEWS README: +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) ../$(@F).adoc-parsed && cp -f ../$(@F).adoc-parsed ../$(@F) # Workarounds for https://github.com/github/markup/issues/1095 # require direct definition of our attributes in each source # document, in order for GitHub Web-UI to render them nicely # (unfortunately, asciidoc configs and includes are not handled # at this time). Hopefully this will go away at some point. # The following rule updates definitions in source asciidoc files # between GH_MARKUP_1095_INCLUDE_BEGIN/END tags with contents of # current docs/asciidoc-vars.conf file. It is intended to be used # by maintainers (or brave contributors who would dare edit those # definitions), to apply them into the committed document sources. # Not bothering about with "make dist" constraints etc. - changes # the contents of srcdir directly and intentionally. # NOTE: Using `read -r` per POSIX standard to avoid backslashes # being treated as escape characters: # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html MAINTAINER_ASCIIDOCS_RECIPE_DEBUG_STREAM = /dev/null #MAINTAINER_ASCIIDOCS_RECIPE_DEBUG_STREAM = &2 maintainer-asciidocs: @USEDREV="`git log -1 --oneline --pretty=format:'%h (%cs) %s' docs/asciidoc-vars.conf`" || exit ; \ USEDREV_NOSUBJ="`git log -1 --oneline --pretty=format:'%h (%cs)' docs/asciidoc-vars.conf`" || exit ; \ echo "$@: Updating asciidoc text sources with docs/asciidoc-vars.conf as of commit: $${USEDREV}"; \ echo "//GH_MARKUP_1095_INCLUDE_BEGIN//$${USEDREV}" > docs/asciidoc-vars.conf.lastrev.tmp || exit ; \ find . -name '*.adoc' -or -name '*.txt' | ( \ FILES=""; \ while read F ; do \ grep -E '^//+GH_MARKUP_1095_INCLUDE_(BEGIN|END)' "$$F" >/dev/null \ || { echo "$@: SKIP: no GH_MARKUP_1095_INCLUDE_* tags: $$F"; continue ; } ; \ rm -f "$${F}"*.tmp || exit ; \ EXT="1.tmp"; \ while IFS='' read -r LINE ; do \ case "$${LINE}" in \ "//GH_MARKUP_1095_INCLUDE_BEGIN"*) EXT="2.tmp" ; continue ;; \ "//GH_MARKUP_1095_INCLUDE_END"*|"////GH_MARKUP_1095_INCLUDE_END"*) EXT="3.tmp" ; continue ;; \ esac ; \ printf '%s\n' "$${LINE}" >> "$${F}.$${EXT}" || exit ; \ done < "$$F" || { echo "$@: FAILED injection for $${F}" >&2; exit 1; } ; \ if test -s "$${F}.2.tmp" && test -z "`diff "$${F}.2.tmp" docs/asciidoc-vars.conf | tr -d '\n'`" ; then \ rm -f "$${F}"*.tmp ; \ echo "$@: SKIP: no changes: $$F"; continue ; \ fi; \ cat "$${F}.1.tmp" docs/asciidoc-vars.conf.lastrev.tmp docs/asciidoc-vars.conf > "$${F}.tmp" \ && echo '//GH_MARKUP_1095_INCLUDE_END//' >> "$${F}.tmp" \ && cat "$${F}.3.tmp" >> "$${F}.tmp" \ && mv -f "$${F}.tmp" "$${F}" \ || { echo "$@: FAILED injection for $${F}" >&2; exit 1; } ; \ echo "$@: UPDATED: $$F"; \ FILES="$${FILES} $${F}"; \ rm -f "$${F}"*.tmp ; \ done; \ rm -f docs/asciidoc-vars.conf.lastrev.tmp; \ if test -z "$${FILES}" ; then \ echo "$@: OVERALL-SKIP: No text files found with GH_MARKUP_1095_INCLUDE_ tags, or obsoleted docs/asciidoc-vars.conf contents";\ else \ echo "$@: OVERALL-UPDATED: You may now want to:"; \ echo " make spellcheck-interactive-quick"; \ echo " git add -p $${FILES} && git commit -sm 'Update NUT documentation sources with current docs/asciidoc-vars.conf: $${USEDREV_NOSUBJ}'"; \ fi; \ ) check-NIT check-NIT-devel check-NIT-sandbox check-NIT-sandbox-devel: +cd $(builddir)/tests/NIT && $(MAKE) $(AM_MAKEFLAGS) $@ VERSION_DEFAULT: dummy-stamp @abs_top_srcdir='$(abs_top_srcdir)' ; \ abs_top_builddir='$(abs_top_builddir)' ; \ export abs_top_srcdir ; export abs_top_builddir ; \ NUT_VERSION_QUERY=UPDATE_FILE '$(abs_top_srcdir)/tools/gitlog2version.sh' CLEANFILES += VERSION_DEFAULT.tmp EXTRA_DIST += VERSION_DEFAULT # Best-effort delivery for (overly?) customized distros, e.g. via # echo NUT_VERSION_FORCED_SEMVER=1.1.1 > VERSION_FORCED_SEMVER dist-hook: for D in "$(abs_top_srcdir)" "$(abs_top_builddir)" ; do \ for F in VERSION_FORCED VERSION_FORCED_SEMVER ; do \ if [ -s "$$D/$$F" ] ; then \ cat "$$D/$$F" > "$(top_distdir)/$$F" || true ; \ fi ; \ done ; \ done # This target adds syntax-checking for committed shell script files, # to avoid surprises and delays in finding fatal typos after packaging ### ### Note: currently, shellcheck target calls check-scripts-syntax ### so when both are invoked at once, in the end the check is only ### executed once. Later it is anticipated that shellcheck would ### be implemented by requiring, configuring and calling the tool ### named "shellcheck" for even more code inspection and details. ### Still, there remains value in also checking the script syntax ### by the very version of the shell interpreter that would run ### these scripts in production usage of the resulting packages. ### check-scripts-syntax: @echo 'NOTE: modern bash complains about scripts using backticks (warning not error), which we ignore in NUT codebase for portability reasons: `...` obsolete, use $$(...)' @RUNBASH=bash; if [ -x /bin/bash ] && /bin/bash -c 'echo $${BASH_VERSION}' | grep -E '^[456789]\.' ; then RUNBASH=/bin/bash ; else if [ -x /usr/bin/env ] ; then RUNBASH="/usr/bin/env bash"; fi; fi ; \ for F in `git ls-files || find . -type f` ; do \ case "`file "$$F"`" in \ *"Bourne-Again shell script"*) ( set -x ; $$RUNBASH -n "$$F" ; ) ;; \ *"POSIX shell script"*|*"shell script"*) ( set -x ; /bin/sh -n "$$F" ; ) ;; \ esac || { RES=$$? ; echo "ERROR: Syntax check failed for script file: $$F" >&2 ; exit $$RES ; } ; \ done @echo 'SUCCESS: Shell scripts syntax is acceptable, no fatal issues were found' shellcheck-disclaimer: @echo "===============================================================================" @echo "NOTICE: 'make shellcheck' is currently an alias for 'make check-scripts-syntax'" @echo "Later it may become a call to the real shellcheck tool (if available on the" @echo "build system during the configure phase)" @echo "===============================================================================" # Note: currently not part of shellcheck target, because the script below # can test the logic with numerous SHELL_PROGS in a CI setting, and because # check-scripts-syntax probably has checked the basic syntax above already. shellcheck-nde: cd $(srcdir)/tests && SERVICE_FRAMEWORK="selftest" ./nut-driver-enumerator-test.sh shellcheck: shellcheck-disclaimer check-scripts-syntax CPPCHECK = @CPPCHECK@ if HAVE_CPPCHECK cppcheck: cppcheck-cxx11.xml cppcheck-c99.xml # Let the analysis get regenerated due to any change in source; # but note that with our different make implementations to support, # we can not either $(shell find ...) nor blindly say e.g. *.cpp # for each FS structure layer because e.g. there are no ./*.cpp # in the root dir of the codebase (and so make complains there is # `No rule to make target `*.cpp', needed by `cppcheck-cxx11.xml'`) # # Note that the actual `cppcheck` scan finds all files it likes # (so if CPPCHECK_SRC_* misses something, it just won't trigger # automagically a rebuild of the XML in developer working cycles). CPPCHECK_SRC_H = $(top_srcdir)/*/*.h $(top_srcdir)/*/*/*.h # CPPCHECK_SRC_H += $(top_srcdir)/*.h CPPCHECK_SRC_C = $(top_srcdir)/*/*.c $(top_srcdir)/*/*/*.c # CPPCHECK_SRC_C += $(top_srcdir)/*.cpp CPPCHECK_SRC_CXX = $(top_srcdir)/*/*.cpp # CPPCHECK_SRC_CXX += $(top_srcdir)/*.cpp $(top_srcdir)/*/*/*.cpp cppcheck-cxx11.xml: $(CPPCHECK_SRC_CXX) $(CPPCHECK_SRC_H) $(CPPCHECK) --std=c++11 --enable=all --inconclusive --xml --xml-version=2 . 2>$@ cppcheck-c99.xml: $(CPPCHECK_SRC_C) $(CPPCHECK_SRC_H) $(CPPCHECK) --std=c99 --enable=all --inconclusive --xml --xml-version=2 . 2>$@ else !HAVE_CPPCHECK cppcheck: @echo "CPPCHECK analysis not available since 'cppcheck' was not found." endif !HAVE_CPPCHECK sockdebug: +cd $(builddir)/server && $(MAKE) $(AM_MAKEFLAGS) sockdebug$(EXEEXT) # ---------------------------------------------------------------------- # Automatically generate the ChangeLog from Git logs: MAINTAINERCLEANFILES += ChangeLog # CI builds can leave a log of selected features: MAINTAINERCLEANFILES += config.nut_report_feature.log* # Older boundary of the ChangeLog commits range # It can be a tag ('v2.2.0'), a commit hash, a date, ... # See gitrevisions for more information on specifying ranges GITLOG_START_POINT=v2.6.0 # Force ChangeLog regeneration upon make dist (due to nonexistant 'dummy-stamp'), # in case it has already been generated previously # Note that the script is hard-coded to inspect Git workspace which contains # the current dir, and defaults to generate a "ChangeLog" in the current dir. # The script itself is generated from a template, so resides in builddir. dummy-stamp: ChangeLog: dummy-stamp +@$(MAKE) $(AM_MAKEFLAGS) $(abs_top_builddir)/ChangeLog if WITH_PDF_NONASCII_TITLES WITH_PDF_NONASCII_TITLES_ENVVAR = WITH_PDF_NONASCII_TITLES=yes else !WITH_PDF_NONASCII_TITLES WITH_PDF_NONASCII_TITLES_ENVVAR = WITH_PDF_NONASCII_TITLES=no endif !WITH_PDF_NONASCII_TITLES # Be sure to not confuse with a DIST'ed file (and so try to overwrite it); # do however avoid re-generating it if already made on a previous pass and # the Git HEAD pointer (branch) or its actual "index" or "object" database # did not change since then - meaning the local developer or CI did not # modify the metadata (subsequent generation of the huge PDF/HTML files # can cost dearly). # Note there's a bit more fuss about Git internals which NUT should not # really care about encapsulation-wise (detection of NUT_GITDIR location # which may reside elsewhere, e.g. with local repo clones with reference # repo configuration, or submodules). But this is a Git-crawling target # anyway, and in the worst case (Git's design changes) we would spend a # bit of time researching the FS in vain, and go on to re-generate the # ChangeLog when maybe we should not have - oh well. # WARNING: The CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR=true mode here is # default to allow for prettier documentation, but it can require too much # memory for weaker build systems. Set it to false when calling make there. CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR_ENVVAR = true $(abs_top_builddir)/ChangeLog: tools/gitlog2changelog.py dummy-stamp @cd $(abs_top_srcdir) && \ if test -e .git ; then \ NUT_GITDIR=".git" ; if test -r "$${NUT_GITDIR}" -a ! -d "$${NUT_GITDIR}" ; then GD="`grep -E '^gitdir:' "$${NUT_GITDIR}" | sed 's/^gitdir: *//'`" && test -n "$$GD" -a -d "$$GD" && NUT_GITDIR="$$GD" ; fi ; \ if test -s "$@" -a -d "$${NUT_GITDIR}" && test -z "`find "$${NUT_GITDIR}" -newer "$@" 2>/dev/null`" ; then \ echo " DOC-CHANGELOG-GENERATE $@ : SKIP (keep existing)" ; \ echo "Using still-valid ChangeLog file generated earlier from same revision of Git source metadata in '$${NUT_GITDIR}'" >&2 ; \ else \ if test -s "$@" ; then \ echo " DOC-CHANGELOG-GENERATE $@ : RE-GENERATE (older than Git workspace metadata) ..." ; \ else \ echo " DOC-CHANGELOG-GENERATE $@ : GENERATE (currently absent) ..." ; \ fi ; \ CHANGELOG_FILE="$@" $(WITH_PDF_NONASCII_TITLES_ENVVAR) \ CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR="$(CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR_ENVVAR)" \ $(abs_top_builddir)/tools/gitlog2changelog.py $(GITLOG_START_POINT) \ && { echo " DOC-CHANGELOG-GENERATE $@ : SUCCESS"; } \ || { \ echo " DOC-CHANGELOG-GENERATE $@ : FAILED (non-fatal)" >&2 ; \ printf "gitlog2changelog.py failed to generate the ChangeLog.\n\nNOTE: See https://github.com/networkupstools/nut/commits/master for change history.\n\n" > "$@" ; \ } ; \ fi ; \ else \ if test x"$(abs_top_srcdir)" != x"$(abs_top_builddir)" -a -s ./ChangeLog ; then \ echo " DOC-CHANGELOG-GENERATE $@ : SKIP (keep existing)" ; \ if ! diff ./ChangeLog "$@" >/dev/null 2>/dev/null ; then \ echo "Using distributed ChangeLog file from sources (and builddir is not srcdir)" >&2 ; \ rm -f "$@" || true ; \ cp -pf ./ChangeLog "$@" || { cat ./ChangeLog > "$@" ; touch -r ./ChangeLog "$@" || true ; } ; \ else \ echo "Using distributed ChangeLog file from sources (and builddir already has content identical to one in srcdir)" >&2 ; \ fi ; \ else \ if test -s "$@" ; then \ echo " DOC-CHANGELOG-GENERATE $@ : SKIP (keep existing)" ; \ echo "Using distributed ChangeLog file from sources (and builddir is srcdir)" >&2 ; \ else \ echo " DOC-CHANGELOG-GENERATE $@ : FAILED (non-fatal)" >&2 ; \ printf "Failed to generate the ChangeLog.\n\nNOTE: See https://github.com/networkupstools/nut/commits/master for change history.\n\n" > "$@" ; \ fi ; \ fi ; \ fi ChangeLog.adoc: ChangeLog +cd $(abs_top_builddir)/docs && $(MAKE) $(AM_MAKEFLAGS) ../ChangeLog.adoc nut_version.h include/nut_version.h: +cd $(abs_top_builddir)/include && $(MAKE) $(AM_MAKEFLAGS) nut_version.h tools/gitlog2changelog.py: tools/gitlog2changelog.py.in +cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) -s $(@F) # ---------------------------------------------------------------------- # Maintainers targets: distribution signature and hashes # Assume tools are available (and maintainer GPG keys) dist-files: dist dist-sig dist-hash nut-@PACKAGE_VERSION@.tar.gz: dist nut-@PACKAGE_VERSION@.tar.gz.sig: dist-sig nut-@PACKAGE_VERSION@.tar.gz.md5 nut-@PACKAGE_VERSION@.tar.gz.sha256: dist-hash dist-sig: nut-@PACKAGE_VERSION@.tar.gz rm -f nut-@PACKAGE_VERSION@.tar.gz.sig gpg --detach-sign nut-@PACKAGE_VERSION@.tar.gz dist-hash: nut-@PACKAGE_VERSION@.tar.gz md5sum nut-@PACKAGE_VERSION@.tar.gz > nut-@PACKAGE_VERSION@.tar.gz.md5 sha256sum nut-@PACKAGE_VERSION@.tar.gz > nut-@PACKAGE_VERSION@.tar.gz.sha256 # ---------------------------------------------------------------------- # targets from old build system (pre-automake). # supported for a period of time for backward "compatibility". WARN="----------------------------------------------------------------------" build: @echo $(WARN) @echo "Warning: 'make build' is deprecated. Use 'make all' instead." @echo $(WARN) +$(MAKE) $(AM_MAKEFLAGS) all install-bin: @echo $(WARN) @echo "Warning: 'make install-bin' is deprecated." @echo "Use 'make install-exec' instead for a similar effect." @echo $(WARN) +cd common; $(MAKE) $(AM_MAKEFLAGS) install +cd drivers; $(MAKE) $(AM_MAKEFLAGS) install +cd server; $(MAKE) $(AM_MAKEFLAGS) install +cd clients; $(MAKE) $(AM_MAKEFLAGS) install install-man: install-data-recursive @echo $(WARN) @echo "Warning: 'make install-man' is deprecated." @echo "Use 'cd docs/man; make install' instead." @echo $(WARN) +cd docs/man; $(MAKE) $(AM_MAKEFLAGS) install install-conf: @echo $(WARN) @echo "Warning: 'make install-conf' is deprecated." @echo "Use 'cd conf; make install' instead." @echo $(WARN) +cd conf; $(MAKE) $(AM_MAKEFLAGS) install # The target install-data already has a standardized meaning under automake install-dirs: @echo $(WARN) @echo "Warning: 'make install-dirs' is deprecated." @echo "Use 'make installdirs' instead." @echo $(WARN) +$(MAKE) $(AM_MAKEFLAGS) installdirs cgi build-cgi install-cgi install-cgi-dir install-cgi-bin \ install-cgi-man install-cgi-conf install-cgi-html: @echo "Error: 'make $@' no longer exists." @echo "Use './configure --with-cgi' instead." install-lib: @echo "Error: 'make $@' no longer exists." @echo "Use './configure --with-dev' instead." usb build-usb install-usb: @echo "Error: 'make $@' no longer exists." @echo "Use './configure --with-usb' instead." snmp build-snmp install-snmp install-snmp-mgr install-snmp-man: @echo "Error: 'make $@' no longer exists." @echo "Use './configure --with-snmp' instead." setver: @echo "Error: 'make setver' no longer exists." @echo "Edit configure.ac to set version number." # Adjust permissions when installing as `root` into the actual system. # We honour DESTDIR anyway, as someone can install into a chroot etc. # NOTE: Might be an 'install-data-hook' (for dirs) and/or 'install-exec-hook' # (for service restart) but better not force this on everyone? # It is also up to the end-user making such an installation to remove (or not) # dirs and files made below. # To err on the safe side in cross builds, we ignore Windows builds and those # not built for the same system as the build host. install-data-hook: @case "@target_os@" in *mingw*) exit 0;; esac ; \ if [ x"@host_os@" != x"@build_os@" ]; then exit 0 ; fi ; \ if [ x"@target_os@" != x"@build_os@" ]; then exit 0 ; fi ; \ if (command -v id) && [ x"`id -u`" = x0 ] && [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \ echo "================================================================================" >&2 ; \ echo "| NUT data files have been installed into the system, now consider running |" >&2 ; \ echo "| '(sudo) make install-as-root' to apply permissions and service state changes |" >&2 ; \ echo "================================================================================" >&2 ; \ fi if HAVE_SYSTEMD HAVE_SYSTEMD = true else !HAVE_SYSTEMD HAVE_SYSTEMD = false endif !HAVE_SYSTEMD if WITH_SYSTEMD_TMPFILES WITH_SYSTEMD_TMPFILES = true else !WITH_SYSTEMD_TMPFILES WITH_SYSTEMD_TMPFILES = false endif !WITH_SYSTEMD_TMPFILES if WITH_SYSTEMD_PRESET WITH_SYSTEMD_PRESET = true else !WITH_SYSTEMD_PRESET WITH_SYSTEMD_PRESET = false endif !WITH_SYSTEMD_PRESET if WITH_CGI WITH_CGI = true else !WITH_CGI WITH_CGI = false endif !WITH_CGI if WITH_SOLARIS_SMF WITH_SOLARIS_SMF = true else !WITH_SOLARIS_SMF WITH_SOLARIS_SMF = false endif !WITH_SOLARIS_SMF if WITH_SOLARIS_INIT WITH_SOLARIS_INIT = true else !WITH_SOLARIS_INIT WITH_SOLARIS_INIT = false endif !WITH_SOLARIS_INIT # TODO: Actually move this into scripts like Solaris/postinstall # using OS-specific `useradd`/`groupadd`, etc. # Note that as we stop services, we may be dealing with (older) # distros that do not follow current naming in NUT code base. install-as-root: @+echo "$@: starting (no-op if not root)" >&2 ; \ case "@target_os@" in *mingw*) echo "$@: SKIP: not supported for this target_os='@target_os@'" >&2 ; exit 0;; esac ; \ if [ x"@host_os@" != x"@build_os@" ]; then echo "$@: SKIP: build_os='@build_os@' is not host_os='@host_os@'" >&2 ; exit 0 ; fi ; \ if [ x"@target_os@" != x"@build_os@" ]; then echo "$@: SKIP: build_os='@build_os@' is not target_os='@target_os@'" >&2 ; exit 0 ; fi ; \ if (command -v id) && [ x"`id -u`" = x0 ] ; then \ echo "$@: we seem to be root, PROCEEDING" >&2 ; \ else \ echo "$@: SKIP: we seem to NOT be root" >&2 ; \ exit 0 ; \ fi ; \ prefix="@prefix@"; \ if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \ if $(HAVE_SYSTEMD) ; then \ echo "$@: Stop NUT services, if any" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-monitor.service nut-server.service || true ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-driver.service || true ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-driver.target || true ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut-udev-settle.service || true ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ stop nut.target || true ; \ fi ; \ if $(WITH_SOLARIS_SMF) || $(WITH_SOLARIS_INIT) ; then \ if $(WITH_SOLARIS_SMF) ; then \ echo "$@: Stop NUT services, if any" >&2 ; \ SMF_ACTIVE="`/usr/bin/svcs -a -Hostate,fmri | grep svc:/system/power/ | grep -v disabled | awk '{print $$2}'`" ; \ for S in $$SMF_ACTIVE ; do \ /usr/sbin/svcadm disable -ts $$S || true ; \ done ; \ fi ; \ $(top_builddir)/scripts/Solaris/preremove \ || exit ; \ fi ; \ fi ; \ $(MAKE) $(AM_FLAGS) DESTDIR="$(DESTDIR)" install || exit ; \ if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \ if $(WITH_SOLARIS_SMF) || $(WITH_SOLARIS_INIT) ; then \ $(top_builddir)/scripts/Solaris/preinstall && \ $(top_builddir)/scripts/Solaris/postinstall ; \ exit ; \ fi ; \ fi ; \ echo " MKDIR $(DESTDIR)/@STATEPATH@ $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \ $(MKDIR_P) "$(DESTDIR)/@STATEPATH@/upssched" && \ for D in "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" "@CONFPATH@" ; do \ case x"$$D" in \ x|x@*) ;; \ *) echo " MKDIR $(DESTDIR)/$$D" >&2 ; \ $(MKDIR_P) "$(DESTDIR)/$$D" \ || exit ;; \ esac ; \ done ; \ if (command -v chmod) ; then \ echo " CHMOD(0770) $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \ chmod 0770 "$(DESTDIR)/@STATEPATH@/upssched" \ || exit ; \ for D in "@STATEPATH@" "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" ; do \ case x"$$D" in \ x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \ *) echo " CHMOD(0770) $(DESTDIR)/$$D" >&2 ; \ chmod 0770 "$(DESTDIR)/$$D" \ || exit ;; \ esac ; \ done ; \ case x"@CONFPATH@" in \ x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \ *) echo " CHMOD(0751) $(DESTDIR)/@CONFPATH@" >&2 ; \ chmod 0751 "$(DESTDIR)/@CONFPATH@" \ || exit ;; \ esac ; \ for F in hosts.conf.sample upsstats-single.html.sample upsstats.html.sample upsset.conf.sample ; do \ echo " CHMOD(0644) CGI: $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \ chmod 0644 "$(DESTDIR)/@CONFPATH@/$$F" \ || { if $(WITH_CGI) ; then exit 1 ; else true ; fi ; } ; \ done ; \ for F in nut.conf.sample ups.conf.sample upsd.conf.sample upsd.users.sample upsmon.conf.sample upssched.conf.sample ; do \ echo " CHMOD(0640) $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \ chmod 0640 "$(DESTDIR)/@CONFPATH@/$$F" \ || exit ; \ done ; \ else \ echo "$@: WARNING: Can not CHMOD created locations!" >&2 ; \ fi ; \ if (command -v chown) && test 0 -lt "`id -u '@RUN_AS_USER@'`" \ && ( test 0 -lt "`getent group '@RUN_AS_GROUP@' | awk -F: '{print $$3}'`" || test 0 -lt "`id -g '@RUN_AS_GROUP@'`" ) \ ; then \ echo " CHOWN(@RUN_AS_USER@:@RUN_AS_GROUP@) $(DESTDIR)/@STATEPATH@/upssched" >&2 ; \ chown "@RUN_AS_USER@:@RUN_AS_GROUP@" "$(DESTDIR)/@STATEPATH@/upssched" \ || exit ; \ for D in "@STATEPATH@" "@PIDPATH@" "@ALTPIDPATH@" "@ALTSTATEPATH@" ; do \ case x"$$D" in \ x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \ *) echo " CHOWN(@RUN_AS_USER@:@RUN_AS_GROUP@) $(DESTDIR)/$$D" >&2 ; \ chown "@RUN_AS_USER@:@RUN_AS_GROUP@" "$(DESTDIR)/$$D" \ || exit ;; \ esac ; \ done ; \ case x"@CONFPATH@" in \ x|x@*|x/run|x/var/run|x/tmp|x/var/tmp|x/dev/shm|x/etc|x/var|x/usr|x/usr/local|x/usr/local/etc|x/usr/etc) ;; \ *) echo " CHOWN(root:@RUN_AS_GROUP@) $(DESTDIR)/@CONFPATH@" >&2 ; \ chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@" \ || exit ;; \ esac ; \ for F in hosts.conf.sample upsstats-single.html.sample upsstats.html.sample upsset.conf.sample ; do \ echo " CHOWN(root:@RUN_AS_GROUP@) CGI: $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \ chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@/$$F" \ || { if $(WITH_CGI) ; then exit 1 ; else true ; fi ; } ; \ done ; \ for F in nut.conf.sample ups.conf.sample upsd.conf.sample upsd.users.sample upsmon.conf.sample upssched.conf.sample ; do \ echo " CHOWN(root:@RUN_AS_GROUP@) $(DESTDIR)/@CONFPATH@/$$F" >&2 ; \ chown "root:@RUN_AS_GROUP@" "$(DESTDIR)/@CONFPATH@/$$F" \ || exit ; \ done ; \ else \ echo "$@: WARNING: Can not CHOWN created locations!" >&2 ; \ fi ; \ if [ x"$(DESTDIR)" = x -o x"$(DESTDIR)" = x/ ] ; then \ applied_udev=false ; \ if $(HAVE_SYSTEMD) ; then \ echo "$@: Activate default systemd layout, restart services:" >&2 ; \ if $(WITH_SYSTEMD_TMPFILES) ; then \ echo "$@: Apply systemd-tmpfiles presets" >&2 ; \ @SYSTEMD_TMPFILES_PROGRAM@ --create || exit ; \ fi ; \ echo "$@: Learn systemd definition changes" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ daemon-reload || exit ; \ if $(WITH_SYSTEMD_PRESET) ; then \ echo "$@: Apply systemd enabled/disabled service presets" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ preset-all || exit ; \ else \ echo "$@: Apply systemd enabled/disabled service defaults" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ disable nut.target nut-driver.target nut-udev-settle.service nut-monitor nut-server nut-driver-enumerator.path nut-driver-enumerator.service || exit ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ enable nut.target nut-driver.target nut-udev-settle.service nut-monitor nut-server nut-driver-enumerator.path nut-driver-enumerator.service || exit ; \ fi ; \ echo "$@: Reconfigure nut-driver-enumerator (service instance wrapping)" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ restart udev && applied_udev=true || true ; \ $(top_builddir)/scripts/upsdrvsvcctl/nut-driver-enumerator.sh --reconfigure || { RES=$$?; if [ $$RES != 42 ] ; then exit $$RES ; fi ; } ; \ echo "$@: Restart NUT services" >&2 ; \ @SYSTEMD_SYSTEMCTL_PROGRAM@ restart nut-driver-enumerator.service nut-monitor.service nut-server.service || exit ; \ fi ; \ if ! $${applied_udev} && (command -v udevadm); then \ udevadm control --reload-rules && udevadm trigger && applied_udev=true || true ; \ fi ; \ fi ; \ echo "$@: finished SUCCESSFULLY" >&2 # Clean the dist tarball and packages MAINTAINERCLEANFILES_DISTBALL = nut-*.tar.gz # HP-UX: MAINTAINERCLEANFILES_PACKAGES = NUT_HPUX_package@PACKAGE_VERSION@.depot NUT_HPUX_package-@PACKAGE_VERSION@.depot # AIX as below, and RedHat-compatible (cover binary and source packages): MAINTAINERCLEANFILES_PACKAGES += nut*rpm # Debian-compatible (cover binary and source packages): MAINTAINERCLEANFILES_PACKAGES += nut*deb # Solaris SVR4 package archives: MAINTAINERCLEANFILES_PACKAGES += NUT_solaris_*_package@PACKAGE_VERSION@.local.gz NUT_solaris_*_package-@PACKAGE_VERSION@.local.gz # Newer Solaris IPS (aka "pkg(5)" format archives) MAINTAINERCLEANFILES_PACKAGES += *.p5p MAINTAINERCLEANFILES += $(MAINTAINERCLEANFILES_DISTBALL) MAINTAINERCLEANFILES += $(MAINTAINERCLEANFILES_PACKAGES) package: dist +DESTDIR="$(abs_builddir)/_install_pkgprotodir" ; export DESTDIR; \ rm -rf "$$DESTDIR"; \ case "`uname -s`" in \ "HP-UX") \ ( cd scripts/HP-UX && \ $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$DESTDIR" package && \ mv NUT_HPUX_package.depot $(abs_top_builddir)/NUT_HPUX_package-@PACKAGE_VERSION@.depot ) ;; \ "SunOS") \ $(MAKE) $(AM_MAKEFLAGS) && \ $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$DESTDIR" install && \ ( cd scripts/Solaris && \ $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$DESTDIR" package ) && \ $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$DESTDIR" uninstall && \ rm -rf "$$DESTDIR" || \ { echo "FAILED to produce SunOS packages, inspect '$$DESTDIR' for clues" >&2 ; exit 1; } ;; \ "AIX") \ if test -d /usr/src/packages/SPECS -a -w /usr/src/packages/SPECS ; then : ; else echo "Can not write to /usr/src/packages/SPECS" >&2 ; exit 1; fi ; \ if test -d /usr/src/packages/SOURCES -a -w /usr/src/packages/SOURCES ; then : ; else echo "Can not write to /usr/src/packages/SOURCES" >&2 ; exit 1; fi ; \ $(MAKE) $(AM_MAKEFLAGS) dist && \ cp scripts/Aix/nut-aix.spec /usr/src/packages/SPECS && \ cp scripts/Aix/nut.init nut-@PACKAGE_VERSION@.tar.gz /usr/src/packages/SOURCES && \ rpm -ba /usr/src/packages/SPECS/nut-aix.spec && \ mv /usr/src/packages/RPMS/nut*rpm $(abs_top_builddir)/ ;; \ *) echo "Unsupported OS for 'make $@' (no recipe bound)" >&2; exit 1;; \ esac if HAVE_WINDOWS # Steam-roll over all executables/libs we have placed in DESTDIR and copy over # any resolved dependencies from the cross-build (or native MSYS2) environment. # Then hardlink libraries for sbin... (alternative: all bins in one dir) # TOTHINK: Are there more dirs to consider? So far we cover bindir, sbindir and # driverexecdir (e.g. some Linux distros place drivers to /lib/nut while tools # and daemons are in /usr/bin and /usr/sbin), and cgiexecdir, and occasional # helpers like "sockdebug.exe" in libexecdir; anything else?.. # Note we hold existance of cgiexecdir as optional, but the name is expected to # be defined. Other dirs are "just assumed" to exist (that we are not packaging # some NUT build without drivers/tools/daemons). Subject to change if needed. # Currently this is handled by a CHECKING... step that should fail if it hits # anything. install-win-bundle: all @if test -z "$(DESTDIR)" ; then echo "ERROR: '$@': Bundle may only be installed to some DESTDIR prototype area'" >&2 ; exit 1; fi +$(MAKE) $(AM_MAKEFLAGS) DESTDIR='$(DESTDIR)' install +$(MAKE) $(AM_MAKEFLAGS) DESTDIR='$(DESTDIR)' install-win-bundle-thirdparty install-win-bundle-thirdparty: @if test -z "$(DESTDIR)" ; then echo "ERROR: '$@': Bundle may only be installed to some DESTDIR prototype area'" >&2 ; exit 1; fi @echo "Searching which DLLs need to be bundled with NUT for Windows..." >&2 @if test -z "$$ARCH" ; then \ if test -n "$(target)" ; then \ ARCH='$(target)' \ ; else \ if test -n "$(target_triplet)" ; then ARCH='$(target_triplet)' ; fi ; \ fi ; \ fi ; \ if test -n "$$ARCH" ; then export ARCH ; fi ; \ DESTDIR='$(DESTDIR)' ; export DESTDIR ; \ ( cd '$(DESTDIR)' || exit ; \ DESTDIR="" '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ | while read D ; do \ echo " DLL->bin $$D" 2>&1 ; \ cp -pf "$$D" './$(bindir)/' ; \ done ; \ ) || exit ; \ ( if test x"$(bindir)" = x"$(sbindir)" ; then exit 0 ; fi ; \ cd '$(DESTDIR)/$(sbindir)' || exit ; \ '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ | while read D ; do \ echo " DLL->sbin $$D" 2>&1 ; \ ln -f '$(DESTDIR)/$(bindir)'/"`basename "$$D"`" ./ ; \ done ; \ ) || exit ; \ ( if test x"$(driverexecdir)" = x"$(bindir)" ; then exit 0 ; fi ; \ if test x"$(driverexecdir)" = x"$(sbindir)" ; then exit 0 ; fi ; \ cd '$(DESTDIR)/$(driverexecdir)' || exit ; \ '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ | while read D ; do \ echo " DLL->drv $$D" 2>&1 ; \ ln -f '$(DESTDIR)/$(bindir)'/"`basename "$$D"`" ./ ; \ done ; \ ) || exit ; \ ( if test -z "$(cgiexecdir)" -o ! -d "$(DESTDIR)/$(cgiexecdir)" ; then exit 0 ; fi ; \ if test x"$(cgiexecdir)" = x"$(bindir)" ; then exit 0 ; fi ; \ if test x"$(cgiexecdir)" = x"$(sbindir)" ; then exit 0 ; fi ; \ if test x"$(driverexecdir)" = x"$(cgiexecdir)" ; then exit 0 ; fi ; \ cd '$(DESTDIR)/$(cgiexecdir)' || exit ; \ '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ | while read D ; do \ echo " DLL->cgi $$D" 2>&1 ; \ ln -f '$(DESTDIR)/$(bindir)'/"`basename "$$D"`" ./ ; \ done ; \ ) || exit ; \ ( if test x"$(libexecdir)" = x"$(bindir)" ; then exit 0 ; fi ; \ if test x"$(libexecdir)" = x"$(sbindir)" ; then exit 0 ; fi ; \ if test x"$(libexecdir)" = x"$(driverexecdir)" ; then exit 0 ; fi ; \ if test x"$(libexecdir)" = x"$(cgiexecdir)" ; then exit 0 ; fi ; \ cd '$(DESTDIR)/$(libexecdir)' || exit ; \ '$(abs_top_srcdir)/scripts/Windows/dllldd.sh' dllldddir . \ | while read D ; do \ echo " DLL->libexec $$D" 2>&1 ; \ ln -f '$(DESTDIR)/$(bindir)'/"`basename "$$D"`" ./ ; \ done ; \ ) || exit @echo "CHECKING if any executable files were installed to locations other than those covered by this recipe, so might not have needed DLLs bundled near them" >&2 ; \ relbindir="`echo './$(bindir)/' | sed 's,//*,/,g'`" ; \ relsbindir="`echo './$(sbindir)/' | sed 's,//*,/,g'`" ; \ reldriverexecdir="`echo './$(driverexecdir)/' | sed 's,//*,/,g'`" ; \ relcgiexecdir="`echo './$(cgiexecdir)/' | sed 's,//*,/,g'`" ; \ rellibexecdir="`echo './$(libexecdir)/' | sed 's,//*,/,g'`" ; \ cd '$(DESTDIR)' || exit ; \ find . -type f | grep -Ei '\.(exe|dll)$$' \ | grep -vE "^($${relbindir}|$${relsbindir}|$${reldriverexecdir}|$${relcgiexecdir}|$${rellibexecdir})" \ | ( RES=0 ; while IFS= read LINE ; do echo "$$LINE" ; RES=1; done; exit $$RES ) else !HAVE_WINDOWS install-win-bundle: @echo " SKIP '$@' : not enabled for current build configuration" install-win-bundle-thirdparty: @echo " SKIP '$@' : not enabled for current build configuration" endif !HAVE_WINDOWS print-MAINTAINERCLEANFILES print-REALCLEANFILES: @echo $(MAINTAINERCLEANFILES) print-DISTCLEANFILES: @echo $(DISTCLEANFILES) # TODO: Recursive mode to consider patterns defined in sub-dir makefiles git-realclean-check: @if test -e .git && (command -v git); then \ git status --ignored || while read F ; do \ for P in $(MAINTAINERCLEANFILES) ; do \ case "$$F" in \ */$$P) exit 1 ;; \ esac ; \ done; \ done ; \ fi nut-2.8.3/configure.ac0000644000200500020050000100414415001552635011533 00000000000000dnl +------------------------------------------------------------------+ dnl | Network UPS Tools: configure.ac | dnl +------------------------------------------------------------------+ dnl # Support for older autoconf without m4_esyscmd_s m4_ifndef([m4_chomp_all], [m4_define([m4_chomp_all], [m4_format([[%.*s]], m4_bregexp(m4_translit([[$1]], [/], [/ ]), [/*$]), [$1])])]) m4_ifndef([m4_esyscmd_s], [m4_define([m4_esyscmd_s], [m4_chomp_all(m4_esyscmd([$1]))])]) dnl NUT version number is defined here, with a Git suffixed macro like dnl NUT_VERSION_MACRO "2.7.4-2838+gdfc3ac08" dnl defined separately in include/nut_version.h (generated by make) dnl ...or not defined, for quicker rebuilds, depending on settings. dnl Old hard-coded approach (mangled a bit): dnl AC INIT([nut],[2.8.2.1],[https://github.com/networkupstools/nut/issues]) dnl Note: srcdir is only set after AC INIT has completed, but $0 points dnl to the generated configure script which is part of dist tarball and dnl should be at source root too. dnl Note: this gets evaluated (script called) a lot of times during autoconf dnl but ends up as static strings in the generated configure script. It may dnl be beneficial to have a `version.m4` generated by `autogen.sh` and/or dnl shipped in a tarball, allowing for a singular include into configure.ac dnl See https://github.com/networkupstools/nut/issues/1949 for details. dnl Oddly, autoconf-2.69 on CentOS 7 both complains that AC INIT argument dnl is not a literal, and does contain expected values in the generated dnl script and include/config.h. A "pure" m4 solution would be quieter. AC_INIT([nut], m4_esyscmd_s([NUT_VERSION_QUERY=VER50 "`dirname "$0"`/tools/gitlog2version.sh" 2>/dev/null]), [https://github.com/networkupstools/nut/issues],[nut], m4_esyscmd_s([NUT_VERSION_QUERY=URL "`dirname "$0"`/tools/gitlog2version.sh" 2>/dev/null])) dnl See docs/maintainer-guide.txt about releases - updating the version dnl above is a small part of the consistent ritual! dnl PACKAGE_URL="https://www.networkupstools.org/" for development iterations dnl or "https://www.networkupstools.org/historic/v1.2.3/index.html" for release dnl snapshots further set in stone. Either way, there should be a slash and dnl either a filename, or nothing. Adding a bogus filename and chopping it dnl off by `dirname` should do the trick. dnl NOTE: the resulting NUT_WEBSITE_BASE string does not end with a slash! NUT_WEBSITE_BASE="`dirname "${PACKAGE_URL}index.html"`" dnl Fallback, no trailing slash! test -n "${NUT_WEBSITE_BASE-}" || NUT_WEBSITE_BASE='https://www.networkupstools.org' dnl Note: this refers to GITREV at the time of configure script running dnl primarily for better messaging in the script itself (also to render dnl the PDF documentation revision history via docs/docinfo.xml.in). dnl If the NUT codebase in this workspace is being developed and rebuilt dnl without reconfiguration, detailed version in the binaries will differ dnl (that one comes from the NUT_VERSION_MACRO from nut_version.h file). dnl # Example: NUT_SOURCE_GITREV='2.8.2.695.1-696+g0e00f0777' NUT_SOURCE_GITREV="`NUT_VERSION_QUERY=DESC50 "${srcdir}/tools/gitlog2version.sh" 2>/dev/null`" dnl A true/false (literally) response that can be used for prettier messages dnl emitted by NUT code. NUT_SOURCE_GITREV_IS_RELEASE="`NUT_VERSION_QUERY=IS_RELEASE "${srcdir}/tools/gitlog2version.sh" 2>/dev/null || echo false`" NUT_SOURCE_GITREV_IS_PRERELEASE="`NUT_VERSION_QUERY=IS_PRERELEASE "${srcdir}/tools/gitlog2version.sh" 2>/dev/null || echo false`" AS_IF([$NUT_SOURCE_GITREV_IS_RELEASE], [NUT_SOURCE_GITREV_DEVREL="release"], [ AS_IF([$NUT_SOURCE_GITREV_IS_PRERELEASE], [NUT_SOURCE_GITREV_DEVREL="pre-release"], [NUT_SOURCE_GITREV_DEVREL="development iteration"]) ]) dnl Semantic version of most-recent NUT release this code is derived from. dnl It may equal the NUT_SOURCE_GITREV and NUT_SOURCE_GITREV_NUMERIC, but dnl this situation is only expected if NUT_SOURCE_GITREV_IS_RELEASE==true; dnl for a pre-release it may differ from even the base NUT_VERSION numbers dnl (e.g. a commit tagged as 2.8.3-rc5 can have its own NUT_VERSION based dnl on 2.8.2-something, but is assumed as a pre-release for 2.8.3 SEMVER). NUT_SOURCE_GITREV_SEMVER="`NUT_VERSION_QUERY=SEMVER "${srcdir}/tools/gitlog2version.sh" 2>/dev/null`" dnl Gitrev-based build identifier which can be used for e.g. PyPI uploads: dnl # Example: NUT_SOURCE_GITREV_NUMERIC='2.8.2.695.1.696' dnl # NUT_SOURCE_GITREV_NUMERIC="`echo "${NUT_SOURCE_GITREV}" | sed -e 's/^v//' -e 's/@<:@+-@:>@g.*$//' -e 's/-/./g'`" dnl # Without the commit-count since tag (dash-separated part): dnl # Example: NUT_SOURCE_GITREV_NUMERIC='2.8.2.695.1' NUT_SOURCE_GITREV_NUMERIC="`echo "${NUT_SOURCE_GITREV}" | sed -e 's/^v//' -e 's/@<:@+-@:>@g.*$//' -e 's/-@<:@0-9@:>@*$//'`" dnl Note: except for experiments, do not pass this into config.h - use dnl the NUT_VERSION_MACRO from nut_version.h instead. Developers may dnl want to disable their "force-nut-version-header" configure option dnl to reduce rebuild scope and so speed up the iterations with ccache. dnl New "config.h" contents for every reconfig would defeat that purpose! dnl ### AS_IF([test -n "${NUT_SOURCE_GITREV-}"], dnl ### [AC_DEFINE_UNQUOTED([NUT_SOURCE_GITREV], ["${NUT_SOURCE_GITREV}"], [NUT source revision when the build was configured])], dnl ### [AC_DEFINE([NUT_SOURCE_GITREV], [NULL], [NUT source revision when the build was configured: not detected])]) dnl Keep track of command-line options passed to this script: AC_MSG_CHECKING([for CONFIG_FLAGS]) CONFIG_FLAGS="" dnl Keep each token quoted, in case spaces or other special chars crawl in: _flag_enable_inplace_runtime="" for F in "$@" ; do case "$F" in *=*" "*) NF="$(echo "$F" | sed "s,=,=',")""'" && F="$NF" ;; esac case "$F" in --disable-inplace-runtime|--enable-inplace-runtime=no) _flag_enable_inplace_runtime="no" ;; --enable-inplace-runtime*) _flag_enable_inplace_runtime="$F" ;; *) test -z "${CONFIG_FLAGS}" \ && CONFIG_FLAGS="$F" \ || CONFIG_FLAGS="${CONFIG_FLAGS} $F" ;; esac done dnl Keep it "known" that we tried to re-use at least some local configuration dnl so unspecified options are not necessarily at default values for this script AS_IF([test x"${NUT_VERSION_DEPLOYED-}" = x""], [_flag_enable_inplace_runtime="reenter"]) F="" AS_IF([test x"${NUT_VERSION_DEPLOYED-}" != x && test x"${NUT_VERSION_DEPLOYED-}" != x""], [ dnl Even if explicitly disabled... did we re-enter? Save the value to be seen: F="--enable-inplace-runtime='${NUT_VERSION_DEPLOYED}'" ],[ AS_CASE(["${_flag_enable_inplace_runtime}"], [no|""|reenter], [], [F="${_flag_enable_inplace_runtime}"]) ]) AS_IF([test x"$F" != x], [ test -z "${CONFIG_FLAGS}" \ && CONFIG_FLAGS="$F" \ || CONFIG_FLAGS="${CONFIG_FLAGS} $F" ]) unset _flag_enable_inplace_runtime unset F unset NF AC_MSG_RESULT([${CONFIG_FLAGS}]) AC_DEFINE_UNQUOTED([CONFIG_FLAGS],["${CONFIG_FLAGS}"],[Flags passed to configure script]) AC_SUBST(CONFIG_FLAGS) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_SRCDIR(server/upsd.c) AC_CONFIG_MACRO_DIR([m4]) AS_IF([test x"${NUT_SOURCE_GITREV}" = x], [echo "Network UPS Tools version ${PACKAGE_VERSION}"], [AS_IF([test x"${NUT_SOURCE_GITREV}" = x"${PACKAGE_VERSION}"], [echo "Network UPS Tools version ${PACKAGE_VERSION} ${NUT_SOURCE_GITREV_DEVREL}"], [echo "Network UPS Tools version ${PACKAGE_VERSION} (${NUT_SOURCE_GITREV}) ${NUT_SOURCE_GITREV_DEVREL}"]) ]) AC_CANONICAL_TARGET NUT_CHECK_OS NUT_ARG_ENABLE([configure-debug], [Request that this run of the configure script reports more details about values it discovered, primarily for developer troubleshooting], [no]) dnl Further below we shuffle variants of these values possibly stripped of dnl warnings or with added further values. Here we save the most-original copy dnl so it can be passed e.g. to "make distcheck" the way the caller intended. NUT_CONFIG_CFLAGS="" NUT_CONFIG_CPPFLAGS="" NUT_CONFIG_CXXFLAGS="" NUT_CONFIG_LDFLAGS="" AS_IF([test -n "${CFLAGS-}" -a x"${CFLAGS-}" != x" "], [NUT_CONFIG_CFLAGS="${CFLAGS-}"]) AS_IF([test -n "${CXXFLAGS-}" -a x"${CXXFLAGS-}" != x" "], [NUT_CONFIG_CXXFLAGS="${CXXFLAGS-}"]) AS_IF([test -n "${CPPFLAGS-}" -a x"${CPPFLAGS-}" != x" "], [NUT_CONFIG_CPPFLAGS="${CPPFLAGS-}"]) AS_IF([test -n "${LDFLAGS-}" -a x"${LDFLAGS-}" != x" "], [NUT_CONFIG_LDFLAGS="${LDFLAGS-}"]) AC_SUBST([NUT_CONFIG_CFLAGS]) AC_SUBST([NUT_CONFIG_CXXFLAGS]) AC_SUBST([NUT_CONFIG_CPPFLAGS]) AC_SUBST([NUT_CONFIG_LDFLAGS]) NUT_STASH_WARNINGS AC_CONFIG_HEADERS([include/config.h]) AC_PREFIX_DEFAULT(/usr/local/ups) AM_INIT_AUTOMAKE([subdir-objects]) AS_CASE([${target_os}], [*mingw*], [AS_CASE([${CFLAGS-}${CXXFLAGS-}], [*"-std=c"*|*-ansi*], [ AC_MSG_NOTICE( [----------------------------------------------------------------------- WARNING: It seems you are building with MinGW and requested a strict C/C++ language mode. Per https://stackoverflow.com/a/76780217/4715872 MinGW may not define WIN32 and other options needed for proper building and linking. If this happens, please retry with GNU C/C++ language mode options instead. -----------------------------------------------------------------------]) sleep 5 ])] ) dnl +------------------------------------------------------------------- dnl Help avoid "polluting" CFLAGS etc. with auto-settings like "-g -O2" dnl at least if we intend to tune --with-debuginfo anyway (where we check dnl if the caller asked for specific optimizations). Following some dnl experimentation, we do not want to actually mangle the flags provided dnl by autoconf - for GCC at least, the rightmost mentions of conflicting dnl flags on command line win. We just want to know when it is okay to add dnl ours. They may be inherited from "in-place" build setup though. test -n "${CONFIG_CFLAGS-}" || CONFIG_CFLAGS="${CFLAGS-}" test -n "${CONFIG_CXXFLAGS-}" || CONFIG_CXXFLAGS="${CXXFLAGS-}" test -n "${CONFIG_CPPFLAGS-}" || CONFIG_CPPFLAGS="${CPPFLAGS-}" test -n "${CONFIG_LDFLAGS-}" || CONFIG_LDFLAGS="${LDFLAGS-}" AC_SUBST([CONFIG_CFLAGS]) AC_SUBST([CONFIG_CXXFLAGS]) AC_SUBST([CONFIG_CPPFLAGS]) AC_SUBST([CONFIG_LDFLAGS]) dnl +------------------------------------------------------------------- dnl Default to `configure --enable-silent-rules` or `make V=1` for details? dnl This feature seems to require automake-1.13 or newer (1.11+ by other info) dnl On very old systems can comment it away with little loss (then automake-1.10 dnl is known to suffice): m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])], [AC_MSG_NOTICE([Silent Rules feature not defined in this automake version, skipped])]) dnl +------------------------------------------------------------------- dnl we need Autoconf 2.61 or better to enable features of Posix that are extensions to C dnl (and actually 2.64 or better for m4/ax_check_compile_flag.m4 when it is sourced) dnl UPDATE: As tested on CentOS 6, its "autoconf-2.63-5.1.el6.noarch" also suffices. dnl But OpenBSD 6.5 requires autoconf-2.65 and automake-1.13 or newer... AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CFLAGS_BEFORE_ACPROG="${CFLAGS-}"]) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CXXFLAGS_BEFORE_ACPROG="${CXXFLAGS-}"]) ]) AC_MSG_CHECKING(for autoconf macro to enable system extensions) m4_version_prereq(2.61, [ AC_MSG_RESULT(yes) dnl Causes calls to ac_prog stuff, so dittoed below if "no" AC_USE_SYSTEM_EXTENSIONS ], [ AC_MSG_RESULT(no) AC_PROG_CC ]) AC_PREREQ([2.63]) dnl #AC_PREREQ([2.64]) dnl Macro AC_PROG_CC_C99 is obsolete; use AC_PROG_CC dnl Note that NUT does not support building with C89 anyway dnl AC_PROG_CC_C99 dnl Needed for per-target flags AM_PROG_CC_C_O AC_PROG_CPP AC_PROG_CXX AC_PROG_CXX_C_O AC_PATH_PROG([LDD], [ldd]) CFLAGS_AFTER_ACPROG="${CFLAGS-}" CXXFLAGS_AFTER_ACPROG="${CXXFLAGS-}" AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CFLAGS_AFTER_ACPROG="${CFLAGS-}"]) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CXXFLAGS_AFTER_ACPROG="${CXXFLAGS-}"]) ]) dnl # LEGACY DEFAULT FALLBACK which NUT had since 2005 or before: dnl # if autoconf does not set any options, use default/moderate optimizations CFLAGS=${CFLAGS-"-O"} dnl # Not so far a legacy, added for consistency in 2024 :) CXXFLAGS=${CXXFLAGS-"-O"} dnl Check for various integer types AC_TYPE_SSIZE_T AC_TYPE_INTMAX_T AC_TYPE_INT8_T AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_SIZE_T AC_TYPE_UINTMAX_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T dnl +------------------------------------------------------------------- dnl Use "./configure --enable-maintainer-mode" to keep Makefile.in and Makefile dnl in sync after Git updates. AM_MAINTAINER_MODE dnl GNU and BSD make are okay with the syntax, but Sun make/dmake are not: AC_MSG_CHECKING([whether this make implementation supports export VAR=VAL syntax]) dnl # using printf formatting for some funniner shells out there nut_am_output="`printf 'export VAR=VAL\ntest:\n\t@echo "VAR=%s%sVAR%s"\n' '\$' '(' ')' | ${MAKE-make} -f - test`" nut_am_result="$?" AS_IF([test x"${nut_am_result}" = x0 -a x"${nut_am_output}" = x"VAR=VAL"], [ NUT_AM_MAKE_CAN_EXPORT="" AC_MSG_RESULT(yes) ], [ NUT_AM_MAKE_CAN_EXPORT="#ThisMakeCanNotExport# " AC_MSG_RESULT(no: got '${nut_am_output}') ]) AC_SUBST(NUT_AM_MAKE_CAN_EXPORT) dnl Some systems have older autotools without direct macro support for PKG_CONF* NUT_CHECK_PKGCONFIG dnl Various version related processing dnl ---------------------------------- dnl # the following is commented out, because the UPS_VERSION macro now dnl # resides in include/nut_version.h, which is generated by Makefile.am, dnl # rather than in include/config.h, which is generated by configure. The dnl # reason is that the SVN revision should be computed at compile time, dnl # not configure time. dnl AC_DEFINE_UNQUOTED(UPS_VERSION, "${PACKAGE_VERSION}", [NUT version]) dnl However, automatically define the tree version (mostly for AC_SUBST) dnl FIXME: This just picks first 3 chars, assuming single-digit components dnl separated by a dot: TREE_VERSION="`echo ${PACKAGE_VERSION} | awk '{ print substr($0,1,3) }'`" AC_DEFINE_UNQUOTED(TREE_VERSION, "${TREE_VERSION}", [NUT tree version]) dnl Should not be necessary, since old servers have well-defined errors for dnl unsupported commands: NUT_NETVERSION="1.3" AC_DEFINE_UNQUOTED(NUT_NETVERSION, "${NUT_NETVERSION}", [NUT network protocol version]) dnl Fix this early so we can expand with eval later test "${prefix}" = "NONE" && prefix="${ac_default_prefix}" test "${exec_prefix}" = "NONE" && exec_prefix='${prefix}' dnl Note: for practical and platform-independent use, see AX_REALPATH macro AC_CHECK_PROGS([REALPATH], [realpath], []) dnl FIXME: remove after dev-testing dnl UNITTEST_AX_REALPATH dnl exit dnl NOTE: for definition of NUT_* autoconf macros, see m4/ directory dnl and docs/macros.txt dnl +------------------------------------------------------------------+ dnl | default values for things later on (can be overridden) | STATEPATH="/var/state/ups" dnl Historically this refers to *system location* for PID files, dnl and more specifically that for `upsmon` (running as `root`). dnl See also ALTPIDPATH (defaulted to STATEPATH) setting below dnl for the unprivileged daemons (`upsd`, drivers). PIDPATH="/var/run" dnl Honour new LFS recommendations if applied on the build system: AS_IF([test -d "/run"], [PIDPATH="/run"]) AC_CHECK_PROGS([GETENT], [getent], []) AC_CHECK_PROGS([ID], [id], []) PROBE_OS_USER="false" PROBE_OS_GROUP="false" AS_IF([test x"${GETENT}" != x], [ PROBE_OS_USER="${GETENT} passwd " PROBE_OS_GROUP="${GETENT} group " ],[ AS_IF([test x"${ID}" != x], [ PROBE_OS_USER="${ID} -u " AS_IF([test -r "/etc/groups"], [ dnl FIXME: For command prefix usage like used in this dnl script, we might be better off defining a shell dnl function and referring to it. Grep would catch dnl also user names that have a group as secondary! PROBE_OS_GROUP="cat /etc/groups | grep -w " ], [ dnl This shows groups of a USER with specified name! dnl But to probe for cases where string names are dnl same (e.g. "nut" or "ups") this might be good dnl enough. PROBE_OS_GROUP="${ID} -g " ]) AC_MSG_WARN([Can not PROPERLY check existence of group accounts on this system, but can try best-effort]) ],[ AC_MSG_WARN([Can not check existence of user and group accounts on this system]) ]) ] ) dnl Defaults for respective configure options below dnl Note these defaults may change further below depending on OS and dnl certain other configure options (e.g. "in-place replacement") RUN_AS_USER="nobody" RUN_AS_GROUP="nobody" AS_IF([test -n "`${PROBE_OS_GROUP} nogroup`" && ! test -n "`${PROBE_OS_GROUP} "${RUN_AS_GROUP}"`"], [RUN_AS_GROUP="nogroup"] ) dnl NOTE: NUT legacy default, keep as is for least surprise dnl Distributions are however welcome to specify the option to use tmpfs AS_CASE([${target_os}], [*mingw*], [POWERDOWNFLAG="C:\\\\killpower"], dnl NOTE: Double backslashes (times escaping) are correct! [POWERDOWNFLAG="/etc/killpower"] dnl POSIX systems default ) cgiexecdir='${exec_prefix}/cgi-bin' driverexecdir='${exec_prefix}/bin' dnl Note: htmldir per se is originally for nut-cgi resources htmldir='${prefix}/html' htmldocdir='${docdir}/html-doc' htmlmandir='${docdir}/html-man' pkgconfigdir='${libdir}/pkgconfig' dnl Detection of augeas lens dirs is a bit troublesome, since dnl they (if present) reside in location not controlled by NUT. dnl Try detecting based on build parameters, or fall back to dnl hard-coded default location (may break e.g. distcheck). dnl Note it would not work too well for "/usr/local/ups" :) auglensdir='${datarootdir}/augeas/lenses/dist' conftemp="${auglensdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" if test ! -d "${conftemp}"; then auglensdir='${datarootdir}/augeas/lenses' conftemp="${auglensdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" if test ! -d "${conftemp}"; then auglensdir='/usr/share/augeas/lenses/dist' if test ! -d "${auglensdir}"; then auglensdir='/usr/share/augeas/lenses' if test ! -d "${auglensdir}"; then auglensdir='' fi fi fi fi dnl ### NUT_CHECK_LIBREGEX ### Detect below as part of libusb etc. dnl ### LIBREGEX_LIBS='' dnl Disable Hotplug, DevD and udev support on Windows dnl (useful when cross-compiling) case "${target_os}" in *mingw* ) dnl TODO: Actually detect it? See also nut_check_libregex.m4 for same. dnl Here we assumed from practice that it is available... dnl ### if test x"${LIBREGEX_LIBS}" = x ; then dnl ### LIBREGEX_LIBS='-lregex' dnl ### fi hotplugdir='' udevdir='' devddir='' ;; * ) hotplugdir='/etc/hotplug' if test ! -d "${hotplugdir}"; then hotplugdir='' fi udevdir='/lib/udev' if test ! -d "${udevdir}"; then udevdir='/etc/udev' if test ! -d "${udevdir}"; then udevdir='' fi fi devddir='/usr/local/etc/devd' if test ! -d "${devddir}"; then devddir='/etc/devd' if test ! -d "${devddir}"; then devddir='' fi fi ;; esac dnl Note: this deals with run-time settings so that the newly built dnl programs can be "just executed" to use same configuration files dnl and filesystem object permissions as an older deployment of NUT dnl on this system; this specifically does not deal with trying to dnl use same prefix and other paths to fully replace an older setup dnl (a different option might be crafted to do that, but really the dnl arcane distro-dependent packaging recipes are a better way here). dnl This feature is intended for users who want to see if a custom dnl build of NUT supports their hardware or other use-cases better. NUT_ARG_ENABLE([inplace-runtime], [Request configure option defaults for runtime user/group/confpath based on currently installed NUT (to extent these can be detected)], [no]) dnl Check for not re-entering in this run - whether NUT_VERSION_DEPLOYED is set AS_IF([test x"$nut_enable_inplace_runtime" = xyes -a x"${NUT_VERSION_DEPLOYED-}" = x], [ AC_MSG_NOTICE([checking for location, CONFIG_FLAGS and version of an already deployed NUT build (if it reports those)]) dnl If existing NUT installation reports its build options, re-run this dnl script with those flags (overridden by any options passed currently): conftemp="${sbindir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_SBINDIR="${conftemp}" conftemp="${bindir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_BINDIR="${conftemp}" dnl Not-set CGI or DRV paths would be defaulted in due time, dnl probably to bindir. Do not enforce any opinions here. conftemp="${with_cgipath}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_CGIDIR="${conftemp}" AS_CASE([${PREFIX_CGIDIR}], [yes|no], [PREFIX_CGIDIR=""]) conftemp="${with_drvpath}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_DRVDIR="${conftemp}" AS_CASE([${PREFIX_DRVDIR}], [yes|no], [PREFIX_DRVDIR=""]) DEPLOYED_SBINDIR="${PREFIX_SBINDIR}" DEPLOYED_BINDIR="${PREFIX_BINDIR}" DEPLOYED_CGIDIR="${PREFIX_CGIDIR}" DEPLOYED_DRVDIR="${PREFIX_DRVDIR}" dnl Note use of AC_PATH_PROG for specific pathname (not AC_CHECK_PROGS which picks filename variants)! dnl Note: "ordinary" users might not have "sbin" in their default PATH, so appending it: dnl Note: in some systems, the file in PATH is a shell dnl wrapper for /etc/nut/nut.conf MODE support AC_PATH_PROG([DEPLOYED_UPSD], [upsd], [], [${PREFIX_SBINDIR}:${PATH}:/sbin:/usr/sbin:/usr/local/sbin]) dnl ...however "upsc" is a userland tool so should be there: AC_PATH_PROG([DEPLOYED_UPSC], [upsc], [], [${PREFIX_BINDIR}:${PATH}]) dnl Assume some driver that is commonly/always installed; check also Debian-ish packaged locations: AC_PATH_PROG([DEPLOYED_DUMMYUPS], [dummy-ups], [], [${PREFIX_DRVDIR}:${PREFIX_BINDIR}:${PATH}:/usr/lib/nut:/lib/nut]) dnl The CGI client suite is very optional, may well be absent: AC_PATH_PROG([DEPLOYED_UPSIMAGE], [upsimage.cgi], [], [${PREFIX_CGIDIR}:${PREFIX_BINDIR}:${PATH}:/usr/lib/cgi-bin/nut:/usr/libexec/cgi-bin/nut:/usr/libexec/nut:/usr/libexec/nut/cgi-bin:/usr/lib/nut:/usr/lib/nut/cgi-bin]) AS_IF([test -x "${DEPLOYED_UPSD}"], [ AX_REALPATH([$DEPLOYED_UPSD], [DEPLOYED_UPSD]) DEPLOYED_SBINDIR="`dirname "${DEPLOYED_UPSD}"`" ]) AS_IF([test -x "${DEPLOYED_UPSC}"], [ AX_REALPATH([$DEPLOYED_UPSC], [DEPLOYED_UPSC]) DEPLOYED_BINDIR="`dirname "${DEPLOYED_UPSC}"`" ]) AS_IF([test -x "${DEPLOYED_DUMMYUPS}"], [ AX_REALPATH([$DEPLOYED_DUMMYUPS], [DEPLOYED_DUMMYUPS]) DEPLOYED_DRVDIR="`dirname "${DEPLOYED_DUMMYUPS}"`" ]) AS_IF([test -x "${DEPLOYED_UPSIMAGE}"], [ AX_REALPATH([$DEPLOYED_UPSIMAGE], [DEPLOYED_UPSIMAGE]) DEPLOYED_CGIDIR="`dirname "${DEPLOYED_UPSIMAGE}"`" ]) DEPLOYED_PREFIX="" AS_IF([test -d "${DEPLOYED_SBINDIR}"], [DEPLOYED_PREFIX="`dirname "${DEPLOYED_SBINDIR}"`"], [AS_IF([test -d "${DEPLOYED_BINDIR}"], [DEPLOYED_PREFIX="`dirname "${DEPLOYED_BINDIR}"`"])] ) AC_MSG_CHECKING([for CONFIG_FLAGS of an already deployed NUT build (if it reports those)]) CONFIG_FLAGS_DEPLOYED="" NUT_VERSION_DEPLOYED="" DEPLOYED_LIBDIR="" dnl TODO: Similar query can be done for BINDIR tools dnl and for libupsclient-config if deployed locally dnl First check upsc, dummy-ups or nut-scanner (TBD) dnl to detect not only version and CONFIG_OPTS but dnl also the shared library location the best we can. for DEPLOYED_TOOL in \ "${DEPLOYED_UPSC}" \ "${DEPLOYED_DUMMYUPS}" \ "${DEPLOYED_UPSD}" \ ; do AS_IF([test x"${DEPLOYED_TOOL}" = x], [continue]) AS_IF([test -x "${DEPLOYED_TOOL}"], [], [continue]) AC_MSG_CHECKING([for CONFIG_FLAGS from ${DEPLOYED_TOOL}]) CONFIG_FLAGS_DEPLOYED="`"${DEPLOYED_TOOL}" -DV 2>&1 | grep 'configured with flags:' | head -1 | sed 's,^.*configured with flags: *,,'`" \ && test x"${CONFIG_FLAGS_DEPLOYED}" != x \ || CONFIG_FLAGS_DEPLOYED="" dnl NOTE: Currntly NUT_VERSION_DEPLOYED is just informative (or a flag dnl that we've "reentered" the configuration script), so we tolerate a dnl better detailed string that is more than just a version, e.g.: dnl 2.8.2.1829-1829+g8f8a4f417 (development iteration after 2.8.2) built with gcc (Debian 10.2.1-6) 10.2.1 20210110 NUT_VERSION_DEPLOYED="`"${DEPLOYED_TOOL}" -DV 2>&1 | grep 'configured with flags:' | head -1 | sed -e 's,^.*Network UPS Tools version \(.*\) configured with flags:.*$,\1,' -e 's, and *$,,'`" \ && test x"${NUT_VERSION_DEPLOYED}" != x \ || NUT_VERSION_DEPLOYED="" dnl FIXME: Find some more portable solution? Use a platform-dependent dnl "case" or various toolkits? dnl * Probably no need to fuss for Windows builds, as they would dnl anyway use the DLL near EXE after installation. AS_IF([test -x "${LDD}" 2>/dev/null], [ for TOKEN in `$LDD "${DEPLOYED_TOOL}" 2>&1 | grep libupsclient` ; do case "${TOKEN}" in /*/libupsclient*) DEPLOYED_LIBDIR="`dirname "$TOKEN"`" ;; esac done ]) AS_IF([test x"${CONFIG_FLAGS_DEPLOYED}${NUT_VERSION_DEPLOYED}" = x], [], [break]) done AS_IF([test x"${CONFIG_FLAGS_DEPLOYED}" != x], [ AC_MSG_RESULT([CONFIG_FLAGS_DEPLOYED: ${CONFIG_FLAGS_DEPLOYED}]) ],[ AC_MSG_RESULT([CONFIG_FLAGS_DEPLOYED: not reported]) ]) dnl Account for custom paths if known/found: AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--prefix=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--prefix="*) prefix="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ] ) AS_IF([test x"${DEPLOYED_PREFIX}" != x && test x"${DEPLOYED_PREFIX}" != x"${prefix}"], AC_MSG_WARN([Deployed NUT installation uses a PREFIX different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_PREFIX}' vs. '${prefix}']) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--prefix=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --prefix='${DEPLOYED_PREFIX}'" dnl Help re-evaluate it from verbatim defaults in later dnl deployed path determinations e.g. for data(root)dir: prefix="${DEPLOYED_PREFIX}" ]) ]) dnl FIXME? Re-evaluate cgipath and/or drvpath if they are defined with a dnl verbatim '${prefix}' inside, and no hits found in earlier attempts? AS_IF([test x"${DEPLOYED_SBINDIR}" != x && test x"${DEPLOYED_SBINDIR}" != x"${PREFIX_SBINDIR}"], AC_MSG_WARN([Deployed NUT installation uses a SBINDIR different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_SBINDIR}' vs. '${PREFIX_SBINDIR}' ('${sbindir}')]) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--sbindir=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --sbindir='${DEPLOYED_SBINDIR}'"]) ]) AS_IF([test x"${DEPLOYED_BINDIR}" != x && test x"${DEPLOYED_BINDIR}" != x"${PREFIX_BINDIR}"], AC_MSG_WARN([Deployed NUT installation uses a BINDIR different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_BINDIR}' vs. '${PREFIX_BINDIR}' ('${bindir}')]) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--bindir=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --bindir='${DEPLOYED_BINDIR}'"]) ]) AS_IF([test x"${DEPLOYED_CGIDIR}" != x && test x"${DEPLOYED_CGIDIR}" != x"${PREFIX_CGIDIR}"], AC_MSG_WARN([Deployed NUT installation uses a CGIDIR different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_CGIDIR}' vs. '${PREFIX_CGIDIR}' ('${with_cgipath}')]) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--with-cgipath=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --with-cgipath='${DEPLOYED_CGIDIR}'"]) ]) AS_IF([test x"${DEPLOYED_DRVDIR}" != x && test x"${DEPLOYED_DRVDIR}" != x"${PREFIX_DRVDIR}"], AC_MSG_WARN([Deployed NUT installation uses a DRVDIR different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_DRVDIR}' vs. '${PREFIX_DRVDIR}' ('${with_drvpath}')]) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--with-drvpath=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --with-drvpath='${DEPLOYED_DRVDIR}'"]) ]) AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--datarootdir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--datarootdir="*) datarootdir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ] ) conftemp="${datarootdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_DATAROOTDIR="${conftemp}" dnl The dataroot dir (system-wide) here is used to search for datadir candidate info AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--datadir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--datadir="*) datadir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ] ) conftemp="${datadir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_DATADIR="${conftemp}" DATADIR="${PREFIX_DATADIR}" DEPLOYED_DATADIR="" AS_IF([test -e "${PREFIX_DATAROOTDIR}/nut/cmdvartab" || test -e "${PREFIX_DATAROOTDIR}/nut/driver.list"], [DEPLOYED_DATADIR="${PREFIX_DATAROOTDIR}/nut"], [AS_IF([test -e "${PREFIX_DATAROOTDIR}/cmdvartab" || test -e "${PREFIX_DATAROOTDIR}/driver.list"], [DEPLOYED_DATADIR="${PREFIX_DATAROOTDIR}"], [dnl FIXME: Be careful on WIN32 and its "find" vs. that in MINGW? DEPLOYED_DATADIR="`find "${PREFIX_DATAROOTDIR}" -name cmdvartab | head -1 | sed 's,/@<:@^/@:>@*$,,'`" || DEPLOYED_DATADIR="" AS_IF([test -z "${DEPLOYED_DATADIR}"], [DEPLOYED_DATADIR="`find "${PREFIX_DATAROOTDIR}" -name driver.list | head -1 | sed 's,/@<:@^/@:>@*$,,'`" || DEPLOYED_DATADIR=""]) ] )] ) AS_IF([test -z "${DEPLOYED_DATADIR}" && test -d "${PREFIX_DATAROOTDIR}/nut"], [DEPLOYED_DATADIR="${PREFIX_DATAROOTDIR}/nut"]) AS_IF([test x"${DEPLOYED_DATADIR}" != x && test x"${DEPLOYED_DATADIR}" != x"${PREFIX_DATADIR}"], AC_MSG_WARN([Deployed NUT installation uses a DATADIR different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_DATADIR}' vs. '${PREFIX_DATADIR}' ('${datadir}')]) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--datadir=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --datadir='${DEPLOYED_DATADIR}'" DATADIR="${DEPLOYED_DATADIR}" ]) ]) AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--sysconfdir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--sysconfdir="*) sysconfdir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ], [ dnl If there was no custom --sysconfdir=/etc/myNUT passed, dnl try to default it to something from existing deployment. dnl NOTE: Single-quotes are correct for autotools default, dnl expanded at runtime (see conftemp tricks below) conftemp="${sysconfdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" dnl Evaluated here for the message; CONFPATH will be re-evaluated dnl below, after we decide on the sysconfdir value we really like. PREFIX_SYSCONFDIR="${conftemp}" AC_MSG_CHECKING([for in-place replacement default sysconfdir, better than '${PREFIX_SYSCONFDIR}' ('${sysconfdir}')]) DEPLOYED_SYSCONFDIR="" dnl TODO: Any more reasonable defaults? Pile them on here :) for D in \ /etc/nut /etc/ups \ /usr/etc/nut /usr/etc/ups \ /usr/local/etc/nut /usr/local/etc/ups \ /usr/local/nut/etc /usr/local/ups/etc \ ; do if test -e "$D/ups.conf" || test -e "$D/upsmon.conf" \ || ( test -e "$D/upsd.conf" && test -e "$D/upsd.users" ) \ ; then DEPLOYED_SYSCONFDIR="$D" break else if test -d "$D/" && test ! -r "$D/" ; then dnl Keeping order of preference defined by "for" loop: AC_MSG_WARN([Picking directory '${D}' which exists but current build user may not read]) DEPLOYED_SYSCONFDIR="$D" break fi fi done AS_IF([test -n "${DEPLOYED_SYSCONFDIR}"], [ AC_MSG_RESULT([${DEPLOYED_SYSCONFDIR}]) dnl May be used in searches below: sysconfdir="${DEPLOYED_SYSCONFDIR}" CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --sysconfdir='${DEPLOYED_SYSCONFDIR}'" ], [ AC_MSG_RESULT([not detected]) ]) ]) dnl Prepare paths that may be used in user/group searches below: conftemp="${sysconfdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" CONFPATH="${conftemp}" AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--libdir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--libdir="*) libdir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ] ) conftemp="${libdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PREFIX_LIBDIR="${conftemp}" LIBDIR="${PREFIX_LIBDIR}" AS_IF([test x"${DEPLOYED_LIBDIR}" != x && test x"${DEPLOYED_LIBDIR}" != x"${PREFIX_LIBDIR}"], AC_MSG_WARN([Deployed NUT installation uses a LIBDIR different from one specified (wins) or derived (loses) for this build: '${DEPLOYED_LIBDIR}' vs. '${PREFIX_LIBDIR}' ('${libdir}')]) [AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--libdir=*], [], [CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --libdir='${DEPLOYED_LIBDIR}'" LIBDIR="${DEPLOYED_LIBDIR}" ]) ]) AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--libexecdir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--libexecdir="*) libexecdir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ] ) conftemp="${libexecdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" LIBEXECDIR="${conftemp}" AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--with-pkgconfig-dir=*], [ for F in ${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS} ; do case "$F" in "--with-pkgconfig-dir="*) pkgconfigdir="`echo "$F" | ( IFS='=' read K V ; echo "$V" )`" ;; esac done ] ) dnl pkgconfigdir may have more indirections: conftemp="${pkgconfigdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PKGCONFIGDIR="${conftemp}" AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--with-group=*], [], [ AC_MSG_CHECKING([for in-place replacement default group (better than '${RUN_AS_GROUP}')]) nut_inplace_group="" AS_IF([test -d "${udevdir}/rules.d"], [for F in "${udevdir}/rules.d"/*-nut-*.rules ; do if test -s "$F" ; then nut_inplace_group="`grep GROUP= "$F" | head -1 | sed 's,^.* GROUP="*\(.*\)"*.*$,\1,'`" \ && test -n "`${PROBE_OS_GROUP} "${nut_inplace_group}"`" \ && AC_MSG_RESULT([Got from ${F}]) \ && break \ || nut_inplace_group="" fi done ]) AS_IF([test -z "${nut_inplace_group}"], [AS_IF([test -n "`${PROBE_OS_GROUP} nut`"], [nut_inplace_group="nut"], [AS_IF([test -n "`${PROBE_OS_GROUP} ups`"], [nut_inplace_group="ups"])])]) AS_IF([test -n "${nut_inplace_group}"], [ AC_MSG_RESULT([${nut_inplace_group}]) CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --with-group='${nut_inplace_group}'" ], [ AC_MSG_RESULT([not detected]) ]) ]) AS_CASE(["${CONFIG_FLAGS_DEPLOYED} ${CONFIG_FLAGS}"], [*--with-user=*], [], [ AC_MSG_CHECKING([for in-place replacement default user (better than '${RUN_AS_USER}')]) nut_inplace_user="" dnl Beside currently active setting, check the built-in default sugestion AS_IF([test -s "${CONFPATH}/upsmon.conf"], [for nut_inplace_user in \ `grep -E '^ *RUN_AS_USER' "${CONFPATH}/upsmon.conf" | awk '{print $2}'`\ `grep -E '^ *##*RUN_AS_USER' "${CONFPATH}/upsmon.conf" | awk '{print $2}'`\ `grep -E '^ *##* *RUN_AS_USER' "${CONFPATH}/upsmon.conf" | awk '{print $3}'`\ ; do \ AS_IF([test -z "${nut_inplace_user}"], [ test -n "`${PROBE_OS_USER} "${nut_inplace_user}"`" \ && AC_MSG_RESULT([Got from ${CONFPATH}/upsmon.conf]) \ || nut_inplace_user=""]) done ]) AS_IF([test -s "${CONFPATH}/upsmon.conf.sample" && test -z "${nut_inplace_user}"], [for nut_inplace_user in \ `grep -E '^ *RUN_AS_USER' "${CONFPATH}/upsmon.conf.sample" | awk '{print $2}'`\ `grep -E '^ *##*RUN_AS_USER' "${CONFPATH}/upsmon.conf.sample" | awk '{print $2}'`\ `grep -E '^ *##* *RUN_AS_USER' "${CONFPATH}/upsmon.conf.sample" | awk '{print $3}'`\ ; do \ AS_IF([test -z "${nut_inplace_user}"], [ test -n "`${PROBE_OS_USER} "${nut_inplace_user}"`" \ && AC_MSG_RESULT([Got from ${CONFPATH}/upsmon.conf]) \ || nut_inplace_user=""]) done ]) dnl Note: with default short inplace and no prefix, this would look under dnl /usr/local/ups/lib/pkgconfig which may be irrelevant for packaged setups dnl TODO: Any more reasonable defaults? Pile them on here :) for F in \ "${PKGCONFDIR}/libupsclient.pc" \ "${PKGCONFDIR}/libnutclient.pc" \ "${LIBDIR}/pkgconfig/libupsclient.pc" \ "${LIBDIR}/pkgconfig/libnutclient.pc" \ ; do AS_IF([test -z "${nut_inplace_user}" && test -s "$F"], [nut_inplace_user="`grep -E '^ *nutuser=' "$F" | sed 's,^ *nutuser=,,'`" \ && test -n "`${PROBE_OS_USER} "${nut_inplace_user}"`" \ && AC_MSG_RESULT([Got from $F]) \ || nut_inplace_user="" ]) done AS_IF([test -z "${nut_inplace_user}"], [AS_IF([test -n "`${PROBE_OS_USER} nut`"], [nut_inplace_user="nut"], [AS_IF([test -n "`${PROBE_OS_USER} ups`"], [nut_inplace_user="ups"])])]) AS_IF([test -n "${nut_inplace_user}"], [ AC_MSG_RESULT([${nut_inplace_user}]) CONFIG_FLAGS_DEPLOYED="${CONFIG_FLAGS_DEPLOYED} --with-user='${nut_inplace_user}'" ], [ AC_MSG_RESULT([not detected]) ]) ]) AS_IF([test x"${CONFIG_FLAGS_DEPLOYED}" != x], [ AC_MSG_NOTICE([Detected CONFIG_FLAGS for an already deployed NUT installation, using them for --inplace-runtime configuration (restarting script)]) dnl For multiply-specified flags with conflicting values, last mention wins: AC_MSG_NOTICE([exec "$0" $CONFIG_FLAGS_DEPLOYED $CONFIG_FLAGS --disable-inplace-runtime]) AS_IF([test x"${NUT_VERSION_DEPLOYED}" != x], [ AC_MSG_NOTICE([NUT_VERSION_DEPLOYED: ${NUT_VERSION_DEPLOYED}]) ],[ NUT_VERSION_DEPLOYED="" ]) export NUT_VERSION_DEPLOYED dnl # Avoid replacement after re-entering: test -n "${CONFIG_CFLAGS-}" || CONFIG_CFLAGS=" " test -n "${CONFIG_CXXFLAGS-}" || CONFIG_CXXFLAGS=" " test -n "${CONFIG_CPPFLAGS-}" || CONFIG_CPPFLAGS=" " test -n "${CONFIG_LDFLAGS-}" || CONFIG_LDFLAGS=" " export CONFIG_CFLAGS export CONFIG_CXXFLAGS export CONFIG_CPPFLAGS export CONFIG_LDFLAGS AC_MSG_NOTICE([Moving config.log of the original invocation to config.log.inplace-outer just before exec...]) mv -f config.log config.log.inplace-outer || true eval exec "$0" $CONFIG_FLAGS_DEPLOYED $CONFIG_FLAGS --disable-inplace-runtime ],[ AC_MSG_NOTICE([No CONFIG_FLAGS were reported or discovered from existing NUT deployment (if any); restarting script for a clean run]) NUT_VERSION_DEPLOYED="" export NUT_VERSION_DEPLOYED dnl # Avoid replacement after re-entering: test -n "${CONFIG_CFLAGS-}" || CONFIG_CFLAGS=" " test -n "${CONFIG_CXXFLAGS-}" || CONFIG_CXXFLAGS=" " test -n "${CONFIG_CPPFLAGS-}" || CONFIG_CPPFLAGS=" " test -n "${CONFIG_LDFLAGS-}" || CONFIG_LDFLAGS=" " export CONFIG_CFLAGS export CONFIG_CXXFLAGS export CONFIG_CPPFLAGS export CONFIG_LDFLAGS AC_MSG_NOTICE([Moving config.log of the original invocation to config.log.inplace-outer just before exec...]) mv -f config.log config.log.inplace-outer || true AC_MSG_NOTICE([exec "$0" $CONFIG_FLAGS --disable-inplace-runtime]) eval exec "$0" $CONFIG_FLAGS --disable-inplace-runtime ]) ]) dnl Define directory where LIBOBJS replacement functions are AC_CONFIG_LIBOBJ_DIR([common]) dnl +------------------------------------------------------------------- AC_PROG_INSTALL AC_PROG_MKDIR_P AC_PROG_LN_S AC_PROG_EGREP AC_PATH_PROG(AR, ar) AC_CHECK_TOOL(RANLIB, ranlib, :) dnl Postpone call to LT_INIT/AC_CONFIG_FILES to allow disabling static lib AC_C_BIGENDIAN AC_C_INLINE AC_C_FLEXIBLE_ARRAY_MEMBER AC_C_VARARRAYS NUT_ARG_ENABLE([keep_nut_report_feature], [Request that we keep config.nut_report_feature.log (normally deleted by configure script after displaying)], [no]) AS_IF([test x"${NUT_SOURCE_GITREV}" = x], [NUT_REPORT([configured version], [${PACKAGE_VERSION}])], [AS_IF([test x"${NUT_SOURCE_GITREV}" = x"${PACKAGE_VERSION}"], [NUT_REPORT([configured version], [${PACKAGE_VERSION} ${NUT_SOURCE_GITREV_DEVREL}])], [NUT_REPORT([configured version], [${PACKAGE_VERSION} (${NUT_SOURCE_GITREV}) ${NUT_SOURCE_GITREV_DEVREL}])]) ]) NUT_REPORT([Documentation website base URL], [${NUT_WEBSITE_BASE}]) AC_DEFINE_UNQUOTED([NUT_WEBSITE_BASE], "${NUT_WEBSITE_BASE}", [Documentation website base URL, no trailing slash]) dnl Note: the compiler/pragma/attr methods below are custom for NUT codebase: NUT_COMPILER_FAMILY dnl Note: DO NOT AC_DEFINE the "FULL" items: they are generally multi-line. AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ NUT_REPORT_TARGET_WITHOUT_AC_DEFINE([CC_VERSION_FULL], ["${CC_VERSION_FULL}"], [Version and other details of C compiler]) NUT_REPORT_TARGET_WITHOUT_AC_DEFINE([CXX_VERSION_FULL], ["${CXX_VERSION_FULL}"], [Version and other details of C++ compiler]) NUT_REPORT_TARGET_WITHOUT_AC_DEFINE([CPP_VERSION_FULL], ["${CPP_VERSION_FULL}"], [Version and other details of C preprocessor]) ]) NUT_REPORT_TARGET([CC_VERSION], ["${CC_VERSION}"], [Compact version of C compiler]) NUT_REPORT_TARGET([CXX_VERSION], ["${CXX_VERSION}"], [Compact version of C++ compiler]) NUT_REPORT_TARGET([CPP_VERSION], ["${CPP_VERSION}"], [Compact version of C preprocessor]) dnl Help find warning/error details in a wall of text (must be processed before NUT_COMPILER_FAMILY_FLAGS): NUT_ARG_ENABLE([Wcolor], [Request that compiler output is colorized (no = leave it up to compiler defaults)], [no]) NUT_COMPILER_FAMILY_FLAGS AX_C_PRAGMAS AX_C___ATTRIBUTE__ AX_C_PRINTF_STRING_NULL dnl Check if the system provides a boolean type and how it is spelled NUT_CHECK_BOOL dnl All current systems provide time.h; it need not be checked for. dnl Not all systems provide sys/time.h, but those that do, all allow dnl you to include it and time.h simultaneously. dnl NUT codebase provides the include/timehead.h to wrap these nuances. AC_CHECK_HEADERS_ONCE([sys/time.h time.h sys/types.h]) dnl ###obsolete### AC_HEADER_TIME AS_IF([test "$ac_cv_header_sys_time_h" = yes], [AC_DEFINE([TIME_WITH_SYS_TIME],[1],[Define to 1 if you can safely include both and . This macro is deemed obsolete by autotools.]) ], []) CODE_TIMEINCL=" #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif " dnl TEMPORARY to allow certain linux-only buildable drivers AC_CHECK_HEADERS_ONCE([linux/serial.h]) AM_CONDITIONAL(HAVE_LINUX_SERIAL_H, test x"${ac_cv_header_linux_serial_h}" = xyes) AC_CHECK_HEADERS_ONCE([fcntl.h sys/stat.h sys/socket.h netdb.h]) AC_CHECK_FUNCS(flock lockf fcvt fcvtl dup dup2 abs_val abs) AC_CHECK_HEADER([float.h], [AC_DEFINE([HAVE_FLOAT_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([math.h], [AC_DEFINE([HAVE_MATH_H], [1], [Define to 1 if you have .])]) AC_CHECK_DECLS([fabs, fabsf, fabsl, pow10, round], [], [], [#ifdef HAVE_MATH_H # include #endif #ifdef HAVE_FLOAT_H # include #endif ]) AC_CHECK_HEADER([limits.h], [AC_DEFINE([HAVE_LIMITS_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([stdlib.h], [AC_DEFINE([HAVE_STDLIB_H], [1], [Define to 1 if you have .])]) AC_CHECK_DECLS(realpath, [], [], [#ifdef HAVE_LIMITS_H # include #endif #ifdef HAVE_STDLIB_H # include #endif ]) AC_CHECK_HEADER([signal.h], [AC_DEFINE([HAVE_SIGNAL_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([sys/signal.h], [AC_DEFINE([HAVE_SYS_SIGNAL_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([sys/resource.h], [AC_MSG_CHECKING([for struct rlimit and getrlimit()]) AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [struct rlimit limit; getrlimit(RLIMIT_NOFILE, &limit); /* Do not care about actual return value in this test, * normally check for non-zero meaning to look in errno */ ] )], [AC_DEFINE([HAVE_SYS_RESOURCE_H], [1], [Define to 1 if you have with usable struct rlimit and getrlimit().]) AC_MSG_RESULT([ok]) ], [AC_MSG_RESULT([no])] ) AC_LANG_POP([C]) ] ) AC_CHECK_HEADER([poll.h], [AC_DEFINE([HAVE_POLL_H], [1], [Define to 1 if you have .])]) SEMLIBS="" AC_CHECK_HEADER([semaphore.h], [AC_DEFINE([HAVE_SEMAPHORE_H], [1], [Define to 1 if you have .]) AC_LANG_PUSH([C]) myLIBS="${LIBS}" LIBS="" SEMLIBS_LRT="" dnl Solaris 8 builds complain about indirect dependency involved: dnl sem_init nut_scanner-nut-scanner.o dnl (symbol belongs to implicit dependency /usr/lib/librt.so.1) AC_SEARCH_LIBS([sem_init], [pthread], [], [ unset ac_cv_search_sem_init AC_SEARCH_LIBS([sem_init], [pthread], [SEMLIBS_LRT=" -lrt"], [], [-lrt])]) AC_SEARCH_LIBS([sem_open], [pthread], [], [ unset ac_cv_search_sem_open AC_SEARCH_LIBS([sem_open], [pthread], [SEMLIBS_LRT=" -lrt"], [], [-lrt])]) AS_CASE([${ac_cv_search_sem_init}], [no*], [], [SEMLIBS="${ac_cv_search_sem_init}"]) AS_CASE([${ac_cv_search_sem_open}], [no*], [], ["${SEMLIBS}"], [], [SEMLIBS="${ac_cv_search_sem_open}"]) SEMLIBS="${SEMLIBS}${SEMLIBS_LRT}" LIBS="${SEMLIBS}" AC_MSG_CHECKING([for sem_t, sem_init() and sem_destroy()]) AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([ #include ], [sem_t semaphore; sem_init(&semaphore, 0, 4); sem_destroy(&semaphore); /* Do not care about actual return value in this test, * normally check for non-zero meaning to look in errno */ ] )], [AC_DEFINE([HAVE_SEMAPHORE_UNNAMED], [1], [Define to 1 if you have with usable sem_t, sem_init() and sem_destroy() for unnamed semaphores.]) AC_MSG_RESULT([ok]) ], [AC_MSG_RESULT([no])] ) AC_MSG_CHECKING([for sem_t, sem_open() and sem_close()]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #ifdef HAVE_FCNTL_H # include /* For O_* constants */ #endif #ifdef SYS_STAT_H # include /* For mode constants */ #endif ], [sem_t *semaphore = sem_open("/s", O_CREAT, 0644, 4); if (semaphore != SEM_FAILED) sem_close(semaphore); /* Do not care about actual return value in this test, * normally check for non-zero meaning to look in errno */ ] )], [AC_DEFINE([HAVE_SEMAPHORE_NAMED], [1], [Define to 1 if you have with usable sem_t, sem_open() and sem_close() for named semaphores.]) AC_MSG_RESULT([ok]) ], [AC_MSG_RESULT([no])] ) LIBS="${myLIBS}" AC_LANG_POP([C]) ] ) AM_CONDITIONAL(HAVE_SEMAPHORE_LIBS, test -n "${SEMLIBS}") AC_CHECK_FUNCS(cfsetispeed tcsendbreak) AC_CHECK_FUNCS(seteuid setsid getpassphrase) AC_CHECK_FUNCS(on_exit setlogmask) AC_CHECK_DECLS(LOG_UPTO, [], [], [#include ]) dnl These common routines are not available in strict C standard library dnl compilation modes (not part of ANSI or later standard), only in GNU, dnl POSIX or other extension modes. Note that on modern systems they are dnl available, just hidden in headers - so AC_CHECK_FUNCS() finds them dnl by adding a declaration, while the "real" codebase can't use them. AC_MSG_NOTICE( [----------------------------------------------------------------------- The next few tests look for required C library routines; if something is not found, you may need to enable a different C standard or extension macro version. You may also have to configure without extreme warning levels since autotools tests fail those on their own and assume system lacks stuff (although note we try to not involve standard -W* flags here). -----------------------------------------------------------------------]) dnl# AC_CHECK_FUNCS(strcasecmp strncasecmp, dnl# [], [AC_MSG_WARN([Required C library routine not found; try adding __EXTENSIONS__])]) dnl These appear with CFLAGS="-std=c99 -D_POSIX_C_SOURCE=200112L": dnl# Methods below currently do not cause build errors for C99+ modes so are dnl# not tested as thoroughly as those further below: AC_CHECK_FUNCS(strtof strtok_r fileno sigemptyset sigaction, [], [AC_MSG_WARN([Required C library routine not found by linker; try adding -D_POSIX_C_SOURCE=200112L])]) dnl For these we have a fallback implementation via the other, dnl if at least one is available, so initial check is quiet. dnl This typically pops up in POSIX vs. Windows builds: dnl Reminder: the former checks for declarations in headers, dnl the latter checks if known libraries suffice for linker. dnl Might need AC_CHECK_LIBS as well to populate the list with dnl known variants? AC_CHECK_DECLS([localtime_r, localtime_s, gmtime_r, gmtime_s, timegm, _mkgmtime], [], [], [$CODE_TIMEINCL]) AC_CHECK_FUNCS(localtime_r localtime_s gmtime_r gmtime_s timegm _mkgmtime, [], []) AC_MSG_CHECKING([for at least one gmtime implementation]) AS_IF([test x"${ac_cv_func_gmtime_s}-${ac_cv_func_gmtime_r}" = "xno-no" && test x"${ac_cv_have_decl_gmtime_s}-${ac_cv_have_decl_gmtime_r}" = "xno-no"], [ AC_MSG_RESULT([no]) AC_MSG_WARN([Required C library routine gmtime_s nor gmtime_r was not found by linker nor in headers; try adding -D_POSIX_C_SOURCE=200112L and/or -D_POSIX_THREAD_SAFE_FUNCTIONS=200112L]) ],[ AC_MSG_RESULT([yes]) ]) AC_MSG_CHECKING([for at least one localtime implementation]) AS_IF([test x"${ac_cv_func_localtime_s}-${ac_cv_func_localtime_r}" = "xno-no" && test x"${ac_cv_have_decl_localtime_s}-${ac_cv_have_decl_localtime_r}" = "xno-no"], [ AC_MSG_RESULT([no]) AC_MSG_WARN([Required C library routine localtime_s nor localtime_r was not found by linker nor in headers; try adding -D_POSIX_C_SOURCE=200112L and/or -D_POSIX_THREAD_SAFE_FUNCTIONS=200112L]) ],[ AC_MSG_RESULT([yes]) ]) AC_MSG_CHECKING([for at least one timegm implementation]) AS_IF([test x"${ac_cv_func_timegm}-${ac_cv_func__mkgmtime}" = "xno-no" && test x"${ac_cv_have_decl_timegm}-${ac_cv_have_decl__mkgmtime}" = "xno-no"], [ AC_MSG_RESULT([no]) AC_MSG_WARN([Required C library routine timegm nor _mkgmtime was not found by linker nor in headers]) AC_DEFINE_UNQUOTED([WANT_TIMEGM_FALLBACK], [1], [Defined if we want to use timegm_fallback()]) AM_CONDITIONAL([WANT_TIMEGM_FALLBACK], [true]) ],[ AC_MSG_RESULT([yes]) AM_CONDITIONAL([WANT_TIMEGM_FALLBACK], [false]) ]) AC_LANG_PUSH([C]) AC_CHECK_HEADER([string.h], [AC_DEFINE([HAVE_STRING_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([strings.h], [AC_DEFINE([HAVE_STRINGS_H], [1], [Define to 1 if you have .])]) CODE_STRINGINCL='#ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif' AC_CACHE_CHECK([for strcasecmp(s1,s2)], [ac_cv_func_strcasecmp], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [if (strcasecmp("STR1", "str1") != 0) return 1])], [ac_cv_func_strcasecmp=yes], [ac_cv_func_strcasecmp=no] )]) AS_IF([test x"${ac_cv_func_strcasecmp}" = xyes], [AC_DEFINE([HAVE_STRCASECMP], 1, [defined if standard library has, and C standard allows, the strcasecmp(s1,s2) method])], [AC_MSG_WARN([Required C library routine strcasecmp not found; try adding __EXTENSIONS__])] ) AC_CACHE_CHECK([for strncasecmp(s1,s2,n)], [ac_cv_func_strncasecmp], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [if (strncasecmp("STR1", "strX", 2) != 0) return 1])], [ac_cv_func_strncasecmp=yes], [ac_cv_func_strncasecmp=no] )]) AS_IF([test x"${ac_cv_func_strncasecmp}" = xyes], [AC_DEFINE([HAVE_STRNCASECMP], 1, [defined if standard library has, and C standard allows, the strncasecmp(s1,s2,n) method])], [AC_MSG_WARN([Required C library routine strncasecmp not found; try adding __EXTENSIONS__])] ) dnl Note: this changes the original string in argument! dnl Do not pass it constants (strdup them if needed)! AC_CACHE_CHECK([for strlwr(s)], [ac_cv_func_strlwr], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [char s@<:@64@:>@ = {"Some STR1 text"} ; if (strlwr(s) == NULL) return 1])], [ac_cv_func_strlwr=yes], [ac_cv_func_strlwr=no] )]) AS_IF([test x"${ac_cv_func_strlwr}" = xyes], [AC_DEFINE([HAVE_STRLWR], 1, [defined if standard library has, and C standard allows, the strlwr(s1,s2) method])], [AC_MSG_WARN([Optional C library routine strlwr not found])] ) AC_CACHE_CHECK([for strsep(s1,s2)], [ac_cv_func_strsep], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [char arr@<:@64@:>@ = {"Some,tuple,text"} ; char *s = arr; if (strsep(&s, ",") == NULL) return 1])], [ac_cv_func_strsep=yes], [ac_cv_func_strsep=no] )]) AS_IF([test x"${ac_cv_func_strsep}" = xyes], [AC_DEFINE([HAVE_STRSEP], 1, [defined if standard library has, and C standard allows, the strsep(s1,s2) method])], [AC_MSG_WARN([Optional C library routine strsep not found])] ) AM_CONDITIONAL([HAVE_STRSEP], [test x"${ac_cv_func_strsep}" = "xyes"]) AC_CACHE_CHECK([for strstr(s1,s2)], [ac_cv_func_strstr], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [if (strstr("Some str1 text", "str1") == NULL) return 1])], [ac_cv_func_strstr=yes], [ac_cv_func_strstr=no] )]) AS_IF([test x"${ac_cv_func_strstr}" = xyes], [AC_DEFINE([HAVE_STRSTR], 1, [defined if standard library has, and C standard allows, the strstr(s1,s2) method])], [AC_MSG_ERROR([Required C library routine strstr not found])] ) AC_CACHE_CHECK([for strcasestr(s1,s2)], [ac_cv_func_strcasestr], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL], [if (strcasestr("Some STR1 text", "str1") == NULL) return 1])], [ac_cv_func_strcasestr=yes], [ac_cv_func_strcasestr=no] )]) AS_IF([test x"${ac_cv_func_strcasestr}" = xyes], [AC_DEFINE([HAVE_STRCASESTR], 1, [defined if standard library has, and C standard allows, the strcasestr(s1,s2) method])], [AS_IF([test x"${ac_cv_func_strlwr}" = xyes && test x"${ac_cv_func_strstr}" = xyes], [AC_MSG_WARN([Optional C library routine strcasestr not found; a simple wrapper will be built in])] [AC_MSG_WARN([Required C library routine strcasestr not found; try adding _GNU_SOURCE])] )]) AC_CACHE_CHECK([for strptime(s1,s2,tm)], [ac_cv_func_strptime], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL $CODE_TIMEINCL ], [struct tm tm; char *date = "12/30/1999"; char *p = strptime(date, "%m/%d/%Y", &tm); if (p == NULL || *p != '\0') return 1])], [ac_cv_func_strptime=yes], [ac_cv_func_strptime=no] )]) AS_IF([test x"${ac_cv_func_strptime}" = xyes], [AC_DEFINE([HAVE_STRPTIME], 1, [defined if standard library has, and C standard allows, the strptime(s1,s2,tm) method])], [AC_MSG_WARN([Optional C library routine strptime not found; try adding _GNU_SOURCE; a fallback implementation will be built in])] ) dnl Note: per Linux headers, this may need __USE_XOPEN (features.h) dnl which is enabled by _XOPEN_SOURCE via _GNU_SOURCE on the platform. AM_CONDITIONAL([HAVE_STRPTIME], [test x"${ac_cv_func_strptime}" = "xyes"]) AC_CACHE_CHECK([for clock_gettime(CLOCK_MONOTONIC,ts)], [ac_cv_func_clock_gettime], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL $CODE_TIMEINCL ], [struct timespec monoclock_ts; int got_monoclock = clock_gettime(CLOCK_MONOTONIC, &monoclock_ts); if (monoclock_ts.tv_sec < 0 || monoclock_ts.tv_nsec < 0) return 1])], [ac_cv_func_clock_gettime=yes], [ac_cv_func_clock_gettime=no] )]) AS_IF([test x"${ac_cv_func_clock_gettime}" = xyes], [AC_DEFINE([HAVE_CLOCK_GETTIME], 1, [defined if standard library has, and C standard allows, the clock_gettime(clkid,ts) method]) AC_DEFINE([HAVE_CLOCK_MONOTONIC], 1, [defined if standard library has, and C standard allows, the CLOCK_MONOTONIC macro or token])], [AC_MSG_WARN([Optional C library routine clock_gettime not found; will not be used in notifications])] ) dnl Currently these two are the same for us; note also fallback support for dnl older autoconf in SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD way below: AM_CONDITIONAL([HAVE_CLOCK_GETTIME], [test x"${ac_cv_func_clock_gettime}" = "xyes"]) AM_CONDITIONAL([HAVE_CLOCK_MONOTONIC], [test x"${ac_cv_func_clock_gettime}" = "xyes"]) AC_CACHE_CHECK([for strnlen(s1,s2,tm)], [ac_cv_func_strnlen], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL #include ], [size_t len = strnlen("LongString", 5); if (len != 5) return 5; len = strnlen("LongString", 50); if (len != 10) return 10 ])], [ac_cv_func_strnlen=yes], [ac_cv_func_strnlen=no] )]) AS_IF([test x"${ac_cv_func_strnlen}" = xyes], [AC_DEFINE([HAVE_STRNLEN], 1, [defined if standard library has, and C standard allows, the strnlen(s1,s2) method])], [AC_MSG_WARN([Optional C library routine strnlen not found; a fallback implementation will be built in])] ) AM_CONDITIONAL([HAVE_STRNLEN], [test x"${ac_cv_func_strnlen}" = "xyes"]) AC_CACHE_CHECK([for strdup(s)], [ac_cv_func_strdup], [AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([$CODE_STRINGINCL #include ], [[int res = 0; char *t = "Test"; char *s = strdup(t); if (!s || !(s[0]=='T'&&s[1]=='e'&&s[2]=='s'&&s[3]=='t'&&s[4]=='\0') || s == t) res = 1; if (s) free (s); if (res != 0) return res /* autoconf adds ";return 0;" */ ]])], [ac_cv_func_strdup=yes], [ac_cv_func_strdup=no] )]) AS_IF([test x"${ac_cv_func_strdup}" = xyes], [AC_DEFINE([HAVE_STRDUP], 1, [defined if standard library has, and C standard allows, the strdup(s) method])], [AC_MSG_WARN([Required C library routine strdup not found; try adding -D_POSIX_C_SOURCE=200112L])] ) AC_CHECK_HEADER([sys/select.h], [AC_DEFINE([HAVE_SYS_SELECT_H], [1], [Define to 1 if you have .])]) AC_CHECK_HEADER([unistd.h], [AC_DEFINE([HAVE_UNISTD_H], [1], [Define to 1 if you have .])]) AC_CHECK_FUNCS(readlink) AC_CACHE_CHECK([for suseconds_t], [ac_cv_type_suseconds_t], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include #if HAVE_SYS_SELECT_H # include #endif ]], [[suseconds_t us = 1000000; signed long int l = 1000000; if (l != (signed long int)us) return 1; l = -1; us = -1; if (l != (signed long int)us) return 1 /* autoconf adds ";return 0;" */ /* we hope the code above fails if type is not defined or range is not sufficient */ ]])], [ac_cv_type_suseconds_t=yes], [ac_cv_type_suseconds_t=no] )]) AS_IF([test x"${ac_cv_type_suseconds_t}" = xyes], [AC_DEFINE([HAVE_SUSECONDS_T], 1, [defined if standard library has, and C standard allows, the suseconds_t type])], [AC_MSG_WARN([Required C library type suseconds_t not found; try adding -D_POSIX_C_SOURCE=200112L])] ) AC_CACHE_CHECK([for useconds_t], [ac_cv_type_useconds_t], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[useconds_t us = 1000000; unsigned long int l = 1000000; if (l != (unsigned long int)us) return 1 /* autoconf adds ";return 0;" */ /* we hope the code above fails if type is not defined or range is not sufficient */ ]])], [ac_cv_type_useconds_t=yes], [ac_cv_type_useconds_t=no] )]) AS_IF([test x"${ac_cv_type_useconds_t}" = xyes], [AC_DEFINE([HAVE_USECONDS_T], 1, [defined if standard library has, and C standard allows, the useconds_t type])], [AC_MSG_WARN([Required C library type useconds_t not found; try adding -D_POSIX_C_SOURCE=200112L])] ) AC_CACHE_CHECK([for usleep(us)], [ac_cv_func_usleep], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[useconds_t us = 1000; if (usleep(us) != 0) return 1 /* per doc, no errors are returned actually */ /* autoconf adds ";return 0;" */ ]])], [ac_cv_func_usleep=yes], [ac_cv_func_usleep=no] )]) AS_IF([test x"${ac_cv_func_usleep}" = xyes], [AC_DEFINE([HAVE_USLEEP], 1, [defined if standard library has, and C standard allows, the usleep(us) method])], [AC_MSG_WARN([Required C library routine usleep not found; try adding -D_POSIX_C_SOURCE=200112L])] ) dnl OpenBSD (at least) methods to query process info, per dnl https://github.com/openbsd/src/blob/master/bin/ps/ps.c dnl https://kaashif.co.uk/2015/06/18/how-to-get-a-list-of-processes-on-openbsd-in-c/ BSDKVMPROCLIBS="" myLIBS="$LIBS" LIBS="$LIBS -lkvm" AC_CACHE_CHECK([for BSD KVM process info libs], [ac_cv_lib_bsd_kvm_proc], [AC_LINK_IFELSE( [AC_LANG_PROGRAM([[ #include #include #include #include #include ]], [[ char errbuf[_POSIX2_LINE_MAX]; kvm_t *kernel = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); int nentries = 0; struct kinfo_proc *kinfo = kvm_getprocs(kernel, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &nentries); int i; for (i = 0; i < nentries; ++i) { printf("%s\n", kinfo[i].p_comm); } /* autoconf adds ";return 0;" */ /* we hope the code above fails if type is not defined or range is not sufficient */ ]])], [ac_cv_lib_bsd_kvm_proc=yes BSDKVMPROCLIBS="-lkvm" ], [ac_cv_lib_bsd_kvm_proc=no] )]) LIBS="$myLIBS" AS_IF([test x"${ac_cv_lib_bsd_kvm_proc}" = xyes], [AC_DEFINE([HAVE_LIB_BSD_KVM_PROC], 1, [defined if we have libs, includes and methods for BSD KVM process info])] ) dnl https://github.com/illumos/illumos-gate/blob/master/usr/src/uts/common/sys/procfs.h#L318 dnl https://github.com/illumos/illumos-gate/blob/master/usr/src/cmd/ps/ps.c AC_CACHE_CHECK([for Solaris/illumos process info libs], [ac_cv_lib_illumos_proc], [AC_LINK_IFELSE( [AC_LANG_PROGRAM([[ #include #include ]], [[ psinfo_t info; printf("%s", info.pr_fname) /* autoconf adds ";return 0;" */ /* we hope the code above fails if type is not defined or range is not sufficient */ ]])], [ac_cv_lib_illumos_proc=yes ], [ac_cv_lib_illumos_proc=no] )]) LIBS="$myLIBS" AS_IF([test x"${ac_cv_lib_illumos_proc}" = xyes], [AC_DEFINE([HAVE_LIB_ILLUMOS_PROC], 1, [defined if we have libs, includes and methods for Solaris/illumos process info])] ) AC_LANG_POP([C]) dnl These routines' arg types differ in strict C standard mode dnl from what they use in the modes expected by NUT codebase: dnl bind() : /usr/include/x86_64-linux-gnu/sys/socket.h:123:12: note: expected '__CONST_SOCKADDR_ARG {aka union }' but argument is of type 'struct sockaddr *' dnl accept() : /usr/include/x86_64-linux-gnu/sys/socket.h:243:12: note: expected '__SOCKADDR_ARG {aka union }' but argument is of type 'struct sockaddr *' dnl connect() : /usr/include/x86_64-linux-gnu/sys/socket.h:137:12: note: expected '__CONST_SOCKADDR_ARG {aka union }' but argument is of type 'const struct sockaddr *' dnl sendto() : /usr/include/x86_64-linux-gnu/sys/socket.h:163:16: note: expected '__CONST_SOCKADDR_ARG {aka union }' but argument is of type 'struct sockaddr *' dnl recvfrom() : /usr/include/x86_64-linux-gnu/bits/socket2.h:64:1: note: expected '__SOCKADDR_ARG {aka union }' but argument is of type 'struct sockaddr *' AC_MSG_CHECKING([whether ln -sr works]) dnl We need to relative-symlink some files. Or hardlink. Or copy... LN_S_R="cp -pR" if test "$as_ln_s" = "ln -s" ; then _abs_srcdir="`cd "${srcdir}" && pwd`" || _abs_srcdir="" _abs_builddir="`pwd`" AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) srcdir='${srcdir}' _abs_srcdir='${_abs_srcdir}' _abs_builddir='${_abs_builddir}']) ]) if test x"${_abs_srcdir}" = x"${_abs_builddir}" ; then LN_S_R="ln" else dnl NOTE: Here we check equality of the file systems by the dnl devices they are mounted from (first column in df output): _fs_srcdir="`df "${_abs_srcdir}" | tail -1 | awk '{print $1}'`" || fs_srcdir="XXXs" _fs_builddir="`df "${_abs_builddir}" | tail -1 | awk '{print $1}'`" || fs_builddir="XXXb" AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) _fs_srcdir='${_fs_srcdir}' _fs_builddir='${_fs_builddir}']) ]) if test x"${_fs_srcdir}" = x"${_fs_builddir}" ; then LN_S_R="ln" else dnl Source and build areas are in different filesystems, dnl can not hardlink - keep copying approach in place AC_MSG_NOTICE([Source and build areas are in different filesystems, or we could not detect this for sure - avoiding hardlinks]) fi unset _fs_srcdir _fs_builddir fi unset _abs_srcdir _abs_builddir dnl Explore GNU ln (or compatible) with relative symlink support DIR1="$(mktemp -d "dir1.XXXXXXX")" && \ DIR2="$(mktemp -d "dir2.XXXXXXX")" && \ touch "${DIR1}/a" && \ $as_ln_s -r "${DIR1}/a" "${DIR2}/b" && \ ls -la "${DIR2}/b" | grep '\.\./' > /dev/null && \ LN_S_R="$as_ln_s -r" rm -rf "${DIR1}" "${DIR2}" fi AC_SUBST([LN_S_R], [${LN_S_R}]) if test "$LN_S_R" = "ln -s -r" ; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no, using $LN_S_R]) fi dnl the following may add stuff to LIBOBJS (is this still needed?) AC_CHECK_FUNCS(vsnprintf snprintf, [], [ AC_LIBOBJ(snprintf) AC_TYPE_LONG_DOUBLE AC_TYPE_LONG_LONG_INT ]) AC_REPLACE_FUNCS(setenv unsetenv strerror atexit) case ${target_os} in solaris2* ) dnl On Solaris, this allows errno to use thread local storage CFLAGS="${CFLAGS} -D_REENTRANT" ;; aix* ) dnl On AIX, this allows errno to use thread local storage CFLAGS="${CFLAGS} -D_REENTRANT" ;; hpux11* ) dnl It seems like the thread safe string functions will not be included dnl on 64 bit HP-UX unless we define _REENTRANT CFLAGS="${CFLAGS} -D_REENTRANT" ;; esac dnl optind handling: dnl need to check if unistd.h is enough, else try getopt.h, else need decls AC_CHECK_DECLS(optind, [], [ AC_CHECK_HEADERS(getopt.h, [ AC_DEFINE(NEED_GETOPT_H, 1, [Define if getopt.h is needed]) ], [ AC_DEFINE(NEED_GETOPT_DECLS, 1, [Define to use explicit getopt declarations]) ], [AC_INCLUDES_DEFAULT]) ], [AC_INCLUDES_DEFAULT]) dnl do a 2nd check to ensure inclusion of getopt.h, in case optind is known AC_CHECK_HEADERS(getopt.h, [ AC_DEFINE(NEED_GETOPT_H, 1, [Define if getopt.h is needed]) ], [ AC_DEFINE(NEED_GETOPT_DECLS, 1, [Define to use explicit getopt declarations]) ], [AC_INCLUDES_DEFAULT]) dnl also check for getopt_long AC_CHECK_FUNCS(getopt_long) dnl FreeBSD serial locking compatibility - look for uu_lock in libutil.h AC_CHECK_DECLS(uu_lock, [ AC_DEFINE(HAVE_UU_LOCK, 1, [Use uu_lock for locking (FreeBSD)]) SERLIBS="-lutil" dnl put in some better defaults for FreeBSD RUN_AS_USER="uucp" ], [ SERLIBS="" ], [ #include #include ]) AC_CHECK_DECLS(__func__, [], [ AC_CHECK_DECLS(__FUNCTION__, [ AC_DEFINE(__func__, __FUNCTION__, [Replace missing __func__ declaration]) ], [ AC_DEFINE(__func__, __LINE__, [Replace missing __func__ declaration]) ], [AC_INCLUDES_DEFAULT]) ], [AC_INCLUDES_DEFAULT]) dnl Solaris compatibility - check for -lnsl and -lsocket AC_SEARCH_LIBS(gethostbyname, nsl) AC_SEARCH_LIBS(connect, socket) AC_CHECK_HEADERS(sys/modem.h stdarg.h varargs.h, [], [], [AC_INCLUDES_DEFAULT]) dnl pthread related checks dnl Note: pthread_tryjoin_np() should be available since glibc 2.3.3, according dnl to https://man7.org/linux/man-pages/man3/pthread_tryjoin_np.3.html AC_SEARCH_LIBS([pthread_create], [pthread], [AC_DEFINE(HAVE_PTHREAD, 1, [Define to enable pthread support code]) AC_SEARCH_LIBS([pthread_tryjoin_np], [pthread], [AC_DEFINE(HAVE_PTHREAD_TRYJOIN, 1, [Define to enable pthread_tryjoin support code])], []) ], []) dnl ---------------------------------------------------------------------- dnl Check for types and define possible replacements NUT_TYPE_SOCKLEN_T NUT_CHECK_SOCKETLIB NUT_FUNC_GETNAMEINFO_ARGTYPES AC_CACHE_CHECK([for inet_ntop() with IPv4 and IPv6 support], [ac_cv_func_inet_ntop], [AC_LANG_PUSH([C]) dnl e.g. add "-lws2_32" for mingw builds dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above SAVED_LIBS="$LIBS" LIBS="$LIBS $NETLIBS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([[ #if HAVE_WINDOWS_H # undef inline # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # if HAVE_WINSOCK2_H # include # endif # if HAVE_WS2TCPIP_H # include # endif #else # include #endif #include ]], [[/* const char* inet_ntop(int af, const void* src, char* dst, size_t cnt); */ char buf[128]; printf("%s", inet_ntop(AF_INET, "1.2.3.4", buf, 10)); printf("%s", inet_ntop(AF_INET6, "::1", buf, 10)) /* autoconf adds ";return 0;" */ ]])], [ac_cv_func_inet_ntop=yes], [ac_cv_func_inet_ntop=no] ) AC_LANG_POP([C]) LIBS="$SAVED_LIBS" ]) AS_IF([test x"${ac_cv_func_inet_ntop}" = xyes], [AC_DEFINE([HAVE_INET_NTOP], 1, [defined if system has the inet_ntop() method])], [AC_MSG_WARN([Required C library routine inet_ntop() not found]) AS_CASE([${target_os}], [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] ) ] ) AC_CACHE_CHECK([for inet_pton() with IPv4 and IPv6 support], [ac_cv_func_inet_pton], [AC_LANG_PUSH([C]) dnl e.g. add "-lws2_32" for mingw builds dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above SAVED_LIBS="$LIBS" LIBS="$LIBS $NETLIBS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([[ #if HAVE_WINDOWS_H # undef inline # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # if HAVE_WINSOCK2_H # include # endif # if HAVE_WS2TCPIP_H # include # endif #else # include #endif #include ]], [[/* int inet_pton(int af, const char *src, char *dst); */ struct in_addr ipv4; struct in6_addr ipv6; printf("%i ", inet_pton(AF_INET, "1.2.3.4", &ipv4)); printf("%i ", inet_pton(AF_INET6, "::1", &ipv6)) /* autoconf adds ";return 0;" */ ]])], [ac_cv_func_inet_pton=yes], [ac_cv_func_inet_pton=no] ) AC_LANG_POP([C]) LIBS="$SAVED_LIBS" ]) AS_IF([test x"${ac_cv_func_inet_pton}" = xyes], [AC_DEFINE([HAVE_INET_PTON], 1, [defined if system has the inet_pton() method])], [AC_MSG_WARN([Required C library routine inet_pton() not found]) AS_CASE([${target_os}], [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] ) ] ) AC_CACHE_CHECK([for struct pollfd], [ac_cv_struct_pollfd], [AC_LANG_PUSH([C]) dnl e.g. add "-lws2_32" for mingw builds dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above SAVED_LIBS="$LIBS" LIBS="$LIBS $NETLIBS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM([[ #if HAVE_WINDOWS_H # undef inline # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # if HAVE_WINSOCK2_H # include # endif # if HAVE_WS2TCPIP_H # include # endif #else # include #endif #include ]], [[ struct pollfd pfd; pfd.fd = 0; /* autoconf adds ";return 0;" */ ]])], [ac_cv_struct_pollfd=yes], [ac_cv_struct_pollfd=no] ) AC_LANG_POP([C]) LIBS="$SAVED_LIBS" ]) AS_IF([test x"${ac_cv_struct_pollfd}" = xyes], [AC_DEFINE([HAVE_STRUCT_POLLFD], 1, [defined if system has the struct pollfd type])], [AC_MSG_WARN([Required C library type struct pollfd not found]) AS_CASE([${target_os}], [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] ) ] ) NETLIBS_GETADDRS="" dnl For `nut-scanner -m auto` modes, see also: dnl https://stackoverflow.com/a/41151132/4715872 dnl https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses (since ~Windows Vista) dnl https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersinfo (before Windows XP; not recommended later) dnl Must check in global context, to have it not-defined where appropriate too NUT_CHECK_HEADER_IPHLPAPI AC_CHECK_HEADERS_ONCE([ifaddrs.h netinet/in.h net/if.h]) AC_CHECK_FUNCS([getifaddrs], [], [ AS_CASE([${target_os}], [*mingw*], [ dnl Check for GetAdaptersAddresses / GetAdaptersInfo AS_IF([test x"${nut_cv_header_iphlpapi_h}" = xyes], [ myIPHLPAPI_TEST_HEADERS=' #if HAVE_WINDOWS_H # undef inline # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include # if HAVE_WINSOCK2_H # include # endif # if HAVE_IPHLPAPI_H # include # endif #endif #include ' myIPHLPAPI_TEST_GAA=' /* ULONG GetAdaptersAddresses(ULONG af, ULONG flags, void* rsvd, PIP_ADAPTER_ADDRESSES addrs, PULONG sizeptr); */ IP_ADAPTER_ADDRESSES buf@<:@8@:>@; ULONG bufsz = sizeof(buf); printf("%ld ", GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST, NULL, buf, &bufsz)); printf("%ld ", GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_DNS_SERVER, NULL, buf, &bufsz)); printf("%ld ", GetAdaptersAddresses(AF_INET6, GAA_FLAG_SKIP_ANYCAST, NULL, buf, &bufsz)) /* autoconf adds ";return 0;" */ ' AC_CACHE_CHECK([for GetAdaptersAddresses() with IPv4 and IPv6 support], [ac_cv_func_GetAdaptersAddresses], [AC_LANG_PUSH([C]) dnl e.g. add "-lws2_32" for mingw builds, maybe "-liphlpapi" dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above SAVED_LIBS="$LIBS" LIBS="$LIBS $NETLIBS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM( [${myIPHLPAPI_TEST_HEADERS}], [${myIPHLPAPI_TEST_GAA}])], [ac_cv_func_GetAdaptersAddresses=yes ], [ NETLIBS_GETADDRS="-liphlpapi" LIBS="$LIBS $NETLIBS $NETLIBS_GETADDRS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM( [${myIPHLPAPI_TEST_HEADERS}], [${myIPHLPAPI_TEST_GAA}])], [ ac_cv_func_GetAdaptersAddresses=yes ], [ ac_cv_func_GetAdaptersAddresses=no NETLIBS_GETADDRS="" ] ) ] ) AC_LANG_POP([C]) LIBS="$SAVED_LIBS" ]) AS_IF([test x"${ac_cv_func_GetAdaptersAddresses}" = xyes], [AC_DEFINE([HAVE_GETADAPTERSADDRESSES], 1, [defined if system has the GetAdaptersAddresses() method])], [ AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_WARN([WIN32 library routine GetAdaptersAddresses() not found]) ]) AS_CASE([${target_os}], [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] ) ] ) myIPHLPAPI_TEST_GAI=' /* ULONG GetAdaptersInfo(PIP_ADAPTER_INFO addrs, PULONG sizeptr); */ IP_ADAPTER_INFO buf@<:@8@:>@; ULONG bufsz = sizeof(buf); printf("%ld ", GetAdaptersInfo(buf, &bufsz)) /* autoconf adds ";return 0;" */ ' AC_CACHE_CHECK([for GetAdaptersInfo() with IPv4 only support], [ac_cv_func_GetAdaptersInfo], [AC_LANG_PUSH([C]) dnl e.g. add "-lws2_32" for mingw builds dnl the NETLIBS are set by NUT_CHECK_SOCKETLIB above SAVED_LIBS="$LIBS" LIBS="$LIBS $NETLIBS $NETLIBS_GETADDRS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM( [${myIPHLPAPI_TEST_HEADERS}], [${myIPHLPAPI_TEST_GAI}])], [ac_cv_func_GetAdaptersInfo=yes ], [ NETLIBS_GETADDRS="-liphlpapi" LIBS="$LIBS $NETLIBS $NETLIBS_GETADDRS" AX_RUN_OR_LINK_IFELSE( [AC_LANG_PROGRAM( [${myIPHLPAPI_TEST_HEADERS}], [${myIPHLPAPI_TEST_GAI}])], [ ac_cv_func_GetAdaptersInfo=yes ], [ ac_cv_func_GetAdaptersInfo=no NETLIBS_GETADDRS="" ] ) ] ) AC_LANG_POP([C]) LIBS="$SAVED_LIBS" ]) AS_IF([test x"${ac_cv_func_GetAdaptersInfo}" = xyes], [AC_DEFINE([HAVE_GETADAPTERSINFO], 1, [defined if system has the GetAdaptersInfo() method])], [ AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_WARN([WIN32 library routine GetAdaptersInfo() not found]) ]) AS_CASE([${target_os}], [*mingw*], [AC_MSG_WARN([Windows antivirus might block this test])] ) ] ) ]) ] )] ) AC_SUBST([NETLIBS_GETADDRS]) dnl ---------------------------------------------------------------------- dnl Check for Python binary program names per language version dnl to embed into scripts and Make rules NUT_CHECK_PYTHON_DEFAULT dnl ---------------------------------------------------------------------- dnl Check for "require Modbus with USB support" situation before we mangle dnl caller-provided with_* values below (by --with-drivers and --with-all) nut_with_modbus_and_usb=auto AC_ARG_WITH(modbus+usb, AS_HELP_STRING([--with-modbus+usb], [Require Modbus with USB support (auto)]), [ case "${withval}" in no) dnl # AC_MSG_ERROR(invalid option --without-modbus+usb - see docs/configure.txt) AC_MSG_NOTICE([Treating --without-modbus+usb as not-requiring that used libmodbus supports RTU USB]) nut_with_modbus_and_usb="no" ;; auto) nut_with_modbus_and_usb="auto" ;; yes|'') if test -z "${with_usb}"; then with_usb="${withval}"; fi if test -z "${with_modbus}"; then with_modbus="${withval}"; fi nut_with_modbus_and_usb="yes" ;; *) AC_MSG_ERROR(invalid option --with-modbus+usb='${withval}' - see docs/configure.txt) ;; esac ], [ dnl Explicit request to build apc_modbus with both modbus and usb dnl support specified on command line implies we want them present dnl together too by default dnl FIXME: Extend to --with-drivers=all or that would not be dnl a least-surprise breakage for packagers? case x"${with_drivers}" in *apc_modbus*) dnl Note: defaulting of with_modbus=yes will be handled dnl below by --with-drivers if test x"${with_usb}" = xyes ; then nut_with_modbus_and_usb="yes" AC_MSG_WARN([Treating explicit requests to build apc_modbus and toe libusb as building --with-modbus+usb=yes]) fi ;; *) if test x"${with_usb}" = xyes -a x"${with_modbus}" = xyes \ -a x"${with_modbus_includes}" != x -a x"${with_modbus_libs}" != x \ ; then nut_with_modbus_and_usb="yes" AC_MSG_WARN([Treating explicit requests to build NUT with both modbus (with custom includes and libs) and usb as building --with-modbus+usb=yes]) fi ;; esac ]) dnl ---------------------------------------------------------------------- dnl check for --with-drivers=all (or --with-drivers=name[,name...]) flag dnl Note: a few drivers are NUT software constructs (NUTSW_DRIVERLIST) dnl e.g. dummy-ups, clone and clone-outlet; they do not have a separate dnl toggle or dependency at the moment. Earlier NUT releases before 2.8.0 dnl grouped them with serial drivers, which were enabled by default. dnl Autoconf versions before 2.62 do not allow consecutive quadrigraphs dnl (square brackets), so the help string depends on the version used AC_MSG_CHECKING(which drivers to build) AC_ARG_WITH(drivers, AS_HELP_STRING([m4_version_prereq(2.62, [@<:@--with-drivers=driver@<:@,driver@:>@@:>@], [[[[--with-drivers=driver@<:@,driver@:>@]]]])], [Only build specific drivers (all)]), [ case "${withval}" in yes|no|'') AC_MSG_ERROR(invalid option --with(out)-drivers - see docs/configure.txt) ;; all) dnl Explicit request to build all drivers (unless specified), or fail DRIVER_BUILD_LIST="all" if test -z "${with_serial}"; then with_serial="yes"; fi if test -z "${with_usb}"; then with_usb="yes"; fi if test -z "${with_snmp}"; then with_snmp="yes"; fi if test -z "${with_neon}"; then with_neon="yes"; fi if test -z "${with_powerman}"; then with_powerman="yes"; fi if test -z "${with_modbus}"; then with_modbus="yes"; fi if test -z "${with_ipmi}"; then with_ipmi="yes"; fi dnl Platform-dependent snowflakes that are required or auto: if test -z "${with_gpio}"; then dnl NOTE: Currently we only support a Linux libgpiod dnl backend for GPIO; eventually there could be more. dnl Also note that since March 2023 the very different dnl libgpiod v2.x is out (requires kernel 5.17.4+) case ${target_os} in linux*) with_gpio="auto";; dnl # TODO: Detect 2018+ distros? *) with_gpio="auto";; esac fi if test -z "${with_linux_i2c}"; then case ${target_os} in linux*) with_linux_i2c="yes";; *) with_linux_i2c="auto";; esac fi if test -z "${with_macosx_ups}"; then if test -d /System/Library/Frameworks/IOKit.framework/ ; then with_macosx_ups="yes" else with_macosx_ups="auto" fi fi AC_MSG_RESULT(${DRIVER_BUILD_LIST}) ;; auto) dnl Explicit request to build all drivers that we can DRIVER_BUILD_LIST="all" if test -z "${with_serial}"; then with_serial="${withval}"; fi if test -z "${with_usb}"; then with_usb="${withval}"; fi if test -z "${with_snmp}"; then with_snmp="${withval}"; fi if test -z "${with_neon}"; then with_neon="${withval}"; fi if test -z "${with_powerman}"; then with_powerman="${withval}"; fi if test -z "${with_modbus}"; then with_modbus="${withval}"; fi if test -z "${with_ipmi}"; then with_ipmi="${withval}"; fi if test -z "${with_gpio}"; then with_gpio="${withval}"; fi if test -z "${with_linux_i2c}"; then with_linux_i2c="${withval}"; fi if test -z "${with_macosx_ups}"; then with_macosx_ups="${withval}"; fi AC_MSG_RESULT(${DRIVER_BUILD_LIST}) ;; *) DRIVER_BUILD_LIST="`echo ${withval} | sed 's/,/ /g'`" AC_MSG_RESULT(${DRIVER_BUILD_LIST}) AS_IF([test -n "$DRIVER_BUILD_LIST"], [dnl DRVLIST is occasionally synced with drivers/Makefile.am dnl NOTE: Currently "USB_DRIVERLIST" is not used standalone: DRVLIST_NAMES="NUTSW_DRIVERLIST SERIAL_DRIVERLIST USB_LIBUSB_DRIVERLIST SERIAL_USB_DRIVERLIST SNMP_DRIVERLIST NEONXML_DRIVERLIST MACOSX_DRIVERLIST MODBUS_DRIVERLIST LINUX_I2C_DRIVERLIST POWERMAN_DRIVERLIST IPMI_DRIVERLIST GPIO_DRIVERLIST" get_drvlist() ( dnl Note escaped brackets - "against" m4 parser m4_version_prereq(2.62, [LB="@<:@"; RB="@:>@"], [LB="[["; RB="]]"] ) SPACE="`printf "$LB"' \t'"$RB"`" SPACES="${SPACE}*" sed -e "s/${SPACES}""$LB"'+'"$RB"'*='"${SPACES}/=/" \ -e "s/^${SPACES}//" < "$srcdir/drivers/Makefile.am" \ | { C=false; V=false while read LINE ; do case "$LINE" in *'\') C=true; if $V ; then echo "$LINE" ; fi ;; *) C=false; V=false ;; esac case "$LINE" in "$1"=*) echo "$LINE" | sed -e 's,^'"$LB"'^='"$RB"'*=,,' -e 's,\$,,' V=$C ;; esac done } | tr '\n' ' ' | sed -e "s,${SPACE}${SPACES}, ," -e "s,${SPACES}\$,," ) for DRVLIST_NAME in $DRVLIST_NAMES; do OUT="`get_drvlist "$DRVLIST_NAME"`" \ && test -n "$OUT" || OUT="" eval $DRVLIST_NAME="\$OUT" AC_MSG_NOTICE([Will check custom driver selection against $DRVLIST_NAME="$OUT"]) done dnl Note: do not quote the expansion below to keep it multi-token: for DRV in $DRIVER_BUILD_LIST ; do DRV_HITS="" AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) = Checking DRV="$DRV"]) ]) for DRVLIST_NAME in $DRVLIST_NAMES; do AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) == Checking DRVLIST_NAME="$DRVLIST_NAME"]) ]) eval DRVLIST="\${$DRVLIST_NAME}" AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) == Contents DRVLIST="$DRVLIST"]) ]) for DN in $DRVLIST ; do AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) === Checking DN="$DN"]) ]) AS_IF([test x"$DN" = x"$DRV"], [ DRV_HITS="$DRV_HITS $DRVLIST_NAME" AS_CASE(["$DRVLIST_NAME"], [NUTSW_DRIVERLIST], [ AC_MSG_NOTICE([Building NUT-Software-only driver "$DRV"]) ], [SERIAL_DRIVERLIST], [ AS_IF([test -z "${with_serial}"], [AC_MSG_NOTICE([Requiring --with-serial=yes for driver "$DRV"]) with_serial=yes] )], [USB_LIBUSB_DRIVERLIST], [ AS_IF([test -z "${with_usb}"], [AC_MSG_NOTICE([Requiring --with-usb=yes for driver "$DRV"]) with_usb=yes] )], [SERIAL_USB_DRIVERLIST], [ dnl e.g. nutdrv_qx that can do both AS_IF([test -z "${with_usb}"], [AC_MSG_NOTICE([Requiring --with-usb=yes for driver "$DRV"]) with_usb=yes] ) AS_IF([test -z "${with_serial}"], [AC_MSG_NOTICE([Requiring --with-serial=yes for driver "$DRV"]) with_serial=yes] )], [SNMP_DRIVERLIST], [ AS_IF([test -z "${with_snmp}"], [AC_MSG_NOTICE([Requiring --with-snmp=yes for driver "$DRV"]) with_snmp=yes] )], [NEONXML_DRIVERLIST], [ AS_IF([test -z "${with_neon}"], [AC_MSG_NOTICE([Requiring --with-neon=yes for driver "$DRV"]) with_neon=yes] )], [MACOSX_DRIVERLIST], [ dnl NOTE: This one is a bit special, dnl just one certain driver so far AS_IF([test -z "${with_macosx_ups}"], [AC_MSG_NOTICE([Requiring --with-macosx-ups=yes for driver "$DRV"]) with_macosx_ups=yes] )], [MODBUS_DRIVERLIST], [ AS_IF([test -z "${with_modbus}"], [AC_MSG_NOTICE([Requiring --with-modbus=yes for driver "$DRV"]) with_modbus=yes] )], [LINUX_I2C_DRIVERLIST], [ AS_IF([test -z "${with_linux_i2c}"], [AC_MSG_NOTICE([Requiring --with-linux-i2c=yes for driver "$DRV"]) with_linux_i2c=yes] )], [POWERMAN_DRIVERLIST], [ AS_IF([test -z "${with_powerman}"], [AC_MSG_NOTICE([Requiring --with-powerman=yes for driver "$DRV"]) with_powerman=yes] )], [IPMI_DRIVERLIST], [ AS_IF([test -z "${with_ipmi}"], [AC_MSG_NOTICE([Requiring --with-ipmi=yes for driver "$DRV"]) with_ipmi=yes] )], [GPIO_DRIVERLIST], [ AS_IF([test -z "${with_gpio}"], [AC_MSG_NOTICE([Requiring --with-gpio=yes for driver "$DRV"]) with_gpio=yes] )], [AC_MSG_WARN([Unhandled DRVLIST_NAME=$DRVLIST_NAME])] ) break dnl Break once, maybe a driver hits several categories ]) done done AS_IF([test -z "${DRV_HITS}"], [AC_MSG_ERROR([Requested driver '$DRV' is not defined in drivers/Makefile.am (or configure.ac has a bug/lag detecting driver lists)])]) done ]) ;; esac ], [ dnl Implicit request to build whatever is enabled; dnl do not force --with-all here: DRIVER_BUILD_LIST="all" AC_MSG_RESULT(all available) ]) AM_CONDITIONAL(SOME_DRIVERS, test "${DRIVER_BUILD_LIST}" != "all") if test "${DRIVER_BUILD_LIST}" != "all"; then NUT_REPORT([only build specific drivers], [${DRIVER_BUILD_LIST}]) fi dnl ---------------------------------------------------------------------- dnl check for --with-all (or --without-all, or --with-all=auto) flag AC_MSG_CHECKING(for --with-all) AC_ARG_WITH(all, AS_HELP_STRING([--with-all], [enable serial, usb, snmp, neon, ipmi, powerman, modbus, gpio (currently on Linux released after ~2018), linux_i2c (on Linux), macosx-ups (on MacOS), cgi, dev, avahi, nut-scanner, nutconf, dev-libnutconf, pynut]), [ if test -n "${withval}"; then dnl Note: we allow "no" as a positive value, because dnl this is what the user expects from --without-all dnl Note: these settings do not touch generation of dnl "--with-docs=...", that is handled separately if test -z "${with_serial}"; then with_serial="${withval}"; fi if test -z "${with_usb}"; then with_usb="${withval}"; fi if test -z "${with_snmp}"; then with_snmp="${withval}"; fi if test -z "${with_neon}"; then with_neon="${withval}"; fi if test -z "${with_powerman}"; then with_powerman="${withval}"; fi if test -z "${with_modbus}"; then with_modbus="${withval}"; fi if test -z "${with_ipmi}"; then with_ipmi="${withval}"; fi dnl Platform-dependent snowflakes that are required or auto: if test -z "${with_gpio}"; then dnl NOTE: Currently we only support a Linux libgpiod dnl backend for GPIO; eventually there could be more. dnl Also note that since March 2023 the very different dnl libgpiod v2.x is out (requires kernel 5.17.4+) with_gpio="${withval}" case ${target_os} in linux*) ;; *) test x"${withval}" = xno || with_gpio="auto" ;; esac fi if test -z "${with_linux_i2c}"; then with_linux_i2c="${withval}" case ${target_os} in linux*) ;; *) test x"${withval}" = xno || with_linux_i2c="auto" ;; esac fi if test -z "${with_macosx_ups}"; then with_macosx_ups="${withval}" if ! test -d /System/Library/Frameworks/IOKit.framework/ ; then test x"${withval}" = xno || with_macosx_ups="auto" fi fi dnl These are not driver families, but other features: if test -z "${with_cgi}"; then with_cgi="${withval}"; fi if test -z "${with_dev}"; then with_dev="${withval}"; fi if test -z "${with_avahi}"; then with_avahi="${withval}"; fi if test -z "${with_nut_scanner}"; then with_nut_scanner="${withval}"; fi if test -z "${with_nutconf}"; then with_nutconf="${withval}"; fi dnl dev-libnutconf is experimental, and relies on dnl functional C++11 that we only check for later; dnl at best, we can follow main nutconf request dnl (explicit from caller, or set a few lines above) if test -z "${with_dev_libnutconf}" ; then if test "${withval}" = no ; then with_dev_libnutconf="no" else case "${with_dev}${with_nutconf}" in *no*) with_dev_libnutconf="no" ;; *auto*) with_dev_libnutconf="auto" ;; yesyes) with_dev_libnutconf="yes" ;; esac fi fi if test -n "${PYTHON}${PYTHON2}${PYTHON3}" -a x"${withval}" = xyes \ || test x"${withval}" != xyes \ ; then dnl We expect Python to be available (augeas etc), dnl so if it is present - try to provide the PyNUT dnl binding module: if test -z "${with_pynut}"; then with_pynut="${withval}"; fi dnl However, do not let "--with-all" break builds dnl on servers that lack some GUI modules in their dnl Python installations; "auto" is defaulted below. dnl # if test -z "${with_nut_monitor}"; then with_nut_monitor="${withval}"; fi fi AC_MSG_RESULT([${withval}]) else AC_MSG_RESULT(not given) fi ], [ AC_MSG_RESULT(not given) ]) dnl ---------------------------------------------------------------------- dnl declare a number of --with-FEATURE options. Do this early, so that dnl they are listed near the top by "./configure --help"; however, dnl note that options with further investigation methods are listed dnl a bit below to be grouped with their additional with/enable help. dnl Depends on C++ support being available and enabled NUT_ARG_WITH([nutconf], [build and install the nutconf tool (experimental, has compiler/coverage warnings)], [auto]) NUT_ARG_WITH([dev], [build and install the development files], [no]) dnl Depends on C++ support being available and enabled dnl Does not depend on nutconf or dev explicitly (but warns about inconsistencies) NUT_ARG_WITH([dev-libnutconf], [deliver the C++ library behind the nutconf tool and its headers (experimental)], [no]) dnl Activate WITH_UNMAPPED_DATA_POINTS for troubleshooting and evolution? dnl Note that production drivers must conform to docs/nut-names.txt NUT_ARG_WITH([unmapped-data-points], [represent USB-HID and SNMP data points discovered during subdriver generation but not mapped to nut-names yet], [no]) AS_IF([test x"${nut_with_unmapped_data_points}" = xyes], [AC_DEFINE(WITH_UNMAPPED_DATA_POINTS, 1, [Define to enable data points discovered during subdriver generation but not mapped to nut-names yet])], [AC_DEFINE(WITH_UNMAPPED_DATA_POINTS, 0, [Define to enable data points discovered during subdriver generation but not mapped to nut-names yet])] ) dnl The NUT legacy option was --with-doc; however to simplify configuration dnl in some common packaging frameworks, we also allow --with-docs as dnl a second-class citizen (if both are set, the old option name wins). dnl Also note that the legacy default was "man=yes" due to requirements dnl of the "make distcheck", but it was reduced to "man=auto" so that dnl the usual builds can pass by default on systems without asciidoc. NUT_ARG_WITH([docs], [build and install documentation (alias to --with-doc)], [man=auto]) NUT_ARG_WITH([doc], [build and install documentation (see docs/configure.txt for many variants of the option)], [${nut_with_docs}]) dnl NOTE: Sections may be strings, not pure numbers, on some platforms: NUT_ARG_WITH([docs-man-section-api], [man page section for library APIs], [3]) NUT_ARG_WITH([docs-man-section-cfg], [man page section for configuration files], [5]) NUT_ARG_WITH([docs-man-section-cmd-sys], [man page section for system management commands], [8]) NUT_ARG_WITH([docs-man-section-cmd-usr], [man page section for user commands], [1]) dnl NOTE: Until X-Mas 2021, the default was "legacy" (now "medium") NUT_ARG_ENABLE([warnings], [enable warning presets that were picked as useful in maintainership and CI practice (variants include gcc-minimal, gcc-medium, gcc-hard, clang-minimal, clang-medium, clang-hard, all; auto-choosers: hard, medium, minimal, yes=auto='gcc or clang or all at hardcoded default difficulty')], [auto]) NUT_ARG_ENABLE([Werror], [fail the build if compiler emits any warnings (treat them as errors)], [no]) NUT_ARG_WITH([debuginfo], [enable compiler options for debug-friendly builds of all NUT binaries ("no" by default; "auto" means "yes unless CFLAGS say otherwise")], [no]) dnl To help find warning/error details in a wall of text, see --enable-Wcolor handled above dnl ---------------------------------------------------------------------- dnl Check for with-ssl, and --with-nss or --with-openssl which can be used dnl by NUT as well as its networking-capable dependencies (net-snmp, etc.) dnl Only one can be enabled at a time, with a preference for OpenSSL dnl if both are available nut_ssl_lib="" NUT_ARG_WITH([ssl], [enable SSL support (either NSS or OpenSSL)], [auto]) NUT_ARG_WITH([nss], [enable SSL support using Mozilla NSS], [auto]) NUT_ARG_WITH([openssl], [enable SSL support using OpenSSL], [auto]) dnl ${nut_with_ssl}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_ssl}" != "no"; then dnl check if either NSS or OpenSSL was explicitly requested if test "${nut_with_nss}" = "yes"; then NUT_CHECK_LIBNSS if test "${nut_have_libnss}" != "yes"; then AC_MSG_ERROR([Mozilla NSS not found (required for SSL support)]) fi elif test "${nut_with_openssl}" = "yes"; then NUT_CHECK_LIBOPENSSL if test "${nut_have_openssl}" != "yes"; then AC_MSG_ERROR([OpenSSL not found (required for SSL support)]) fi else dnl Prefer OpenSSL over NSS otherwise NUT_CHECK_LIBOPENSSL if test "${nut_have_openssl}" != "yes"; then NUT_CHECK_LIBNSS if test "${nut_have_libnss}" != "yes"; then dnl Only abort if SSL has been explicitly requested by the user if test "${nut_with_ssl}" = "yes"; then AC_MSG_ERROR([Neither Mozilla NSS nor OpenSSL was found, but one is needed for the requested SSL support.]) else AC_MSG_WARN([Neither Mozilla NSS nor OpenSSL was found (required for SSL support)]) fi nut_with_ssl="no" else nut_with_nss="${nut_have_libnss}" fi else nut_with_openssl="${nut_have_openssl}" fi fi fi AM_CONDITIONAL(WITH_NSS, test "${nut_with_nss}" = "yes") AM_CONDITIONAL(WITH_OPENSSL, test "${nut_with_openssl}" = "yes") NUT_REPORT_FEATURE([enable SSL support], [${nut_with_ssl}], [${nut_ssl_lib}], [WITH_SSL], [Define to enable SSL]) dnl ---------------------------------------------------------------------- dnl Check for presence and compiler flags of various libraries NUT_ARG_WITH([serial], [build and install serial drivers], [yes]) dnl These checks are performed unconditionally, even if the corresponding dnl --with-* options are not given. This is because we cannot predict dnl what will be in the --with-drivers argument. NUT_CHECK_LIBREGEX NUT_ARG_WITH([usb], [build and install USB drivers, optionally require build with specified version of libusb library and API: (auto|libusb-0.1|libusb-1.0)], [auto]) nut_usb_lib="" NUT_CHECK_LIBUSB NUT_ARG_WITH([snmp], [build and install SNMP drivers], [auto]) NUT_CHECK_LIBNETSNMP NUT_ARG_WITH([neon], [build and install neon based XML/HTTP driver], [auto]) NUT_CHECK_LIBNEON NUT_ARG_WITH([powerman], [build and install Powerman PDU client driver], [auto]) NUT_CHECK_LIBPOWERMAN NUT_ARG_WITH([modbus], [build and install modbus drivers], [auto]) NUT_CHECK_LIBMODBUS NUT_ARG_WITH([gpio], [build and install GPIO driver], [auto]) NUT_CHECK_LIBGPIO NUT_ARG_WITH([avahi], [build and install Avahi support], [auto]) NUT_CHECK_LIBAVAHI NUT_ARG_WITH([ipmi], [build and install IPMI PSU driver], [auto]) NUT_ARG_WITH([freeipmi], [enable IPMI support using FreeIPMI], [auto]) dnl NUT_ARG_WITH([openipmi], [enable IPMI support using OpenIPMI], [auto]) dnl Platform-dependent drivers, currently their detection code is directly dnl spelled out in configure.ac NUT_ARG_WITH([macosx_ups], [build and install Mac OS X Power Sources meta-driver], [auto]) NUT_ARG_WITH([linux_i2c], [build and install i2c drivers], [auto]) dnl A Python GUI client application for the sysadmin desktop dnl (not necessarily on the NUT server itself): NUT_ARG_WITH([nut_monitor], [install the NUT-Monitor GUI files], [auto]) NUT_ARG_WITH([pynut], [install the PyNUT module files (yes, no, app, auto)], [auto]) dnl Note: we did NUT_CHECK_PYTHON2 NUT_CHECK_PYTHON3 etc above, dnl and if at all possible, we generate the files from .in templates dnl anyway by running this configure script. The question is about dnl installing these features or not. dnl Note: more for tests than other reasons, there is also an option dnl value to "force" the installation. dnl The gettext "msgfmt" tool (or equivalent) can be used to maintain dnl human-language text translations. Currently this is used specifically dnl in the Python NUT-Monitor app sources (*.po => *.mo conversions). AC_PATH_PROGS([MSGFMT], [msgfmt], [none]) AM_CONDITIONAL([HAVE_MSGFMT], [test "x${MSGFMT}" != "xnone"]) dnl ---------------------------------------------------------------------- dnl checks related to --with-serial dnl ${nut_with_serial}: any value except "yes" or "no" is treated as "auto". dnl Below we try to detect if we can build serial drivers, and if we must? AS_IF([test "${nut_with_serial}" != "no"], [AS_IF([test "${nut_with_serial}" != "yes"],[nut_with_serial="auto"]) CFLAGS_SAVED_SERIAL="${CFLAGS}" AS_IF([test "${GCC}" = yes], [CFLAGS_SAVED_WERROR="${CFLAGS} -Wall -Werror" CFLAGS_SAVED_WNOERROR="${CFLAGS} -Wno-error" ], [CFLAGS_SAVED_WERROR="${CFLAGS}" CFLAGS_SAVED_WNOERROR="${CFLAGS}" ]) dnl At least recent *BSD distros have deprecated sys/termios.h and spew dnl warnings that termios.h should be used instead. This is redundantly dnl fatal for pedantic builds where we aim to have no warnings in code. dnl So there AC_CHECK_HEADERS does find the header, but we don't really dnl want to use it unless we have no choice: if there is a warning while dnl trying sys/ version, try the plain header path (without fatal warnings), dnl and only if that is missing - retry with the sys/ version again (and dnl no warnings still). CFLAGS="${CFLAGS_SAVED_WERROR}" AC_CHECK_HEADERS(sys/termios.h, [], [ CFLAGS="${CFLAGS_SAVED_WNOERROR}" AC_CHECK_HEADERS(termios.h, [], [ AC_CHECK_HEADERS(sys/termios.h, [], [], [AC_INCLUDES_DEFAULT]) ], [AC_INCLUDES_DEFAULT]) ], [AC_INCLUDES_DEFAULT]) dnl CFLAGS at this point suffice for surviving a compilation with termios.h dnl Don't mind the stupid code below, it just probes the tokens and dnl sails around compiler warnings AC_MSG_CHECKING([for struct termios and speed_t]) AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #if defined(HAVE_SYS_TERMIOS_H) # include /* for speed_t */ #else # if defined(HAVE_TERMIOS_H) # include # endif /* HAVE_TERMIOS_H */ #endif /* HAVE_SYS_TERMIOS_H */ void getspeed(speed_t* b) { *b = B19200; } ], [struct termios tio; if (!tcgetattr(0, &tio)) { return 1; } speed_t baudrate; getspeed(&baudrate); ] )], [AC_MSG_RESULT([ok]) nut_have_serial_types=yes ], [AC_MSG_RESULT([no, struct termios and/or speed_t not found in discovered headers]) nut_have_serial_types=no ] ) AC_LANG_POP([C]) dnl Restore common set-or-discovered CFLAGS CFLAGS="${CFLAGS_SAVED_SERIAL}" AC_MSG_CHECKING([whether we can build serial drivers]) AS_CASE(["${target_os}"], [*mingw*], [ AS_IF([test "${nut_have_serial_types}" != yes], [AC_MSG_WARN([not with system includes, but can try with our fallback for the target platform]) nut_have_serial_types=yes] ) ]) AS_IF([test "${nut_have_serial_types}" = yes], [AS_IF([test "${nut_with_serial}" = "auto"],[nut_with_serial="yes"])], [AS_IF([test "${nut_with_serial}" = "auto"],[nut_with_serial="no"]) AS_IF([test "${nut_with_serial}" = "yes"],[AC_MSG_ERROR([no, and were required to])]) ]) AS_IF([test "${nut_with_serial}" = "yes"], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ]) NUT_REPORT_DRIVER([build serial drivers], [${nut_with_serial}], [], [WITH_SERIAL], [Define to enable serial support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-usb are in its m4 file and NUT_CHECK_LIBUSB() called above dnl Note: there is no libusb-config script (and variable) for libusb-1.0 AM_CONDITIONAL(WITH_LIBUSB_1_0, test "${nut_usb_lib}" = "(libusb-1.0)") AM_CONDITIONAL(WITH_LIBUSB_0_1, test "${nut_usb_lib}" = "(libusb-0.1)" -o "${nut_usb_lib}" = "(libusb-0.1-config)") NUT_REPORT_DRIVER([build USB drivers], [${nut_with_usb}], [${nut_usb_lib}], [WITH_USB], [Define to enable USB support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-neon dnl ${nut_with_neon}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_neon}" = "yes" -a "${nut_have_neon}" != "yes"; then AC_MSG_ERROR([neon libraries not found, required for neon based XML/HTTP driver]) fi if test "${nut_with_neon}" != "no"; then nut_with_neon="${nut_have_neon}" fi NUT_REPORT_DRIVER([build neon based XML driver], [${nut_with_neon}], [], [WITH_NEON], [Define to enable Neon HTTP support]) AM_CONDITIONAL([HAVE_NEON], [test "${nut_have_neon}" = "yes"]) dnl ---------------------------------------------------------------------- dnl checks related to --with-avahi dnl ${nut_with_avahi}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_avahi}" = "yes" -a "${nut_have_avahi}" != "yes"; then AC_MSG_ERROR([avahi libraries not found]) fi if test "${nut_with_avahi}" != "no"; then nut_with_avahi="${nut_have_avahi}" fi NUT_REPORT_FEATURE([enable Avahi support], [${nut_with_avahi}], [], [WITH_AVAHI], [Define to enable Avahi support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-powerman dnl ${nut_with_powerman}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_powerman}" = "yes" -a "${nut_have_libpowerman}" != "yes"; then AC_MSG_ERROR([Powerman client libraries not found, required for Powerman PDU client driver]) fi if test "${nut_with_powerman}" != "no"; then nut_with_powerman="${nut_have_libpowerman}" fi NUT_REPORT_DRIVER([build Powerman PDU client driver], [${nut_with_powerman}], [], [WITH_LIBPOWERMAN], [Define to enable Powerman PDU support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-modbus dnl ${nut_with_modbus}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_modbus}" = "yes" -a "${nut_have_libmodbus}" != "yes"; then AC_MSG_ERROR([modbus library not found, required for Modbus drivers]) fi if test "${nut_with_modbus_and_usb}" = "yes" -a "${nut_have_libmodbus_usb}" != "yes"; then AC_MSG_ERROR([modbus library variant with RTU USB support not found, required for USB-capable Modbus drivers]) fi if test "${nut_with_modbus}" != "no"; then nut_with_modbus="${nut_have_libmodbus}" fi NUT_REPORT_DRIVER([build Modbus drivers], [${nut_with_modbus}], [], [WITH_MODBUS], [Define to enable Modbus support]) AS_IF([test "${nut_with_modbus}" != "no"], [ dnl Only display this detail when building modbus at all dnl Config definition NUT_MODBUS_HAS_USB is set in the dnl detection method (if nut_have_libmodbus_usb=="yes") NUT_REPORT_DRV([build Modbus drivers with RTU USB support], [${nut_have_libmodbus_usb}]) ]) AM_CONDITIONAL(WITH_MODBUS_USB, [test "${nut_with_modbus}" = "yes" && test "${nut_have_libmodbus_usb}" = yes && test "${nut_with_usb}" = yes && test "${nut_with_modbus_and_usb}" != "no"]) dnl ---------------------------------------------------------------------- dnl Check for with-ipmi, and --with-freeipmi (or --with-openipmi) dnl Only one can be enabled at a time, with a preference for FreeIPMI dnl if both are available (since it is the only one supported ATM!!) nut_ipmi_lib="" dnl ${nut_with_ipmi}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_ipmi}" != "no"; then dnl check if FreeIPMI (and maybe later OpenIPMI) was explicitly requested if test "${nut_with_freeipmi}" = "yes"; then NUT_CHECK_LIBFREEIPMI if test "${nut_have_freeipmi}" != "yes"; then AC_MSG_ERROR([FreeIPMI not found, required for IPMI support]) fi dnl Implies --with-ipmi nut_with_ipmi="yes" dnl elif test "${nut_with_openipmi}" = "yes"; then dnl AC_MSG_ERROR([OpenIPMI is not yet supported]) dnl NUT_CHECK_LIBOPENIPMI dnl if test "${nut_have_openipmi}" != "yes"; then dnl AC_MSG_ERROR([OpenIPMI not found, required for IPMI support]) dnl fi dnl Implies --with-ipmi dnl nut_with_ipmi="yes" dnl AC_DEFINE(WITH_OPENIPMI, 1, [Define to enable IPMI support using OpenIPMI]) else dnl Prefer FreeIPMI over OpenIPMI otherwise NUT_CHECK_LIBFREEIPMI if test "${nut_have_freeipmi}" != "yes"; then if test "${nut_with_ipmi}" = "yes"; then AC_MSG_ERROR([FreeIPMI not found, required for IPMI support]) fi nut_with_ipmi="no" dnl NUT_CHECK_OPENIPMI dnl if test "${nut_have_openipmi}" != "yes"; then dnl if test "${nut_with_ipmi}" = "yes"; then dnl AC_MSG_ERROR([Neither GNU FreeIPMI nor OpenIPMI was found (required for IPMI support)]) dnl fi dnl nut_with_ipmi="no" dnl else dnl Implies --with-ipmi dnl nut_with_ipmi="yes" dnl nut_with_openipmi="yes" dnl fi else dnl Implies --with-ipmi nut_with_ipmi="yes" nut_with_freeipmi="yes" AC_DEFINE(WITH_FREEIPMI, 1, [Define to enable IPMI support using FreeIPMI]) fi fi fi NUT_REPORT_DRIVER([build IPMI driver], [${nut_with_ipmi}], [${nut_ipmi_lib}], [WITH_IPMI], [Define to enable IPMI support]) dnl Note: we still have to manually enable complementary AC_DEFINEs (see above) dnl and AM_CONDITIONALs (see below)... AM_CONDITIONAL(WITH_FREEIPMI, test "${nut_with_freeipmi}" = "yes") dnl AM_CONDITIONAL(WITH_OPENIPMI, test "${nut_with_openipmi}" = "yes") dnl ---------------------------------------------------------------------- dnl Check for with-gpio if test "${nut_with_gpio}" = "yes" -a "${nut_have_gpio}" != "yes"; then AC_MSG_ERROR([No supported GPIO library was found, required for GPIO driver]) fi dnl ${nut_with_gpio}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_gpio}" != "no"; then nut_with_gpio="${nut_have_gpio}" fi dnl NOTE: m4 scriptlet also defines WITH_LIBGPIO_VERSION like 0x00020000 in config.h NUT_REPORT_DRIVER([build GPIO driver (library v${GPIO_VERSION})], [${nut_with_gpio}], [${nut_gpio_lib}], [WITH_GPIO], [Define to enable GPIO support]) dnl ---------------------------------------------------------------------- dnl The Mac OS X meta-driver looks at IOKit Power Sources keys managed by dnl the internal USB UPS driver. dnl dnl FIXME: be slightly more clever here: if test "${nut_with_macosx_ups}" != no; then if test -d /System/Library/Frameworks/IOKit.framework/ ; then nut_with_macosx_ups="yes" else if test "${nut_with_macosx_ups}" = yes; then AC_MSG_ERROR([macosx-ups was required but can not be fulfilled for this build: not MacOS]) fi nut_with_macosx_ups="no" fi fi NUT_REPORT_DRIVER([build Mac OS X meta-driver], [${nut_with_macosx_ups}], [${nut_macosx_ups_lib}], [WITH_MACOSX], [Define to enable Mac OS X meta-driver]) dnl ---------------------------------------------------------------------- dnl checks related to --with_linux_i2c dnl Check for i2c header on Linux, used for ASEM UPS driver LIBI2C_LIBS="" if test "${nut_with_linux_i2c}" != no; then case ${target_os} in linux* ) AC_CHECK_HEADER( [linux/i2c-dev.h], [AC_DEFINE([HAVE_LINUX_I2C_DEV_H], [1], [Define to 1 if you have .])] ) AC_CHECK_HEADER( [i2c/smbus.h], [AC_DEFINE([HAVE_LINUX_SMBUS_H], [1], [Define to 1 if you have .])] ) nut_have_linux_i2c="no" AC_CHECK_DECLS( [i2c_smbus_access, i2c_smbus_read_byte_data, i2c_smbus_write_byte_data, i2c_smbus_read_word_data, i2c_smbus_write_word_data, i2c_smbus_read_block_data], [nut_have_linux_i2c="yes"], [], [#include #ifdef HAVE_LINUX_I2C_DEV_H #include #endif #ifdef HAVE_LINUX_SMBUS_H #include #endif ] ) dnl Builds for bitness/arch other than system default can be dnl "compromised" by lack of respective binary library, so dnl even if we have the right headers, ultimate link fails. dnl Note: here we keep the verdict from above, or make it worse. LIBS_SAVED="$LIBS" LIBS="" AS_IF([test "${nut_have_linux_i2c}" = yes], [ nut_have_linux_i2c="no" AC_SEARCH_LIBS(i2c_smbus_read_byte, i2c, [ AC_SEARCH_LIBS(i2c_smbus_access, i2c, [ AC_SEARCH_LIBS(i2c_smbus_read_byte_data, i2c, [ AC_SEARCH_LIBS(i2c_smbus_write_byte_data, i2c, [ AC_SEARCH_LIBS(i2c_smbus_read_word_data, i2c, [ AC_SEARCH_LIBS(i2c_smbus_write_word_data, i2c, [ AC_SEARCH_LIBS(i2c_smbus_read_block_data, i2c, [ [nut_have_linux_i2c="yes"] ])])])])])])])]) dnl # Note: *with* (desire) is not "no" in this big if-clause AS_IF([test "${nut_have_linux_i2c}" = yes], [nut_with_linux_i2c="yes"], [AS_IF([test "${nut_with_linux_i2c}" = "yes"], [AC_MSG_ERROR(i2c was required but can not be fulfilled for this build)], [nut_with_linux_i2c="no"]) ]) LIBI2C_LIBS="$LIBS" LIBS="$LIBS_SAVED" ;; * ) if test "${nut_with_linux_i2c}" = yes; then AC_MSG_ERROR([i2c was required but can not be fulfilled for this build: not linux]) fi nut_with_linux_i2c="no" ;; esac fi NUT_REPORT_DRIVER( [build i2c based drivers], [${nut_with_linux_i2c}], [], [WITH_LINUX_I2C], [Define to enable I2C support] ) dnl ---------------------------------------------------------------------- dnl Check for --with-wrap NUT_ARG_WITH([wrap], [enable libwrap (tcp-wrappers) support], [auto]) dnl ${nut_with_wrap}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_wrap}" != "no"; then dnl check for libwrap compiler flags NUT_CHECK_LIBWRAP fi if test "${nut_with_wrap}" = "yes" -a "${nut_have_libwrap}" != "yes"; then AC_MSG_ERROR([libwrap not found]) fi if test "${nut_with_wrap}" != "no"; then nut_with_wrap="${nut_have_libwrap}" fi NUT_REPORT_FEATURE([enable libwrap (tcp-wrappers) support], [${nut_with_wrap}], [], [WITH_WRAP], [Define to enable libwrap (tcp-wrappers) support]) dnl ---------------------------------------------------------------------- dnl Check for --with-libltdl and --with-nut-scanner dnl Note: libltdl is primarily used by nut-scanner now; however some dnl side projects and forks of NUT have more creative uses for it dnl and might eventually land in NUT codebase proper. NUT_ARG_WITH([libltdl], [enable libltdl (Libtool dlopen abstraction) support], [auto]) dnl Note: default could be overridden above by --with-all handling. dnl While nut-scanner decides at run-time if it would use third-party shared dnl library files (bundled along or not, if available for the platform), its dnl binary must be configured now and built against their headers at least. NUT_ARG_WITH([nut-scanner], [build and install nut-scanner tool (requires libltdl; optionally libusb, libneon, libsnmp)], [auto]) dnl ${nut_with_libltdl}: any value except "yes" or "no" is treated as "auto". if test x"${nut_with_libltdl}" != x"no"; then if test x"${nut_with_nut_scanner}" = x"yes"; then dnl Require libltdl to be present (or fail the configure script) nut_with_libltdl="yes" fi dnl check for libltdl compiler flags NUT_CHECK_LIBLTDL fi if test x"${nut_with_libltdl}" = x"yes" -a x"${nut_have_libltdl}" != x"yes"; then AC_MSG_ERROR([libltdl not found]) fi if test x"${nut_with_libltdl}" != x"no"; then nut_with_libltdl="${nut_have_libltdl}" fi NUT_REPORT_FEATURE([enable libltdl (Libtool dlopen abstraction) support], [${nut_with_libltdl}], [], [WITH_LIBLTDL], [Define to enable libltdl (Libtool dlopen abstraction) support]) dnl Explicitly report if we are building nut-scanner or not dnl since it requires libltdl if test x"${nut_with_libltdl}" = x"no" && test x"${nut_with_nut_scanner}" = x"yes"; then AC_MSG_ERROR([libltdl support was disabled or not found, but --with-nut-scanner was requested and requires it]) fi if test x"${nut_with_nut_scanner}" = x"auto"; then nut_with_nut_scanner="${nut_with_libltdl}" fi NUT_REPORT_PROGRAM([build nut-scanner], [${nut_with_nut_scanner}], [], [WITH_NUT_SCANNER], [Define to enable nut-scanner tool support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-cgi NUT_ARG_WITH([cgi], [build and install the CGI programs], [no]) dnl ${nut_with_cgi}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_cgi}" != "no"; then dnl check for libgd compiler flags NUT_CHECK_LIBGD fi if test "${nut_with_cgi}" = "yes" -a "${nut_have_libgd}" != "yes"; then AC_MSG_ERROR([libgd not found, required for CGI build]) fi if test "${nut_with_cgi}" != "no"; then nut_with_cgi="${nut_have_libgd}" fi NUT_REPORT_PROGRAM([build CGI programs], [${nut_with_cgi}], [], [WITH_CGI], [Define to enable CGI (HTTP) support]) dnl ---------------------------------------------------------------------- dnl checks related to --with-pynut and --with-nut_monitor dnl The PYTHON*_REPORT vars also serve as flags that we have certain usable dnl Python interpreter versions to care about below, so we only test for dnl their existence once (in NUT_CHECK*PYTHON* m4 macros). dnl ${nut_with_nut_monitor}: TODO: arg values to request Python 2 gtk2, dnl Python 3 qt5, or both AC_MSG_CHECKING([if we want install NUT-Monitor desktop application]) AC_MSG_RESULT([${nut_with_nut_monitor}]) nut_with_nut_monitor_py2gtk2="" nut_with_nut_monitor_py3qt5="" nut_with_nut_monitor_desktop="" dnl TODO: Add a way to define this path? will have app/ maybe module/ inside... nut_with_nut_monitor_dir="${datarootdir}/nut-monitor" PYTHON_FAILED_TEST_DETAILS="" AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_nut_monitor-1: ${nut_with_nut_monitor}]) ]) if test x"${nut_with_nut_monitor}" != xno ; then dnl While we might just install for "yes" request, in hopes user would dnl get their Python ecosystem in place later, we need some criteria to dnl avoid installing it always :) Also, need to substitute the shebang. if test -z "${PYTHON}${PYTHON2}${PYTHON3}" ; then case "${nut_with_nut_monitor}" in "auto") nut_with_nut_monitor="no" PYTHON_FAILED_TEST_DETAILS="No Python 2/3 interpreter was found" ;; "yes") AC_MSG_ERROR([No Python 2/3 interpreter was found, required for NUT-Monitor desktop application]) ;; esac fi fi AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_nut_monitor-2: ${nut_with_nut_monitor}]) ]) if test x"${nut_with_nut_monitor}" != xno ; then dnl Note: no double-quoting for use, the command string may be multi-token dnl HACK NOTE: Here we redirect outputs to "&5" which is autoconf stream dnl for "config.log" details since... forever? Still, hardcoded numbers... PYTHON2_TEST_MODULES="re,glob,codecs,gtk,gtk.glade,gobject,ConfigParser" PYTHON3_TEST_MODULES="re,glob,codecs,PyQt5.uic,configparser" if test -n "${PYTHON2_VERSION_INFO_REPORT}" ; then AC_MSG_CHECKING([if we have Python2 prerequisites for NUT-Monitor desktop application]) if ${PYTHON2} -c "import ${PYTHON2_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py2gtk2="yes" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) case ${target_os} in solaris*|sunos*|SunOS*|illumos*) # At least on OpenIndiana, the pygobject-27 build is only # delivered in a 64-bit variant, while the default link to # the python2.7 script interpreter is 64-bit. This precludes # the use of NUT-Monitor-py2gtk2 which is otherwise possible # (and useful for testing) on the platform. AS_CASE([x"${PYTHON2}"], [x*" "*], [], [x/usr/bin/python*], [ AC_MSG_CHECKING([if a Solarish platform-specific build of Python2 fares better]) AS_CASE([x"${PYTHON2}"], [x/usr/bin/python2], [TRY_PYTHON2_VERS="python2 python2.7 python2.6"], [x/usr/bin/python], [TRY_PYTHON2_VERS="python python2 python2.7 python2.6"], [TRY_PYTHON2_VERS="`basename "${PYTHON2}"`"] ) TRY_BASEDIR="`dirname "${PYTHON}"`" for ARCHDIR in 64 amd64 sparcv9 32 i86 sparcv7 sparc ; do for TRY_VERNAME in $TRY_PYTHON2_VERS ; do TRY_PYTHON2="${TRY_BASEDIR}/${ARCHDIR}/${TRY_VERNAME}" if ${TRY_PYTHON2} -c "import ${PYTHON2_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py2gtk2="yes" AC_MSG_RESULT([yes with ${TRY_PYTHON2}]) dnl FIXME: Track a separate interpreter variable for NUT-Monitor? PYTHON2="${TRY_PYTHON2}" break fi done if test x"${nut_with_nut_monitor_py2gtk2}" = x"yes" ; then break fi done if test x"${nut_with_nut_monitor_py2gtk2}" != x"yes" ; then AC_MSG_RESULT([no]) fi ]) ;; esac if test x"${nut_with_nut_monitor_py2gtk2}" != x"yes" ; then PYTHON_FAILED_TEST_DETAILS="Missing some or all of these Python2 modules: '${PYTHON2_TEST_MODULES}'" fi fi fi if test -n "${PYTHON3_VERSION_INFO_REPORT}" ; then AC_MSG_CHECKING([if we have Python3 prerequisites for NUT-Monitor desktop application]) if ${PYTHON3} -c "import ${PYTHON3_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py3qt5="yes" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) if test -n "${PYTHON_FAILED_TEST_DETAILS}" ; then PYTHON_FAILED_TEST_DETAILS="${PYTHON_FAILED_TEST_DETAILS} and some or all of these Python3 modules: '${PYTHON3_TEST_MODULES}'" else PYTHON_FAILED_TEST_DETAILS="Missing some or all of these Python3 modules: '${PYTHON3_TEST_MODULES}'" fi fi fi dnl Fall back to default interpreter if test -z "${nut_with_nut_monitor_py2gtk2}${nut_with_nut_monitor_py3qt5}" \ && test -n "${PYTHON_VERSION_INFO_REPORT}" \ && test x"${PYTHON_VERSION_INFO_REPORT}" != x"${PYTHON3_VERSION_INFO_REPORT}" \ && test x"${PYTHON_VERSION_INFO_REPORT}" != x"${PYTHON2_VERSION_INFO_REPORT}" \ ; then AC_MSG_CHECKING([if we have Python3 prerequisites for NUT-Monitor desktop application in default Python]) if ${PYTHON} -c "import ${PYTHON3_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py3qt5="yes" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) if test -n "${PYTHON_FAILED_TEST_DETAILS}" ; then PYTHON_FAILED_TEST_DETAILS="${PYTHON_FAILED_TEST_DETAILS} and some or all of these Python3 modules in default Python: '${PYTHON3_TEST_MODULES}'" else PYTHON_FAILED_TEST_DETAILS="Missing some or all of these Python3 modules in default Python: '${PYTHON3_TEST_MODULES}'" fi fi AC_MSG_CHECKING([if we have Python2 prerequisites for NUT-Monitor desktop application in default Python]) if ${PYTHON} -c "import ${PYTHON2_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py2gtk2="yes" PYTHON_FAILED_TEST_DETAILS="" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) case ${target_os} in solaris*|sunos*|SunOS*|illumos*) # See somments above AS_CASE([x"${PYTHON}"], [x*" "*], [], [x/usr/bin/python*], [ AC_MSG_CHECKING([if a Solarish platform-specific build of Python2 fares better]) AS_CASE([x"${PYTHON}"], [x/usr/bin/python2], [TRY_PYTHON2_VERS="python2 python2.7 python2.6"], [x/usr/bin/python], [TRY_PYTHON2_VERS="python python2 python2.7 python2.6"], [TRY_PYTHON2_VERS="`basename "${PYTHON}"`"] ) TRY_BASEDIR="`dirname "${PYTHON}"`" for ARCHDIR in 64 amd64 sparcv9 32 i86 sparcv7 sparc ; do for TRY_VERNAME in $TRY_PYTHON2_VERS ; do TRY_PYTHON2="${TRY_BASEDIR}/${ARCHDIR}/${TRY_VERNAME}" if ${TRY_PYTHON2} -c "import ${PYTHON2_TEST_MODULES}" 1>&5 2>&5 \ ; then nut_with_nut_monitor_py2gtk2="yes" AC_MSG_RESULT([yes with ${TRY_PYTHON2}]) dnl FIXME: Track a separate interpreter variable for NUT-Monitor? PYTHON="${TRY_PYTHON2}" break fi done if test x"${nut_with_nut_monitor_py2gtk2}" = x"yes" ; then break fi done if test x"${nut_with_nut_monitor_py2gtk2}" != x"yes" ; then AC_MSG_RESULT([no]) fi ]) ;; esac if test x"${nut_with_nut_monitor_py2gtk2}" != x"yes" ; then if test -n "${PYTHON_FAILED_TEST_DETAILS}" ; then PYTHON_FAILED_TEST_DETAILS="${PYTHON_FAILED_TEST_DETAILS} and some or all of these Python2 modules in default Python: '${PYTHON2_TEST_MODULES}'" else PYTHON_FAILED_TEST_DETAILS="Missing some or all of these Python2 modules in default Python: '${PYTHON2_TEST_MODULES}'" fi fi fi fi AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_nut_monitor-3: ${nut_with_nut_monitor}]) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_nut_monitor_py2gtk2: ${nut_with_nut_monitor_py2gtk2}]) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_nut_monitor_py3qt5: ${nut_with_nut_monitor_py3qt5}]) ]) dnl Can we satisfy any NUT-Monitor installation request? if test -n "${nut_with_nut_monitor_py2gtk2}${nut_with_nut_monitor_py3qt5}" ; then case "${nut_with_nut_monitor}" in "auto") nut_with_nut_monitor="yes" ;; esac else case "${nut_with_nut_monitor}" in "auto") nut_with_nut_monitor="no" ;; "yes") AC_MSG_ERROR([No Python 2/3 interpreter with needed modules was found, as required for NUT-Monitor desktop application: ${PYTHON_FAILED_TEST_DETAILS}]) ;; esac fi fi AC_MSG_CHECKING([if we can and should install NUT-Monitor desktop application]) AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_nut_monitor-4: ${nut_with_nut_monitor}]) ]) case "${nut_with_nut_monitor}" in "no") if test -n "${PYTHON_FAILED_TEST_DETAILS}" ; then AC_MSG_RESULT([${nut_with_nut_monitor}: ${PYTHON_FAILED_TEST_DETAILS}]) else AC_MSG_RESULT([${nut_with_nut_monitor}]) fi ;; *) AC_MSG_RESULT([${nut_with_nut_monitor}]) ;; esac AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_nut_monitor-5: ${nut_with_nut_monitor}]) ]) if test x"${nut_with_nut_monitor}" != xno ; then if (command -v desktop-file-install || which desktop-file-install) >/dev/null 2>/dev/null ; then case "${nut_with_nut_monitor}" in "auto"|"yes") nut_with_nut_monitor_desktop="desktop-file-install" ;; esac else case "${nut_with_nut_monitor}" in "yes") AC_MSG_WARN([Current OS does not seem to provide desktop-file-install]) nut_with_nut_monitor_desktop="install" ;; "auto") nut_with_nut_monitor_desktop="install" ;; esac fi fi AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) nut_with_nut_monitor-6: ${nut_with_nut_monitor}]) ]) dnl ${nut_with_pynut}: TODO: arg values to request python 2, 3 or both AC_MSG_CHECKING([if we can and should install PyNUT module]) nut_with_pynut_py="" nut_with_pynut_py2="" nut_with_pynut_py3="" if test x"${nut_with_pynut}" != xno \ -a -n "${PYTHON}${PYTHON2}${PYTHON3}" \ ; then if test -n "${PYTHON2}" \ && (command -v ${PYTHON2} || which ${PYTHON2}) >/dev/null 2>/dev/null \ ; then if ${PYTHON2} -c "import socket" \ ; then nut_with_pynut_py2="yes" fi fi if test -n "${PYTHON3}" \ && (command -v ${PYTHON3} || which ${PYTHON3}) >/dev/null 2>/dev/null \ ; then if ${PYTHON3} -c "import socket" \ ; then nut_with_pynut_py3="yes" fi fi dnl Test same-ness of pythons with sys.version also? if test -n "${PYTHON}" \ && (command -v ${PYTHON} || which ${PYTHON}) >/dev/null 2>/dev/null \ && test "${PYTHON}" != "${PYTHON2}" -a "${PYTHON}" != "${PYTHON3}" \ ; then if ${PYTHON} -c "import socket" \ ; then nut_with_pynut_py="yes" fi fi fi if test -z "${nut_with_pynut_py}${nut_with_pynut_py2}${nut_with_pynut_py3}" ; then dnl Not all prereqs are available... case "${nut_with_pynut}" in "auto"|"app") if test "${nut_with_nut_monitor}" = yes ; then AC_MSG_ERROR([Prerequisites for PyNUT not found, can't install as required for NUT-Monitor desktop application]) else nut_with_pynut="no" fi ;; "yes") AC_MSG_ERROR([Prerequisites for PyNUT not found, can't install as required]) ;; esac fi if test x"${nut_with_pynut}" != xno ; then if test -n "${PYTHON_SITE_PACKAGES}${PYTHON2_SITE_PACKAGES}${PYTHON3_SITE_PACKAGES}" \ ; then dnl retain "app" if requested by caller case "${nut_with_pynut}" in "auto") nut_with_pynut="yes" ;; esac else case "${nut_with_pynut}" in "auto") if test "${nut_with_nut_monitor}" = yes -o "${nut_with_nut_monitor}" = force ; then nut_with_pynut="app" else nut_with_pynut="no" fi ;; "yes") dnl Note: this would die for --with-nut_monitor=yes but no site location if test "${nut_with_nut_monitor}" = yes -o "${nut_with_nut_monitor}" = force ; then nut_with_pynut="app" else AC_MSG_ERROR([Python interpreter and/or its site-packages location not found, but required for PyNUT]) fi ;; esac fi fi AC_MSG_RESULT([${nut_with_pynut}]) dnl Note: do not move up to before pynut processing if test "${nut_with_nut_monitor}" = force ; then AC_MSG_NOTICE([overriding nut_with_nut_monitor=yes because caller forced it]) nut_with_nut_monitor=yes nut_with_nut_monitor_py2gtk2=yes nut_with_nut_monitor_py3qt5=yes fi if test "${nut_with_pynut}" = force ; then AC_MSG_NOTICE([overriding nut_with_pynut=yes because caller forced it]) if test "${nut_with_nut_monitor}" = yes ; then nut_with_pynut=app else nut_with_pynut=yes fi fi NUT_REPORT_PROGRAM([install NUT-Monitor desktop application], [${nut_with_nut_monitor}], [], [WITH_NUT_MONITOR], [Define to enable NUT-Monitor desktop application installation]) NUT_REPORT_PROGRAM([install PyNUT binding module], [${nut_with_pynut}], [], [WITH_PYNUT], [Define to enable PyNUT module installation]) dnl One or both of these may be installed: AM_CONDITIONAL(WITH_NUT_MONITOR, test "${nut_with_nut_monitor}" = "yes" && test "${nut_with_nut_monitor_py2gtk2}" = "yes" -o "${nut_with_nut_monitor_py3qt5}" = "yes") AM_CONDITIONAL(WITH_NUT_MONITOR_PY2GTK2, test "${nut_with_nut_monitor_py2gtk2}" = "yes") AM_CONDITIONAL(WITH_NUT_MONITOR_PY3QT5, test "${nut_with_nut_monitor_py3qt5}" = "yes") dnl Install PyNUT as a globally usable module, or just as app internals? AM_CONDITIONAL(WITH_PYNUT_PY, test "${nut_with_pynut_py}" = "yes" -a "${nut_with_pynut}" = yes) AM_CONDITIONAL(WITH_PYNUT_PY2, test "${nut_with_pynut_py2}" = "yes" -a "${nut_with_pynut}" = yes) AM_CONDITIONAL(WITH_PYNUT_PY3, test "${nut_with_pynut_py3}" = "yes" -a "${nut_with_pynut}" = yes) AM_CONDITIONAL(WITH_PYNUT_APP, test "${nut_with_pynut}" = "app") AC_SUBST([nut_with_nut_monitor_dir], [${nut_with_nut_monitor_dir}]) AC_SUBST([nut_with_nut_monitor_py2gtk2], [${nut_with_nut_monitor_py2gtk2}]) AC_SUBST([nut_with_nut_monitor_py3qt5], [${nut_with_nut_monitor_py3qt5}]) AC_SUBST([nut_with_nut_monitor_desktop], [${nut_with_nut_monitor_desktop}]) AC_SUBST([nut_with_nut_monitor], [${nut_with_nut_monitor}]) AC_SUBST([nut_with_pynut], [${nut_with_pynut}]) AC_SUBST([nut_with_pynut_py], [${nut_with_pynut_py}]) AC_SUBST([nut_with_pynut_py2], [${nut_with_pynut_py2}]) AC_SUBST([nut_with_pynut_py3], [${nut_with_pynut_py3}]) dnl MacOS Darwin has a problem with script shebangs, and tends to run anything dnl with shell. On the upside, it has no limit on length or amount of tokens dnl in the shebang line. dnl https://github.com/NixOS/nixpkgs/issues/65351/ AS_CASE([${target_os}], [*darwin*], [ AS_IF([test -n "${PYTHON}" -a x"${PYTHON}" != xno], [ PYTHON=" /usr/bin/env ${PYTHON}"]) AS_IF([test -n "${PYTHON2}" -a x"${PYTHON2}" != xno], [PYTHON2=" /usr/bin/env ${PYTHON2}"]) AS_IF([test -n "${PYTHON3}" -a x"${PYTHON3}" != xno], [PYTHON3=" /usr/bin/env ${PYTHON3}"]) ] ) AS_IF([test "${nut_with_nut_monitor}" != no -o "${nut_with_pynut}" != no], [ NUT_REPORT([use default Python interpreter], [${PYTHON}]) NUT_REPORT([use specific Python2 interpreter], [${PYTHON2}]) NUT_REPORT([use specific Python3 interpreter], [${PYTHON3}]) NUT_REPORT_PATH_INTEGRATIONS([Default Python interpreter site-packages], [${PYTHON_SITE_PACKAGES}]) NUT_REPORT_PATH_INTEGRATIONS([Specific Python2 interpreter site-packages], [${PYTHON2_SITE_PACKAGES}]) NUT_REPORT_PATH_INTEGRATIONS([Specific Python3 interpreter site-packages], [${PYTHON3_SITE_PACKAGES}]) dnl # Python site-packages installation path for specific Python3 interpreter ]) dnl ---------------------------------------------------------------------- dnl checks related to --enable-cppcheck dnl Currently this is experimental; maybe change default to auto in the future dnl At that point, see also defaults in ci_build.sh then (to avoid the workload dnl unless desired). NUT_ARG_ENABLE([cppcheck], [Run a cppcheck on the codebase among checks], [no]) NUT_CHECK_CPPCHECK AC_MSG_CHECKING(whether to run cppcheck among default make check target) case "${nut_enable_cppcheck}" in yes) if test "${nut_have_cppcheck}" = "no" ; then AC_MSG_ERROR([Requested to --enable-cppcheck but did not find a good one]) fi WITH_CPPCHECK=yes ;; no) WITH_CPPCHECK=no ;; auto) if test "${nut_have_cppcheck}" = "yes" ; then WITH_CPPCHECK=yes else WITH_CPPCHECK=no fi ;; esac AC_MSG_RESULT([${WITH_CPPCHECK}]) AM_CONDITIONAL(WITH_CPPCHECK, test "${WITH_CPPCHECK}" = "yes") dnl ---------------------------------------------------------------------- dnl checks related to --enable-check-NIT AC_MSG_CHECKING(whether to run NIT among default make check target) nut_enable_check_NIT="no" AC_ARG_ENABLE([check-NIT], AS_HELP_STRING([--enable-check-NIT], [Run check-NIT among default checks (no)]), [ case "${enableval}" in no) AC_MSG_RESULT(no) ;; *) AC_MSG_RESULT(yes) nut_enable_check_NIT="yes" ;; esac ], [ AC_MSG_RESULT(no) ]) AM_CONDITIONAL(WITH_CHECK_NIT, test "${nut_enable_check_NIT}" = "yes") dnl ---------------------------------------------------------------------- dnl checks related to --enable-spellcheck NUT_CHECK_ASPELL NUT_ARG_ENABLE([spellcheck], [Run spellcheck among default checks], [auto]) AC_MSG_CHECKING(whether to run spellcheck among default make check target) case "${nut_enable_spellcheck}" in yes) if test "${nut_have_aspell}" = "no" ; then AC_MSG_ERROR([Requested to --enable-spellcheck but did not find a good one]) fi WITH_SPELLCHECK=yes ;; no) WITH_SPELLCHECK=no ;; auto) if test "${nut_have_aspell}" = "yes" ; then WITH_SPELLCHECK=yes else WITH_SPELLCHECK=no fi ;; esac AC_MSG_RESULT([${WITH_SPELLCHECK}]) AM_CONDITIONAL(WITH_SPELLCHECK, test "${WITH_SPELLCHECK}" = "yes") dnl ---------------------------------------------------------------------- dnl checks related to --with-doc dnl Always check for AsciiDoc prerequisites, since even if --with-doc dnl is set to 'no', we may still want to build some doc targets manually dnl (so enable the Makefile recipes for those targets if tools are available) NUT_CHECK_ASCIIDOC NUT_REPORT_FEATURE([requested to build and install documentation], [${nut_with_doc}], [], [WITH_ASCIIDOC], [Define to enable Asciidoc support]) DOC_INSTALL_DISTED_MANS=no KNOWN_UNABLE_MANS=no case "${nut_with_doc}" in yes|all|all=yes) nut_doc_build_list="man html-single html-chunked pdf" ;; auto|all=auto) nut_doc_build_list="man=auto html-single=auto html-chunked=auto pdf=auto" ;; skip|all=skip) nut_doc_build_list="man=skip html-single=skip html-chunked=skip pdf=skip" ;; dist-auto) # Experimental, currently only for MANs: prefer disted files if present, auto otherwise nut_doc_build_list="man=dist-auto html-single=dist-auto html-chunked=dist-auto pdf=dist-auto" ;; no|all=no) nut_doc_build_list="" ;; dnl If user passed --with-doc='' they they want nothing, right? "") nut_doc_build_list="" AC_MSG_NOTICE([Got explicit empty list of document formats to build; nothing will be generated]) ;; *) nut_doc_build_list="`echo ${nut_with_doc} | sed 's/,/ /g'`" AC_MSG_NOTICE([Got explicit list of document formats to build or not: ${nut_doc_build_list}; formats not listed will be silently skipped]) ;; esac if test -z "${abs_srcdir}" ; then case "${srcdir}" in /*) abs_srcdir="${srcdir}";; "") AC_MSG_ERROR([Can not detect 'srcdir']) ;; *) abs_srcdir="$(cd "${srcdir}" && pwd)" || AC_MSG_ERROR([Can not detect 'srcdir']) ;; esac fi DOCTESTDIR="$(mktemp -d configure-test.docbuild.$$.XXXXXXX)" && \ DOCTESTDIR="$(cd "$DOCTESTDIR" && pwd)" dnl NOTE: We perform some of these checks/infos also if docs=(man=)skip dnl so we know in later reports if disted files are still an option dnl should we want to not just skip them have_disted_doc_man=no want_disted_doc_man=no if test -s "${abs_srcdir}"/docs/man/snmp-ups.8 ; then dnl Test that groff files exist (building from distributed tarball, not git repo) if test x"PLACEHOLDER" = x"`cat "${abs_srcdir}"/docs/man/snmp-ups.8`" ; then dnl REALLY should not happen in real builds, dnl but may be in distcheck-driven sub-builds dnl where the external build agreed to use dnl fake man pages (e.g. for CI recipe checks) have_disted_doc_man=yes-placeholder else have_disted_doc_man=yes fi fi dnl Note: Do not cover ${nut_doc_build_list} in braces or quotes here, dnl to ensure that it is processed as several space-separated tokens for nut_doc_build_target in $nut_doc_build_list; do case "${nut_doc_build_target}" in *=*=*) rm -rf "${DOCTESTDIR}" AC_MSG_ERROR([Invalid documentation format option: ${nut_doc_build_target}]) ;; *=*) nut_doc_build_target_base="`echo "${nut_doc_build_target}" | sed 's,=.*$,,'`" nut_doc_build_target_flag="`echo "${nut_doc_build_target}" | sed 's,^.*=,,'`" ;; *) nut_doc_build_target_base="${nut_doc_build_target}" nut_doc_build_target_flag="yes" ;; esac case "${nut_doc_build_target_flag}" in yes|no|auto|skip|dist-auto) ;; "") nut_doc_build_target_flag="yes" ;; *) rm -rf "${DOCTESTDIR}" AC_MSG_ERROR([Invalid documentation format option: ${nut_doc_build_target}]) ;; esac AC_MSG_CHECKING([desire and ability to build ${nut_doc_build_target_base} documentation]) AC_MSG_RESULT([${nut_doc_build_target_flag}]) case "${nut_doc_build_target}" in *=no|*=skip) DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" ;; dnl Notes: Document options below assume either no flag value (which dnl by default means "yes"), "yes" which is a requirement, or "auto" dnl to detect if we can build the wanted documentation format and yet dnl not fail if we have no tools to generate it (so add to SKIP list). html-single*) AC_MSG_CHECKING([if asciidoc and a2x versions can build ${nut_doc_build_target_base} (minimum required asciidoc-${ASCIIDOC_MIN_VERSION} a2x-${A2X_MIN_VERSION})]) can_build_doc_html_single=no AX_COMPARE_VERSION([${ASCIIDOC_VERSION}], [ge], [${ASCIIDOC_MIN_VERSION}], [ AX_COMPARE_VERSION([${A2X_VERSION}], [ge], [${A2X_MIN_VERSION}], [ ( cd "$DOCTESTDIR" && ${A2X} --attribute=xhtml11_format --format=xhtml --xsl-file="${abs_srcdir}"/docs/xhtml.xsl --destination-dir=. "${abs_srcdir}"/docs/asciidoc.txt && test -s asciidoc.html ) && can_build_doc_html_single=yes rm -f "$DOCTESTDIR"/asciidoc*.htm* ], []) ], []) if test "${can_build_doc_html_single}" = yes ; then AC_MSG_RESULT(yes) DOC_BUILD_LIST="${DOC_BUILD_LIST} ${nut_doc_build_target_base}" else AC_MSG_RESULT(no) DOC_CANNOTBUILD_LIST="${DOC_CANNOTBUILD_LIST} ${nut_doc_build_target_base}" if test "${nut_doc_build_target_flag}" = "yes" ; then AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation which you requested]) else DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" fi fi ;; html-chunked*) AC_MSG_CHECKING([if asciidoc and a2x versions can build ${nut_doc_build_target_base} (minimum required asciidoc-${ASCIIDOC_MIN_VERSION} a2x-${A2X_MIN_VERSION})]) can_build_doc_html_chunked=no AX_COMPARE_VERSION([${ASCIIDOC_VERSION}], [ge], [${ASCIIDOC_MIN_VERSION}], [ AX_COMPARE_VERSION([${A2X_VERSION}], [ge], [${A2X_MIN_VERSION}], [ ( cd "$DOCTESTDIR" && ${A2X} --attribute=chunked_format --format=chunked --xsl-file="${abs_srcdir}"/docs/chunked.xsl --destination-dir=. "${abs_srcdir}"/docs/FAQ.txt && test -s FAQ.chunked/index.html ) && can_build_doc_html_chunked=yes rm -rf "${DOCTESTDIR}"/FAQ*.chunked* ], []) ], []) if test "${can_build_doc_html_chunked}" = yes ; then AC_MSG_RESULT(yes) DOC_BUILD_LIST="${DOC_BUILD_LIST} ${nut_doc_build_target_base}" else AC_MSG_RESULT(no) DOC_CANNOTBUILD_LIST="${DOC_CANNOTBUILD_LIST} ${nut_doc_build_target_base}" if test "${nut_doc_build_target_flag}" = "yes" ; then AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation which you requested]) else DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" fi fi ;; pdf*) AC_MSG_CHECKING([if dblatex version can build ${nut_doc_build_target_base} (minimum required ${DBLATEX_MIN_VERSION})]) can_build_doc_pdf=no can_build_doc_pdf_nonascii_titles=no AX_COMPARE_VERSION([${DBLATEX_VERSION}], [ge], [${DBLATEX_MIN_VERSION}], [ ( cd "$DOCTESTDIR" && ${A2X} --format=pdf --destination-dir=. "${abs_srcdir}"/docs/asciidoc.txt && test -s asciidoc.pdf ) && can_build_doc_pdf=yes rm -f "${DOCTESTDIR}"/asciidoc.pdf ], []) if test "${can_build_doc_pdf}" = yes ; then AC_MSG_RESULT(yes) DOC_BUILD_LIST="${DOC_BUILD_LIST} ${nut_doc_build_target_base}" AC_MSG_CHECKING([if dblatex can process non-ASCII section titles for PDF]) ( cd "$DOCTESTDIR" && sed -e 's/^Intro/'"`printf '\303\215'`"'ntro/' -e 's/Works in Progress/Works '"`printf '\303\255'`"'n Progress/' < "${abs_srcdir}"/docs/asciidoc.txt > asciidoc.tmp.txt && ${A2X} --format=pdf --destination-dir=. asciidoc.tmp.txt && test -s asciidoc.tmp.pdf ) && can_build_doc_pdf_nonascii_titles=yes rm -f "${DOCTESTDIR}"/asciidoc.tmp.pdf AC_MSG_RESULT(${can_build_doc_pdf_nonascii_titles}) else AC_MSG_RESULT(no) DOC_CANNOTBUILD_LIST="${DOC_CANNOTBUILD_LIST} ${nut_doc_build_target_base}" if test "${nut_doc_build_target_flag}" = "yes" ; then AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation which you requested]) else DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" fi fi ;; man*) dnl Experimental support for --with-doc=man=dist-auto to prefer pre-disted docs if available, below AC_MSG_CHECKING([if we can build ${nut_doc_build_target_base}]) can_build_doc_man=no if test x"${nut_doc_build_target}" = x"man=dist-auto" || test "${nut_doc_build_target_flag}" = "dist-auto"; then want_disted_doc_man=yes fi if test "${nut_have_asciidoc}" = yes ; then ( cd "$DOCTESTDIR" && ${A2X} --format manpage --destination-dir=. --xsltproc-opts="--nonet" "${abs_srcdir}"/docs/man/snmp-ups.txt && test -s snmp-ups.8 ) && can_build_doc_man=yes rm -f "${DOCTESTDIR}"/snmp-ups.8 fi if test "${want_disted_doc_man}" = yes && ( test "${have_disted_doc_man}" = yes || test "${have_disted_doc_man}" = yes-placeholder ) ; then AC_MSG_NOTICE([Requested, and can, install pre-built distributed copies of ${nut_doc_build_target_base} documentation]) DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" DOC_INSTALL_DISTED_MANS="yes" dnl Avoid rebuilding existing build products due to their timestamp dependencies: touch -r "${abs_srcdir}"/docs/man/Makefile.am "${abs_srcdir}"/docs/man/*.{1,2,3,4,5,6,7,8,9}* "${abs_srcdir}"/docs/man/*.{txt,xml,html,pdf} || true else if test "${can_build_doc_man}" = yes ; then AC_MSG_RESULT(yes) AS_IF([test x"${nut_doc_build_target_base}" = xman], dnl Use "man-man" target, otherwise Makefile dnl is satisfied that directory "man" exists: [DOC_BUILD_LIST="${DOC_BUILD_LIST} man-man"], [DOC_BUILD_LIST="${DOC_BUILD_LIST} ${nut_doc_build_target_base}"]) else AC_MSG_RESULT(no) DOC_CANNOTBUILD_LIST="${DOC_CANNOTBUILD_LIST} ${nut_doc_build_target_base}" KNOWN_UNABLE_MANS=yes if test "${nut_doc_build_target_flag}" = "yes" ; then AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation which you requested]) else DOC_SKIPBUILD_LIST="${DOC_SKIPBUILD_LIST} ${nut_doc_build_target_base}" if test "${nut_doc_build_target_flag}" = "auto" || test "${nut_doc_build_target_flag}" = "dist-auto" ; then if test "${have_disted_doc_man}" = yes || test "${have_disted_doc_man}" = yes-placeholder ; then AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation, but can install pre-built distributed copies]) DOC_INSTALL_DISTED_MANS="yes" else AC_MSG_WARN([Unable to build ${nut_doc_build_target_base} documentation, and unable to install pre-built distributed copies because they are absent]) fi fi # Other variants include "no", "skip"... fi fi fi ;; *) rm -rf "${DOCTESTDIR}" AC_MSG_ERROR([--with-doc option refers to unknown documentation format: $nut_doc_build_target]) ;; esac done rm -rf "${DOCTESTDIR}" AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) DOC_BUILD_LIST: '${DOC_BUILD_LIST}']) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) DOC_CANNOTBUILD_LIST: '${DOC_CANNOTBUILD_LIST}']) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) DOC_SKIPBUILD_LIST: '${DOC_SKIPBUILD_LIST}']) ]) case "${nut_with_doc}" in auto) if test -n "${DOC_BUILD_LIST}"; then nut_with_doc="yes" else nut_with_doc="no" fi ;; no) ;; *) if test -n "${DOC_CANNOTBUILD_LIST}"; then DOC_CANNOTBUILD_LIST_LINES="`echo "${DOC_CANNOTBUILD_LIST}" | tr ' ' '\n' | grep -vE '^$'`" for DOCTYPE in ${DOC_BUILD_LIST} ; do if echo "${DOC_CANNOTBUILD_LIST_LINES}" | grep -E "^${DOCTYPE}(|=yes)\$" ; then AC_MSG_ERROR([Unable to build${DOC_CANNOTBUILD_LIST} documentation (check for 'no' results above)]) else if echo "${DOC_CANNOTBUILD_LIST_LINES}" | grep -E "^${DOCTYPE}=(skip|auto|dist-auto)\$" ; then AC_MSG_NOTICE([Unable to build${DOC_CANNOTBUILD_LIST} documentation (check for 'no' results above), skipping]) fi fi done fi if test -n "${DOC_SKIPBUILD_LIST}"; then AC_MSG_NOTICE([Skipping build of${DOC_SKIPBUILD_LIST} documentation (check for 'skip' results above)]) fi if test -n "${DOC_BUILD_LIST}"; then nut_with_doc="yes" else nut_with_doc="no" fi ;; esac AM_CONDITIONAL(WITH_PDF_NONASCII_TITLES, [test x"$can_build_doc_pdf_nonascii_titles" = xyes]) NUT_REPORT_FEATURE([would build specific documentation format(s)], [${nut_with_doc}], [${DOC_BUILD_LIST}], [WITH_DOCS], [Define to enable overall documentation generation]) # To cater for less portable make's, precalculate the target list # for "make check" in "docs/" here... DOC_CHECK_LIST="" if test "${nut_with_doc}" = yes ; then for V in $DOC_BUILD_LIST ; do if test x"$V" = xman-man ; then V=man ; fi DOC_CHECK_LIST="$DOC_CHECK_LIST check-$V" done fi WITH_MANS=no SKIP_MANS=no if echo "${DOC_BUILD_LIST}" | grep -w "man" >/dev/null || test "${DOC_INSTALL_DISTED_MANS}" = "yes" ; then WITH_MANS=yes fi if echo "${DOC_SKIPBUILD_LIST}" | grep -w "man" >/dev/null ; then SKIP_MANS=yes fi if echo "${DOC_CANNOTBUILD_LIST}" | grep -w "man" >/dev/null ; then KNOWN_UNABLE_MANS=yes fi dnl Generally WITH_MANS=no is intentionally fatal for "make distcheck" dnl But some larger distcheck suites check mans once and then focus on dnl other aspects of the project, so they can explicitly skip docs (or dnl just mans) instead. Note that for WITH_MANS=yes the SKIP_MANS value dnl is effectively ignored by docs/man/Makefile.am at this time. AM_CONDITIONAL(WITH_MANS, test "${WITH_MANS}" = "yes") AM_CONDITIONAL(SKIP_MANS, test "${SKIP_MANS}" = "yes") AM_CONDITIONAL(KNOWN_UNABLE_MANS, test "${KNOWN_UNABLE_MANS}" = "yes") AM_CONDITIONAL(DOC_INSTALL_DISTED_MANS, test "${DOC_INSTALL_DISTED_MANS}" = "yes") dnl Reporting have_disted_doc_man not DOC_INSTALL_DISTED_MANS because the former has more values AS_IF([test x"${have_disted_doc_man}" = x], [have_disted_doc_man="did not check"]) NUT_REPORT([can install pre-built documentation (release/dist tarball)], ["${have_disted_doc_man}"]) WITH_HTML_SINGLE=no SKIP_HTML_SINGLE=no if echo "${DOC_BUILD_LIST}" | grep -w "html-single" >/dev/null ; then WITH_HTML_SINGLE=yes fi if echo "${DOC_SKIPBUILD_LIST}" | grep -w "html-single" >/dev/null ; then SKIP_HTML_SINGLE=yes fi AM_CONDITIONAL(WITH_HTML_SINGLE, test "${WITH_HTML_SINGLE}" = "yes") AM_CONDITIONAL(SKIP_HTML_SINGLE, test "${SKIP_HTML_SINGLE}" = "yes") WITH_HTML_CHUNKED=no SKIP_HTML_CHUNKED=no if echo "${DOC_BUILD_LIST}" | grep -w "html-chunked" >/dev/null ; then WITH_HTML_CHUNKED=yes fi if echo "${DOC_SKIPBUILD_LIST}" | grep -w "html-chunked" >/dev/null ; then SKIP_HTML_CHUNKED=yes fi AM_CONDITIONAL(WITH_HTML_CHUNKED, test "${WITH_HTML_CHUNKED}" = "yes") AM_CONDITIONAL(SKIP_HTML_CHUNKED, test "${SKIP_HTML_CHUNKED}" = "yes") WITH_PDFS=no SKIP_PDFS=no if echo "${DOC_BUILD_LIST}" | grep -w "pdf" >/dev/null ; then WITH_PDFS=yes fi if echo "${DOC_SKIPBUILD_LIST}" | grep -w "pdf" >/dev/null ; then SKIP_PDFS=yes fi AM_CONDITIONAL(WITH_PDFS, test "${WITH_PDFS}" = "yes") AM_CONDITIONAL(SKIP_PDFS, test "${SKIP_PDFS}" = "yes") dnl NOTE: Sections may be strings, not pure numbers, on some platforms: MAN_SECTION_API="${nut_with_docs_man_section_api}" MAN_SECTION_CFG="${nut_with_docs_man_section_cfg}" MAN_SECTION_CMD_SYS="${nut_with_docs_man_section_cmd_sys}" MAN_SECTION_CMD_USR="${nut_with_docs_man_section_cmd_usr}" MAN_SECTION_API_BASE="`echo "${MAN_SECTION_API}" | sed 's/^\(@<:@0-9@:>@*\)@<:@^0-9@:>@.*$/\1/'`" MAN_SECTION_CFG_BASE="`echo "${MAN_SECTION_CFG}" | sed 's/^\(@<:@0-9@:>@*\)@<:@^0-9@:>@.*$/\1/'`" MAN_SECTION_CMD_SYS_BASE="`echo "${MAN_SECTION_CMD_SYS}" | sed 's/^\(@<:@0-9@:>@*\)@<:@^0-9@:>@.*$/\1/'`" MAN_SECTION_CMD_USR_BASE="`echo "${MAN_SECTION_CMD_USR}" | sed 's/^\(@<:@0-9@:>@*\)@<:@^0-9@:>@.*$/\1/'`" AC_DEFINE_UNQUOTED([MAN_SECTION_API], ["${MAN_SECTION_API}"], [man page section for library APIs]) AC_DEFINE_UNQUOTED([MAN_SECTION_CFG], ["${MAN_SECTION_CFG}"], [man page section for configuration files]) AC_DEFINE_UNQUOTED([MAN_SECTION_CMD_SYS], ["${MAN_SECTION_CMD_SYS}"], [man page section for system management commands]) AC_DEFINE_UNQUOTED([MAN_SECTION_CMD_USR], ["${MAN_SECTION_CMD_USR}"], [man page section for user commands]) AC_DEFINE_UNQUOTED([MAN_SECTION_API_BASE], ["${MAN_SECTION_API_BASE}"], [base (number only) man page section for library APIs]) AC_DEFINE_UNQUOTED([MAN_SECTION_CFG_BASE], ["${MAN_SECTION_CFG_BASE}"], [base (number only) man page section for configuration files]) AC_DEFINE_UNQUOTED([MAN_SECTION_CMD_SYS_BASE], ["${MAN_SECTION_CMD_SYS_BASE}"], [base (number only) man page section for system management commands]) AC_DEFINE_UNQUOTED([MAN_SECTION_CMD_USR_BASE], ["${MAN_SECTION_CMD_USR_BASE}"], [base (number only) man page section for user commands]) AC_SUBST(MAN_SECTION_API) AC_SUBST(MAN_SECTION_CFG) AC_SUBST(MAN_SECTION_CMD_SYS) AC_SUBST(MAN_SECTION_CMD_USR) AC_SUBST(MAN_SECTION_API_BASE) AC_SUBST(MAN_SECTION_CFG_BASE) AC_SUBST(MAN_SECTION_CMD_SYS_BASE) AC_SUBST(MAN_SECTION_CMD_USR_BASE) dnl ---------------------------------------------------------------------- dnl checks related to --with-dev dnl We only init libtool there to allow AC_DISABLE_STATIC if ( test "${GCC}" = "yes" ) then dnl # Avoid new compilers' warnings/errors about libtool distro flaws in this test like: dnl # error: ISO C forbids conversion of function pointer to object pointer type [-Werror=pedantic] dnl # {"nm_test_func", (void *) &nm_test_func}, dnl # or ones about LTO (-flto -fno-common) as discussed and suggested dnl # in https://www.mail-archive.com/libtool@gnu.org/msg14037.html - dnl # all leading to undefined "global_symbol_pipe" in the generated dnl # libtool script, and resulting in errors like `... | | ...` below : dnl # libtool: link: /usr/bin/nm -B .libs/upsclient.o \ dnl # ../common/.libs/libcommonclient.a | | /usr/bin/sed 's/.* //' \ dnl # | sort | uniq > .libs/libupsclient.exp dnl # ../libtool: syntax error: `|' unexpected CFLAGS_SAVED_NOPEDANTIC="$CFLAGS" AS_CASE(["${CFLAGS}"],[*"-pedantic"*],[CFLAGS="${CFLAGS} -Wno-pedantic"]) AS_CASE(["${CFLAGS}"],[*"-Werror"*],[CFLAGS="${CFLAGS} -Wno-error"]) AS_CASE(["${CFLAGS}"],[*"-flto"*],[CFLAGS="${CFLAGS} -ffat-lto-objects"]) fi dnl See https://www.gnu.org/software/libtool/manual/html_node/LT_005fINIT.html dnl #OBSOLETED:# LT_INIT and AC_PROG_LIBTOOL dnl # Hack around the libtool script: as of version 58 (current in 2021), dnl # they use code like below to detect library paths: dnl # if test yes = "$GCC"; then ... lt_search_path_spec=`$CC -print-search-dirs | ... dnl # which explodes when non-default architecture is used for the build, dnl # where e.g. "CC=gcc" and "CFLAGS=-m32" on a 64-bit capable system. dnl # And similarly for compilation-checks to link third-party libraries. SAVED_GCC="$GCC" SAVED_CC="$CC" if ( test "${GCC}" = "yes" ) then case "$CFLAGS$LDFLAGS" in *-m32*) CC="$CC -m32" ;; *-m64*) CC="$CC -m64" ;; esac fi m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) dnl # NOTE: This also initializes `hardcode_libdir_flag_spec` and dnl # `hardcode_libdir_flag_spec_CXX` that we use in LDFLAGS_NUT_RPATH LT_INIT AC_SUBST([LIBTOOL_DEPS]) GCC="$SAVED_GCC" CC="$SAVED_CC" if ( test "${GCC}" = "yes" ) then CFLAGS="$CFLAGS_SAVED_NOPEDANTIC" fi dnl ${nut_with_dev}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_dev}" != "no"; then nut_with_dev="yes" else AC_DISABLE_STATIC fi AM_CONDITIONAL(WITH_DEV, test "${nut_with_dev}" = "yes") NUT_REPORT_FEATURE([build and install the development files], [${nut_with_dev}], [], [WITH_DEV], [Define to enable development files support]) dnl ---------------------------------------------------------------------- dnl checks related to MS Windows support (MingW) AC_CHECK_TOOL([WINDMC], [windmc], [none]) AC_CHECK_TOOL([WINDRES], [windres], [none]) if test "x$WINDMC" != "xnone" -a "x$WINDRES" != "xnone" ; then nut_have_mingw_resgen="yes" fi AM_CONDITIONAL([HAVE_MINGW_RESGEN], [test "${nut_have_mingw_resgen}" = "yes"]) dnl Also define a generic automake condition for general Windows compilation: dnl do we at least have the header file(s) we require for the platform dnl (more files may be optional e.g. for different generations of networking) dnl Could just use ..._COND_IF([HAVE_WINDOWS_H],... but it is not present in dnl some older versions of autotools. (Note autoconf expands in comments too). AS_IF([test "x$nut_cv_header_windows_h" = xyes], [AM_CONDITIONAL([HAVE_WINDOWS], [test "${nut_have_mingw_resgen}" = "yes"])], [AM_CONDITIONAL([HAVE_WINDOWS], [false])] ) dnl ---------------------------------------------------------------------- PREFIX="${prefix}" NUT_REPORT_SETTING_PATH([Default installation prefix path], PREFIX, "${prefix}", [Default installation prefix path]) AC_MSG_CHECKING(if requested state path) AC_ARG_WITH(statepath, AS_HELP_STRING([--with-statepath=PATH], [path for ups state files (${STATEPATH}, typically /var/state/ups)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-statepath - see docs/configure.txt) ;; *) STATEPATH="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) NUT_REPORT_SETTING_PATH([State file path], STATEPATH, "${STATEPATH}", [Path for UPS driver state files]) dnl --------------------------------------------------------------------- dnl The 'alt pid path' is used by the drivers (via main.c) and upsd, since dnl ideally they do not run as root and will not be able to write to the usual dnl /var/run path. This defaults to the STATEPATH since they should be dnl able to write there. dnl AC_MSG_CHECKING(if requested alt pid path) AC_ARG_WITH(altpidpath, AS_HELP_STRING([--with-altpidpath=PATH], [path for NUT driver/upsd .pid files not running as root ()]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-altpidpath - see docs/configure.txt) ;; *) ALTPIDPATH="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [ ALTPIDPATH="${STATEPATH}" AC_MSG_RESULT([default]) ]) NUT_REPORT_SETTING_PATH([Unprivileged PID file path], ALTPIDPATH, "${ALTPIDPATH}", [Path for pid files of processes not running as root, such as drivers and upsd (usually STATEPATH)]) AC_MSG_CHECKING(if requested pidpath) AC_ARG_WITH(pidpath, AS_HELP_STRING([--with-pidpath=PATH], [Path for root-owned .pid files (${PIDPATH}, typically /var/run)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-pidpath - see docs/configure.txt) ;; *) PIDPATH="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) NUT_REPORT_SETTING_PATH([Privileged PID file path], PIDPATH, "${PIDPATH}", [Path for pid files of processes running as root, such as upsmon]) dnl -------------------------------------------------------------------- dnl Legacy default was /etc/killpower, but modern distros may prefer some dnl temporary filesystem (no I/O storage device impact) as long as it is dnl mounted at least read-only late in shutdown routine. The upsmon program dnl writes it as root, so this may well be in /var/run or in NUT PID/state dnl path (if that location remains mounted in run-time OS distribution). dnl Ideally the filesystems with `upsmon` program and libraries it needs dnl also remain mounted, so `upsmon -K` may be queried late in shutdown - dnl and we can avoid hardcoding such paths into those shutdown hooks. dnl Note that upsmon removes this file early in any daemonized start-up. AC_MSG_CHECKING(if requested default upsmon POWERDOWNFLAG path) AC_ARG_WITH(powerdownflag, AS_HELP_STRING([--with-powerdownflag=PATH], [default path for upsmon POWERDOWNFLAG file (${POWERDOWNFLAG}, typically /etc/killpower)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-powerdownflag - see docs/configure.txt) ;; *) POWERDOWNFLAG="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) dnl # This should be internal detail for "upsmon -K" implementation, dnl # so not necessarily reported (reduce noise): dnl NUT_REPORT_SETTING_PATH([Default upsmon POWERDOWNFLAG path], dnl POWERDOWNFLAG, "${POWERDOWNFLAG}", [Default path for upsmon POWERDOWNFLAG file]) dnl --------------------------------------------------------------------- AC_MSG_CHECKING(if requested driver path) AC_ARG_WITH(drvpath, AS_HELP_STRING([--with-drvpath=PATH], [where to install UPS drivers (EPREFIX/bin)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-drvpath - see docs/configure.txt) ;; *) driverexecdir="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) conftemp="${driverexecdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" DRVPATH="${conftemp}" NUT_REPORT_SETTING_PATH([Driver program path], DRVPATH, "${conftemp}", [Default path for UPS drivers]) AC_MSG_CHECKING(if requested cgi path) AC_ARG_WITH(cgipath, AS_HELP_STRING([--with-cgipath=PATH], [where to install CGI programs (EPREFIX/cgi-bin)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-cgipath - see docs/configure.txt) ;; *) cgiexecdir="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) conftemp="${cgiexecdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" CGIPATH="${conftemp}" NUT_REPORT_SETTING_PATH([CGI program path], CGIPATH, "${conftemp}", [Default path for CGI programs]) AC_MSG_CHECKING(if requested html path) AC_ARG_WITH(htmlpath, AS_HELP_STRING([--with-htmlpath=PATH], [where to install HTML files (PREFIX/html)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-htmlpath - see docs/configure.txt) ;; *) htmldir="${withval}" AC_MSG_RESULT([specified]) ;; esac ], [AC_MSG_RESULT([default])]) conftemp="${htmldir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" HTMLPATH="${conftemp}" NUT_REPORT_SETTING_PATH([HTML file path], HTMLPATH, "${conftemp}", [Default path for HTML files (CGI templates)]) AC_MSG_CHECKING(network port number) AC_ARG_WITH(port, AS_HELP_STRING([--with-port=PORT], [port for network communications (3493)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-port - see docs/configure.txt) ;; *) PORT="${withval}" ;; esac ], [ PORT="3493" ]) AC_DEFINE_UNQUOTED(PORT, ${PORT}, [Port for network communications]) AC_MSG_RESULT(${PORT}) AC_MSG_CHECKING(facility for syslog) AC_ARG_WITH(logfacility, AS_HELP_STRING([--with-logfacility=FACILITY], [facility for log messages (LOG_DAEMON)]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-logfacility - see docs/configure.txt) ;; *) LOGFACILITY="${withval}" ;; esac ], [ LOGFACILITY="LOG_DAEMON" ]) AC_DEFINE_UNQUOTED(LOG_FACILITY, ${LOGFACILITY}, [Desired syslog facility - see syslog(3)]) AC_MSG_RESULT(${LOGFACILITY}) AC_MSG_CHECKING(which driver man pages to install) DRIVER_MAN_LIST_PAGES="" if test "${WITH_MANS}" = "yes"; then if test "${DRIVER_BUILD_LIST}" = "all"; then DRIVER_MAN_LIST=all AC_MSG_RESULT(all available) else DRIVER_MAN_LIST="" for i in ${DRIVER_BUILD_LIST}; do dnl See if source or pre-generated (tarball) doc file exists: if test -f ${srcdir}/docs/man/$i.txt -o -f ${srcdir}/docs/man/$i.8; then DRIVER_MAN_LIST="${DRIVER_MAN_LIST} $i.8" DRIVER_MAN_LIST_PAGES="${DRIVER_MAN_LIST_PAGES} $i.txt" fi done AC_MSG_RESULT(${DRIVER_MAN_LIST}) fi else DRIVER_MAN_LIST="" AC_MSG_RESULT([none (manpages disabled)]) fi dnl By default as we iterate (and git commit) the codebase during development, dnl prerequisites for that header file change and cause much of the C code dnl to be rebuilt and re-linked. For developers fixing one small part of the dnl project after another (*and* committing fixes as they go on), the version dnl string reported by their new binaries may be of lesser consequence than dnl iterating *quickly* and rebuiding just what "really" changed! dnl Still, this speed-up is not default to avoid surprises for core team. AC_MSG_CHECKING(whether to force nut_version.h generation for every make run) dnl Value is "FORCE" or empty, substituted into Makefile.am rule: FORCE_NUT_VERSION="FORCE" AC_ARG_ENABLE(force-nut-version-header, AS_HELP_STRING([--enable-force-nut-version-header], [Force nut_version.h generation for every make run (yes)]), [ case "${enableval}" in no) AC_MSG_RESULT(no) FORCE_NUT_VERSION="" ;; *) AC_MSG_RESULT(yes) ;; esac ], [ AC_MSG_RESULT(no) ]) AC_MSG_CHECKING(whether to strip debug symbols) AC_ARG_ENABLE(strip, AS_HELP_STRING([--enable-strip], [Strip debugging symbols from binaries (no)]), [ case "${enableval}" in no) AC_MSG_RESULT(no) ;; *) AC_MSG_RESULT(yes) CFLAGS="${CFLAGS} -s" ;; esac ], [ AC_MSG_RESULT(no) ]) AC_MSG_CHECKING(whether to install pkg-config *.pc files) AC_ARG_WITH(pkgconfig-dir, AS_HELP_STRING([--with-pkgconfig-dir=PATH], [where to install pkg-config *.pc files (EPREFIX/lib/pkgconfig)]), [ case "${withval}" in yes|auto) ;; no) pkgconfigdir="" ;; *) pkgconfigdir="${withval}" ;; esac ], []) dnl Note: currently pkgconfigdir='${libdir}/pkgconfig' literally dnl goes into lib/Makefile.am substitution for pkgconfig_DATA. dnl By default we get ${libdir}/pkgconfig and below expand it to dnl => ${exec_prefix}/lib/pkgconfig => ${prefix}/lib/pkgconfig => real path conftemp="${pkgconfigdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" PKGCONFIGDIR="${conftemp}" if test -n "${pkgconfigdir}"; then AC_MSG_RESULT(using ${pkgconfigdir} => ${conftemp}) NUT_REPORT_PATH_INTEGRATIONS([pkg-config *.pc directory], [${pkgconfigdir} => ${conftemp}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_PKG_CONFIG, test -n "${pkgconfigdir}") dnl Only check the option here (and show in help near pkg-config) dnl See LDFLAGS_NUT_RPATH determination further below NUT_ARG_ENABLE([ldflags-nut-rpath], [Suggest linker flags for NUT C library consumers to set RPATH for uncommon location], [auto]) NUT_ARG_ENABLE([ldflags-nut-rpath-cxx], [Suggest linker flags for NUT C++ library consumers to set RPATH for uncommon location], [auto]) dnl Options for Solaris/illumos `make install` and `make package` AC_MSG_CHECKING(whether to make Solaris SVR4 packages) solarispkg_svr4="auto" AC_ARG_WITH([solaris-pkg-svr4], AS_HELP_STRING([--with-solaris-pkg-svr4=(yes|auto|no)], [Enable construction of Solaris SVR4 packages (auto)]), [ case "${withval}" in auto|"") solarispkg_svr4="auto" ;; yes|no) solarispkg_svr4="${withval}" ;; *) AC_MSG_ERROR([Unexpected argument for --with-solaris-pkg-svr4=${withval}]) ;; esac ], []) if test x"$solarispkg_svr4" = xauto ; then if test -x /usr/bin/pkgtrans && test -x /usr/bin/pkgmk && test -x /usr/bin/pkgproto ; then solarispkg_svr4="yes" else solarispkg_svr4="no" fi fi AC_MSG_RESULT([${solarispkg_svr4}]) AM_CONDITIONAL(WITH_SOLARIS_PKG_SVR4, test x"$solarispkg_svr4" = x"yes") AC_MSG_CHECKING(whether to make Solaris IPS packages) solarispkg_ips="auto" AC_ARG_WITH([solaris-pkg-ips], AS_HELP_STRING([--with-solaris-pkg-ips=(yes|auto|no)], [Enable construction of Solaris IPS packages (auto)]), [ case "${withval}" in auto|"") solarispkg_ips="auto" ;; yes|no) solarispkg_ips="${withval}" ;; *) AC_MSG_ERROR([Unexpected argument for --with-solaris-pkg-ips=${withval}]) ;; esac ], []) if test x"$solarispkg_ips" = xauto ; then if test -x /usr/bin/pkg && test -x /usr/bin/pkgmogrify && test -x /usr/bin/pkgdepend ; then solarispkg_ips="yes" else solarispkg_ips="no" fi fi AC_MSG_RESULT([${solarispkg_ips}]) AM_CONDITIONAL(WITH_SOLARIS_PKG_IPS, test x"$solarispkg_ips" = x"yes") dnl NOTE: Be sure to customize e.g. --datadir=/usr/share/nut to install dnl these scripts not into default location as e.g. /usr/share/solaris-smf AC_MSG_CHECKING(whether to install Solaris SMF files) solarissmf="auto" AC_ARG_WITH([solaris-smf], AS_HELP_STRING([--with-solaris-smf=(yes|auto|no)], [Enable installation of NUT scripts and manifests for Solaris Service Management Framework (auto)]), [ case "${withval}" in auto|"") solarissmf="auto" ;; yes|no) solarissmf="${withval}" ;; *) AC_MSG_ERROR([Unexpected argument for --with-solaris-smf=${withval}]) ;; esac ], []) if test x"$solarissmf" = xauto ; then if test -x /usr/sbin/svcadm && test -x /usr/sbin/svccfg && test -x /usr/bin/svcs ; then solarissmf="yes" else case "${solarispkg_ips}${solarispkg_svr4}" in *yes*) solarisinit="yes" ;; dnl Want to install so we can generally package *) solarissmf="no" ;; dnl Target not solarish esac fi fi AC_MSG_RESULT([${solarissmf}]) NUT_REPORT_FEATURE([consider basic SMF support], [${solarissmf}], [], [WITH_SOLARIS_SMF], [Define to consider basic SMF support (provide units and configuration files)]) AC_MSG_CHECKING(whether to install Solaris SVR4 (legacy) init-script files) solarisinit="auto" AC_ARG_WITH([solaris-init], AS_HELP_STRING([--with-solaris-init=(yes|auto|no)], [Enable installation of NUT legacy init-scripts for Solaris/illumos (auto)]), [ case "${withval}" in auto|"") solarisinit="auto" ;; yes|no) solarisinit="${withval}" ;; *) AC_MSG_ERROR([Unexpected argument for --with-solaris-init=${withval}]) ;; esac ], []) if test x"$solarisinit" = xauto ; then dnl Depends on usability of SMF or making for packaging case "${solarispkg_ips}${solarispkg_svr4}" in *yes*) solarisinit="yes" ;; dnl Want to install so we can generally package *) case ${target_os} in solaris*|sunos*|SunOS*|illumos*) if test "$solarissmf" = x"yes" ; then dnl no need on modern OSes solarisinit="no" else solarisinit="yes" fi ;; *) solarisinit="no" ;; dnl Some other OS esac ;; esac fi AC_MSG_RESULT([${solarisinit}]) AM_CONDITIONAL(WITH_SOLARIS_INIT, test x"$solarisinit" = x"yes") dnl Note: Currently there is no reliable automatic detection - dnl users have to ask they want systemd units installed, or dnl risk auto-detection like seen below. AC_MSG_CHECKING(whether to install systemd unit files) AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files (auto)]), [systemdsystemunitdir="${withval}"], [systemdsystemunitdir="auto"]) case "${systemdsystemunitdir}" in yes|auto|"") AS_IF([test x"$have_PKG_CONFIG" = xyes], [def_systemdsystemunitdir="`$PKG_CONFIG --variable=systemdsystemunitdir systemd 2>/dev/null`" && test -n "$def_systemdsystemunitdir" || \ def_systemdsystemunitdir="`$PKG_CONFIG --variable=systemdsystemunitdir libsystemd 2>/dev/null`" || def_systemdsystemunitdir=""], [def_systemdsystemunitdir=""]) AS_IF([test x"${def_systemdsystemunitdir}" = x], [ AS_IF([test "${systemdsystemunitdir}" = yes], [AC_MSG_ERROR([--with-systemdsystemunitdir=${systemdsystemunitdir} was requested, but PKG_CONFIG could not be queried for the system settings])]) systemdsystemunitdir="" ], [systemdsystemunitdir="${def_systemdsystemunitdir}"]) unset def_systemdsystemunitdir ;; no) systemdsystemunitdir="" ;; *) AS_IF([test -d "${systemdsystemunitdir}"], [], [AC_MSG_WARN([--with-systemdsystemunitdir='${systemdsystemunitdir}' was requested, but that location does not currently exist in build environment - just so you know...])]) ;; esac if test "${systemdsystemunitdir}" = "auto" ; then systemdsystemunitdir=""; fi if test -n "${systemdsystemunitdir}"; then have_systemd="yes" AC_MSG_RESULT(using ${systemdsystemunitdir}) NUT_REPORT_PATH_INTEGRATIONS([Service units for systemd], [${systemdsystemunitdir}]) else have_systemd="no" AC_MSG_RESULT(no) fi dnl Note: we may want tighter integration, e.g. systemd-notify support dnl configured as a further option/flag (see --with-systemd below). dnl This one is a very basic yes/no toggle for unit file delivery. NUT_REPORT_FEATURE([consider basic systemd support], [${have_systemd}], [], [HAVE_SYSTEMD], [Define to consider basic systemd support (provide units and configuration files)]) dnl This option is only provided so that make distcheck can override it, dnl otherwise we ask pkg-config whenever --with-systemdsystemunitdir is dnl given AC_PATH_PROG([SYSTEMD_SYSTEMCTL_PROGRAM], [systemctl], [/usr/bin/systemctl]) dnl Similarly for presets (list of svcs enabled/disabled by default) AC_MSG_CHECKING(whether to install systemd preset files) AC_ARG_WITH([systemdsystempresetdir], [AS_HELP_STRING([--with-systemdsystempresetdir=DIR], [Directory for systemd preset files (auto)])], [systemdsystempresetdir="${withval}"], [systemdsystempresetdir="auto"]) dnl Note: this option is enabled only if systemdsystemunitdir is not trivial if test -n "${systemdsystemunitdir}"; then case "${systemdsystempresetdir}" in yes|auto|"") AS_IF([test x"$have_PKG_CONFIG" = xyes], [def_systemdsystempresetdir="`$PKG_CONFIG --variable=systemdsystempresetdir systemd 2>/dev/null`" && test -n "$def_systemdsystempresetdir" || \ def_systemdsystempresetdir="`$PKG_CONFIG --variable=systemdsystempresetdir libsystemd 2>/dev/null`" || def_systemdsystempresetdir=""], [def_systemdsystempresetdir=""]) AS_IF([test x"${def_systemdsystempresetdir}" = x], [ AS_IF([test "${systemdsystempresetdir}" = yes], [AC_MSG_ERROR([--with-systemdsystempresetdir=${systemdsystempresetdir} was requested, but PKG_CONFIG could not be queried for the system settings])]) systemdsystempresetdir="" ], [systemdsystempresetdir="${def_systemdsystempresetdir}"]) unset def_systemdsystempresetdir ;; no) systemdsystempresetdir="" ;; *) AS_IF([test -d "${systemdsystempresetdir}"], [], [AC_MSG_WARN([--with-systemdsystempresetdir='${systemdsystempresetdir}' was requested, but that location does not currently exist in build environment - just so you know...])]) ;; esac fi if test "${systemdsystempresetdir}" = "auto" ; then systemdsystempresetdir=""; fi if test -n "${systemdsystempresetdir}"; then AC_MSG_RESULT(using ${systemdsystempresetdir}) NUT_REPORT_PATH_INTEGRATIONS([Service unit presets for systemd], [${systemdsystempresetdir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL([WITH_SYSTEMD_PRESET], [test x"${systemdsystempresetdir}" != "x"]) dnl Similarly for shutdown integration hooks AC_MSG_CHECKING(whether to install systemd shutdown files) AC_ARG_WITH([systemdshutdowndir], AS_HELP_STRING([--with-systemdshutdowndir=DIR], [Directory for systemd shutdown scripts (auto)]), [systemdshutdowndir="${withval}"], [systemdshutdowndir="auto"]) dnl Note: this option is enabled only if systemdsystemunitdir is not trivial if test -n "${systemdsystemunitdir}"; then case "${systemdshutdowndir}" in yes|auto|"") AS_IF([test x"$have_PKG_CONFIG" = xyes], [def_systemdshutdowndir="`$PKG_CONFIG --variable=systemdshutdowndir systemd 2>/dev/null`" && test -n "$def_systemdshutdowndir" || \ def_systemdshutdowndir="`$PKG_CONFIG --variable=systemdshutdowndir libsystemd 2>/dev/null`" || def_systemdshutdowndir=""], [def_systemdshutdowndir=""]) AS_IF([test x"${def_systemdshutdowndir}" = x], [ AS_IF([test "${systemdshutdowndir}" = yes], [AC_MSG_ERROR([--with-systemdshutdowndir=${systemdshutdowndir} was requested, but PKG_CONFIG could not be queried for the system settings])]) systemdshutdowndir="" ], [systemdshutdowndir="${def_systemdshutdowndir}"]) unset def_systemdshutdowndir ;; no) systemdshutdowndir="" ;; *) AS_IF([test -d "${systemdshutdowndir}"], [], [AC_MSG_WARN([--with-systemdshutdowndir='${systemdshutdowndir}' was requested, but that location does not currently exist in build environment - just so you know...])]) ;; esac fi if test "${systemdshutdowndir}" = "auto" ; then systemdshutdowndir=""; fi if test -n "${systemdshutdowndir}"; then AC_MSG_RESULT(using ${systemdshutdowndir}) NUT_REPORT_PATH_INTEGRATIONS([Shutdown hooks for systemd], [${systemdshutdowndir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL([WITH_SYSTEMD_SHUTDOWN], [test x"${systemdshutdowndir}" != "x"]) dnl Note: if (systemd-)tmpfiles tech is present, it can be useful even for dnl daemons starting not as systemd units, to pre-create /var/run/nut etc. AC_MSG_CHECKING([whether to install systemd tmpfiles files]) AC_ARG_WITH([systemdtmpfilesdir], AS_HELP_STRING([--with-systemdtmpfilesdir=DIR], [Directory for systemd tmpfiles scripts (auto)]), [systemdtmpfilesdir="${withval}"], [systemdtmpfilesdir="auto"]) case "${systemdtmpfilesdir}" in yes|auto|"") AS_IF([test x"$have_PKG_CONFIG" = xyes], [def_systemdtmpfilesdir="`$PKG_CONFIG --variable=tmpfilesdir systemd 2>/dev/null`" && test -n "$def_systemdtmpfilesdir" || \ def_systemdtmpfilesdir="`$PKG_CONFIG --variable=tmpfilesdir libsystemd 2>/dev/null`" || def_systemdtmpfilesdir=""], [def_systemdtmpfilesdir=""]) AS_IF([test x"${def_systemdtmpfilesdir}" = x], [ AS_IF([test "${systemdtmpfilesdir}" = yes], [AC_MSG_ERROR([--with-systemdtmpfilesdir=${systemdtmpfilesdir} was requested, but PKG_CONFIG could not be queried for the system settings])]) systemdtmpfilesdir="" ], [systemdtmpfilesdir="${def_systemdtmpfilesdir}"]) unset def_systemdtmpfilesdir ;; no) systemdtmpfilesdir="" ;; *) AS_IF([test -d "${systemdtmpfilesdir}"], [], [AC_MSG_WARN([--with-systemdtmpfilesdir='${systemdtmpfilesdir}' was requested, but that location does not currently exist in build environment - just so you know...])]) ;; esac if test "${systemdtmpfilesdir}" = "auto" ; then systemdtmpfilesdir=""; fi if test -n "${systemdtmpfilesdir}"; then AC_MSG_RESULT(using ${systemdtmpfilesdir}) NUT_REPORT_PATH_INTEGRATIONS([Systemd-tmpfiles configs], [${systemdtmpfilesdir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL([WITH_SYSTEMD_TMPFILES], [test x"${systemdtmpfilesdir}" != "x"]) dnl What pathname would we embed into unit files ExecStartPre? dnl TODO? Any need to make it a --with-... argument? AC_PATH_PROG([SYSTEMD_TMPFILES_PROGRAM], [systemd-tmpfiles], [/usr/bin/systemd-tmpfiles]) dnl Note: we may want binaries with sd_notify and similar features regardless dnl of building and delivering unit files (which may be crafted separately). dnl TODO: although end-user deployments (for custom builds) may be lacking dnl libsystemd development files, they might have a `systemd-notify` program dnl intended to help scripted service units. Consider making use of that then. NUT_ARG_WITH([libsystemd], [build binaries with tighter systemd integration (notifications etc)], [auto]) NUT_CHECK_LIBSYSTEMD AC_MSG_CHECKING(whether requested and can build binaries with tighter systemd integration support) AS_IF([test x"${nut_with_libsystemd}" = xyes && test x"${nut_have_libsystemd}" != xyes], [AC_MSG_ERROR([--with-libsystemd was requested, but the library was not found or usable])]) AS_CASE(["${nut_with_libsystemd}"], [yes|no], [have_libsystemd="${nut_with_libsystemd}"], [AS_IF([test x"${nut_have_libsystemd}" = xyes], [with_libsystemd="yes"], [with_libsystemd="no"]) ]) AC_MSG_RESULT(${with_libsystemd}) AC_PATH_PROG([SYSTEMD_ANALYZE_PROGRAM], [systemd-analyze], [/usr/bin/systemd-analyze]) dnl Relevant since 2023: https://github.com/systemd/systemd/pull/25916 SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY=no AS_IF([test -x "$SYSTEMD_ANALYZE_PROGRAM"], [ AC_MSG_CHECKING([if your systemd version supports Type=notify]) myFILE="`mktemp systemd-analyze-XXXXXX.service`" cat > "$myFILE" << EOF @<:@Unit@:>@ Description=temp @<:@Service@:>@ ExecStart=/bin/true Type=notify EOF if myOUT="`"$SYSTEMD_ANALYZE_PROGRAM" verify "$myFILE" 2>&1`" \ && ! (echo "$myOUT" | grep "Failed to parse service type, ignoring") \ ; then SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY=yes fi rm -f "$myFILE" AC_MSG_RESULT([${SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY}]) ]) SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD=no AS_IF([test -x "$SYSTEMD_ANALYZE_PROGRAM"], [ AC_MSG_CHECKING([if your systemd version supports Type=notify-reload]) myFILE="`mktemp systemd-analyze-XXXXXX.service`" cat > "$myFILE" << EOF @<:@Unit@:>@ Description=temp @<:@Service@:>@ ExecStart=/bin/true Type=notify-reload EOF if myOUT="`"$SYSTEMD_ANALYZE_PROGRAM" verify "$myFILE" 2>&1`" \ && ! (echo "$myOUT" | grep "Failed to parse service type, ignoring") \ ; then SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD=yes fi rm -f "$myFILE" AC_MSG_RESULT([${SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD}]) ]) AS_IF([test x"${with_libsystemd}" = xyes && test x"${SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY}" = xyes], [ dnl Built with sd_notify support dnl Note: `upsd -FF` both runs without forking and leaves a PID file, as dnl needed for `upsd -c reload` in legacy scripts and old habits to work: SYSTEMD_DAEMON_ARGS_UPSD="-FF" SYSTEMD_DAEMON_TYPE_UPSD="notify" SYSTEMD_DAEMON_ARGS_UPSLOG="-F" SYSTEMD_DAEMON_TYPE_UPSLOG="notify" SYSTEMD_DAEMON_ARGS_UPSMON="-F" SYSTEMD_DAEMON_TYPE_UPSMON="notify" SYSTEMD_DAEMON_ARGS_DRIVER="-FF" SYSTEMD_DAEMON_TYPE_DRIVER="notify" AS_IF([test x"${SYSTEMD_SUPPORTS_DAEMON_TYPE_NOTIFY_RELOAD}" = xyes], [ dnl Macro supported since aclocal-1.11: m4_ifdef([AM_COND_IF], [AM_COND_IF([HAVE_CLOCK_GETTIME], [AM_COND_IF([HAVE_CLOCK_MONOTONIC], [SYSTEMD_DAEMON_TYPE_DRIVER="notify-reload"])])], [AS_IF([test x"${ac_cv_func_clock_gettime}" = "xyes"], [SYSTEMD_DAEMON_TYPE_DRIVER="notify-reload"])]) ]) dnl Calling shell, upsdrvctl, driver, and then it forks... ugh! dnl https://github.com/systemd/systemd/issues/25961 dnl FIXME: if NotifyAccess=cgroup appears, use it (consult SYSTEMD_VERSION) SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER="NotifyAccess=all" dnl Similar for UPSMON with its two processes: SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON="NotifyAccess=all" dnl UPSD is started directly by systemd and does not fork: SYSTEMD_DAEMON_NOTIFYACCESS_UPSD="NotifyAccess=main" dnl Similarly for upslog (per settings above): SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG="NotifyAccess=main" dnl Note: at this time we do not pre-define watchdog settings, dnl to avoid breaking something by a poorly hardcoded guess. dnl This is something end-users should do for their deployment, dnl especially for drivers SYSTEMD_DAEMON_WATCHDOG_DRIVER="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSD="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSLOG="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSMON="#WatchdogSec=240s" ], [ dnl "Usual" daemons that happen to be spawned by systemd SYSTEMD_DAEMON_ARGS_UPSD="-F" SYSTEMD_DAEMON_TYPE_UPSD="simple" SYSTEMD_DAEMON_ARGS_UPSLOG="-F" SYSTEMD_DAEMON_TYPE_UPSLOG="simple" SYSTEMD_DAEMON_ARGS_UPSMON="-F" SYSTEMD_DAEMON_TYPE_UPSMON="simple" SYSTEMD_DAEMON_ARGS_DRIVER="" SYSTEMD_DAEMON_TYPE_DRIVER="forking" SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER="" SYSTEMD_DAEMON_NOTIFYACCESS_UPSD="" SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG="" SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON="" dnl Watchdog should not be configured for not-notifying units, right? SYSTEMD_DAEMON_WATCHDOG_DRIVER="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSD="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSLOG="#WatchdogSec=240s" SYSTEMD_DAEMON_WATCHDOG_UPSMON="#WatchdogSec=240s" ]) NUT_REPORT_FEATURE([build with tighter systemd support], [${with_libsystemd}], [], [WITH_LIBSYSTEMD], [Define to build with tighter systemd support (sd_notify etc)]) nut_with_libsystemd_inhibitor=0 AS_IF([test x"${with_libsystemd}" = xyes && test x"${nut_have_libsystemd_inhibitor}" = xyes], [nut_with_libsystemd_inhibitor=1]) AC_DEFINE_UNQUOTED(WITH_LIBSYSTEMD_INHIBITOR, [${nut_with_libsystemd_inhibitor}], [Define as 1 if we can use systemd inhibitor interface here]) AM_CONDITIONAL([WITH_LIBSYSTEMD_INHIBITOR], [test x"${nut_with_libsystemd_inhibitor}" = x1]) dnl dnl Tests for CppUnit availability and usability (will be built if we can, dnl and if valgrind is enabled for this configuration - reported below). dnl Using CppUnit implies C++ support! dnl Theoretically, libcppunit-dev will pull up to g++, through libstdc++... dnl AM_PATH_CPPUNIT(1.9.6) dnl # Tests with gcc-4.8 require this C++11 option to be provided explicitly dnl # gcc-4.6 does not support this yet; newer gcc's should be ok by default. dnl # Could use `AX_CXX_COMPILE_STDCXX_11([noext], [optional])` if it were dnl # available everywhere. Or AX_CHECK_COMPILE_FLAG if it was ubiquitous: dnl ###AX_CHECK_COMPILE_FLAG([-std=c++11], dnl ### [CXXFLAGS="$CXXFLAGS -std=c++11" dnl ### have_cxx11=yes], dnl ### [have_cxx11=no]) AC_MSG_CHECKING(for C++11 support in current compiler) have_cxx11=unknown my_CXXFLAGS="$CXXFLAGS" AC_LANG_PUSH([C++]) CPLUSPLUS_DECL=' #include #if __cplusplus < 201103L #error This library needs at least a C++11 compliant compiler #endif /* Make sure it supports modern syntax */ #include #include ' CPLUSPLUS_MAIN=' printf("%ld\n", __cplusplus); /* Make sure it supports modern syntax */ std::map map; map.emplace("key", "value"); ' AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[${CPLUSPLUS_DECL}]], [[${CPLUSPLUS_MAIN}]])], [AC_MSG_RESULT([yes, out of the box]) have_cxx11=yes], [AS_CASE(["${CXXFLAGS}"], [*"-std="*|*"-ansi"*], [ AC_MSG_RESULT([no, not with the standard already set in CXXFLAGS='${CXXFLAGS}']) have_cxx11=no ],[ CXXFLAGS="$CXXFLAGS -std=c++11" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[${CPLUSPLUS_DECL}]], [[${CPLUSPLUS_MAIN}]])], [AC_MSG_RESULT([yes, GCC-style (as C++11)]) have_cxx11=yes], [CXXFLAGS="$CXXFLAGS -std=c++0x" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[${CPLUSPLUS_DECL}]], [[${CPLUSPLUS_MAIN}]])], [AC_MSG_RESULT([yes, GCC-style (as C++0X)]) have_cxx11=yes], [AC_MSG_RESULT([no]) CXXFLAGS="$my_CXXFLAGS" have_cxx11=no])])])]) NUT_REPORT_FEATURE([build C++11 codebase (client library, etc.)], [${have_cxx11}], [], [HAVE_CXX11], [Define to enable C++11 support]) AC_LANG_POP([C++]) unset CPLUSPLUS_MAIN unset CPLUSPLUS_DECL AC_MSG_CHECKING(for have_cppunit) have_cppunit="no" dnl CPPUNIT_NUT_CXXFLAGS are set below if suitable, but can be dnl disabled further below if nut_with_debuginfo gets applied dnl for all NUT build products: CPPUNIT_NUT_CXXFLAGS="" AS_IF([test x"$have_PKG_CONFIG" = xyes], [AS_IF([test x"${have_cxx11}" = xyes], [ifdef([PKG_CHECK_MODULES], [PKG_CHECK_MODULES(CPPUNIT, cppunit, have_cppunit=yes, have_cppunit=no)], [have_cppunit=no]) AS_IF([test "${have_cppunit}" != "yes"], [AC_MSG_WARN([libcppunit not found - those C++ tests will not be built.]) have_cppunit=no], [AS_IF([test "x$GXX" = xyes], [CPPUNIT_NUT_CXXFLAGS="-g -O0"]) ]) ]) ], [AC_MSG_WARN([pkg-config not found, can not look properly for libcppunit - those C++ tests will not be built.]) have_cppunit=no] ) AC_MSG_RESULT(${have_cppunit}) dnl On some systems, CppUnit inexplicably fails with trivial assertions dnl so it should not be enabled with those environments, corrupting the dnl test results with misleading errors. dnl Tracked in https://github.com/networkupstools/nut/issues/1126 dnl One such situation was e.g. "clang++ + arm64(QEMU) + -m64" while dnl this was not seen with other compilers or bitness on same system. AS_IF([test "${have_cppunit}" = "yes"], [AC_MSG_CHECKING([if current toolkit can build and run cppunit tests (e.g. no ABI issues, related segfaults, etc.)]) dnl Code below is largely a stripped variant of our tests/example.cpp and cpputest.cpp CPLUSPLUS_DECL=' #include #include #include #include #include class ExampleTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ExampleTest ); CPPUNIT_TEST( testOne ); CPPUNIT_TEST_SUITE_END(); public: void setUp() {}; void tearDown() {}; void testOne(); }; CPPUNIT_TEST_SUITE_REGISTRATION( ExampleTest ); void ExampleTest::testOne() { int i = 1; float f = 1.0; int cast = static_cast(f); CPPUNIT_ASSERT_EQUAL_MESSAGE("Casted float is not the expected int (assert_eq)", i, cast ); CPPUNIT_ASSERT_MESSAGE("Casted float is not the expected int (assert)", (i == cast) ); } ' CPLUSPLUS_MAIN=' CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(), std::cerr ) ); bool res = runner.run(); return res ? 0 : 1; ' my_CXXFLAGS="$CXXFLAGS" my_LDFLAGS="$LDFLAGS" my_LIBS="$LIBS" CXXFLAGS="$myCXXFLAGS $pkg_cv_CPPUNIT_CFLAGS $pkg_cv_CPPUNIT_CXXFLAGS" LDFLAGS="$my_LDFLAGS $pkg_cv_CPPUNIT_LDFLAGS" LIBS="$my_LIBS $pkg_cv_CPPUNIT_LIBS" AC_LANG_PUSH([C++]) AX_RUN_OR_LINK_IFELSE([AC_LANG_PROGRAM([[${CPLUSPLUS_DECL}]], [[${CPLUSPLUS_MAIN}]])], [have_cppunit=yes], [have_cppunit=no]) CXXFLAGS="$my_CXXFLAGS" LDFLAGS="$my_LDFLAGS" LIBS="$my_LIBS" AC_LANG_POP([C++]) unset CPLUSPLUS_MAIN unset CPLUSPLUS_DECL AC_MSG_RESULT(${have_cppunit}) ]) dnl # By default keep the originally detected have_cppunit value AC_MSG_CHECKING(for impact from --enable-cppunit option - should we build cppunit tests?) AC_ARG_ENABLE(cppunit, [AS_HELP_STRING([--enable-cppunit], [enable CPPUNIT tests for C++ bindings (yes, no, force, auto)])], [AS_CASE(["${enableval}"], ["force"], [AS_IF([test x"${have_cppunit}" = xyes], [], [ AC_MSG_WARN([--enable-cppunit=yes can not be satisfied, but developer asked for it]) have_cppunit=yes ])], ["yes"], [AS_IF([test x"${have_cppunit}" = xyes], [], [AC_MSG_ERROR([--enable-cppunit=yes can not be satisfied])])], ["no"], [have_cppunit=no] dnl # "auto" and other values keep what was detected (or not) )]) AC_MSG_RESULT(${have_cppunit}) NUT_REPORT_FEATURE([build C++ tests with CPPUNIT], [${have_cppunit}], [], [HAVE_CPPUNIT], [Define to enable CPPUNIT tests]) dnl ---------------------------------------------------------------------- AC_MSG_CHECKING(whether we can and want to build nutconf configuration-management tool) AS_CASE(["${nut_with_nutconf}"], ["auto"], [AS_IF([test x"${have_cxx11}" = xyes], [nut_with_nutconf="yes"], [nut_with_nutconf="no"])], ["yes"], [AS_IF([test x"${have_cxx11}" = xyes], [], [AC_MSG_ERROR([explicit --with-nutconf=yes can not be satisfied: C++11 support not enabled])])], ["no"], [nut_with_nutconf=no] ) AC_MSG_RESULT(${nut_with_nutconf}) AM_CONDITIONAL(WITH_NUTCONF, test "${nut_with_nutconf}" = "yes") NUT_REPORT_PROGRAM([build and install the nutconf tool (experimental, may lack support for recent NUT options)], [${nut_with_nutconf}], [], [WITH_NUTCONF], [Define to enable nutconf tool support]) dnl ---------------------------------------------------------------------- dnl Depends on C++, potentially nutconf and dev... dnl If not enabled for delivery, the library is built as internal detail dnl of the tool (if that is enabled) AC_MSG_CHECKING([whether we can and want to deliver the libnutconf library and headers]) AS_CASE(["${nut_with_dev_libnutconf}"], ["auto"], [AS_IF([test x"${have_cxx11}" = xyes], [nut_with_dev_libnutconf="yes"], [nut_with_dev_libnutconf="no"])], ["yes"], [AS_IF([test x"${have_cxx11}" = xyes], [], [AC_MSG_ERROR([explicit --with-dev-libnutconf=yes can not be satisfied: C++11 support not enabled])])], ["no"], [nut_with_dev_libnutconf=no] ) AC_MSG_RESULT(${nut_with_dev_libnutconf}) AM_CONDITIONAL(WITH_DEV_LIBNUTCONF, test "${nut_with_dev_libnutconf}" = "yes") NUT_REPORT_PROGRAM([build and install the deliver the libnutconf library and headers (experimental)], [${nut_with_dev_libnutconf}], [], [WITH_DEV_LIBNUTCONF], [Define to enable delivery of libnutconf developer files]) AS_IF([test x"$nut_with_dev_libnutconf" = x"yes" -a x"${nut_with_dev}" != x"yes"], [ AC_MSG_WARN([You are effectively building --with-dev-libnutconf --without-dev, so would only get this library and headers but maybe not others it might need]) ]) AS_IF([test x"$nut_with_dev_libnutconf" = x"yes" -a x"${nut_with_nutconf}" != x"yes"], [ AC_MSG_NOTICE([You are effectively building --with-dev-libnutconf --without-nutconf, so would only get the library and headers but not the tool]) ]) AS_IF([test x"$nut_with_dev_libnutconf" != x"yes" -a x"${nut_with_nutconf}" = x"yes"], [ AC_MSG_NOTICE([You are effectively building --without-dev-libnutconf --with-nutconf, so would only get the tool (library and headers are just its internal detail during build)]) ]) dnl At least the lib and/or the tool delivery are enabled, generate the dnl automake rules to build the library (privately or publicly, that depends): AM_CONDITIONAL(WITH_LIBNUTCONF, [test x"${nut_with_dev_libnutconf}" = x"yes" -o x"${nut_with_nutconf}" = x"yes"]) dnl ---------------------------------------------------------------------- AC_MSG_CHECKING(whether to install Augeas configuration-management lenses) AC_ARG_WITH(augeas-lenses-dir, AS_HELP_STRING([--with-augeas-lenses-dir=PATH], [where to install Augeas configuration-management lenses (/usr/share/augeas/lenses{/dist,/})]), [ case "${withval}" in yes) if test -z "${auglensdir}"; then AC_MSG_RESULT(no) AC_MSG_ERROR([augeas lenses directory requested but not found in default location]) fi if ! test -s scripts/augeas/nutupsconf.aug.in ; then AC_MSG_RESULT(no) AC_MSG_ERROR([augeas lenses directory requested but a non-trivial scripts/augeas/nutupsconf.aug.in was not provided by autogen.sh or dist archive]) fi ;; auto) if ! test -s scripts/augeas/nutupsconf.aug.in ; then AC_MSG_WARN([augeas lenses directory skipped because a non-trivial scripts/augeas/nutupsconf.aug.in was not provided by autogen.sh or dist archive]) auglensdir="" fi ;; no) auglensdir="" ;; *) auglensdir="${withval}" ;; esac ], []) if test -n "${auglensdir}"; then AC_MSG_RESULT(using ${auglensdir}) NUT_REPORT_PATH_INTEGRATIONS([Augeas lenses directory], [${auglensdir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_AUGLENS, test -n "${auglensdir}") if test -n "${auglensdir}"; then auglenstestsdir="${auglensdir}/tests" else auglenstestsdir='' fi AC_PATH_PROGS([AUGPARSE], [augparse], [none]) AM_CONDITIONAL([HAVE_AUGPARSE], [test "x${AUGPARSE}" != "xnone"]) AC_MSG_CHECKING([whether to enable Augeas configuration-management lenses tests]) if test "x${AUGPARSE}" != xnone ; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi dnl ---------------------------------------------------------------------- AC_MSG_CHECKING(whether to install hotplug rules) AC_ARG_WITH(hotplug-dir, AS_HELP_STRING([--with-hotplug-dir=PATH], [where to install hotplug rules (${hotplugdir}); typically /etc/hotplug]), [ case "${withval}" in yes) if test -z "${hotplugdir}"; then AC_MSG_RESULT(no) AC_MSG_ERROR([hotplug directory requested but not found]) fi ;; auto) ;; no) hotplugdir="" ;; *) hotplugdir="${withval}" ;; esac ], []) if test -n "${hotplugdir}"; then AC_MSG_RESULT(using ${hotplugdir}) NUT_REPORT_PATH_INTEGRATIONS([Hotplug rules directory], [${hotplugdir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_HOTPLUG, test -n "${hotplugdir}") AC_MSG_CHECKING(whether to install udev rules) AC_ARG_WITH(udev-dir, AS_HELP_STRING([--with-udev-dir=PATH], [where to install udev rules (${udevdir}; typically /lib/udev or /etc/udev)]), [ case "${withval}" in yes) dnl Typically /lib/udev or /etc/udev if test -z "${udevdir}"; then AC_MSG_RESULT(no) AC_MSG_ERROR([udev directory requested but not found]) fi if test "${nut_with_usb}" = yes && ! test -s scripts/udev/nut-usbups.rules.in ; then AC_MSG_RESULT(no) AC_MSG_ERROR([udev directory and USB driver support requested but a non-trivial scripts/udev/nut-usbups.rules.in was not provided by autogen.sh or dist archive]) fi ;; auto) if test "${nut_with_usb}" = yes && ! test -s scripts/udev/nut-usbups.rules.in ; then AC_MSG_WARN([udev directory skipped because a non-trivial scripts/udev/nut-usbups.rules.in was not provided by autogen.sh or dist archive]) udevdir="" fi ;; no) udevdir="" ;; *) udevdir="${withval}" ;; esac ], []) if test -n "${udevdir}"; then AC_MSG_RESULT(using ${udevdir}) NUT_REPORT_PATH_INTEGRATIONS([Udev rules directory], [${udevdir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_UDEV, test -n "${udevdir}") dnl FreeBSD devd support: AC_MSG_CHECKING(whether to install FreeBSD devd.conf file) AC_ARG_WITH(devd-dir, AS_HELP_STRING([--with-devd-dir=PATH], [where to install devd.conf file (${devddir}; typically /usr/local/etc/devd or /etc/devd)]), [ case "${withval}" in yes) dnl Typically /usr/local/etc/devd or /etc/devd if test -z "${devddir}"; then AC_MSG_RESULT(no) AC_MSG_ERROR([devd directory requested but not found]) fi if test "${nut_with_usb}" = yes && ! test -s scripts/devd/nut-usbups.rules.in -a -s scripts/devd/nut-usb.conf.in ; then AC_MSG_RESULT(no) AC_MSG_ERROR([devd directory and USB driver support requested but non-trivial scripts/devd/nut-usbups.rules.in and scripts/devd/nut-usb.conf.in were not provided by autogen.sh or dist archive]) fi ;; auto) if test "${nut_with_usb}" = yes && ! test -s scripts/devd/nut-usbups.rules.in -a -s scripts/devd/nut-usb.conf.in ; then AC_MSG_WARN([devd directory skipped because non-trivial scripts/devd/nut-usbups.rules.in and scripts/devd/nut-usb.conf.in were not provided by autogen.sh or dist archive]) devddir="" fi ;; no) devddir="" ;; *) devddir="${withval}" ;; esac ], []) if test -n "${devddir}"; then AC_MSG_RESULT(using ${devddir}) NUT_REPORT_PATH_INTEGRATIONS([FreeBSD devd rules directory], [${devddir}]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_DEVD, test -n "${devddir}") dnl FreeBSD quirks support: freebsdquirksdir="" AC_MSG_CHECKING(whether to install FreeBSD site-local USB quirks file) AC_ARG_WITH(freebsd-quirks-dir, AS_HELP_STRING([--with-freebsd-quirks-dir=PATH], [where to install nut-usb.quirks file (${datadir}; typically /usr/local/share/nut)]), [ case "${withval}" in yes) dnl Typically /usr/local/share/nut freebsdquirksdir="${datadir}" ;; auto) dnl Are we building for FreeBSD with such customizations? if test -s /boot/loader.conf.local ; then freebsdquirksdir="${datadir}" fi if test "${nut_with_usb}" = yes && ! test -s scripts/devd/nut-usb.quirks ; then AC_MSG_WARN([freebsd-quirks-dir directory skipped because a non-trivial scripts/devd/nut-usb.quirks was not provided by autogen.sh or dist archive]) freebsdquirksdir="" fi ;; no) freebsdquirksdir="" ;; *) freebsdquirksdir="${withval}" ;; esac ], []) if test -n "${freebsdquirksdir}"; then AC_MSG_RESULT(using ${freebsdquirksdir}) NUT_REPORT_PATH_INTEGRATIONS([FreeBSD site-local USB quirks directory (add into /boot/loader.conf.local)], [${freebsdquirksdir}]) else AC_MSG_RESULT(no) fi if test -n "${freebsdquirksdir}" ; then dnl Expand datadir or similar macros in this path conftemp="${freebsdquirksdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" freebsdquirksdir="${conftemp}" if test -z "${freebsdquirksdir}"; then AC_MSG_ERROR([freebsd-quirks-dir requested but not found (resolved as empty)]) fi if test "${nut_with_usb}" = yes && ! test -s scripts/devd/nut-usb.quirks ; then AC_MSG_ERROR([freebsd-quirks-dir directory and USB driver support requested, but a non-trivial scripts/devd/nut-usb.quirks was not provided by autogen.sh or dist archive]) fi fi AM_CONDITIONAL(WITH_FREEBSD_QUIRKS_DIR, test -n "${freebsdquirksdir}") dnl dnl AIX system AM_CONDITIONAL([SYSTEM_AIX], [test "xAIX" = "x`uname -s 2>/dev/null`"]) dnl processor type AC_DEFINE_UNQUOTED(CPU_TYPE, ["$target_cpu"], [Define processor type]) dnl Can use valgrind for memory-leak testing, if present dnl FIXME: Set to "auto" after ensuring that we pass on all NUT CI farm platforms with_valgrind="no" AC_PATH_PROGS([VALGRIND], [valgrind], [none]) dnl Caller can provide a specific valgrind implementation to use: AC_ARG_WITH(valgrind, AS_HELP_STRING([--with-valgrind=(yes|no|auto|PATH)], [whether to use valgrind for memory-leak testing (no)]), [ dnl ### echo "Caller said: '${withval}'... Discovered tool: '${VALGRIND}'... " case "${withval}" in yes) if test "x$VALGRIND" = "xnone"; then AC_MSG_RESULT(no) AC_MSG_ERROR([valgrind requested but not found]) fi with_valgrind="yes" ;; auto) with_valgrind="auto" ;; no) with_valgrind="no" ;; *) AC_PATH_PROGS([VALGRIND], ["${withval}"], [none]) if test "x$VALGRIND" = "xnone"; then AC_MSG_RESULT(no) AC_MSG_ERROR([valgrind requested but not found]) fi with_valgrind="yes" ;; esac ], []) dnl Even if the tool is installed, it may be not usable on build platform. dnl QEMU may further complicate things, providing CPUs that formally match dnl a supported family but crash in practice, or hopefully rejected early: dnl valgrind: fatal error: unsupported CPU. dnl Supported CPUs are: dnl * x86 (practically any; Pentium-I or above), AMD Athlon or above) dnl * AMD Athlon64/Opteron dnl * ARM (armv7) dnl * MIPS (mips32 and above; mips64 and above) dnl * PowerPC (most; ppc405 and above) dnl * System z (64bit only - s390x; z990 and above) dnl Even if the tool does basically start, on some QEMU systems it crashes dnl later (e.g. claims Signal 11 in tear-down after a successful test), so dnl we support an explicit --without-valgrind (aka --with-valgrind=no) too. dnl In some versions of OpenIndiana it was also seen to fail with SIGILL dnl when running `valgrind /bin/sh ` and even `valgrind /bin/true` dnl but succeeded for other programs; and those failures left a log of core dnl dump files on the CI build agent: dnl vex x86->IR: unhandled instruction bytes: 0x2E 0x8D 0x74 0x26 dnl ==360612== valgrind: Unrecognised instruction at address 0x3ffe291b. dnl ==360612== at 0x3FFE291B: strchr (in /lib/ld.so.1) dnl ==360612== by 0x3FFCEB5B: procenv_user (in /lib/ld.so.1) dnl ==360612== by 0x3FFCB34A: setup (in /lib/ld.so.1) dnl ==360612== by 0x3FFDBC49: _setup (in /lib/ld.so.1) dnl ==360612== by 0x3FFC0D94: _rt_boot (in /lib/ld.so.1) dnl ==360612== by 0x37FEFE46: ??? AS_IF([test -n "${VALGRIND}" && test x"${VALGRIND}" != xnone && test "x${with_valgrind}" != xno], [ AC_MSG_CHECKING([whether valgrind is usable on current platform]) AS_IF([( ${VALGRIND} --help >/dev/null 2>/dev/null )], [ TESTCMD="/bin/sh -c true" echo 'int main(void) { return 0; }' > test-true.c && \ ${CC} ${CFLAGS} test-true.c -o test-true && \ ./test-true && \ TESTCMD="./test-true" AS_IF([( ${VALGRIND} $TESTCMD >/dev/null 2>/dev/null )], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) VALGRIND="none" ]) rm -f ./test-true ./test-true.c unset TESTCMD ], [AC_MSG_RESULT([no]) VALGRIND="none" ]) AS_IF([test "x$VALGRIND" = "xnone" && test "x${with_valgrind}" = "xyes"], [ AC_MSG_ERROR([valgrind requested but '${VALGRIND}' is not usable]) ]) ]) if test "x${with_valgrind}" = "xauto"; then if test "x$VALGRIND" = "xnone"; then with_valgrind="no" else with_valgrind="yes" fi fi AC_MSG_CHECKING(whether to use valgrind for memory-leak testing) if test "x${with_valgrind}" = "xyes"; then AC_MSG_RESULT(using ${VALGRIND}) AC_MSG_NOTICE([Do not forget to build with debug (e.g. pass '-g' in CFLAGS for GCC) for best results with valgrind tests]) else AC_MSG_RESULT(no) fi AM_CONDITIONAL([HAVE_VALGRIND], [test "x${VALGRIND}" != "xnone"]) AM_CONDITIONAL([WITH_VALGRIND], [test "x${with_valgrind}" = "xyes"]) AC_MSG_CHECKING([whether to build cppunit tests using valgrind support]) if test "x${with_valgrind}" = xyes && test "x${have_cppunit}" = xyes ; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi dnl expand ${sysconfdir} and write it out - note that most packages dnl override it to be /etc/nut, /etc/ups or similar, while the dnl autotools default would be $prefix/etc conftemp="${sysconfdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" CONFPATH="${conftemp}" NUT_REPORT_SETTING_PATH([Config file path], CONFPATH, "${conftemp}", [Default path for configuration files]) dnl same for datadir conftemp="${datadir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" NUT_DATADIR="${conftemp}" NUT_REPORT_SETTING_PATH([Data file path], NUT_DATADIR, "${conftemp}", [Default path for data files]) dnl same for mandir conftemp="${mandir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" NUT_MANDIR="${conftemp}" NUT_REPORT_SETTING_PATH([Man page path], NUT_MANDIR, "${conftemp}", [Default path for man page files]) dnl same for bindir conftemp="${bindir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" BINDIR="${conftemp}" NUT_REPORT_SETTING_PATH([Tool program path], BINDIR, "${conftemp}", [Default path for user executables]) dnl same for sbindir conftemp="${sbindir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" SBINDIR="${conftemp}" NUT_REPORT_SETTING_PATH([System program path], SBINDIR, "${conftemp}", [Default path for system executables]) dnl same for libdir conftemp="${libdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" LIBDIR="${conftemp}" NUT_REPORT_SETTING_PATH([System library path], LIBDIR, "${conftemp}", [Default path for system libraries]) dnl same for libexecdir conftemp="${libexecdir}" eval conftemp=\"${conftemp}\" eval conftemp=\"${conftemp}\" LIBEXECDIR="${conftemp}" NUT_REPORT_SETTING_PATH([System exec-library path], LIBEXECDIR, "${conftemp}", [Default path for system exec-libraries]) dnl ---------------------------------------------------------------------- dnl Check if NUT recipe metadata should propagate an uncommon RPATH AC_MSG_CHECKING([whether NUT libdir='${LIBDIR}' is among common search paths]) DEFAULT_SEARCH_DIRS="`LANG=C LC_ALL=C ${CC} --print-search-dirs 2>/dev/null | grep libraries: | sed 's,^@<:@^=@:>@*=,,'`" 2>/dev/null || DEFAULT_SEARCH_DIRS="" NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS="" NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS_TEXT="" if test x"${DEFAULT_SEARCH_DIRS}" = x ; then NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS="got empty list" NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS_TEXT="could not detect default library search paths" else AS_CASE(["${target_os}"], [*mingw*], [ dnl # At least tooling on MSYS2 semi-native builds can return dnl # semicolon-separated paths with possibly "C:/mingw..." spelling DEFAULT_SEARCH_DIRS="`echo ":$DEFAULT_SEARCH_DIRS" | sed 's,\(@<:@:;@:>@\)\(@<:@A-Z@:>@\):/,:/\2/,g' | tr ':' '\n' | sed 's,/*$,,'`" ], [DEFAULT_SEARCH_DIRS="`echo "$DEFAULT_SEARCH_DIRS" | tr ':' '\n' | sed 's,/*$,,'`"] ) NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS="no" NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS_TEXT="NUT libdir is not among common search paths" dnl # FIXME: ARCH subdirs on some platforms dnl # If NUT libdir does not exist, it is not systemic right away if test -d "${LIBDIR}" ; then LIBDIR_REALPATH="`cd "${LIBDIR}" && pwd`" || LIBDIR_REALPATH="${LIBDIR}" LIBDIR_REALPATH="`echo "${LIBDIR_REALPATH}" | sed 's,/*$,,'`" for D in ${DEFAULT_SEARCH_DIRS} ; do if test x"$D" = x"${LIBDIR_REALPATH}" ; then NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS="yes" NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS_TEXT="NUT libdir is among common search paths" break else D_REALPATH="`cd "${D}" 2>/dev/null && pwd`" && \ if test x"${D_REALPATH}" = x"${LIBDIR_REALPATH}" ; then NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS="yes" NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS_TEXT="NUT libdir is among common search paths" break fi fi done fi fi AC_MSG_RESULT([${NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS}]) AS_IF([test x"${nut_enable_configure_debug}" = xyes && test x"${DEFAULT_SEARCH_DIRS}" != x], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) Checked paths: ${DEFAULT_SEARCH_DIRS}]) ]) dnl Check if we want to expose non-standard RPATH to third-party consumers dnl of libupsclient etc. Keep verbatim dollar-var here, expand in pkg-config! dnl NOTE: hardcode_libdir_flag_spec(_CXX) vars come from LT INIT above dnl For "auto", we check for non-std path and set "no" if prefix/libdir *is* common LDFLAGS_NUT_RPATH='' LDFLAGS_NUT_RPATH_CXX='' AC_MSG_CHECKING([whether to suggest a LDFLAGS_NUT_RPATH in pkg-config et al, and which]) RPATH_CIRCUMSTANCE='' case "${nut_enable_ldflags_nut_rpath}" in no) ;; auto|yes|"") dnl FIXME: perhaps prefer the new-ELF tricks for "runpath" dnl (so LD_LIBRARY_PATH can override the built-in suggestion) if test "${nut_enable_ldflags_nut_rpath}" = auto ; then RPATH_CIRCUMSTANCE="${NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS_TEXT}" case "${NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS}" in "got empty list"|no) ;; dnl # keep "auto" yes) nut_enable_ldflags_nut_rpath=no ;; esac fi if test "${nut_enable_ldflags_nut_rpath}" != no ; then if test x"${hardcode_libdir_flag_spec}" != x ; then LDFLAGS_NUT_RPATH="`libdir='${libdir}'; eval echo "${hardcode_libdir_flag_spec}"`" else RPATH_CIRCUMSTANCE="autotools did not report a way to specify rpath for C" dnl # LDFLAGS_NUT_RPATH='-R${libdir} -Wl,-rpath,${libdir}' fi fi ;; *) LDFLAGS_NUT_RPATH="${nut_enable_ldflags_nut_rpath}" ;; esac AS_IF([test x"${LDFLAGS_NUT_RPATH}" = x], [AC_MSG_RESULT([none]) AS_IF([test x"${RPATH_CIRCUMSTANCE}" != x], [ AC_MSG_NOTICE([Reason: ${RPATH_CIRCUMSTANCE}])]) ], [AC_MSG_RESULT([yes: ${LDFLAGS_NUT_RPATH}]) AS_IF([test x"${RPATH_CIRCUMSTANCE}" != x], [ AC_MSG_NOTICE([Warning: ${RPATH_CIRCUMSTANCE}])]) ] ) AC_MSG_CHECKING([whether to suggest a LDFLAGS_NUT_RPATH_CXX in pkg-config et al, and which]) RPATH_CIRCUMSTANCE='' case "${nut_enable_ldflags_nut_rpath_cxx}" in no) ;; auto|yes|"") dnl FIXME: perhaps prefer the new-ELF tricks for "runpath" dnl (so LD_LIBRARY_PATH can override the built-in suggestion) if test "${nut_enable_ldflags_nut_rpath_cxx}" = auto ; then RPATH_CIRCUMSTANCE="${NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS_TEXT}" case "${NUT_LIBDIR_IN_DEFAULT_SEARCH_DIRS}" in "got empty list"|no) ;; dnl # keep "auto" yes) nut_enable_ldflags_nut_rpath_cxx=no ;; esac fi if test "${nut_enable_ldflags_nut_rpath_cxx}" != no ; then if test x"${hardcode_libdir_flag_spec_CXX}" != x ; then LDFLAGS_NUT_RPATH_CXX="`libdir='${libdir}'; eval echo "${hardcode_libdir_flag_spec_CXX}"`" else RPATH_CIRCUMSTANCE="autotools did not report a way to specify rpath for C++" dnl # LDFLAGS_NUT_RPATH_CXX='-R${libdir} -Wl,-rpath,${libdir}' fi fi ;; *) LDFLAGS_NUT_RPATH_CXX="${nut_enable_ldflags_nut_rpath_cxx}" ;; esac AS_IF([test x"${LDFLAGS_NUT_RPATH_CXX}" = x], [AC_MSG_RESULT([none]) AS_IF([test x"${RPATH_CIRCUMSTANCE}" != x], [ AC_MSG_NOTICE([Reason: ${RPATH_CIRCUMSTANCE}])]) ], [AC_MSG_RESULT([yes: ${LDFLAGS_NUT_RPATH_CXX}]) AS_IF([test x"${RPATH_CIRCUMSTANCE}" != x], [ AC_MSG_NOTICE([Warning: ${RPATH_CIRCUMSTANCE}])]) ] ) dnl ---------------------------------------------------------------------- dnl checks related to --with-snmp enabled on command-line dnl ${nut_with_snmp}: any value except "yes" or "no" is treated as "auto". if test "${nut_with_snmp}" = "yes" -a "${nut_have_libnetsnmp}" != "yes"; then AC_MSG_ERROR([Net-SNMP libraries not found, required for SNMP drivers]) fi if test "${nut_with_snmp}" != "no"; then nut_with_snmp="${nut_have_libnetsnmp}" else nut_have_libnetsnmp_static="no" fi NUT_REPORT_DRIVER([build SNMP drivers], [${nut_with_snmp}], [], [WITH_SNMP], [Define to enable SNMP support]) NUT_REPORT_DRIVER([build SNMP drivers with statically linked lib(net)snmp], [${nut_have_libnetsnmp_static}], [], [WITH_SNMP_STATIC], [Define to use SNMP support with a statically linked libnetsnmp]) if test -n "${host_alias}" ; then NUT_REPORT_TARGET(AUTOTOOLS_HOST_ALIAS, "${host_alias}", [host env spec we run on]) else if test -n "${host}" ; then NUT_REPORT_TARGET(AUTOTOOLS_HOST_ALIAS, "${host}", [host env spec we run on]) fi fi if test -n "${build_alias}" ; then NUT_REPORT_TARGET(AUTOTOOLS_BUILD_ALIAS, "${build_alias}", [host env spec we built on]) else if test -n "${build}" ; then NUT_REPORT_TARGET(AUTOTOOLS_BUILD_ALIAS, "${build}", [host env spec we built on]) fi fi if test -n "${target_alias}" ; then NUT_REPORT_TARGET(AUTOTOOLS_TARGET_ALIAS, "${target_alias}", [host env spec we built for]) else if test -n "${target}" ; then NUT_REPORT_TARGET(AUTOTOOLS_TARGET_ALIAS, "${target}", [host env spec we built for]) fi fi if test -n "${host_cpu}" -a -n "${host_os}" ; then NUT_REPORT_TARGET(AUTOTOOLS_HOST_SHORT_ALIAS, "${host_cpu}-${host_os}", [host OS short spec we run on]) fi if test -n "${build_cpu}" -a -n "${build_os}" ; then NUT_REPORT_TARGET(AUTOTOOLS_BUILD_SHORT_ALIAS, "${build_cpu}-${build_os}", [host OS short spec we built on]) fi if test -n "${target_cpu}" -a -n "${target_os}" ; then NUT_REPORT_TARGET(AUTOTOOLS_TARGET_SHORT_ALIAS, "${target_cpu}-${target_os}", [host OS short spec we built for]) fi AC_MSG_CHECKING([whether compiler suggests a MULTIARCH value]) dnl Recent GCC generally supports this call, although it often returns empty dnl Some versions of CLANG also have it, others reject the unknown CLI switch compiler_multiarch="`${CC} -print-multiarch 2>/dev/null`" || compiler_multiarch="" if test -n "${compiler_multiarch}" ; then NUT_REPORT_TARGET(MULTIARCH_TARGET_ALIAS, "${compiler_multiarch}", [host multiarch spec we build for (as suggested by compiler being used)]) fi dnl ---------------------------------------------------------------------- dnl Check the user and group to run as last, so we can use the paths configured dnl above as data sources for default values if building an in-place replacement AC_MSG_CHECKING(if requested user to run as) AC_ARG_WITH(user, AS_HELP_STRING([--with-user=username], [user for programs started as root (${RUN_AS_USER})]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-user - see docs/configure.txt) ;; *) RUN_AS_USER="${withval}" nut_user_given=yes AC_MSG_RESULT([specified]) ;; esac ], [ nut_user_given=no AC_MSG_RESULT([default]) ]) NUT_REPORT_SETTING([User to run as], RUN_AS_USER, "${RUN_AS_USER}", [User to switch to if started as root]) AC_MSG_CHECKING(if requested group membership of user to run as) AC_ARG_WITH(group, AS_HELP_STRING([--with-group=groupname], [group membership of user for programs started as root (${RUN_AS_GROUP})]), [ case "${withval}" in yes|no) AC_MSG_ERROR(invalid option --with(out)-group - see docs/configure.txt) ;; *) RUN_AS_GROUP="${withval}" nut_group_given=yes AC_MSG_RESULT([specified]) ;; esac ], [ nut_group_given=no AC_MSG_RESULT([default]) ]) NUT_REPORT_SETTING([Group of user to run as], RUN_AS_GROUP, "${RUN_AS_GROUP}", [Group membership of user to switch to if started as root]) dnl check that --with-user is given if --with-group is given. if test "${nut_user_given}" = "yes" -a "${nut_group_given}" = "no"; then AC_MSG_ERROR([If you specify --with-user, you also must specify --with-group]) elif test "${nut_user_given}" = "no" -a "${nut_group_given}" = "yes"; then AC_MSG_ERROR([If you specify --with-group, you also must specify --with-user]) fi dnl ---------------------------------------------------------------------- dnl Current date now=`TZ=UTC date +%Y-%m-%d` AC_SUBST(now) AC_SUBST(OS_NAME) AC_SUBST(TREE_VERSION) AC_SUBST(NUT_NETVERSION) AC_SUBST(FORCE_NUT_VERSION) AC_SUBST(NUT_SOURCE_GITREV) AC_SUBST(NUT_SOURCE_GITREV_IS_RELEASE) AC_SUBST(NUT_SOURCE_GITREV_IS_PRERELEASE) AC_SUBST(NUT_SOURCE_GITREV_SEMVER) AC_SUBST(NUT_SOURCE_GITREV_NUMERIC) AC_SUBST(NUT_WEBSITE_BASE) AC_SUBST(LIBSSL_CFLAGS) AC_SUBST(LIBSSL_LIBS) AC_SUBST(LIBSSL_LDFLAGS_RPATH) AC_SUBST(LIBSSL_REQUIRES) AC_SUBST(LIBGD_CFLAGS) AC_SUBST(LIBGD_LDFLAGS) AC_SUBST(LIBNETSNMP_CFLAGS) AC_SUBST(LIBNETSNMP_LIBS) AC_SUBST(LIBREGEX_LIBS) AC_SUBST(LIBUSB_CFLAGS) AC_SUBST(LIBUSB_LIBS) AC_SUBST(LIBNEON_CFLAGS) AC_SUBST(LIBNEON_LIBS) AC_SUBST(LIBAVAHI_CFLAGS) AC_SUBST(LIBAVAHI_LIBS) AC_SUBST(LIBPOWERMAN_CFLAGS) AC_SUBST(LIBPOWERMAN_LIBS) AC_SUBST(LIBMODBUS_CFLAGS) AC_SUBST(LIBMODBUS_LIBS) AC_SUBST(LIBIPMI_CFLAGS) AC_SUBST(LIBIPMI_LIBS) AC_SUBST(LIBGPIO_CFLAGS) AC_SUBST(LIBGPIO_LIBS) AC_SUBST(LIBI2C_LIBS) AC_SUBST(DOC_BUILD_LIST) AC_SUBST(DOC_CHECK_LIST) AC_SUBST(LIBWRAP_CFLAGS) AC_SUBST(LIBWRAP_LIBS) AC_SUBST(LIBLTDL_CFLAGS) AC_SUBST(LIBLTDL_LIBS) AC_SUBST(LIBSYSTEMD_CFLAGS) AC_SUBST(LIBSYSTEMD_LIBS) AC_SUBST(SYSTEMD_DAEMON_ARGS_UPSD) AC_SUBST(SYSTEMD_DAEMON_TYPE_UPSD) AC_SUBST(SYSTEMD_DAEMON_ARGS_UPSLOG) AC_SUBST(SYSTEMD_DAEMON_TYPE_UPSLOG) AC_SUBST(SYSTEMD_DAEMON_ARGS_UPSMON) AC_SUBST(SYSTEMD_DAEMON_TYPE_UPSMON) AC_SUBST(SYSTEMD_DAEMON_ARGS_DRIVER) AC_SUBST(SYSTEMD_DAEMON_TYPE_DRIVER) AC_SUBST(SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER) AC_SUBST(SYSTEMD_DAEMON_NOTIFYACCESS_UPSD) AC_SUBST(SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG) AC_SUBST(SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON) AC_SUBST(SYSTEMD_DAEMON_WATCHDOG_UPSD) AC_SUBST(SYSTEMD_DAEMON_WATCHDOG_UPSLOG) AC_SUBST(SYSTEMD_DAEMON_WATCHDOG_UPSMON) AC_SUBST(SYSTEMD_DAEMON_WATCHDOG_DRIVER) AC_SUBST(SYSTEMD_TMPFILES_PROGRAM) AC_SUBST(DRIVER_BUILD_LIST) AC_SUBST(DRIVER_MAN_LIST) AC_SUBST(DRIVER_MAN_LIST_PAGES) AC_SUBST(DRIVER_INSTALL_TARGET) AC_SUBST(BSDKVMPROCLIBS) AC_SUBST(NETLIBS) AC_SUBST(SERLIBS) AC_SUBST(SEMLIBS) AC_SUBST(PREFIX) AC_SUBST(PIDPATH) AC_SUBST(STATEPATH) AC_SUBST(ALTPIDPATH) dnl #Not in main codebase yet# AC_SUBST(ALTSTATEPATH) AC_SUBST(CONFPATH) AC_SUBST(POWERDOWNFLAG) AC_SUBST(BINDIR) AC_SUBST(LIBDIR) AC_SUBST(PKGCONFIGDIR) AC_SUBST(NUT_DATADIR, [`eval echo "${NUT_DATADIR}"`]) AC_SUBST(NUT_MANDIR, [`eval echo "${NUT_MANDIR}"`]) AC_SUBST(NUT_LIBEXECDIR, [`eval echo "${LIBEXECDIR}"`]) AC_SUBST(LDFLAGS_NUT_RPATH) AC_SUBST(LDFLAGS_NUT_RPATH_CXX) AC_SUBST(DRVPATH) AC_SUBST(SBINDIR) AC_SUBST(PORT) AC_SUBST(RUN_AS_USER) AC_SUBST(RUN_AS_GROUP) AC_SUBST(SUN_LIBUSB) AC_SUBST(WORDS_BIGENDIAN) AC_SUBST(cgiexecdir) AC_SUBST(devddir) AC_SUBST(driverexecdir) AC_SUBST(freebsdquirksdir) AC_SUBST(htmldir) AC_SUBST(htmldocdir) AC_SUBST(htmlmandir) AC_SUBST(pkgconfigdir) AC_SUBST(systemdsystemunitdir) AC_SUBST(systemdsystempresetdir) AC_SUBST(systemdshutdowndir) AC_SUBST(systemdtmpfilesdir) AC_SUBST(auglensdir) AC_SUBST(auglenstestsdir) AC_SUBST(hotplugdir) AC_SUBST(udevdir) dnl On a related note to warning setup below, we limit the minimum C and C++ dnl standard versions to ones we actively strive to support (C99 and C++11, dnl GNU dialects tend to work on more systems if supported by compiler there). dnl It is assumed that on very old systems whose compilers do not know these dnl standards (only support ANSI/C89/C90 or older), as well as for builds dnl that explicitly specify a CFLAGS="-std=..." (for GCC/CLANG toolkits), dnl nothing should get added to CFLAGS/CXXFLAGS by this method: NUT_COMPILER_FAMILY_FLAGS_DEFAULT_STANDARD dnl Filter through known variants first, so automatic choices can be made. dnl Note that clang identifies as gcc-compatible so should be probed first. dnl TODO: Flip this default to "hard" when we clear existing codebase. dnl Note: the "gcc-legacy" option is intentionally undocumented, it acts as dnl least-surprise default if caller did not specify any --enable-warnings. dnl Note: Currently the "gcc-minimal" mode below adapts to builds with dnl C89/C90/ANSI mode to be less noisy. Keep this in mind if changing the dnl default "nut_warning_difficulty" and/or the case handling below. dnl NOTE: Until X-Mas 2021, the default was "minimal" (now "medium") nut_warning_difficulty="medium" AC_MSG_CHECKING([whether to pre-set warnings (from '${nut_enable_warnings}')]) AS_CASE(["${nut_enable_warnings}"], [no|all|gcc-legacy|gcc-minimal|clang-minimal|gcc-medium|clang-medium|gcc-hard|clang-hard], [], [clang], [nut_enable_warnings="${nut_enable_warnings}-${nut_warning_difficulty}"], [gcc], [ AS_CASE(["${CFLAGS}"], [*89*|*90*|*ansi*], [nut_enable_warnings="${nut_enable_warnings}-minimal"], [nut_enable_warnings="${nut_enable_warnings}-${nut_warning_difficulty}"] )], [yes|auto|""], [ AS_IF([test "${CLANGCC}" = "yes"], [nut_enable_warnings="clang-${nut_warning_difficulty}"], [AS_IF([test "${GCC}" = "yes"], [ AS_CASE(["${CFLAGS}"], [*89*|*90*|*ansi*], [nut_enable_warnings="gcc-minimal"], [AS_CASE(["$CC_VERSION"], [*" "1.*|*" "2.*|3.*|*" "4.0*|*" "4.1*|*" "4.2*|*" "4.3*], [ AC_MSG_WARN([Very old GCC in use, disabling warnings]) dnl #AS_IF([test x"${nut_enable_Werror}" = xauto], [nut_enable_Werror="no"]) nut_enable_Werror="no" nut_enable_warnings="no"], [*" "4.4*|*" "4.5*|*" "4.6*|*" "4.7*|*" "4.8*], [nut_enable_warnings="gcc-legacy"], [nut_enable_warnings="gcc-${nut_warning_difficulty}"] )] )], [nut_enable_warnings="all"]) ]) ], [hard|auto-hard|auto=hard], [ AS_IF([test "${CLANGCC}" = "yes"], [nut_enable_warnings="clang-hard"], [AS_IF([test "${GCC}" = "yes"], [nut_enable_warnings="gcc-hard"], [nut_enable_warnings="all"]) ]) ], [medium|auto-medium|auto=medium], [ AS_IF([test "${CLANGCC}" = "yes"], [nut_enable_warnings="clang-medium"], [AS_IF([test "${GCC}" = "yes"], [nut_enable_warnings="gcc-medium"], [nut_enable_warnings="all"]) ]) ], [minimal|auto-minimal|auto=minimal], [ AS_IF([test "${CLANGCC}" = "yes"], [nut_enable_warnings="clang-minimal"], [AS_IF([test "${GCC}" = "yes"], [nut_enable_warnings="gcc-minimal"], [nut_enable_warnings="all"]) ]) ], [legacy], [AS_IF([test "${GCC}" = "yes"], [nut_enable_warnings="gcc-legacy"], [nut_enable_warnings="no"])], [AC_MSG_WARN([Unsupported variant for --enable-warnings=${nut_enable_warnings}, ignored]) nut_enable_warnings="no" ] ) AC_MSG_RESULT([${nut_enable_warnings}]) dnl # Nothing special for gcc - we tend to survive it with GNU standard >= 99 dnl # and fail with strict C standard. Suggestions welcome for "gcc-hard" to dnl # make a difference. dnl # Note that "medium" and "hard" settings tend to trigger warnings also dnl # from system headers, so we try to avoid them, using "-isystem path" dnl # pre-set in our `m4/nut_compiler_family.m4` script: dnl # https://stackoverflow.com/questions/36355232/disable-certain-warnings-for-system-headers dnl # and "-Wno-system-headers" below. dnl # Some of the compiler flags (including those added by pkg-config of some dnl # third-party dependency packages) can upset older compiler releases which dnl # did not yet support those. Flags like "-Wno-unknown-warning" for GCC or dnl # "-Wno-unknown-warning-option" for CLANG should take care of that at least dnl # for toolkit versions that support these - set in NUT_COMPILER_FAMILY_FLAGS dnl # Majority of sanity checks are enabled by "-Wextra" on both GCC and CLANG dnl # and "-Weverything" additionally on CLANG. They are impractically picky, dnl # especially with fallout from system headers that we can not impact anyway dnl # so the "difficulty level" pre-sets exclude certain warning classes from dnl # that report. dnl ### Special exclusion picks for clang-hard: dnl # -Wno-unused-macros -- system headers define a lot of stuff we do not use, dnl # gotta be fatal right? dnl # -Wno-reserved-id-macro -- configure script tends to define _GNU_SOURCE_, dnl # __EXTENSIONS__ etc. which are underscored and reserved for compilers dnl # -Wno-padded -- NSPR and NSS headers get to issue lots of that dnl # -Wno-c++98-compat-pedantic -Wno-c++98-compat -- our C++ code uses nullptr dnl # as requested by newer linters, and C++98 does not. We require C++11 dnl # or newer anyway, and skip building C++ library and test otherwise. dnl # -Wno-exit-time-destructors -- "(static) const something" items would be dnl # de-allocated en-masse when the program exits, not GC'ed at run-time. dnl # Oh well... dnl # -Wno-fuse-ld-path -- not much in our control what recipes the autotools dnl # on the build host generate... this tries to avoid failures due to: dnl # clang-13: error: '-fuse-ld=' taking a path is deprecated. dnl # Use '--ld-path=' instead [-Werror,-Wfuse-ld-path] dnl # -Wno-unsafe-buffer-usage -- clang-16 introduced a check too smart for dnl # its own good. It detects use of pointer aritmetics as arrays are dnl # walked, which is indeed potentially dangerous. And also is nearly dnl # unavoidable in C (at least not without major rewrites of the world). dnl # -Wno-documentation-unknown-command -fcomment-block-commands=retval -- dnl # some clang versions sanity-check Doxygen style comments, but do not dnl # recognize "\retval" key word. These options try to both ignore the dnl # problematic area, and to add it as recognized (TODO: scripted check dnl # for abilities of the current build's compiler instead) dnl # -Wno-missing-include-dirs -- do not break on missing include directories, dnl # whether from user-provided config options, or pkg-config, or our own dnl # ci_build.sh preparations (e.g. -I${top_srcdir}/tmp/include when it dnl # is not populated yet) dnl ### Special exclusion picks for clang-medium (same as hard, plus...): dnl # -Wno-global-constructors -- using "const something" out of method context dnl # potentially impacts start-up time and may be prone to race conditions dnl # (for non-trivial interconnected objects), better be re-architected. dnl # -Wno-float-conversion -Wno-double-promotion -Wno-implicit-float-conversion dnl # -- reduce noise due to floating-point literals like "3.14" being a C dnl # double type (a "3.14f" literal is a C float) cast implicitly into dnl # float variables. Also variadic functions like printf() cast their dnl # floating-point arguments into double (and small integer types into dnl # "int") which then confuses pedantic checks of printf("%f", floatval). dnl # -Wno-conversion -- similarly for error: implicit conversion loses dnl # floating-point precision: 'double' to 'float' [-Werror,-Wconversion] dnl # max_output = atof(sValue); dnl # -Wno-cast-qual -- our code calls some library methods in ways which use dnl # a "const char *" as a "char *" or vice-versa. Sometimes these method dnl # signatures differ between dependency releases; sometimes they just dnl # happened too hard to unravel cleanly and add more warnings. dnl # This exclusion may be removed after common warnings are solved, dnl # to allow progress on rectifying these cases next. dnl # -Wno-incompatible-pointer-types-discards-qualifiers -- our code often dnl # defines (char*) as the type for struct fields and method arguments, dnl # but initializes/passes (char[]) variables or fixed strings. dnl # This makes at least clang-3.4 quite upset and noisy (seems newer dnl # versions care less about this situation). dnl # -Wno-disabled-macro-expansion -- some system definitions of strncmp() dnl # and other routines are in fact recursive macros. The -Weverything dnl # mode of clang(-3.4) disables their handling, unless told otherwise. dnl # -Wno-incompatible-function-pointer-types-strict -- some system definitions dnl # of methods for signals are not compatible with even those systems' dnl # definitions of default signals, e.g. void vs. int arguments: dnl # #define SIG_IGN (void (*)())1 dnl # extern void (*signal(int, void (*)(int)))(int); dnl # (NUT signal handler methods do have the int signal number) dnl # This is currently quiesced for clang-17; better solutions are welcome. dnl # -Wno-nullable-to-nonnull-conversion -- newer system headers are tagged dnl # with hints about _Nullable vs. _Nonnull pointers. The general idea dnl # is respectable for memory safety and could be addressed for true old dnl # C99 toolkits and current language spec e.g. with macros... later. dnl # Currently it is more like whack-a-mole as distros update headers. AS_CASE(["${nut_enable_warnings}"], [all], [ CFLAGS="${CFLAGS} -Wall" CXXFLAGS="${CXXFLAGS} -Wall" ], [clang-hard], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wno-system-headers -Wno-missing-include-dirs -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -fcomment-block-commands=retval -Wno-documentation-unknown-command -Wno-cast-qual -pedantic -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wno-system-headers -Wno-missing-include-dirs -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -fcomment-block-commands=retval -Wno-documentation-unknown-command -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-exit-time-destructors -Wno-fuse-ld-path -Wno-unsafe-buffer-usage" ], [clang-medium], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wno-system-headers -Wno-missing-include-dirs -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -fcomment-block-commands=retval -Wno-documentation-unknown-command -Wno-cast-qual -pedantic -Wno-fuse-ld-path -Wno-unsafe-buffer-usage -Wno-float-conversion -Wno-double-promotion -Wno-implicit-float-conversion -Wno-conversion -Wno-incompatible-pointer-types-discards-qualifiers -Wno-incompatible-function-pointer-types-strict -Wno-nullable-to-nonnull-conversion" CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wno-system-headers -Wno-missing-include-dirs -Wall -Wextra -Weverything -Wno-disabled-macro-expansion -Wno-unused-macros -Wno-reserved-id-macro -Wno-padded -Wno-documentation -fcomment-block-commands=retval -Wno-documentation-unknown-command -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-exit-time-destructors -Wno-global-constructors -Wno-fuse-ld-path -Wno-unsafe-buffer-usage -Wno-nullable-to-nonnull-conversion" ], [clang-minimal], [ CFLAGS="${CFLAGS} -ferror-limit=0 -Wall -Wextra -Wno-documentation -Wno-documentation-unknown-command -fcomment-block-commands=retval" CXXFLAGS="${CXXFLAGS} -ferror-limit=0 -Wall -Wextra -Wno-documentation -Wno-documentation-unknown-command -fcomment-block-commands=retval" ], [gcc-legacy], [CFLAGS="${CFLAGS} -Wall -Wsign-compare"], [gcc-minimal], [ dnl Builds with C89 (and aliases) are quite noisy for C99+ syntax used dnl in NUT. The minimal-warnings should not complain in these builds. dnl To make matters worse, many modern OS and third-party library dnl headers can not be used with "C90 + pedantic" mode of GCC, either. CFLAGS="${CFLAGS} -Wall -Wsign-compare" CXXFLAGS="${CXXFLAGS} -Wall -Wextra" AS_CASE(["${CFLAGS}"], [*89*|*90*|*ansi*], [], [CFLAGS="${CFLAGS} -Wextra -pedantic"] ) ], [gcc-medium|gcc-hard], [ CFLAGS="${CFLAGS} -Wno-system-headers -Wall -Wextra -Wsign-compare" CXXFLAGS="${CXXFLAGS} -Wno-system-headers -Wall -Wextra" AS_CASE(["${CFLAGS}"], [*89*|*90*|*ansi*], [], [CFLAGS="${CFLAGS} -pedantic"] ) ] ) AS_IF([test x"${nut_enable_warnings}" != xno || test x"${nut_enable_Werror}" != xno], [AS_IF([test "x${CLANGCC}" = "xyes" || test "x${GCC}" = "xyes"], [AS_CASE(["${target_os}"], [*mingw*], [ AC_MSG_NOTICE( [GCC on WIN32 builds warns about '%lld' etc. via PRId64 etc. even though modern libraries support long-long printing in practice (older ones did not - hence the warning). Forcing "-Wno-format" into warnings options. ]) CFLAGS="${CFLAGS} -Wno-format" CXXFLAGS="${CXXFLAGS} -Wno-format" ] ) ]) ]) AC_MSG_CHECKING([whether to make warnings fatal]) AS_CASE(["${nut_enable_Werror}"], [yes|auto], [ CFLAGS="${CFLAGS} -Werror" CXXFLAGS="${CXXFLAGS} -Werror" ], [no], [ CFLAGS="${CFLAGS} -Wno-error" CXXFLAGS="${CXXFLAGS} -Wno-error" ] ) AC_MSG_RESULT([${nut_enable_Werror}]) dnl Some compilers (e.g. older clang-3.4) have issues with built-in methods dnl that are implemented as macros in system headers -- but only for some dnl sources like snmp-ups.c, nutscan-serial.c, scan_eaton_serial.c, serial.c, dnl scan_avahi.c, scan_xml_http.c, scan_snmp.c... (Seems they all refer to dnl -DNETSNMP_USE_INLINE among other options, and tends to happen more with dnl OpenSSL-enabled builds). Check if we like them? AC_CHECK_HEADER([string.h], [AC_LANG_PUSH([C]) CFLAGS_SAVED="${CFLAGS}" CFLAGS_BUILTIN_STR="-fno-builtin-strchr -fno-builtin-strcmp -fno-builtin-strncmp" CFLAGS="${CFLAGS} -Werror -Wunreachable-code ${LIBNETSNMP_CFLAGS} ${LIBLTDL_CFLAGS} ${LIBNEON_CFLAGS} ${LIBSSL_CFLAGS}" AC_MSG_CHECKING([whether we should disable string built-ins]) dnl AC_DEFINE([HAVE_STRING_H], [1], [Define to 1 if you have .]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [char *s = "v1", c = '%'; if (strcmp(s, "v1") != 0) return 1; if (strchr(s, '1') == NULL) return 1; if (strchr(s, c) != NULL) return 1 /* no ";return 0;" here - autoconf adds one */ ])], [CFLAGS="${CFLAGS_SAVED}" AC_MSG_RESULT([no, they are not a problem])], [CFLAGS="${CFLAGS_BUILTIN_STR} ${CFLAGS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [char *s = "v1", c = '%'; if (strcmp(s, "v1") != 0) return 1; if (strchr(s, '1') == NULL) return 1; if (strchr(s, c) != NULL) return 1 /* no ";return 0;" here - autoconf adds one */ ])], [CFLAGS="${CFLAGS_BUILTIN_STR} ${CFLAGS_SAVED}" AC_MSG_RESULT([yes, this solves a problem])], [CFLAGS="${CFLAGS_SAVED} -Werror -Wno-unreachable-code ${LIBNETSNMP_CFLAGS} ${LIBLTDL_CFLAGS} ${LIBNEON_CFLAGS} ${LIBSSL_CFLAGS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [char *s = "mibs", c = '%'; /* Macro version of strcmp() has problems with strings shorter than * 3 or 4 bytes, so to avoid nailing "-Warray-bounds" as well, * here we just test for longer strings - existing NUT sources were * fixed for this situation already */ if (strcmp(s, "mibs") != 0) return 1; if (strchr(s, 'b') == NULL) return 1; if (strchr(s, c) != NULL) return 1 /* no ";return 0;" here - autoconf adds one */ ])], [dnl CFLAGS="${CFLAGS_SAVED} -Wno-unreachable-code" dnl NOTE: Empirically, constrain to just LIBNETSNMP_CFLAGS CFLAGS="${CFLAGS_SAVED}" LIBLTDL_CFLAGS="${LIBLTDL_CFLAGS} -Wno-unreachable-code" LIBNETSNMP_CFLAGS="${LIBNETSNMP_CFLAGS} -Wno-unreachable-code" AC_MSG_RESULT([no, but -Wno-unreachable-code solves the problem for this compiler])], [CFLAGS="${CFLAGS_SAVED}" AC_MSG_RESULT([no, this does not solve the problem or is not supported]) ]) ]) ] ) AC_LANG_POP([C])] ) dnl Similar to above, for s_addr = htonl((ntohl(ip->start.s_addr) + 1)); dnl which causes "shadowed local variable" as (re-)defined in nested macros. dnl Technically also needs to `#include ` for struct in_addr dnl but that should be pulled by inet.h anyway AC_CHECK_HEADER([arpa/inet.h], [AC_LANG_PUSH([C]) CFLAGS_SAVED="${CFLAGS}" CFLAGS_BUILTIN_NTOHL="-fno-builtin-htonl -fno-builtin-ntohl" CFLAGS="${CFLAGS} -Werror -Wunreachable-code -Wshadow ${LIBNETSNMP_CFLAGS} ${LIBLTDL_CFLAGS} ${LIBNEON_CFLAGS} ${LIBSSL_CFLAGS}" AC_MSG_CHECKING([whether we should disable htonl/ntohl built-ins]) dnl AC_DEFINE([HAVE_ARPA_INET_H], [1], [Define to 1 if you have .]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [struct in_addr sin = {0}; sin.s_addr = htonl((ntohl(sin.s_addr) + 1)) /* no ";return 0;" here - autoconf adds one */ ])], [CFLAGS="${CFLAGS_SAVED}" AC_MSG_RESULT([no, they are not a problem])], [CFLAGS="${CFLAGS_BUILTIN_NTOHL} ${CFLAGS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [struct in_addr sin = {0}; sin.s_addr = htonl((ntohl(sin.s_addr) + 1)) /* no ";return 0;" here - autoconf adds one */ ])], [CFLAGS="${CFLAGS_BUILTIN_NTOHL} ${CFLAGS_SAVED}" AC_MSG_RESULT([yes, this solves a problem])], [CFLAGS="${CFLAGS_SAVED} -Werror -Wno-shadow ${LIBNETSNMP_CFLAGS} ${LIBLTDL_CFLAGS} ${LIBNEON_CFLAGS} ${LIBSSL_CFLAGS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [struct in_addr sin = {0}; sin.s_addr = htonl((ntohl(sin.s_addr) + 1)) ])], [CFLAGS="${CFLAGS_SAVED}" LIBLTDL_CFLAGS="${LIBLTDL_CFLAGS} -Wno-shadow" LIBNETSNMP_CFLAGS="${LIBNETSNMP_CFLAGS} -Wno-shadow" AC_MSG_RESULT([no, but -Wno-shadow solves the problem for this compiler])], [CFLAGS="${CFLAGS_SAVED}" AC_MSG_RESULT([no, this does not solve the problem or is not supported]) ]) ]) ] ) AC_LANG_POP([C])] ) dnl Finally restore warnings settings that the caller might have provided in CFLAGS etc NUT_POP_WARNINGS dnl Due to possibly repetitive content, generate unique settings dnl relative to the top_builddir (distcheck and all): AC_MSG_CHECKING([for top build dir for this configure run]) TOP_BUILDDIR="" AS_IF([test -n "${ac_abs_top_builddir}" && test -d "${ac_abs_top_builddir}"], [TOP_BUILDDIR="${ac_abs_top_builddir}"], [AS_IF([test -n "${ac_pwd}" && test -d "${ac_pwd}"], [TOP_BUILDDIR="${ac_pwd}"], [TOP_BUILDDIR="`dirname "$0"`" TOP_BUILDDIR="`cd "$TOP_BUILDDIR" && pwd`" || AC_MSG_ERROR([Can not detect TOP_BUILDDIR])] )] ) dnl Quoted in case someone copy-pastes this path and it has whitespaces: AC_MSG_RESULT(['${TOP_BUILDDIR}']) ABS_TOP_BUILDDIR="`cd "${TOP_BUILDDIR}" && pwd`" || AC_MSG_ERROR([Can not detect ABS_TOP_BUILDDIR]) ABS_TOP_SRCDIR="`cd "${abs_srcdir}" && pwd`" || AC_MSG_ERROR([Can not detect ABS_TOP_SRCDIR]) AM_CONDITIONAL([BUILDING_IN_TREE], [test "${ABS_TOP_BUILDDIR}" = "${ABS_TOP_SRCDIR}"]) dnl When building ON Windows (mingw/MSYS2, cygwin, etc.) fudge these dnl path strings back to what native OS methods would recognize. AS_CASE([${target_os}], [*mingw*], [ AC_MSG_NOTICE([Will try to resolve Windows paths to ABS_TOP_SRCDIR and ABS_TOP_BUILDDIR with cygpath or mingw/msys pwd -W tool (would fail if not a native build)]) dnl Cygwin path resolver AC_CHECK_TOOL([CYGPATH], [cygpath], [none]) AS_IF([test "x${CYGPATH}" != "xnone" && test x"`${CYGPATH}`" != x], [ tmp="`${CYGPATH} -m "${ABS_TOP_BUILDDIR}" | sed -e 's,/,\\\\\\\\,g'`" && test -n "$tmp" && test -d "$tmp" && ABS_TOP_BUILDDIR="$tmp" tmp="`${CYGPATH} -m "${ABS_TOP_SRCDIR}" | sed 's,/,\\\\\\\\,g'`" && test -n "$tmp" && test -d "$tmp" && ABS_TOP_SRCDIR="$tmp" ],[ dnl MSYS pwd with -W option to resolve AC_CHECK_TOOL([PWDTOOL], [pwd], [none]) AS_IF([test "x${PWDTOOL}" != "xnone" && test x"`${PWDTOOL} -W`" != x], [ tmp="`(cd "${ABS_TOP_BUILDDIR}" && ${PWDTOOL} -W) | sed 's,/,\\\\\\\\,g'`" && test -n "$tmp" && test -d "$tmp" && ABS_TOP_BUILDDIR="$tmp" tmp="`(cd "${ABS_TOP_SRCDIR}" && ${PWDTOOL} -W) | sed 's,/,\\\\\\\\,g'`" && test -n "$tmp" && test -d "$tmp" && ABS_TOP_SRCDIR="$tmp" ]) ]) AC_MSG_NOTICE([FWIW, assuming ABS_TOP_SRCDIR="$ABS_TOP_SRCDIR" and ABS_TOP_BUILDDIR="$ABS_TOP_BUILDDIR"]) ]) dnl Use these at best for tests (e.g. nutconf), not production code: AC_DEFINE_UNQUOTED([ABS_TOP_SRCDIR], ["${ABS_TOP_SRCDIR}"], [NUT source directory when the build was configured]) AC_DEFINE_UNQUOTED([ABS_TOP_BUILDDIR], ["${ABS_TOP_BUILDDIR}"], [NUT build directory when the build was configured]) AC_MSG_CHECKING([whether to install External API integration script: Enphase Monitor]) nut_with_extapi_enphase="no" AC_ARG_ENABLE([extapi-enphase], AS_HELP_STRING([--enable-extapi-enphase=(yes|auto|no)], [Enable installation of integration script for External API: Enphase Monitor (default: no)]), [ case "${enableval}" in yes|"") nut_enable_extapi_enphase="auto" ;; auto|no) nut_enable_extapi_enphase="${enableval}" ;; *) AC_MSG_ERROR([Unexpected argument for --enable-extapi-enphase=${enableval}]) ;; esac ], []) if test x"$nut_enable_extapi_enphase" != xno ; then dnl Depends on usability of further programs and bash version dnl Luckily the script checks that itself, before handling CLI args /usr/bin/env bash "${ABS_TOP_SRCDIR}/scripts/external_apis/enphase/enphase-monitor.in" --help >/dev/null \ && nut_can_extapi_enphase="yes" \ || nut_can_extapi_enphase="no" if test x"$nut_enable_extapi_enphase" = xyes && x"$nut_can_extapi_enphase" = xno ; then AC_MSG_ERROR([Caller required installation --enable-extapi-enphase but the system can not run it]) fi nut_enable_extapi_enphase="${nut_can_extapi_enphase}" fi AC_MSG_RESULT([${nut_enable_extapi_enphase}]) AM_CONDITIONAL(ENABLE_EXTAPI_ENPHASE, test x"$nut_enable_extapi_enphase" = x"yes") AC_MSG_CHECKING([whether to customize ${TOP_BUILDDIR}/scripts/systemd/nut-common-tmpfiles.conf.in for this system]) dnl TOTHINK: Some distributions make the directories below owned dnl by "root:${RUN_AS_GROUP}" with 77x permissions. Is it safer?.. AS_IF([test -n "$systemdtmpfilesdir"], [mkdir -p "${TOP_BUILDDIR}"/scripts/systemd cat > "${TOP_BUILDDIR}"/scripts/systemd/nut-common-tmpfiles.conf.in << EOF # Network UPS Tools (NUT) systemd integration # Distributed under the terms of GPLv2+ # See https://networkupstools.org/ # and https://github.com/networkupstools/nut/ # See also: https://github.com/networkupstools/nut/wiki/Technicalities:-Work-with-PID-and-state-file-paths#pidpath-altpidpath-statepath # State file (e.g. upsd to driver pipes) and PID file location for NUT: d @STATEPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - # Default PIPEFN and LOCKFN locations per upssched.conf: d @STATEPATH@/upssched 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @STATEPATH@ EOF AS_IF([test "$STATEPATH" != "$PIDPATH"], [AS_CASE(["${PIDPATH}"], [*/run|*/tmp|*/shm], [], dnl Do not intrude into system paths; TODO: add more if appropriate for some Linux distro [cat >> "${TOP_BUILDDIR}"/scripts/systemd/nut-common-tmpfiles.conf.in << EOF # Primarily used by upsmon and upslog, possibly running as root: d @PIDPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @PIDPATH@ EOF ])]) AS_IF([test -n "$ALTPIDPATH" && test "$STATEPATH" != "$ALTPIDPATH" && test "$PIDPATH" != "$ALTPIDPATH"], [cat >> "${TOP_BUILDDIR}"/scripts/systemd/nut-common-tmpfiles.conf.in << EOF # Should be used as upsd and driver PID file location for NUT # (if ALTPIDPATH differs from STATEPATH): d @ALTPIDPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @ALTPIDPATH@ EOF]) dnl Generally added to support some forks AS_IF([test -n "$ALTSTATEPATH" && test "$STATEPATH" != "$ALTSTATEPATH" && test "$ALTSTATEPATH" != "$ALTPIDPATH" && test "$PIDPATH" != "$ALTSTATEPATH"], [cat >> "${TOP_BUILDDIR}"/scripts/systemd/nut-common-tmpfiles.conf.in << EOF # Some NUT variants also maintain an ALTSTATEPATH: d @ALTSTATEPATH@ 0770 @RUN_AS_USER@ @RUN_AS_GROUP@ - - X @ALTSTATEPATH@ EOF]) ]) AC_MSG_RESULT([done]) dnl # ccache versions 4.5 and newer support namespacing of the objects dnl # to facilitate more targeted eviction with --evict-namespace and dnl # perhaps --evict-older-than options. Here we bolt a namespace with dnl # NUT as the project and CPU architecture for resulting binaries; dnl # maybe we might use distro as well but some overlaps may be possible dnl # that result in same objects for different-looking build roots. dnl # Note this is enabled by default (explicit --without-... disables it). dnl # Has practical effect if NUT_AM_MAKE_CAN_EXPORT test is successful. AS_IF([test x"${CCACHE_NAMESPACE}" = x], [ CCACHE_NAMESPACE="nut" dnl # Variables in this list are defined earlier in the script for T in "${compiler_multiarch}" "${target_alias}" "${target}" "${target_cpu}-${target_os}" ; do if test x"$T" != x -a x"$T" != x- ; then CCACHE_NAMESPACE="${CCACHE_NAMESPACE}:${T}" break fi done unset T ]) AC_ARG_WITH(CCACHE_NAMESPACE, AS_HELP_STRING([--with-CCACHE_NAMESPACE=namespace], [which ccache namespace to use for built binaries; typically nut:${autotools_target})]), [ case "${withval}" in no) CCACHE_NAMESPACE="" ;; yes) # Use user envvar or calculation above ;; *) CCACHE_NAMESPACE="${withval}" ;; esac ], []) NUT_REPORT_TARGET(CCACHE_NAMESPACE, "${CCACHE_NAMESPACE}", [ccache namespace tag (if ccache is used and new enough)]) AS_IF([test x"$CCACHE_NAMESPACE" != x -a x"$NUT_AM_MAKE_CAN_EXPORT" != x], [ AC_MSG_WARN([CCACHE_NAMESPACE setting may have no effect: this make implementation seems to not support "export VAR=VAL" syntax]) ]) dnl # Mark it as a "precious variable", for more details see dnl # https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Setting-Output-Variables.html AC_ARG_VAR(CCACHE_NAMESPACE) dnl # Also list some other ccache options which ci_build.sh can fiddle with. dnl # While that script "exports" them so it can call both configuration and dnl # the build, their values may be unknown when a developer re-runs "make". dnl # Normally most of the options would persist under $CCACHE_DIR/ccache.conf dnl # and we would not pass them via envvars. AC_ARG_VAR(CCACHE_BASEDIR) AC_ARG_VAR(CCACHE_DIR) AC_ARG_VAR(CCACHE_PATH) dnl Some versions of ccache take poorly to an exported empty CCACHE_DIR etc. dnl Avoid exporting them if not set at the configure time (assuming ci_build.sh dnl integration or user's shell profile sets them persistently) AS_IF([test x"${CCACHE_NAMESPACE-}" = x], [NUT_AM_EXPORT_CCACHE_NAMESPACE="#"], [NUT_AM_EXPORT_CCACHE_NAMESPACE=""]) AC_SUBST(NUT_AM_EXPORT_CCACHE_NAMESPACE) AS_IF([test x"${CCACHE_BASEDIR-}" = x], [NUT_AM_EXPORT_CCACHE_BASEDIR="#"], [NUT_AM_EXPORT_CCACHE_BASEDIR=""]) AC_SUBST(NUT_AM_EXPORT_CCACHE_BASEDIR) AS_IF([test x"${CCACHE_DIR-}" = x], [NUT_AM_EXPORT_CCACHE_DIR="#"], [NUT_AM_EXPORT_CCACHE_DIR=""]) AC_SUBST(NUT_AM_EXPORT_CCACHE_DIR) dnl Application of PATH_DURING_CONFIGURE is also fenced by NUT_AM_EXPORT_CCACHE_PATH: AS_IF([test x"${CCACHE_PATH-}" = x], [NUT_AM_EXPORT_CCACHE_PATH="#"], [NUT_AM_EXPORT_CCACHE_PATH=""]) AC_SUBST(NUT_AM_EXPORT_CCACHE_PATH) PATH_DURING_CONFIGURE="$PATH" AC_SUBST(PATH_DURING_CONFIGURE) dnl Some binaries, like CPPUNIT tests, have similar flags already added dnl We might wipe their specific options below if consistently applying dnl debug-friendly options to everything AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CONFIG_CFLAGS='${CONFIG_CFLAGS}']) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CONFIG_CXXFLAGS='${CONFIG_CXXFLAGS}']) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CONFIG_CPPFLAGS='${CONFIG_CPPFLAGS}']) AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) CONFIG_LDFLAGS='${CONFIG_LDFLAGS}']) ]) AC_MSG_CHECKING([whether to enable debug info in all NUT binaries]) nut_with_debuginfo_C="${nut_with_debuginfo}" nut_with_debuginfo_CXX="${nut_with_debuginfo}" AS_CASE(["${CONFIG_CFLAGS}"], [*-O*|*-g*], [ AS_IF([test x"${nut_with_debuginfo_C}" = xauto], [ nut_with_debuginfo_C="Related settings already specified by caller CFLAGS, not changing anything" ]) ], [ dnl No competing options are provided AS_IF([test x"${nut_with_debuginfo_C}" = xauto], [nut_with_debuginfo_C="yes"]) ]) AS_CASE(["${CONFIG_CXXFLAGS}"], [*-O*|*-g*], [ AS_IF([test x"${nut_with_debuginfo_CXX}" = xauto], [ nut_with_debuginfo_CXX="Related settings already specified by caller CXXFLAGS, not changing anything" ]) ], [ dnl No competing options are provided AS_IF([test x"${nut_with_debuginfo_CXX}" = xauto], [nut_with_debuginfo_CXX="yes"]) ]) AS_CASE(["${nut_with_debuginfo_C}"], [yes], [ AS_IF([test x"${CLANGCC}" = x"yes" -o x"${GCC}" = x"yes"], [ dnl Where we can enable debug, minimize the optimizations. dnl On some platforms LIBNETSNMP_CFLAGS or some such defines dnl _FORTIFY_SOURCE=N which in turn "requires compiling with dnl optimization", so we can not disable it in CFLAGS applied dnl in the end of each and every build command line (highest dnl priority). However, CPPFLAGS are before (making these dnl lines an implementation-dependent hack)... dnl AS_IF([set | grep -E 'FORTIFY_SOURCE'], [], [CFLAGS="${CFLAGS} -O0"]) CPPFLAGS="${CPPFLAGS} -O0" CFLAGS="${CFLAGS} -g3 -gdwarf-2" ],[nut_with_debuginfo_C="Unknown C compiler, not adding options"] )], dnl # [no]: By default we do not add debug info [legacy], [ dnl # Apply legacy defaults if no flags were specified by caller or detected by autoconf AS_IF([test x"${CFLAGS_AFTER_ACPROG}" = x], [CFLAGS="-O ${CFLAGS}"]) ] ) AS_CASE(["${nut_with_debuginfo_CXX}"], [yes], [ AS_IF([test "x$CLANGXX" = xyes -o "x$GXX" = xyes], [ dnl Where we can enable debug, minimize the optimizations. dnl NOTE: Concerns for -O0 behavior commented above are about C code, dnl not seen (yet) with C++. CXXFLAGS="${CXXFLAGS} -O0 -g3 -gdwarf-2" dnl Use same settings for CPPUNIT tests (they bump their own by default) CPPUNIT_NUT_CXXFLAGS="" ],[nut_with_debuginfo_CXX="Unknown C++ compiler, not adding options"] )], dnl # [no]: By default we do not add debug info [legacy], [ dnl # Apply legacy defaults if no flags were specified by caller or detected by autoconf AS_IF([test x"${CXXFLAGS_AFTER_ACPROG}" = x], [CXXFLAGS="-O ${CXXFLAGS}"]) ] ) AC_MSG_RESULT([C: ${nut_with_debuginfo_C}; C++: ${nut_with_debuginfo_CXX}]) dnl Only in the end, do you understand... AC_SUBST(CPPUNIT_NUT_CXXFLAGS) AC_MSG_NOTICE([Generating "data" files from templates, see below for executable scripts]) AC_CONFIG_FILES([ clients/Makefile common/Makefile conf/Makefile conf/upsmon.conf.sample conf/upssched.conf.sample data/html/header.html data/html/Makefile data/Makefile data/driver.list docs/Makefile docs/cables/Makefile docs/docinfo.xml docs/man/Makefile drivers/Makefile include/Makefile lib/libupsclient.pc lib/libnutclient.pc lib/libnutconf.pc lib/libnutclientstub.pc lib/libnutscan.pc lib/Makefile scripts/Aix/nut-aix.spec scripts/RedHat/ups scripts/augeas/Makefile scripts/augeas/nutnutconf.aug scripts/augeas/nutupsdconf.aug scripts/augeas/nutupsdusers.aug scripts/augeas/nutupsmonconf.aug scripts/augeas/nutupsschedconf.aug scripts/augeas/nuthostsconf.aug scripts/augeas/nutupssetconf.aug scripts/avahi/nut.service scripts/devd/Makefile scripts/external_apis/Makefile scripts/external_apis/enphase/enphase-monitor@.service scripts/hotplug/Makefile scripts/hotplug/libhidups scripts/HP-UX/nut.psf scripts/installer/Makefile scripts/python/Makefile scripts/python/module/Makefile scripts/python/module/PyNUT.py scripts/python/module/setup.py scripts/upsdrvsvcctl/Makefile scripts/systemd/Makefile scripts/systemd/nut.target scripts/systemd/nut-common-tmpfiles.conf scripts/systemd/nut-driver.target scripts/systemd/nut-driver@.service scripts/systemd/nut-logger.service scripts/systemd/nut-monitor.service scripts/systemd/nut-server.service scripts/systemd/nut-driver-enumerator.service scripts/systemd/nut-driver-enumerator.path scripts/systemd/nut-driver-enumerator-daemon.service scripts/systemd/nut-driver-enumerator-daemon-activator.service scripts/systemd/nut-driver-enumerator-daemon-activator.path scripts/Solaris/nut-driver-enumerator.xml scripts/Solaris/nut-driver.xml scripts/Solaris/nut-logger.xml scripts/Solaris/nut-monitor.xml scripts/Solaris/nut-server.xml scripts/Solaris/nut.xml scripts/Solaris/Makefile scripts/Solaris/pkginfo scripts/udev/Makefile scripts/udev/nut-ipmipsu.rules scripts/ufw/Makefile scripts/ufw/nut.ufw.profile scripts/valgrind/.valgrind.supp scripts/Windows/Makefile scripts/Windows/Installer/NUT-Installer.xml scripts/Makefile server/Makefile tools/Makefile tools/nut-scanner/Makefile tools/nutconf/Makefile tests/Makefile tests/NIT/Makefile Makefile ]) AC_MSG_NOTICE([Generating templated script files that should be marked executable]) m4_foreach_w([SCRIPTFILE], [ lib/libupsclient-config scripts/Aix/nut.init scripts/HP-UX/postinstall scripts/RedHat/upsd scripts/RedHat/upsmon scripts/augeas/gen-nutupsconf-aug.py scripts/external_apis/enphase/enphase-monitor scripts/python/app/NUT-Monitor-py2gtk2 scripts/python/app/NUT-Monitor-py3qt5 scripts/python/module/test_nutclient.py scripts/upsdrvsvcctl/nut-driver-enumerator.sh scripts/upsdrvsvcctl/upsdrvsvcctl scripts/systemd/nutshutdown scripts/Solaris/svc-nut-server scripts/Solaris/svc-nut-logger scripts/Solaris/svc-nut-monitor scripts/Solaris/precheck.py scripts/Solaris/preinstall scripts/Solaris/postinstall scripts/Solaris/preremove scripts/Solaris/postremove scripts/Solaris/preproto.pl scripts/Solaris/nut scripts/valgrind/valgrind.sh tools/gitlog2changelog.py tools/nut-snmpinfo.py ], [ dnl Autoconf substitutes the token above specified in plain text, dnl e.g. the brace below is empty and bracket gives verbatim varname dnl However on at least NetBSD it ends up as a flawed expansion dnl (varname with a slash) due to this generated shell code: dnl printf ... "Script: lib/libupsclient-config brace:(${lib/libupsclient-config}) bracket:(SCRIPTFILE)" dnl so this block remains commented away until specific troubleshooting dnl is needed by any developers (locally on their systems!) dnl AS_IF([test x"${nut_enable_configure_debug}" = xyes], [ dnl AC_MSG_NOTICE([(CONFIGURE-DEVEL-DEBUG) Script: SCRIPTFILE brace:(${SCRIPTFILE}) bracket:([SCRIPTFILE])]) dnl ]) AC_CONFIG_FILES(SCRIPTFILE, chmod +x "SCRIPTFILE") ]) AC_MSG_NOTICE([Generating templated script files whose templates might have been generated (or not) by autogen.sh calling our helper scripts]) m4_foreach_w([SCRIPTFILE], [ scripts/augeas/nutupsconf.aug scripts/udev/nut-usbups.rules scripts/devd/nut-usb.conf ], [ AC_MSG_CHECKING([whether to generate SCRIPTFILE]) AS_IF([test -s SCRIPTFILE.in && ! test -f SCRIPTFILE.in.AUTOGEN_WITHOUT], [AC_MSG_RESULT(yes) AC_CONFIG_FILES(SCRIPTFILE)], [AC_MSG_RESULT(no)] ) ]) dnl Define this before AC_OUTPUT(), so not inside the report routine below: AM_CONDITIONAL(KEEP_NUT_REPORT, test x"${nut_enable_keep_nut_report_feature-}" = xyes) dnl Prints a long list of files generated from templates... AC_OUTPUT dnl Normally the latest action, for the summary to be visible: NUT_REPORT_COMPILERS NUT_PRINT_FEATURE_REPORT dnl Stopping short of patching the unknown script, we can warn about the issue dnl (visibly as it impacts next activities of the caller): AS_IF([test -s "${ABS_TOP_SRCDIR}/install-sh" && grep -w MKDIRPROG "${ABS_TOP_SRCDIR}/install-sh" >/dev/null], [AS_IF([grep -v '#' "${ABS_TOP_SRCDIR}/install-sh" | grep -E '\$mkdirprog.*-p' >/dev/null], [], [AC_MSG_WARN([=====================================================]) AC_MSG_WARN([Your system provided (or NUT tarball included) an]) AC_MSG_WARN(['install-sh' implementation which is not safe for]) AC_MSG_WARN([parallel installs; export MKDIRPROG='mkdir -p']) AC_MSG_WARN([may help, otherwise run 'make install' sequentially.]) AC_MSG_WARN([This should not impact parallel builds.]) AC_MSG_WARN([=====================================================]) ]) ]) AS_IF([test x"${NUT_VERSION_DEPLOYED-}" = x""], [ AC_MSG_NOTICE([==========================================================]) AC_MSG_NOTICE([You have configured a build for "in-place" replacement]) AC_MSG_NOTICE([of an existing NUT installation. You are advised to first]) AC_MSG_NOTICE([install into a temporary DESTDIR and verify the fliesystem]) AC_MSG_NOTICE([layout of the new build against what you already have.]) AC_MSG_NOTICE([Check INSTALL.nut.adoc for practical details and example.]) AC_MSG_NOTICE([==========================================================]) ]) nut-2.8.3/include/0000755000200500020050000000000015001555410010736 500000000000000nut-2.8.3/include/nut_stdint.h0000644000200500020050000001140114777767434013255 00000000000000/* * nut_stdint.h - Network UPS Tools sets of integer types having specified widths * * Copyright (C) 2011 Arjen de Korte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_STDINT_H_SEEN #define NUT_STDINT_H_SEEN 1 /* "config.h" is generated by autotools and lacks a header guard, so * we use an unambiguously named macro we know we must have, as one. * It must be the first header: be sure to know all about system config. */ #ifndef NUT_NETVERSION # include "config.h" #endif #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS 1 #endif #if defined HAVE_INTTYPES_H # include #endif #if defined HAVE_STDINT_H # include #endif #if defined HAVE_LIMITS_H # include #endif #ifndef SIZE_MAX #define SIZE_MAX ((size_t)(-1LL)) #endif #ifndef SSIZE_MAX #define SSIZE_MAX ((ssize_t)(-1LL)) #endif /* Printing format for size_t and ssize_t */ #ifndef PRIuSIZE # ifdef PRIsize # define PRIuSIZE PRIsize # else # if defined(__MINGW32__) || defined (WIN32) # define PRIuSIZE "llu" # else # define PRIuSIZE "zu" # endif # endif #endif #ifndef PRIxSIZE # if defined(__MINGW32__) || defined (WIN32) # define PRIxSIZE "llx" # else # define PRIxSIZE "zx" # endif #endif /* Note: Windows headers are known to define at least "d" values, * so macros below revolve around that and not "i" directly */ #ifndef PRIiSIZE # ifdef PRIssize # define PRIiSIZE PRIssize # else # ifdef PRIdSIZE # define PRIiSIZE PRIdSIZE # else # if defined(__MINGW32__) || defined (WIN32) # define PRIiSIZE "lld" # else # define PRIiSIZE "zd" # endif # define PRIdSIZE PRIiSIZE # endif # endif #else # ifndef PRIdSIZE # define PRIdSIZE PRIiSIZE # endif #endif /* format for size_t and ssize_t */ /* Printing format for uintmax_t and intmax_t */ #ifndef PRIuMAX # if defined(__MINGW32__) || defined (WIN32) # if (SIZEOF_VOID_P == 8) # ifdef PRIu64 # define PRIuMAX PRIu64 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIuMAX "llu" # endif # endif # if (SIZEOF_VOID_P == 4) # ifdef PRIu32 # define PRIuMAX PRIu32 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIuMAX "lu" # endif # endif # else /* assume new enough compiler and standard... check "%j" support via configure? */ # define PRIuMAX "ju" # endif #endif /* format for uintmax_t and intmax_t */ #ifndef PRIdMAX # ifdef PRIiMAX # define PRIdMAX PRIiMAX # else # if defined(__MINGW32__) || defined (WIN32) # if (SIZEOF_VOID_P == 8) # ifdef PRId64 # define PRIdMAX PRId64 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIdMAX "lld" # endif # endif # if (SIZEOF_VOID_P == 4) # ifdef PRId32 # define PRIdMAX PRId32 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIdMAX "ld" # endif # endif # else /* assume new enough compiler and standard... check "%j" support via configure? */ # define PRIdMAX "jd" # endif # define PRIiMAX PRIdMAX # endif #else # ifndef PRIiMAX # define PRIiMAX PRIdMAX # endif #endif /* format for uintmax_t and intmax_t */ #ifndef PRIxMAX # if defined(__MINGW32__) || defined (WIN32) # if (SIZEOF_VOID_P == 8) # ifdef PRIx64 # define PRIxMAX PRIx64 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIxMAX "llx" # endif # endif # if (SIZEOF_VOID_P == 4) # ifdef PRIx32 # define PRIxMAX PRIx32 # else /* assume new enough compiler and standard, and no Windows %I64 etc... check "%ll" support via configure? */ # define PRIxMAX "lx" # endif # endif # else /* assume new enough compiler and standard... check "%j" support via configure? */ # define PRIxMAX "jx" # endif #endif /* format for uintmax_t and intmax_t */ #endif /* NUT_STDINT_H_SEEN */ nut-2.8.3/include/config.h.in0000644000200500020050000015157615001555007012722 00000000000000/* include/config.h.in. Generated from configure.ac by autoheader. */ /* NUT build directory when the build was configured */ #undef ABS_TOP_BUILDDIR /* NUT source directory when the build was configured */ #undef ABS_TOP_SRCDIR /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Path for pid files of processes not running as root */ #undef ALTPIDPATH /* host env spec we built on */ #undef AUTOTOOLS_BUILD_ALIAS /* host OS short spec we built on */ #undef AUTOTOOLS_BUILD_SHORT_ALIAS /* host env spec we run on */ #undef AUTOTOOLS_HOST_ALIAS /* host OS short spec we run on */ #undef AUTOTOOLS_HOST_SHORT_ALIAS /* host env spec we built for */ #undef AUTOTOOLS_TARGET_ALIAS /* host OS short spec we built for */ #undef AUTOTOOLS_TARGET_SHORT_ALIAS /* Default path for user executables */ #undef BINDIR /* ccache namespace tag (if ccache is used and new enough) */ #undef CCACHE_NAMESPACE /* Compact version of C compiler */ #undef CC_VERSION /* Default path for CGI programs */ #undef CGIPATH /* Flags passed to configure script */ #undef CONFIG_FLAGS /* Default path for configuration files */ #undef CONFPATH /* Compact version of C preprocessor */ #undef CPP_VERSION /* Define processor type */ #undef CPU_TYPE /* Define to 1 if your C++ compiler doesn't accept -c and -o together. */ #undef CXX_NO_MINUS_C_MINUS_O /* Compact version of C++ compiler */ #undef CXX_VERSION /* Default path for UPS drivers */ #undef DRVPATH /* Define to nothing if C supports flexible array members, and to 1 if it does not. That way, with a declaration like `struct s { int n; double d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99 compilers. When computing the size of such an object, don't use 'sizeof (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)' instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with MSVC and with C++ compilers. */ #undef FLEXIBLE_ARRAY_MEMBER /* String spelling of boolean type implementation */ #undef FOUND_BOOLEAN_IMPLEM_STR /* C spelling of boolean type */ #undef FOUND_BOOLEAN_TYPE /* C spelling of boolean type false value */ #undef FOUND_BOOLEAN_VALUE_FALSE /* C spelling of boolean type true value */ #undef FOUND_BOOLEAN_VALUE_TRUE /* String spelling of bool type implementation */ #undef FOUND_BOOL_IMPLEM_STR /* C spelling of bool type */ #undef FOUND_BOOL_TYPE /* String spelling of bool_t type implementation */ #undef FOUND_BOOL_T_IMPLEM_STR /* C spelling of bool_t type */ #undef FOUND_BOOL_T_TYPE /* C spelling of bool_t type false value */ #undef FOUND_BOOL_T_VALUE_FALSE /* C spelling of bool_t type true value */ #undef FOUND_BOOL_T_VALUE_TRUE /* C spelling of bool type false value */ #undef FOUND_BOOL_VALUE_FALSE /* C spelling of bool type true value */ #undef FOUND_BOOL_VALUE_TRUE /* String spelling of _Bool type implementation */ #undef FOUND__BOOL_IMPLEM_STR /* C spelling of _Bool type */ #undef FOUND__BOOL_TYPE /* C spelling of _Bool type false value */ #undef FOUND__BOOL_VALUE_FALSE /* C spelling of _Bool type true value */ #undef FOUND__BOOL_VALUE_TRUE /* Define to the type of arg 1 for getnameinfo. */ #undef GETNAMEINFO_TYPE_ARG1 /* Define to the type of arg 2 for getnameinfo. */ #undef GETNAMEINFO_TYPE_ARG2 /* Define to the type of args 4 and 6 for getnameinfo. */ #undef GETNAMEINFO_TYPE_ARG46 /* Define to the type of arg 7 for getnameinfo. */ #undef GETNAMEINFO_TYPE_ARG7 /* Define to 1 if you have the `abs' function. */ #undef HAVE_ABS /* Define to 1 if you have the `abs_val' function. */ #undef HAVE_ABS_VAL /* Define to 1 if you have the `atexit' function. */ #undef HAVE_ATEXIT /* Define to 1 if you have the header file. */ #undef HAVE_AVAHI_CLIENT_CLIENT_H /* Define to 1 if you have the `avahi_client_new' function. */ #undef HAVE_AVAHI_CLIENT_NEW /* Define to 1 if you have the header file. */ #undef HAVE_AVAHI_COMMON_MALLOC_H /* Define to 1 if you have the `avahi_free' function. */ #undef HAVE_AVAHI_FREE /* Boolean type ${FOUND_BOOLEAN_TYPE} is defined as an enum with specific values allowed */ #undef HAVE_BOOLEAN_IMPLEM_ENUM /* Boolean type ${FOUND_BOOLEAN_TYPE} is defined as a general-purpose number type (int) */ #undef HAVE_BOOLEAN_IMPLEM_INT /* Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as a preprocessor macro (type/implem is questionable) */ #undef HAVE_BOOLEAN_IMPLEM_MACRO /* Name of ${FOUND_BOOLEAN_TYPE} is defined as camel-case token */ #undef HAVE_BOOLEAN_TYPE_CAMELCASE /* Name of ${FOUND_BOOLEAN_TYPE} is defined as lower-case token */ #undef HAVE_BOOLEAN_TYPE_LOWERCASE /* Name of ${FOUND_BOOLEAN_TYPE} is defined as upper-case token */ #undef HAVE_BOOLEAN_TYPE_UPPERCASE /* Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as camel-case tokens */ #undef HAVE_BOOLEAN_VALUE_CAMELCASE /* Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as lower-case tokens */ #undef HAVE_BOOLEAN_VALUE_LOWERCASE /* Boolean values of ${FOUND_BOOLEAN_TYPE} are defined as upper-case tokens */ #undef HAVE_BOOLEAN_VALUE_UPPERCASE /* Boolean type ${FOUND_BOOL_TYPE} is defined as an enum with specific values allowed */ #undef HAVE_BOOL_IMPLEM_ENUM /* Boolean type ${FOUND_BOOL_TYPE} is defined as a general-purpose number type (int) */ #undef HAVE_BOOL_IMPLEM_INT /* Boolean values of ${FOUND_BOOL_TYPE} are defined as a preprocessor macro (type/implem is questionable) */ #undef HAVE_BOOL_IMPLEM_MACRO /* Name of ${FOUND_BOOL_TYPE} is defined as camel-case token */ #undef HAVE_BOOL_TYPE_CAMELCASE /* Name of ${FOUND_BOOL_TYPE} is defined as lower-case token */ #undef HAVE_BOOL_TYPE_LOWERCASE /* Name of ${FOUND_BOOL_TYPE} is defined as upper-case token */ #undef HAVE_BOOL_TYPE_UPPERCASE /* Boolean type ${FOUND_BOOL_T_TYPE} is defined as an enum with specific values allowed */ #undef HAVE_BOOL_T_IMPLEM_ENUM /* Boolean type ${FOUND_BOOL_T_TYPE} is defined as a general-purpose number type (int) */ #undef HAVE_BOOL_T_IMPLEM_INT /* Boolean values of ${FOUND_BOOL_T_TYPE} are defined as a preprocessor macro (type/implem is questionable) */ #undef HAVE_BOOL_T_IMPLEM_MACRO /* Name of ${FOUND_BOOL_T_TYPE} is defined as camel-case token */ #undef HAVE_BOOL_T_TYPE_CAMELCASE /* Name of ${FOUND_BOOL_T_TYPE} is defined as lower-case token */ #undef HAVE_BOOL_T_TYPE_LOWERCASE /* Name of ${FOUND_BOOL_T_TYPE} is defined as upper-case token */ #undef HAVE_BOOL_T_TYPE_UPPERCASE /* Boolean values of ${FOUND_BOOL_T_TYPE} are defined as camel-case tokens */ #undef HAVE_BOOL_T_VALUE_CAMELCASE /* Boolean values of ${FOUND_BOOL_T_TYPE} are defined as lower-case tokens */ #undef HAVE_BOOL_T_VALUE_LOWERCASE /* Boolean values of ${FOUND_BOOL_T_TYPE} are defined as upper-case tokens */ #undef HAVE_BOOL_T_VALUE_UPPERCASE /* Boolean values of ${FOUND_BOOL_TYPE} are defined as camel-case tokens */ #undef HAVE_BOOL_VALUE_CAMELCASE /* Boolean values of ${FOUND_BOOL_TYPE} are defined as lower-case tokens */ #undef HAVE_BOOL_VALUE_LOWERCASE /* Boolean values of ${FOUND_BOOL_TYPE} are defined as upper-case tokens */ #undef HAVE_BOOL_VALUE_UPPERCASE /* Define to 1 if you have the `cfsetispeed' function. */ #undef HAVE_CFSETISPEED /* defined if standard library has, and C standard allows, the clock_gettime(clkid,ts) method */ #undef HAVE_CLOCK_GETTIME /* defined if standard library has, and C standard allows, the CLOCK_MONOTONIC macro or token */ #undef HAVE_CLOCK_MONOTONIC /* Define to enable CPPUNIT tests */ #undef HAVE_CPPUNIT /* Define to 1 if you have the header file. */ #undef HAVE_CSTDBOOL /* Define to enable C++11 support */ #undef HAVE_CXX11 /* Define to 1 if C supports variable-length arrays. */ #undef HAVE_C_VARARRAYS /* Define to 1 if you have the declaration of `fabs', and to 0 if you don't. */ #undef HAVE_DECL_FABS /* Define to 1 if you have the declaration of `fabsf', and to 0 if you don't. */ #undef HAVE_DECL_FABSF /* Define to 1 if you have the declaration of `fabsl', and to 0 if you don't. */ #undef HAVE_DECL_FABSL /* Define to 1 if you have the declaration of `gmtime_r', and to 0 if you don't. */ #undef HAVE_DECL_GMTIME_R /* Define to 1 if you have the declaration of `gmtime_s', and to 0 if you don't. */ #undef HAVE_DECL_GMTIME_S /* Define to 1 if you have the declaration of `i2c_smbus_access', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_ACCESS /* Define to 1 if you have the declaration of `i2c_smbus_read_block_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_READ_BLOCK_DATA /* Define to 1 if you have the declaration of `i2c_smbus_read_byte_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_READ_BYTE_DATA /* Define to 1 if you have the declaration of `i2c_smbus_read_word_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_READ_WORD_DATA /* Define to 1 if you have the declaration of `i2c_smbus_write_byte_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_WRITE_BYTE_DATA /* Define to 1 if you have the declaration of `i2c_smbus_write_word_data', and to 0 if you don't. */ #undef HAVE_DECL_I2C_SMBUS_WRITE_WORD_DATA /* Define to 1 if you have the declaration of `localtime_r', and to 0 if you don't. */ #undef HAVE_DECL_LOCALTIME_R /* Define to 1 if you have the declaration of `localtime_s', and to 0 if you don't. */ #undef HAVE_DECL_LOCALTIME_S /* Define to 1 if you have the declaration of `LOG_UPTO', and to 0 if you don't. */ #undef HAVE_DECL_LOG_UPTO /* Define to 1 if you have the declaration of `optind', and to 0 if you don't. */ #undef HAVE_DECL_OPTIND /* Define to 1 if you have the declaration of `pow10', and to 0 if you don't. */ #undef HAVE_DECL_POW10 /* Define to 1 if you have the declaration of `realpath', and to 0 if you don't. */ #undef HAVE_DECL_REALPATH /* Define to 1 if you have the declaration of `regcomp', and to 0 if you don't. */ #undef HAVE_DECL_REGCOMP /* Define to 1 if you have the declaration of `regexec', and to 0 if you don't. */ #undef HAVE_DECL_REGEXEC /* Define to 1 if you have the declaration of `round', and to 0 if you don't. */ #undef HAVE_DECL_ROUND /* Define to 1 if you have the declaration of `timegm', and to 0 if you don't. */ #undef HAVE_DECL_TIMEGM /* Define to 1 if you have the declaration of `uu_lock', and to 0 if you don't. */ #undef HAVE_DECL_UU_LOCK /* Define to 1 if you have the declaration of `_mkgmtime', and to 0 if you don't. */ #undef HAVE_DECL__MKGMTIME /* Define to 1 if you have the declaration of `__FUNCTION__', and to 0 if you don't. */ #undef HAVE_DECL___FUNCTION__ /* Define to 1 if you have the declaration of `__func__', and to 0 if you don't. */ #undef HAVE_DECL___FUNC__ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the `dup' function. */ #undef HAVE_DUP /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `fcvt' function. */ #undef HAVE_FCVT /* Define to 1 if you have the `fcvtl' function. */ #undef HAVE_FCVTL /* Define to 1 if you have the `fileno' function. */ #undef HAVE_FILENO /* Define to 1 if you have . */ #undef HAVE_FLOAT_H /* Define to 1 if you have the `flock' function. */ #undef HAVE_FLOCK /* Define if FreeIPMI support is available */ #undef HAVE_FREEIPMI /* Define if FreeIPMI 1.1.X / 1.2.X support is available */ #undef HAVE_FREEIPMI_11X_12X /* Define to 1 if you have the header file. */ #undef HAVE_FREEIPMI_FREEIPMI_H /* Define if FreeIPMI monitoring support is available */ #undef HAVE_FREEIPMI_MONITORING /* Define to 1 if you have the header file. */ #undef HAVE_GDFONTMB_H /* Define to 1 if you have the header file. */ #undef HAVE_GD_H /* defined if system has the GetAdaptersAddresses() method */ #undef HAVE_GETADAPTERSADDRESSES /* defined if system has the GetAdaptersInfo() method */ #undef HAVE_GETADAPTERSINFO /* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define to 1 if you have the `getopt_long' function. */ #undef HAVE_GETOPT_LONG /* Define to 1 if you have the `getpassphrase' function. */ #undef HAVE_GETPASSPHRASE /* Define to 1 if you have the `gmtime_r' function. */ #undef HAVE_GMTIME_R /* Define to 1 if you have the `gmtime_s' function. */ #undef HAVE_GMTIME_S /* Define to 1 if you have the `gpiod_chip_close' function. */ #undef HAVE_GPIOD_CHIP_CLOSE /* Define to 1 if you have the `gpiod_chip_open' function. */ #undef HAVE_GPIOD_CHIP_OPEN /* Define to 1 if you have the `gpiod_chip_open_by_name' function. */ #undef HAVE_GPIOD_CHIP_OPEN_BY_NAME /* Define to 1 if you have the header file. */ #undef HAVE_GPIOD_H /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H /* defined if system has the inet_ntop() method */ #undef HAVE_INET_NTOP /* defined if system has the inet_pton() method */ #undef HAVE_INET_PTON /* Define to 1 if you have the `init_snmp' function. */ #undef HAVE_INIT_SNMP /* Define to 1 if the system has the type `intmax_t'. */ #undef HAVE_INTMAX_T /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the iphlpapi.h header file. */ #undef HAVE_IPHLPAPI_H /* Define to 1 if you have the header file. */ #undef HAVE_IPMI_MONITORING_H /* Define if you have Boutell's libgd installed */ #undef HAVE_LIBGD /* Define to enable libltdl support */ #undef HAVE_LIBLTDL /* Define to 1 if you have the header file. */ #undef HAVE_LIBPOWERMAN_H /* Define to 1 for build where we can support general regex matching. */ #undef HAVE_LIBREGEX /* Define to 1 if you have the `libusb_detach_kernel_driver' function. */ #undef HAVE_LIBUSB_DETACH_KERNEL_DRIVER /* Define to 1 if you have the `libusb_detach_kernel_driver_np' function. */ #undef HAVE_LIBUSB_DETACH_KERNEL_DRIVER_NP /* Define to 1 if you have the `libusb_get_port_number' function. */ #undef HAVE_LIBUSB_GET_PORT_NUMBER /* Define to 1 if you have the header file. */ #undef HAVE_LIBUSB_H /* Define to 1 if you have the `libusb_init' function. */ #undef HAVE_LIBUSB_INIT /* Define to 1 if you have the `libusb_kernel_driver_active' function. */ #undef HAVE_LIBUSB_KERNEL_DRIVER_ACTIVE /* Define to 1 if you have the `libusb_set_auto_detach_kernel_driver' function. */ #undef HAVE_LIBUSB_SET_AUTO_DETACH_KERNEL_DRIVER /* Define to 1 if you have the `libusb_strerror' function. */ #undef HAVE_LIBUSB_STRERROR /* defined if we have libs, includes and methods for BSD KVM process info */ #undef HAVE_LIB_BSD_KVM_PROC /* defined if we have libs, includes and methods for Solaris/illumos process info */ #undef HAVE_LIB_ILLUMOS_PROC /* Define to 1 if you have . */ #undef HAVE_LIMITS_H /* Define to 1 if you have . */ #undef HAVE_LINUX_I2C_DEV_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_SERIAL_H /* Define to 1 if you have . */ #undef HAVE_LINUX_SMBUS_H /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have the `localtime_s' function. */ #undef HAVE_LOCALTIME_S /* Define to 1 if you have the `lockf' function. */ #undef HAVE_LOCKF /* Define to 1 if the system has the type `long double'. */ #undef HAVE_LONG_DOUBLE /* Define to 1 if the system has the type `long long int'. */ #undef HAVE_LONG_LONG_INT /* Define to 1 if you have the header file. */ #undef HAVE_LTDL_H /* Define to 1 if you have the header file. */ #undef HAVE_LUSB0_USB_H /* Define to 1 if you have . */ #undef HAVE_MATH_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_MODBUS_H /* Define to 1 if you have the `modbus_new_rtu' function. */ #undef HAVE_MODBUS_NEW_RTU /* Define to 1 if you have the `modbus_new_rtu_usb' function. */ #undef HAVE_MODBUS_NEW_RTU_USB /* Define to 1 if you have the `modbus_new_tcp' function. */ #undef HAVE_MODBUS_NEW_TCP /* Define to 1 if you have the `modbus_set_byte_timeout' function. */ #undef HAVE_MODBUS_SET_BYTE_TIMEOUT /* Define to 1 if you have the `modbus_set_response_timeout' function. */ #undef HAVE_MODBUS_SET_RESPONSE_TIMEOUT /* 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 to 1 if you have the header file. */ #undef HAVE_NET_IF_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_SNMP_NET_SNMP_CONFIG_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_SNMP_NET_SNMP_INCLUDES_H /* Define to 1 if you have the `ne_set_connect_timeout' function. */ #undef HAVE_NE_SET_CONNECT_TIMEOUT /* Define to 1 if you have the `ne_sock_connect_timeout' function. */ #undef HAVE_NE_SOCK_CONNECT_TIMEOUT /* Define to 1 if you have the header file. */ #undef HAVE_NE_XMLREQ_H /* Define to 1 if you have the `ne_xml_dispatch_request' function. */ #undef HAVE_NE_XML_DISPATCH_REQUEST /* Define to 1 if you have the header file. */ #undef HAVE_NSS_H /* Define to 1 if you have the `NSS_Init' function. */ #undef HAVE_NSS_INIT /* Define to 1 if you have the `on_exit' function. */ #undef HAVE_ON_EXIT /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define to 1 if you have the `pm_connect' function. */ #undef HAVE_PM_CONNECT /* Define to 1 if you have . */ #undef HAVE_POLL_H /* define if your compiler has pragmas for GCC diagnostic ignored "-Wc++98-compat(-pedantic)" and for push-pop support */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT /* define if your compiler has pragmas for GCC diagnostic ignored "-Wc++98-compat(-pedantic)" and for push-pop support (outside function bodies) */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_BESIDEFUNC /* define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-nonliteral" or "-Wformat-security" and for push-pop support */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL /* define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-nonliteral" or "-Wformat-security" and for push-pop support (outside function bodies) */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL_BESIDEFUNC /* define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-truncation" or "-Werror=stringop-truncation" and for push-pop support */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION /* define if your compiler has pragmas for GCC diagnostic ignored "-Wformat-truncation" or "-Werror=stringop-truncation" and for push-pop support (outside function bodies) */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION_BESIDEFUNC /* define if your compiler has pragmas for GCC diagnostic ignored "-Wunreachable-code(-break)" and for push-pop support */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE /* define if your compiler has pragmas for GCC diagnostic ignored "-Wunreachable-code(-break)" and for push-pop support (outside function bodies) */ #undef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BESIDEFUNC /* define if your compiler has #pragma clang diagnostic ignored "-Wdeprecated-declarations" */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS /* define if your compiler has #pragma clang diagnostic ignored "-Wdeprecated-declarations" (outside functions) */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS_BESIDEFUNC /* define if your compiler has #pragma clang diagnostic ignored "-Wunreachable-code-return" */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN /* define if your compiler has #pragma clang diagnostic ignored "-Wunreachable-code-return" (outside functions) */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN_BESIDEFUNC /* define if your compiler has #pragma clang diagnostic push and pop */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP /* define if your compiler has #pragma clang diagnostic push and pop outside function bodies */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP_BESIDEFUNC /* define if your compiler has #pragma clang diagnostic push and pop inside function bodies */ #undef HAVE_PRAGMA_CLANG_DIAGNOSTIC_PUSH_POP_INSIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Waddress" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ADDRESS /* define if your compiler has #pragma GCC diagnostic ignored "-Waddress" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ADDRESS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Warray-bounds" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ARRAY_BOUNDS /* define if your compiler has #pragma GCC diagnostic ignored "-Warray-bounds" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ARRAY_BOUNDS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wassign-enum" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM /* define if your compiler has #pragma GCC diagnostic ignored "-Wassign-enum" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ASSIGN_ENUM_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wcast-align" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN /* define if your compiler has #pragma GCC diagnostic ignored "-Wcast-align" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_ALIGN_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wcast-function-type-strict" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT /* define if your compiler has #pragma GCC diagnostic ignored "-Wcast-function-type-strict" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wcovered-switch-default" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT /* define if your compiler has #pragma GCC diagnostic ignored "-Wcovered-switch-default" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT /* define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_PEDANTIC /* define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_PEDANTIC_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wdeprecated-declarations" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DECLARATIONS /* define if your compiler has #pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_DEPRECATED_DYNAMIC_EXCEPTION_SPEC_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wexit-time-destructors" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS /* define if your compiler has #pragma GCC diagnostic ignored "-Wexit-time-destructors" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wextra-semi" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wextra-semi-stmt" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT /* define if your compiler has #pragma GCC diagnostic ignored "-Wextra-semi-stmt" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXTRA_SEMI_STMT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-nonliteral" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-nonliteral" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-overflow" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-overflow" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-security" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-security" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-truncation" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION /* define if your compiler has #pragma GCC diagnostic ignored "-Wformat-truncation" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_TRUNCATION_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wglobal-constructors" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS /* define if your compiler has #pragma GCC diagnostic ignored "-Wglobal-constructors" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_MAYBE_UNINITIALIZED /* define if your compiler has #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_MAYBE_UNINITIALIZED_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wold-style-cast" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_OLD_STYLE_CAST_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wpedantic" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_PEDANTIC /* define if your compiler has #pragma GCC diagnostic ignored "-Wpedantic" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_PEDANTIC_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wsign-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wsign-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wsign-conversion" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_CONVERSION /* define if your compiler has #pragma GCC diagnostic ignored "-Wsign-conversion" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SIGN_CONVERSION_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wstrict-prototypes" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES /* define if your compiler has #pragma GCC diagnostic ignored "-Wstrict-prototypes" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wstringop-truncation" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRINGOP_TRUNCATION /* define if your compiler has #pragma GCC diagnostic ignored "-Wstringop-truncation" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRINGOP_TRUNCATION_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wsuggest-destructor-override" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_DESTRUCTOR_OVERRIDE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wsuggest-override" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_SUGGEST_OVERRIDE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-type-limit-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_TYPE_LIMIT_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE /* define if your compiler has #pragma GCC diagnostic ignored "-Wtautological-unsigned-zero-compare" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_UNSIGNED_ZERO_COMPARE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wtype-limits" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS /* define if your compiler has #pragma GCC diagnostic ignored "-Wtype-limits" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-break" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-break" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_BREAK_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-return" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN /* define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code-return" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE_RETURN_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wunused-function" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNUSED_FUNCTION /* define if your compiler has #pragma GCC diagnostic ignored "-Wunused-parameter" */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNUSED_PARAMETER /* define if your compiler has #pragma GCC diagnostic ignored "-Wweak-vtables" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_WEAK_VTABLES_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" (outside functions) */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_ZERO_AS_NULL_POINTER_CONSTANT_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic push and pop */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP /* define if your compiler has #pragma GCC diagnostic push and pop outside function bodies */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC /* define if your compiler has #pragma GCC diagnostic push and pop inside function bodies */ #undef HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_INSIDEFUNC /* Define to enable pthread support code */ #undef HAVE_PTHREAD /* Define to enable pthread_tryjoin support code */ #undef HAVE_PTHREAD_TRYJOIN /* Define to 1 if you have the `readlink' function. */ #undef HAVE_READLINK /* Define to 1 if you have . */ #undef HAVE_REGEX_H /* Define to 1 if you have the `sd_booted' function. */ #undef HAVE_SD_BOOTED /* Define to 1 if you have the `sd_bus_call_method' function. */ #undef HAVE_SD_BUS_CALL_METHOD /* Define to 1 if you have the `sd_bus_default_system' function. */ #undef HAVE_SD_BUS_DEFAULT_SYSTEM /* Define to 1 if you have the `sd_bus_error_free' function. */ #undef HAVE_SD_BUS_ERROR_FREE /* Define to 1 if you have the `sd_bus_flush_close_unref' function. */ #undef HAVE_SD_BUS_FLUSH_CLOSE_UNREF /* Define to 1 if you have the `sd_bus_get_property_trivial' function. */ #undef HAVE_SD_BUS_GET_PROPERTY_TRIVIAL /* Define to 1 if you have the `sd_bus_message_read_basic' function. */ #undef HAVE_SD_BUS_MESSAGE_READ_BASIC /* Define to 1 if you have the `sd_bus_message_unref' function. */ #undef HAVE_SD_BUS_MESSAGE_UNREF /* Define to 1 if you have the `sd_bus_open_system' function. */ #undef HAVE_SD_BUS_OPEN_SYSTEM /* Define to 1 if you have the `sd_bus_open_system_with_description' function. */ #undef HAVE_SD_BUS_OPEN_SYSTEM_WITH_DESCRIPTION /* Define to 1 if you have the `sd_bus_set_description' function. */ #undef HAVE_SD_BUS_SET_DESCRIPTION /* Define to 1 if you have the `sd_notify' function. */ #undef HAVE_SD_NOTIFY /* Define to 1 if you have the `sd_notify_barrier' function. */ #undef HAVE_SD_NOTIFY_BARRIER /* Define to 1 if you have the `sd_watchdog_enabled' function. */ #undef HAVE_SD_WATCHDOG_ENABLED /* Define to 1 if you have . */ #undef HAVE_SEMAPHORE_H /* Define to 1 if you have with usable sem_t, sem_open() and sem_close() for named semaphores. */ #undef HAVE_SEMAPHORE_NAMED /* Define to 1 if you have with usable sem_t, sem_init() and sem_destroy() for unnamed semaphores. */ #undef HAVE_SEMAPHORE_UNNAMED /* Define to 1 if you have the `setenv' function. */ #undef HAVE_SETENV /* Define to 1 if you have the `seteuid' function. */ #undef HAVE_SETEUID /* Define to 1 if you have the `setlogmask' function. */ #undef HAVE_SETLOGMASK /* Define to 1 if you have the `setsid' function. */ #undef HAVE_SETSID /* Define to 1 if you have the `sigaction' function. */ #undef HAVE_SIGACTION /* Define to 1 if you have the `sigemptyset' function. */ #undef HAVE_SIGEMPTYSET /* Define to 1 if you have . */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the `SSL_CTX_new' function. */ #undef HAVE_SSL_CTX_NEW /* Define to 1 if you have the header file. */ #undef HAVE_SSL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if you have the header file. */ #undef HAVE_STDBOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have . */ #undef HAVE_STDLIB_H /* defined if standard library has, and C standard allows, the strcasecmp(s1,s2) method */ #undef HAVE_STRCASECMP /* defined if standard library has, and C standard allows, the strcasestr(s1,s2) method */ #undef HAVE_STRCASESTR /* defined if standard library has, and C standard allows, the strdup(s) method */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have . */ #undef HAVE_STRINGS_H /* Define to 1 if you have . */ #undef HAVE_STRING_H /* defined if standard library has, and C standard allows, the strlwr(s1,s2) method */ #undef HAVE_STRLWR /* defined if standard library has, and C standard allows, the strncasecmp(s1,s2,n) method */ #undef HAVE_STRNCASECMP /* defined if standard library has, and C standard allows, the strnlen(s1,s2) method */ #undef HAVE_STRNLEN /* defined if standard library has, and C standard allows, the strptime(s1,s2,tm) method */ #undef HAVE_STRPTIME /* defined if standard library has, and C standard allows, the strsep(s1,s2) method */ #undef HAVE_STRSEP /* defined if standard library has, and C standard allows, the strstr(s1,s2) method */ #undef HAVE_STRSTR /* Define to 1 if you have the `strtof' function. */ #undef HAVE_STRTOF /* Define to 1 if you have the `strtok_r' function. */ #undef HAVE_STRTOK_R /* defined if system has the struct pollfd type */ #undef HAVE_STRUCT_POLLFD /* defined if standard library has, and C standard allows, the suseconds_t type */ #undef HAVE_SUSECONDS_T /* Define to consider basic systemd support (provide units and configuration files) */ #undef HAVE_SYSTEMD /* Define to 1 if you have the header file. */ #undef HAVE_SYSTEMD_SD_BUS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYSTEMD_SD_DAEMON_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MODEM_H /* Define to 1 if you have with usable struct rlimit and getrlimit(). */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have . */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have . */ #undef HAVE_SYS_SIGNAL_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_TERMIOS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TCPD_H /* Define to 1 if you have the `tcsendbreak' function. */ #undef HAVE_TCSENDBREAK /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H /* Define to 1 if you have the `timegm' function. */ #undef HAVE_TIMEGM /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if the system has the type `uintmax_t'. */ #undef HAVE_UINTMAX_T /* Define to 1 if you have . */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `unsetenv' function. */ #undef HAVE_UNSETENV /* Define to 1 if the system has the type `unsigned long long int'. */ #undef HAVE_UNSIGNED_LONG_LONG_INT /* Define to 1 if you have the `usb_detach_kernel_driver_np' function. */ #undef HAVE_USB_DETACH_KERNEL_DRIVER_NP /* Define to 1 if you have the header file. */ #undef HAVE_USB_H /* Define to 1 if you have the `usb_init' function. */ #undef HAVE_USB_INIT /* defined if standard library has, and C standard allows, the useconds_t type */ #undef HAVE_USECONDS_T /* defined if standard library has, and C standard allows, the usleep(us) method */ #undef HAVE_USLEEP /* Use uu_lock for locking (FreeBSD) */ #undef HAVE_UU_LOCK /* Define to 1 if you have the header file. */ #undef HAVE_VARARGS_H /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* Define to 1 if you have the windows.h header file. */ #undef HAVE_WINDOWS_H /* Define to 1 if you have the header file. */ #undef HAVE_WINSOCK2_H /* Define to enable libwrap support */ #undef HAVE_WRAP /* Define to 1 if you have the header file. */ #undef HAVE_WS2TCPIP_H /* Boolean type ${FOUND__BOOL_TYPE} is defined as an enum with specific values allowed */ #undef HAVE__BOOL_IMPLEM_ENUM /* Boolean type ${FOUND__BOOL_TYPE} is defined as a general-purpose number type (int) */ #undef HAVE__BOOL_IMPLEM_INT /* Boolean values of ${FOUND__BOOL_TYPE} are defined as a preprocessor macro (type/implem is questionable) */ #undef HAVE__BOOL_IMPLEM_MACRO /* Name of ${FOUND__BOOL_TYPE} is defined as camel-case token */ #undef HAVE__BOOL_TYPE_CAMELCASE /* Name of ${FOUND__BOOL_TYPE} is defined as lower-case token */ #undef HAVE__BOOL_TYPE_LOWERCASE /* Name of ${FOUND__BOOL_TYPE} is defined as upper-case token */ #undef HAVE__BOOL_TYPE_UPPERCASE /* Boolean values of ${FOUND__BOOL_TYPE} are defined as camel-case tokens */ #undef HAVE__BOOL_VALUE_CAMELCASE /* Boolean values of ${FOUND__BOOL_TYPE} are defined as lower-case tokens */ #undef HAVE__BOOL_VALUE_LOWERCASE /* Boolean values of ${FOUND__BOOL_TYPE} are defined as upper-case tokens */ #undef HAVE__BOOL_VALUE_UPPERCASE /* Define to 1 if you have the `_mkgmtime' function. */ #undef HAVE__MKGMTIME /* define if your compiler has __attribute__ */ #undef HAVE___ATTRIBUTE__ /* define if your compiler has __attribute__((noreturn)) */ #undef HAVE___ATTRIBUTE__NORETURN /* define if your compiler has __attribute__((unused)) for function arguments */ #undef HAVE___ATTRIBUTE__UNUSED_ARG /* define if your compiler has __attribute__((unused)) for functions */ #undef HAVE___ATTRIBUTE__UNUSED_FUNC /* Default path for HTML files (CGI templates) */ #undef HTMLPATH /* Default path for system libraries */ #undef LIBDIR /* Default path for system exec-libraries */ #undef LIBEXECDIR /* Desired syslog facility - see syslog(3) */ #undef LOG_FACILITY /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* man page section for library APIs */ #undef MAN_SECTION_API /* base (number only) man page section for library APIs */ #undef MAN_SECTION_API_BASE /* man page section for configuration files */ #undef MAN_SECTION_CFG /* base (number only) man page section for configuration files */ #undef MAN_SECTION_CFG_BASE /* man page section for system management commands */ #undef MAN_SECTION_CMD_SYS /* base (number only) man page section for system management commands */ #undef MAN_SECTION_CMD_SYS_BASE /* man page section for user commands */ #undef MAN_SECTION_CMD_USR /* base (number only) man page section for user commands */ #undef MAN_SECTION_CMD_USR_BASE /* host multiarch spec we build for (as suggested by compiler being used) */ #undef MULTIARCH_TARGET_ALIAS /* Define to use explicit getopt declarations */ #undef NEED_GETOPT_DECLS /* Define if getopt.h is needed */ #undef NEED_GETOPT_H /* Default path for data files */ #undef NUT_DATADIR /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_DRAFT_BLUMENTHAL_AES_04 /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmAES128PrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmAES192PrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmAES256PrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmAESPrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmDESPrivProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMAC192SHA256AuthProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMAC256SHA384AuthProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMAC384SHA512AuthProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMACMD5AuthProtocol /* Variable or macro by this name is not resolvable */ #undef NUT_HAVE_LIBNETSNMP_usmHMACSHA1AuthProtocol /* Default path for man page files */ #undef NUT_MANDIR /* Define to use libmodbus USB backend */ #undef NUT_MODBUS_HAS_USB /* Define to let the libmodbus linking type be known for troubleshooting */ #undef NUT_MODBUS_LINKTYPE_STR /* ${COMMENT} */ #undef NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32 /* ${COMMENT} */ #undef NUT_MODBUS_TIMEOUT_ARG_sec_usec_uint32_cast_timeval_fields /* ${COMMENT} */ #undef NUT_MODBUS_TIMEOUT_ARG_timeval /* ${COMMENT} */ #undef NUT_MODBUS_TIMEOUT_ARG_timeval_numeric_fields /* NUT network protocol version */ #undef NUT_NETVERSION /* Documentation website base URL, no trailing slash */ #undef NUT_WEBSITE_BASE /* Name of package */ #undef PACKAGE /* 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 home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Path for pid files of processes running as root */ #undef PIDPATH /* Port for network communications */ #undef PORT /* Default installation prefix path */ #undef PREFIX /* Define to 0 if your libc can printf("%s", NULL) sanely, or to 1 if your libc requires workarounds to print NULL values. */ #undef REQUIRE_NUT_STRARG /* Group membership of user to switch to if started as root */ #undef RUN_AS_GROUP /* User to switch to if started as root */ #undef RUN_AS_USER /* Default path for system executables */ #undef SBINDIR /* The size of `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P /* Base file name of dynamic library on build system */ #undef SOFILE_LIBAVAHI /* Base file name of dynamic library on build system */ #undef SOFILE_LIBFREEIPMI /* Base file name of dynamic library on build system */ #undef SOFILE_LIBNEON /* Base file name of dynamic library on build system */ #undef SOFILE_LIBNETSNMP /* Base file name of dynamic library on build system */ #undef SOFILE_LIBUSB0 /* Base file name of dynamic library on build system */ #undef SOFILE_LIBUSB1 /* Path to dynamic library on build system */ #undef SOPATH_LIBAVAHI /* Path to dynamic library on build system */ #undef SOPATH_LIBFREEIPMI /* Path to dynamic library on build system */ #undef SOPATH_LIBNEON /* Path to dynamic library on build system */ #undef SOPATH_LIBNETSNMP /* Path to dynamic library on build system */ #undef SOPATH_LIBUSB0 /* Path to dynamic library on build system */ #undef SOPATH_LIBUSB1 /* Path for UPS driver state files */ #undef STATEPATH /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 for Sun version of the libusb. */ #undef SUN_LIBUSB /* Define to 1 if you can safely include both and . This macro is deemed obsolete by autotools. */ #undef TIME_WITH_SYS_TIME /* NUT tree version */ #undef TREE_VERSION /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Version number of package */ #undef VERSION /* Defined if we want to use timegm_fallback() */ #undef WANT_TIMEGM_FALLBACK /* Define if WSAStartup is needed. */ #undef WINDOWS_SOCKETS /* Define to enable Asciidoc support */ #undef WITH_ASCIIDOC /* Define to enable Avahi support */ #undef WITH_AVAHI /* Define to enable CGI (HTTP) support */ #undef WITH_CGI /* Define to enable development files support */ #undef WITH_DEV /* Define to enable delivery of libnutconf developer files */ #undef WITH_DEV_LIBNUTCONF /* Define to enable overall documentation generation */ #undef WITH_DOCS /* Define to enable IPMI support using FreeIPMI */ #undef WITH_FREEIPMI /* Define to enable GPIO support */ #undef WITH_GPIO /* Define to enable IPMI support */ #undef WITH_IPMI /* Define libgpio C API version generation */ #undef WITH_LIBGPIO_VERSION /* Define libgpio C API version generation as string */ #undef WITH_LIBGPIO_VERSION_STR /* Define to enable libltdl (Libtool dlopen abstraction) support */ #undef WITH_LIBLTDL /* Define to enable Powerman PDU support */ #undef WITH_LIBPOWERMAN /* Define to build with tighter systemd support (sd_notify etc) */ #undef WITH_LIBSYSTEMD /* Define as 1 if we can use systemd inhibitor interface here */ #undef WITH_LIBSYSTEMD_INHIBITOR /* Define to 1 for version 0.1 of the libusb (via pkg-config or libusb-config). */ #undef WITH_LIBUSB_0_1 /* Define to 1 for version 1.0 of the libusb (via pkg-config). */ #undef WITH_LIBUSB_1_0 /* Define to enable I2C support */ #undef WITH_LINUX_I2C /* Define to enable Mac OS X meta-driver */ #undef WITH_MACOSX /* Define to enable Modbus support */ #undef WITH_MODBUS /* Define to enable Neon HTTP support */ #undef WITH_NEON /* Define to enable SSL support using Mozilla NSS */ #undef WITH_NSS /* Define to enable nutconf tool support */ #undef WITH_NUTCONF /* Define to enable NUT-Monitor desktop application installation */ #undef WITH_NUT_MONITOR /* Define to enable nut-scanner tool support */ #undef WITH_NUT_SCANNER /* Define to enable SSL support using OpenSSL */ #undef WITH_OPENSSL /* Define to enable PyNUT module installation */ #undef WITH_PYNUT /* Define to enable serial support */ #undef WITH_SERIAL /* Define to enable SNMP support */ #undef WITH_SNMP /* Define to use SNMP support with a statically linked libnetsnmp */ #undef WITH_SNMP_STATIC /* Define to consider basic SMF support (provide units and configuration files) */ #undef WITH_SOLARIS_SMF /* Define to enable SSL */ #undef WITH_SSL /* Define to enable data points discovered during subdriver generation but not mapped to nut-names yet */ #undef WITH_UNMAPPED_DATA_POINTS /* Define to enable USB support */ #undef WITH_USB /* Define to 1 for libusb versions where we can support "busport" USB matching value. */ #undef WITH_USB_BUSPORT /* Define to enable libwrap (tcp-wrappers) support */ #undef WITH_WRAP /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Define to 1 if on MINIX. */ #undef _MINIX /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE /* Define to 1 if you need to in order for `stat' and other things to work. */ #undef _POSIX_SOURCE /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Replace missing __func__ declaration */ #undef __func__ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef int16_t /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef int64_t /* Define to the type of a signed integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef int8_t /* Define to the widest signed integer type if and do not define. */ #undef intmax_t /* Define to `unsigned int' if does not define. */ #undef size_t /* type to use in place of socklen_t if not defined */ #undef socklen_t /* Define to `int' if does not define. */ #undef ssize_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t /* Define to the widest unsigned integer type if and do not define. */ #undef uintmax_t nut-2.8.3/include/str.h0000644000200500020050000001534414777767434011704 00000000000000/* str.h - Common string-related functions * * Copyright (C) * 2000 Russell Kroll * 2015 Daniele Pezzini * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef NUT_STR_H_SEEN #define NUT_STR_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* Some compilers and/or C libraries do not handle printf("%s", NULL) correctly */ #ifndef NUT_STRARG # if (defined REQUIRE_NUT_STRARG) && (REQUIRE_NUT_STRARG == 0) # define NUT_STRARG(x) (x) # else /* Is required, or not defined => err on safe side */ # define NUT_STRARG(x) (x?x:"(null)") # endif #endif /* Remove all * - leading and trailing (str_trim[_m]()) * - leading (str_ltrim[_m]()) * - trailing (str_rtrim[_m])) * instances of * - *character* (plain versions) * - each character in *characters* ('_m' versions) * from a string. * - *string*: null-terminated byte string from which characters are to be removed; * - *character*: character that has to be removed from *string*; * - *characters*: null-terminated byte string of characters to be removed from string. * Return: * - NULL, if *string* is NULL, otherwise * - *string* without the specified characters (upto an empty string). */ char *str_trim(char *string, const char character); char *str_trim_m(char *string, const char *characters); char *str_ltrim(char *string, const char character); char *str_ltrim_m(char *string, const char *characters); char *str_rtrim(char *string, const char character); char *str_rtrim_m(char *string, const char *characters); /* Remove all * - leading and trailing (str_trim_space()) * - leading (str_ltrim_space()) * - trailing (str_rtrim_space()) * spaces (as identified by isspace()) from a string. * - *string*: null-terminated byte string from which spaces are to be removed. * Return: * - NULL, if *string* is NULL, otherwise * - *string* without the specified spaces (upto an empty string). */ char *str_trim_space(char *string); char *str_ltrim_space(char *string); char *str_rtrim_space(char *string); /* Tell whether a string can be converted to a number of type str_is_[_strict](). * - *string*: the null-terminated byte string to check; * - *base*: the base the string must conform to. * The same restrictions of the corresponding str_to_[_strict]() functions apply. * If *string* can be converted to a valid number of type , return 1. * Otherwise, return 0 with errno set to: * - ENOMEM, if available memory is insufficient; * - EINVAL, if the value of *base* is not supported or no conversion could be performed; * - ERANGE, if the converted value would be out of the acceptable range of . */ int str_is_short(const char *string, const int base); int str_is_short_strict(const char *string, const int base); int str_is_ushort(const char *string, const int base); int str_is_ushort_strict(const char *string, const int base); int str_is_int(const char *string, const int base); int str_is_int_strict(const char *string, const int base); int str_is_uint(const char *string, const int base); int str_is_uint_strict(const char *string, const int base); int str_is_long(const char *string, const int base); int str_is_long_strict(const char *string, const int base); int str_is_ulong(const char *string, const int base); int str_is_ulong_strict(const char *string, const int base); int str_is_double(const char *string, const int base); int str_is_double_strict(const char *string, const int base); /* Convert a string to a number of type str_to_[_strict](). * - *string*: the null-terminated byte string to convert, * 'strict' versions' strings shall not contain spaces (as identified by isspace()), * - short, int, long: strtol()'s restrictions apply, * - ushort, uint, ulong: strtoul()'s restrictions apply, plus: * - plus ('+') and minus ('-') signs (and hence negative values) are not supported, * - double: strtod()'s restrictions apply, plus: * - infinity and nan are not supported, * - radix character (decimal point character) must be a period ('.'); * - *number*: a pointer to a that will be filled upon execution; * - *base*: the base the string must conform to, * - short, ushort, int, uint, long, ulong: acceptable values as in strtol()/strtoul(), * - double: 0 for auto-select, 10 or 16. * On success, return 1 with *number* being the result of the conversion of *string*. * On failure, return 0 with *number* being 0 and errno set to: * - ENOMEM, if available memory is insufficient; * - EINVAL, if the value of *base* is not supported or no conversion can be performed; * - ERANGE, if the converted value is out of the acceptable range of . */ int str_to_short(const char *string, short *number, const int base); int str_to_short_strict(const char *string, short *number, const int base); int str_to_ushort(const char *string, unsigned short *number, const int base); int str_to_ushort_strict(const char *string, unsigned short *number, const int base); int str_to_int(const char *string, int *number, const int base); int str_to_int_strict(const char *string, int *number, const int base); int str_to_uint(const char *string, unsigned int *number, const int base); int str_to_uint_strict(const char *string, unsigned int *number, const int base); int str_to_long(const char *string, long *number, const int base); int str_to_long_strict(const char *string, long *number, const int base); int str_to_ulong(const char *string, unsigned long *number, const int base); int str_to_ulong_strict(const char *string, unsigned long *number, const int base); int str_to_double(const char *string, double *number, const int base); int str_to_double_strict(const char *string, double *number, const int base); /* Return non-zero if string s ends exactly with suff * Note: s=NULL always fails the test; otherwise suff=NULL always matches */ int str_ends_with(const char *s, const char *suff); #ifndef HAVE_STRSEP /* Makefile should add the implem to libcommon(client).la */ char *strsep(char **stringp, const char *delim); #define HAVE_STRSEP 1 #endif #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_STR_H_SEEN */ nut-2.8.3/include/nut_bool.h0000644000200500020050000000741714777767434012717 00000000000000/* * nut_bool.h - Network UPS Tools boolean type definitions * which should ensure a "nut_bool_t" name with * lower-case values "true" and "false" * * Inspired by earlier efforts and numerous definitions in NUT codebase. * Copyright (C) 2024 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_BOOL_H_SEEN #define NUT_BOOL_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* "config.h" is generated by autotools and lacks a header guard, so * we use an unambiguously named macro we know we must have, as one. * It must be the first header: be sure to know all about system config. */ #ifndef NUT_NETVERSION # include "config.h" #endif /* See also https://en.cppreference.com/w/cpp/header/cstdbool for more * info about what should be available where per standard approach. */ #ifdef __cplusplus # if defined HAVE_CSTDBOOL_H || defined HAVE_CSTDBOOL # include # else # ifdef HAVE_STDBOOL_H # include # endif # endif #else /* plain C */ # ifdef HAVE_STDBOOL_H # include # endif #endif /* Is the goal achieved by the system headers or compiler itself, * so we can just alias to existing type and its values? */ #if defined __bool_true_false_are_defined && __bool_true_false_are_defined typedef bool nut_bool_t; #elif defined FOUND__BOOL_TYPE && defined HAVE__BOOL_VALUE_LOWERCASE typedef FOUND__BOOL_TYPE nut_bool_t; #elif defined FOUND_BOOL_TYPE && defined HAVE_BOOL_VALUE_LOWERCASE typedef FOUND_BOOL_TYPE nut_bool_t; #elif defined FOUND_BOOLEAN_TYPE && defined HAVE_BOOLEAN_VALUE_LOWERCASE typedef FOUND_BOOLEAN_TYPE nut_bool_t; #elif defined FOUND_BOOL_T_TYPE && defined HAVE_BOOL_T_VALUE_LOWERCASE typedef FOUND_BOOL_T_TYPE nut_bool_t; #else /* Need a new type; can we use an enum with lower-case values? */ # if (defined true && defined false) || defined HAVE__BOOL_VALUE_LOWERCASE || defined HAVE_BOOL_VALUE_LOWERCASE || defined HAVE_BOOLEAN_VALUE_LOWERCASE || defined HAVE_BOOL_T_VALUE_LOWERCASE /* Lower-case true/false are known */ # if defined FOUND__BOOL_TYPE /* Got a C99 built-in mandated by the standard */ typedef FOUND__BOOL_TYPE nut_bool_t; # else typedef int nut_bool_t; # endif # elif defined FOUND__BOOL_VALUE_TRUE && defined FOUND__BOOL_VALUE_FALSE typedef enum nut_bool_enum { false = FOUND__BOOL_VALUE_FALSE, true = FOUND__BOOL_VALUE_TRUE } nut_bool_t; # elif defined FOUND_BOOL_VALUE_TRUE && defined FOUND_BOOL_VALUE_FALSE typedef enum nut_bool_enum { false = FOUND_BOOL_VALUE_FALSE, true = FOUND_BOOL_VALUE_TRUE } nut_bool_t; # elif defined FOUND_BOOLEAN_VALUE_TRUE && defined FOUND_BOOLEAN_VALUE_FALSE typedef enum nut_bool_enum { false = FOUND_BOOLEAN_VALUE_FALSE, true = FOUND_BOOLEAN_VALUE_TRUE } nut_bool_t; # elif defined FOUND_BOOL_T_VALUE_TRUE && defined FOUND_BOOL_T_VALUE_FALSE typedef enum nut_bool_enum { false = FOUND_BOOL_T_VALUE_FALSE, true = FOUND_BOOL_T_VALUE_TRUE } nut_bool_t; # else typedef enum nut_bool_enum { false = 0, true = 1 } nut_bool_t; # endif #endif #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_BOOL_H_SEEN */ nut-2.8.3/include/timehead.h0000644000200500020050000000630014777767434012644 00000000000000/* timehead.h - from the autoconf docs: sanely include the right time headers everywhere Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2020-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_TIMEHEAD_H_SEEN #define NUT_TIMEHEAD_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #ifndef HAVE_STRPTIME /* Use fallback implementation provided in e.g. libcommon(client).la: */ char * strptime(const char *buf, const char *fmt, struct tm *tm); #endif #if !(defined HAVE_LOCALTIME_R && HAVE_LOCALTIME_R) && !(defined HAVE_DECL_LOCALTIME_R && HAVE_DECL_LOCALTIME_R) # if (defined HAVE_LOCALTIME_S && HAVE_LOCALTIME_S) || (defined HAVE_DECL_LOCALTIME_S && HAVE_DECL_LOCALTIME_S) /* A bit of a silly trick, but should help on MSYS2 builds it seems * errno_t localtime_s(struct tm *_Tm, const time_t *_Time) */ # define localtime_r(timer, buf) (localtime_s(buf, timer) ? NULL : buf) # else # include /* memcpy */ static inline struct tm *localtime_r( const time_t *timer, struct tm *buf ) { /* Note NUT_WIN32_INCOMPLETE : not thread-safe per se! */ struct tm *tmp = localtime (timer); memcpy(buf, tmp, sizeof(struct tm)); return buf; } # endif #endif #if !(defined HAVE_GMTIME_R && HAVE_GMTIME_R) && !(defined HAVE_DECL_GMTIME_R && HAVE_DECL_GMTIME_R) # if (defined HAVE_GMTIME_S && HAVE_GMTIME_S) || (defined HAVE_DECL_GMTIME_S && HAVE_DECL_GMTIME_S) /* See comment above */ # define gmtime_r(timer, buf) (gmtime_s(buf, timer) ? NULL : buf) # else # include /* memcpy */ static inline struct tm *gmtime_r( const time_t *timer, struct tm *buf ) { /* Note NUT_WIN32_INCOMPLETE : not thread-safe per se! */ struct tm *tmp = gmtime (timer); memcpy(buf, tmp, sizeof(struct tm)); return buf; } # endif #endif #if !(defined HAVE_TIMEGM && HAVE_TIMEGM) && !(defined HAVE_DECL_TIMEGM && HAVE_DECL_TIMEGM) # if (defined HAVE__MKGMTIME && HAVE__MKGMTIME) || (defined HAVE_DECL__MKGMTIME && HAVE_DECL__MKGMTIME) # define timegm(tm) _mkgmtime(tm) # else # ifdef WANT_TIMEGM_FALLBACK /* use an implementation from fallbacks in NUT codebase */ # define timegm(tm) timegm_fallback(tm) # else # error "No fallback implementation for timegm" # endif # endif #endif #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_TIMEHEAD_H_SEEN */ nut-2.8.3/include/nutconf.hpp0000644000200500020050000033606015001552635013061 00000000000000/* nutconf.hpp - Nut configuration file manipulation API Copyright (C) 2012 Eaton Author: Emilien Kia Copyright (C) 2024-2025 NUT Community Author: Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUTCONF_H_SEEN #define NUTCONF_H_SEEN 1 #include "nutstream.hpp" #include #include #include #include #include #include #include #include #include #include /* See include/common.h for details behind this */ #ifndef NUT_UNUSED_VARIABLE #define NUT_UNUSED_VARIABLE(x) (void)(x) #endif #ifdef __cplusplus namespace nut { class NutParser; class NutConfigParser; class DefaultConfigParser; class GenericConfigParser; /** * Helper to specify if a configuration variable is set or not. * In addition of its value. */ template class Settable { protected: Type _value; bool _set; std::string errMsg_ENOTSET()const { static const std::string msg = "Can not retrieve a Settable value of " "an instance that was not assigned yet " "(or was last known cleared)"; return msg; } public: Settable():_set(false){} Settable(const Settable& val):_value(val._value), _set(val._set){} Settable(const Type& val):_value(val), _set(true){} /* Avoid implicit copy/move operator declarations */ Settable(Settable&&) = default; Settable& operator=(const Settable&) = default; Settable& operator=(Settable&&) = default; bool set()const{return _set;} void clear(){_set = false;} operator const Type&()const #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (!set()) throw std::invalid_argument(errMsg_ENOTSET()); return _value; } operator Type&() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (!set()) throw std::invalid_argument(errMsg_ENOTSET()); return _value; } const Type& operator *()const #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (!set()) throw std::invalid_argument(errMsg_ENOTSET()); return _value; } Type& operator *() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (!set()) throw std::invalid_argument(errMsg_ENOTSET()); return _value; } Settable& operator=(const Type& val){_value = val; _set = true; return *this;} bool operator==(const Settable& val)const { if(!set() && !val.set()) return false; else return (set() && val.set() && _value==val._value); } bool operator==(const Type& val)const #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if(!set()) return false; else try { #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_MAYBE_UNINITIALIZED) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif // some compilers are concerned that Settable._value // may be queried as un-initialized here (for equality) // but we are supposed to rule that out with "if set()"... return _value == val; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_MAYBE_UNINITIALIZED) #pragma GCC diagnostic pop #endif } catch(...) { throw std::invalid_argument(errMsg_ENOTSET()); } } }; /** * \brief Serialisable interface * * Classes that implement this interface provide way to serialize * and deserialize instances to/from streams. */ class Serialisable { protected: /** Formal constructor */ Serialisable() {} public: /** * \brief Deserializer * * \param istream Input stream * * \retval true in case of success * \retval false in case of read error */ virtual bool parseFrom(NutStream & istream) = 0; /** * \brief Serializer * * \param ostream Output stream * * \retval true in case of success * \retval false in case of write error */ virtual bool writeTo(NutStream & ostream) const = 0; /** Destructor */ virtual ~Serialisable(); }; // end of class Serialisable /** * \brief Mix a boolean (yes/no) or wider integer range */ class BoolInt { private: Settable b; Settable i; public: /** If set, its value specifies if we want i==0/1 to mean false/true * in value-equality and type-cast operators for int and bool types. * NOTE: If true, assignment from "0" and "1" strings sets the int * not bool stored value representation! * NOTE: Survives the clear() call which applies to stored value, * but would be reset by assignment from another BoolInt object. */ Settable bool01; /** Leave all contents un-set */ BoolInt() { clearWithBool01(); } BoolInt(const bool val) { *this = val; } BoolInt(const bool val, bool newBool01) { this->bool01 = newBool01; *this = val; } BoolInt(const int val) { *this = val; } BoolInt(const int val, bool newBool01) { this->bool01 = newBool01; *this = val; } BoolInt(const char* val) { *this = val; } BoolInt(const char* val, bool newBool01) { this->bool01 = newBool01; *this = val; } BoolInt(const std::string &val) { *this = val; } BoolInt(const std::string &val, bool newBool01) { this->bool01 = newBool01; *this = val; } BoolInt(const BoolInt& other) { *this = other; } BoolInt(const BoolInt& other, bool newBool01) { this->bool01 = newBool01; *this = other; this->bool01 = newBool01; } inline void clear() { i = 0; b = false; i.clear(); b.clear(); } inline void clearWithBool01() { clear(); bool01 = false; bool01.clear(); } inline BoolInt& operator=(const BoolInt& other) { clearWithBool01(); if (other.b.set()) b = other.b; if (other.i.set()) i = other.i; if (other.bool01.set()) bool01 = other.bool01; return *this; } inline BoolInt& operator=(BoolInt&& other) { clearWithBool01(); if (other.b.set()) b = other.b; if (other.i.set()) i = other.i; if (other.bool01.set()) bool01 = other.bool01; return *this; } inline BoolInt& operator=(int val) { clear(); i = val; return *this; } inline BoolInt& operator=(bool val) { clear(); b = val; return *this; } inline BoolInt& operator=(const char* s) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (!s) throw std::invalid_argument( "BoolInt value from string is is not supported"); std::string src(s); return (*this = src); } inline BoolInt& operator=(std::string src) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { static const Settable b0(false); static const Settable b1(true); // NOTE: Not a pointer, is not null at least if (src.empty()) throw std::invalid_argument( "BoolInt value from string is is not supported"); clear(); if ("false" == src) { b = b0; return *this; } if ("off" == src) { b = b0; return *this; } if ("0" == src) { if (bool01.set() && bool01 == false) { i = 0; } else { b = b0; } return *this; } if ("no" == src) { b = b0; return *this; } if ("true" == src) { b = b1; return *this; } if ("on" == src) { b = b1; return *this; } if ("1" == src) { if (bool01.set() && bool01 == false) { i = 1; } else { b = b1; } return *this; } if ("yes" == src) { b = b1; return *this; } if ("ok" == src) { b = b1; return *this; } std::stringstream ss(src); int result; if (ss >> result && ss.rdbuf()->in_avail() == 0) { // Conversion succeeded and all chars were read // (e.g. not a decimal number) i = result; #ifdef DEBUG std::cerr << "BoolInt assigned from '" << src << "': got int '" << result << "'" << " stream empty? " << ss.rdbuf()->in_avail() << std::endl; #endif return *this; } throw std::invalid_argument("BoolInt value from '" + src + "' string not understood as bool nor int"); } inline BoolInt& operator<<(bool other) { *this = other; return *this; } inline BoolInt& operator<<(int other) { *this = other; return *this; } inline BoolInt& operator<<(std::string other) { *this = other; return *this; } inline BoolInt& operator<<(const char* other) { *this = other; return *this; } inline bool operator==(const BoolInt& other)const { // Either direct values are set and then equal; optionally // else numeric values of int and bool are cross-equal. if (b.set() && other.b.set()) return (b == other.b); if (i.set() && other.i.set()) return (i == other.i); if ((bool01.set() && bool01 == true) || (!bool01.set() && other.bool01.set() && other.bool01 == true) ) { // false if at least one object has neither i nor b // values "set()", or if their numeric values do not // match up as 0 or 1 exactly vs. boolean values. #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_MAYBE_UNINITIALIZED) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif // some compilers are concerned that Settable._value // may be queried as un-initialized here (for 0/1 equality) // but we are supposed to rule that out with "if set()"... try { if (i.set() && other.b.set()) return ( (other.b && i == 1) || (!other.b && i == 0) ); } catch (...) {} try { if (b.set() && other.i.set()) return ( (b && other.i == 1) || (!b && other.i == 0) ); } catch (...) {} #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_MAYBE_UNINITIALIZED) #pragma GCC diagnostic pop #endif } return false; } inline bool operator==(const bool other)const { if (b.set()) return (b == other); if (bool01.set() && bool01 == true) { if (i.set()) return ((other && i == 1) || (!other && i == 0)); } return false; } inline bool operator==(const int other)const { if (i.set()) return (i == other); if (bool01.set() && bool01 == true) { if (b.set()) return ((b && other == 1) || (!b && other == 0)); } return false; } inline bool operator==(const std::string other)const { BoolInt tmp; if (bool01.set()) tmp.bool01 = bool01; tmp = other; return (*this == tmp); } inline bool operator==(const char* s)const { if (!s) return false; std::string src(s); return (*this == src); } inline bool set()const #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (i.set() && b.set()) throw std::invalid_argument( "BoolInt value somehow got both bool and int values set"); return (i.set() || b.set()); } operator int() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (i.set()) return i; if (bool01.set() && bool01 == true) { if (b.set()) { /** Cause use of operator to avoid warnings like * "may be used uninitialized in this function" */ if (b == true) return 1; return 0; } } else { throw std::invalid_argument( "BoolInt value not set to int"); } throw std::invalid_argument( "BoolInt value not set, neither to bool nor to int"); } operator bool() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (b.set()) return b; if (bool01.set() && bool01 == true) { if (i.set()) { if (i == 0) return false; if (i == 1) return true; } } else { throw std::invalid_argument( "BoolInt value not set to bool"); } throw std::invalid_argument( "BoolInt value not set, neither to bool nor to int"); } inline std::string toString()const #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { if (b.set()) { if (b == true) return "yes"; return "no"; } if (i.set()) { if (bool01.set() && bool01 == true) { if (i == 0) return "no"; if (i == 1) return "yes"; } std::ostringstream ss; ss << i; return ss.str(); } throw std::invalid_argument( "BoolInt value not set, neither to bool nor to int"); } // FIXME: `std::string s = bi;` just won't work // but we can use `s = bi.toString()` or `cout << bi` operator std::string()const { return this->toString(); } operator std::string&()const { return *(new std::string(this->operator std::string())); } }; std::ostream& operator << (std::ostream &os, const BoolInt &bi); inline std::ostream& operator << (std::ostream &os, const BoolInt &bi) { return (os << bi.toString()); } /** * \brief Certificate Identification structure for NUT * * Contains a certificate name and database password */ struct CertIdent { Settable certName, certDbPass; inline bool operator==(const CertIdent& ident)const { return certName == ident.certName && certDbPass == ident.certDbPass; } inline bool set()const { return certName.set() && certDbPass.set(); } }; /** * \brief Certificate protected host structure for NUT * * Contains a host name, certificate name and option flags */ struct CertHost { Settable host, certName; nut::BoolInt certVerify, forceSsl; inline bool operator==(const CertHost& other)const { return certName == other.certName && host == other.host && certVerify == other.certVerify && forceSsl == other.forceSsl; } inline bool set()const { return certName.set() && host.set() && certVerify.set() && forceSsl.set(); } }; /** * NUT config parser. */ class NutParser { public: enum ParsingOption { OPTION_DEFAULT = 0, /** Colon character is considered as string character and not as specific token. Useful for IPv6 addresses */ OPTION_IGNORE_COLON = 1 }; NutParser(const char* buffer = nullptr, unsigned int options = OPTION_DEFAULT); NutParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); virtual ~NutParser(); /** Parsing configuration functions * \{ */ void setOptions(unsigned int options){_options = options;} unsigned int getOptions()const{return _options;} void setOptions(unsigned int options, bool set = true); void unsetOptions(unsigned int options){setOptions(options, false);} bool hasOptions(unsigned int options)const{return (_options&options) == options;} /** \} */ struct Token { enum TokenType { TOKEN_UNKNOWN = -1, TOKEN_NONE = 0, TOKEN_STRING = 1, TOKEN_QUOTED_STRING, TOKEN_COMMENT, TOKEN_BRACKET_OPEN, TOKEN_BRACKET_CLOSE, TOKEN_EQUAL, TOKEN_COLON, TOKEN_EOL } type; std::string str; Token():type(TOKEN_NONE),str(){} Token(TokenType type_arg, const std::string& str_arg=""):type(type_arg),str(str_arg){} Token(TokenType type_arg, char c):type(type_arg),str(1, c){} Token(const Token& tok):type(tok.type),str(tok.str){} /* Avoid implicit copy/move operator declarations */ Token(Token&&) = default; Token& operator=(const Token&) = default; Token& operator=(Token&&) = default; bool is(TokenType type_arg)const{return this->type==type_arg;} bool operator==(const Token& tok)const{return tok.type==type && tok.str==str;} operator bool()const{return type!=TOKEN_UNKNOWN && type!=TOKEN_NONE;} }; /** Parsing functions * \{ */ std::string parseCHARS(); std::string parseSTRCHARS(); Token parseToken(); std::list parseLine(); /** \} */ #ifndef UNITEST_MODE protected: #endif /* UNITEST_MODE */ size_t getPos()const; void setPos(size_t pos); char charAt(size_t pos)const; void pushPos(); size_t popPos(); void rewind(); void back(); char get(); char peek(); private: unsigned int _options; std::string _buffer; size_t _pos; std::vector _stack; }; typedef std::list ConfigParamList; struct GenericConfigSectionEntry { std::string name; ConfigParamList values; // std::string comment; }; struct GenericConfigSection { /** Section entries map */ typedef std::map EntryMap; std::string name; // std::string comment; EntryMap entries; const GenericConfigSectionEntry& operator [] (const std::string& varname)const{return entries.find(varname)->second;} GenericConfigSectionEntry& operator [] (const std::string& varname){return entries[varname];} bool empty()const; void clear(); }; class BaseConfiguration { friend class GenericConfigParser; public: virtual ~BaseConfiguration(); protected: virtual void setGenericConfigSection(const GenericConfigSection& section) = 0; }; class NutConfigParser : public NutParser { public: virtual void parseConfig(); /* Declared for cleaner overrides; arg ignored in current class */ virtual void parseConfig(BaseConfiguration* config); protected: NutConfigParser(const char* buffer = nullptr, unsigned int options = OPTION_DEFAULT); NutConfigParser(const std::string& buffer, unsigned int options = OPTION_DEFAULT); virtual void onParseBegin()=0; virtual void onParseComment(const std::string& comment)=0; virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "")=0; virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "")=0; virtual void onParseEnd()=0; }; class DefaultConfigParser : public NutConfigParser { public: DefaultConfigParser(const char* buffer = nullptr); DefaultConfigParser(const std::string& buffer); protected: virtual void onParseSection(const GenericConfigSection& section)=0; virtual void onParseBegin() override; virtual void onParseComment(const std::string& comment) override; virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "") override; virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "") override; virtual void onParseEnd() override; GenericConfigSection _section; ///> Currently parsed section }; class GenericConfigParser : public DefaultConfigParser { public: GenericConfigParser(const char* buffer = nullptr); GenericConfigParser(const std::string& buffer); virtual void parseConfig(BaseConfiguration* config) override; protected: virtual void onParseSection(const GenericConfigSection& section) override; BaseConfiguration* _config; }; class GenericConfiguration : public BaseConfiguration, public Serialisable { public: /** Sections map */ typedef std::map SectionMap; GenericConfiguration(){} virtual ~GenericConfiguration() override; void parseFromString(const std::string& str); /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream) override; bool writeTo(NutStream & ostream) const override; /** \} */ // FIXME Let be public or set it as protected with public accessors ? SectionMap sections; const GenericConfigSection& operator[](const std::string& secname)const{return sections.find(secname)->second;} GenericConfigSection& operator[](const std::string& secname){return sections[secname];} protected: virtual void setGenericConfigSection(const GenericConfigSection& section) override; /** * \brief Configuration parameters getter * * \param[in] section Section name * \param[in] entry Entry name * \param[out] params Configuration parameters * \param[in] caseSensitive Use case-sensitive entry name matching? (default: true) * * \retval true if the entry was found * \retval false otherwise */ bool get(const std::string & section, const std::string & entry, ConfigParamList & params, bool caseSensitive = true) const; /** * \brief Global scope configuration parameters getter * * \param[in] entry Entry name * \param[out] params Configuration parameters * \param[in] caseSensitive Use case-sensitive entry name matching? (default: true) * * \retval true if the entry was found * \retval false otherwise */ inline bool get(const std::string & entry, ConfigParamList & params, bool caseSensitive = true) const { return get("", entry, params, caseSensitive); } /** * \brief Configuration parameters setter * * The section and entry are created unless they already exist. * * \param[in] section Section name * \param[in] entry Entry name * \param[in] params Configuration parameters */ void set(const std::string & section, const std::string & entry, const ConfigParamList & params); /** * \brief Global scope configuration parameters setter * * The entry is created unless it already exists. * * \param[in] entry Entry name * \param[in] params Configuration parameters */ inline void set(const std::string & entry, const ConfigParamList & params) { set("", entry, params); } /** * \brief Add configuration parameters * * The section and entry are created unless they already exist. * Current parameters are kept, the provided are added to the list end. * * \param[in] section Section name * \param[in] entry Entry name * \param[in] params Configuration parameters */ void add(const std::string & section, const std::string & entry, const ConfigParamList & params); /** * \brief Add global scope configuration parameters * * The entry is created unless they already exists. * Current parameters are kept, the provided are added to the list end. * * \param[in] entry Entry name * \param[in] params Configuration parameters */ inline void add(const std::string & entry, const ConfigParamList & params) { add("", entry, params); } /** * \brief Configuration parameters removal * * Removes the entry, only. * Does nothing if the section or the entry don't exist. * * \param section Section name * \param entry Entry name */ void remove(const std::string & section, const std::string & entry); /** * \brief Global scope configuration parameters removal * * Removes the entry, only. * Does nothing if the entry don't exist. * * \param entry Entry name */ inline void remove(const std::string & entry) { remove("", entry); } /** * \brief Configuration section removal * * Removes entire section (if exists). * * \param section Section name */ void removeSection(const std::string & section); /** Global scope configuration removal */ inline void removeGlobal() { removeSection(""); } /** * \brief Configuration string getter * * Empty string is returned if the section or entry doesn't exist. * * \param section Section name * \param entry Entry name * \param caseSensitive Use case-sensitive entry name matching? (default: true) * * \return Configuration parameter as string */ std::string getStr( const std::string & section, const std::string & entry, bool caseSensitive = true) const; /** * \brief Configuration string getter * * Empty string is returned if the section or entry doesn't exist. * * \param section Section name * \param entry Entry name (as C char array or string literal) * \param caseSensitive Use case-sensitive entry name matching? (default: true) * * \return Configuration parameter as string */ std::string getStr( const std::string & section, const char * entry, bool caseSensitive = true) const { std::string sEntry{entry}; return getStr(section, sEntry, caseSensitive); } /** * \brief Global scope configuration string getter * * Empty string is returned if the entry doesn't exist. * * \param entry Entry name * \param caseSensitive Use case-sensitive entry name matching? (default: true) * * \return Configuration parameter as string */ inline std::string getStr( const std::string & entry, bool caseSensitive = true) const { return getStr("", entry, caseSensitive); } /** * \brief Configuration string setter * * \param section Section name * \param entry Entry name * \param value Parameter value */ void setStr( const std::string & section, const std::string & entry, const std::string & value); /** * \brief Global scope configuration string setter * * \param entry Entry name * \param value Parameter value */ inline void setStr( const std::string & entry, const std::string & value) { setStr("", entry, value); } /** * \brief Configuration flag getter * * False is returned if the section or entry doesn't exist. * If a flag exists in configuration (any value is ignored), * it is effectively True. * * \param section Section name * \param entry Entry name * * \return Configuration parameter as boolean */ bool getFlag( const std::string & section, const std::string & entry) const; /** * \brief Global scope configuration flag getter * * False is returned if the entry doesn't exist. * If a flag exists in configuration (any value is ignored), * it is effectively True. * * \param entry Entry name * * \return Configuration parameter as boolean */ inline bool getFlag(const std::string & entry) const { return getFlag("", entry); } /** * \brief Configuration flag setter (mentioned == true) * * Note: to unset a flag, we just use remove() method. * * \param section Section name * \param entry Entry name */ void setFlag( const std::string & section, const std::string & entry, bool val = true); /** * \brief Global scope configuration flag setter (mentioned == true) * * Note: to unset a flag, we just use remove() method. * * \param entry Entry name */ inline void setFlag( const std::string & entry, bool val = true) { setFlag("", entry, val); } /** * \brief Configuration boolean option getter * * Value depends on original string representation of a setting. * * \param section Section name * \param entry Entry name * \param val Default value * * \return Configuration parameter as boolean (or the default if not defined) */ bool getBool( const std::string & section, const std::string & entry, bool val = false) const; /** * \brief Configuration boolean option getter * * Value depends on original string representation of a setting. * * \param section Section name * \param entry Entry name * \param val Default value * * \return Configuration parameter as boolean (or the default if not defined) */ // Avoid error: implicit conversion turns string literal // into bool: 'const char[7]' to 'bool' bool getBool( const std::string & section, const char * entry, bool val = false) const { return getBool(section, std::string(entry), val); } /** * \brief Global scope configuration boolean option getter * * Value depends on original string representation of a setting. * * \param entry Entry name * \param val Default value * * \return Configuration parameter as boolean (or the default if not defined) */ inline bool getBool(const std::string & entry, bool val = false) const { return getBool("", entry, val); } /** * \brief Configuration boolean option setter * * \param section Section name * \param entry Entry name * \param val Default value */ inline void setBool( const std::string & section, const std::string & entry, bool val = true) { setStr(section, entry, bool2str(val)); } /** * \brief Global scope configuration boolean option setter * * \param entry Entry name * \param val Default value */ inline void setBool( const std::string & entry, bool val = true) { setBool("", entry, val); } /** * \brief Configuration boolean option setter from a string * * \param section Section name * \param entry Entry name * \param val Default value */ inline void setBool( const std::string & section, const std::string & entry, const std::string & val = "true") { // Normalize: bool b = str2bool(val); setStr(section, entry, bool2str(b)); } /** * \brief Global scope configuration boolean option setter from a string * * \param entry Entry name * \param val Default value */ inline void setBool( const std::string & entry, const std::string & val = "true") { setBool("", entry, val); } /** * \brief Configuration number getter * * \param section Section name * \param entry Entry name * \param val Default value * * \return Configuration parameter as number (or the default if not defined) */ long long int getInt( const std::string & section, const std::string & entry, long long int val = 0) const; /** * \brief Global scope configuration number getter * * \param entry Entry name * \param val Default value * * \return Configuration parameter as number (or the default if not defined) */ inline long long int getInt(const std::string & entry, long long int val = 0) const { return getInt("", entry, val); } /** * \brief Configuration number setter * * \param section Section name * \param entry Entry name * \param val Default value */ void setInt( const std::string & section, const std::string & entry, long long int val); /** * \brief Global scope configuration number setter * * \param entry Entry name * \param val Default value */ inline void setInt( const std::string & entry, long long int val) { setInt("", entry, val); } /** * \brief Configuration number getter (hex value even if without leading "0x") * * \param section Section name * \param entry Entry name * \param val Default value * * \return Configuration parameter as number (or the default if not defined) */ long long int getIntHex( const std::string & section, const std::string & entry, long long int val = 0) const; /** * \brief Global scope configuration number getter (hex value even if without leading "0x") * * \param entry Entry name * \param val Default value * * \return Configuration parameter as number (or the default if not defined) */ inline long long int getIntHex(const std::string & entry, long long int val = 0) const { return getIntHex("", entry, val); } /** * \brief Configuration number setter (hex value even if without leading "0x") * * \param section Section name * \param entry Entry name * \param val Default value */ void setIntHex( const std::string & section, const std::string & entry, long long int val); /** * \brief Global scope configuration number setter (hex value even if without leading "0x") * * \param entry Entry name * \param val Default value */ inline void setIntHex( const std::string & entry, long long int val) { setIntHex("", entry, val); } /** * \brief Configuration floating-point number getter * * \param section Section name * \param entry Entry name * \param val Default value * * \return Configuration parameter as number (or the default if not defined) */ double getDouble( const std::string & section, const std::string & entry, double val = 0.0) const; /** * \brief Global scope configuration floating-point number getter * * \param entry Entry name * \param val Default value * * \return Configuration parameter as number (or the default if not defined) */ inline double getDouble(const std::string & entry, double val = 0.0) const { return getDouble("", entry, val); } /** * \brief Configuration floating-point number setter * * \param section Section name * \param entry Entry name * \param val Default value */ void setDouble( const std::string & section, const std::string & entry, double val); /** * \brief Global scope configuration floating-point number setter * * \param entry Entry name * \param val Default value */ inline void setDouble( const std::string & entry, double val) { setDouble("", entry, val); } /** * \brief Cast numeric type with range check * * Throws an exception on cast error. * * \param number Number * \param min Minimum * \param max Maximum * * \return \c number which was cast to target type */ template static T range_cast(long long int number, long long int min, long long int max) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::range_error) #endif { if (number < min) { std::stringstream e; e << "Failed to range-cast " << number << " (underflows " << min << ')'; throw std::range_error(e.str()); } if (number > max) { std::stringstream e; e << "Failed to range-cast " << number << " (overflows " << max << ')'; throw std::range_error(e.str()); } return static_cast(number); } /** * \brief Configuration mixed boolean/int option getter * * Value depends on original string representation of a setting. * * \param section Section name * \param entry Entry name * \param val Default value * * \return Configuration parameter as BoolInt type for original * values which have a boolean or integer-numeric meaning * (or the default if not defined) */ nut::BoolInt getBoolInt( const std::string & section, const std::string & entry, nut::BoolInt val = false) const; /** * \brief Global scope configuration mixed boolean/int option getter * * Value depends on original string representation of a setting. * * \param entry Entry name * \param val Default value * * \return Configuration parameter as BoolInt type for original * values which have a boolean or integer-numeric meaning * (or the default if not defined) */ inline nut::BoolInt getBoolInt(const std::string & entry, nut::BoolInt val = false) const { return getBoolInt("", entry, val); } /** * \brief Configuration mixed boolean/int option setter * * Input value types are auto-converted through BoolInt * type for sanity checks (e.g. throw exceptions for * invalid string contents) and are stored as strings * internally. * * \param section Section name * \param entry Entry name * \param val Default value */ inline void setBoolInt( const std::string & section, const std::string & entry, nut::BoolInt val = true) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::invalid_argument) #endif { setStr(section, entry, val); } /** * \brief Global scope configuration mixed boolean/int option setter * * \param entry Entry name * \param val Default value */ inline void setBoolInt( const std::string & entry, nut::BoolInt val = true) { setBoolInt("", entry, val); } /** * \brief Resolve string as Boolean value * * \param str String * * \retval true IFF the string expresses a known true value * \retval false otherwise (no errors emitted for bogus inputs) */ static bool str2bool(const std::string & str); /** * \brief Convert Boolean value to string * * \param val Boolean value * * \return \c val as string */ static const std::string & bool2str(bool val); }; // end of class GenericConfiguration class UpsmonConfiguration : public Serialisable { public: UpsmonConfiguration(); void parseFromString(const std::string& str); Settable debugMin, pollFailLogThrottleMax; Settable offDuration, oblbDuration, overDuration; Settable runAsUser, shutdownCmd, notifyCmd, powerDownFlag; /* yes|no (boolean) or a delay */ Settable shutdownExit; /* practically boolean, but in 0|1 written form (bool01 fiddling) */ Settable certVerify, forceSsl, alarmCritical; Settable certPath; CertIdent certIdent; std::list certHosts; Settable minSupplies, pollFreq, pollFreqAlert, hostSync; Settable deadTime, rbWarnTime, noCommWarnTime, finalDelay; enum NotifyFlag { NOTIFY_IGNORE = 0, NOTIFY_SYSLOG = 1, NOTIFY_WALL = 1 << 1, NOTIFY_EXEC = 1 << 2 }; enum NotifyType { NOTIFY_ONLINE = 0, NOTIFY_ONBATT, NOTIFY_LOWBATT, NOTIFY_FSD, NOTIFY_COMMOK, NOTIFY_COMMBAD, NOTIFY_SHUTDOWN, NOTIFY_REPLBATT, NOTIFY_NOCOMM, NOTIFY_NOPARENT, NOTIFY_CAL, NOTIFY_NOTCAL, NOTIFY_OFF, NOTIFY_NOTOFF, NOTIFY_BYPASS, NOTIFY_NOTBYPASS, NOTIFY_ECO, NOTIFY_NOTECO, NOTIFY_ALARM, NOTIFY_NOTALARM, NOTIFY_OVER, NOTIFY_NOTOVER, NOTIFY_TRIM, NOTIFY_NOTTRIM, NOTIFY_BOOST, NOTIFY_NOTBOOST, NOTIFY_OTHER = 28, NOTIFY_NOTOTHER, NOTIFY_SUSPEND_STARTING = 30, NOTIFY_SUSPEND_FINISHED, NOTIFY_TYPE_MAX }; static NotifyFlag NotifyFlagFromString(const std::string& str); static NotifyType NotifyTypeFromString(const std::string& str); Settable notifyFlags[NOTIFY_TYPE_MAX]; Settable notifyMessages[NOTIFY_TYPE_MAX]; struct Monitor { std::string upsname, hostname; uint16_t port; unsigned int powerValue; std::string username, password; bool isPrimary; }; std::list monitors; /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream) override; bool writeTo(NutStream & ostream) const override; /** \} */ }; // end of class UpsmonConfiguration class UpsmonConfigParser : public NutConfigParser { public: UpsmonConfigParser(const char* buffer = nullptr); UpsmonConfigParser(const std::string& buffer); void parseUpsmonConfig(UpsmonConfiguration* config); protected: virtual void onParseBegin() override; virtual void onParseComment(const std::string& comment) override; virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "") override; virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "") override; virtual void onParseEnd() override; UpsmonConfiguration* _config; }; class NutConfiguration: public Serialisable { public: NutConfiguration(); void parseFromString(const std::string& str); enum NutMode { MODE_UNKNOWN = -1, MODE_NONE = 0, MODE_STANDALONE, MODE_NETSERVER, MODE_NETCLIENT, MODE_CONTROLLED, MODE_MANUAL, }; Settable mode; Settable allowNoDevice, allowNotAllListeners, poweroffQuiet; Settable upsdOptions, upsmonOptions; Settable poweroffWait; Settable debugLevel; static NutMode NutModeFromString(const std::string& str); /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream) override; bool writeTo(NutStream & ostream) const override; /** \} */ }; class NutConfConfigParser : public NutConfigParser { public: NutConfConfigParser(const char* buffer = nullptr); NutConfConfigParser(const std::string& buffer); void parseNutConfConfig(NutConfiguration* config); protected: virtual void onParseBegin() override; virtual void onParseComment(const std::string& comment) override; virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "") override; virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "") override; virtual void onParseEnd() override; NutConfiguration* _config; }; class UpsdConfiguration : public Serialisable { public: UpsdConfiguration(); void parseFromString(const std::string& str); Settable debugMin; Settable maxAge, maxConn, trackingDelay, certRequestLevel; Settable statePath, certFile, certPath; Settable allowNoDevice, allowNotAllListeners, disableWeakSsl; struct Listen { std::string address; Settable port; inline bool operator==(const Listen& listen)const { return address == listen.address && port == listen.port; } }; std::list listens; CertIdent certIdent; /** Serialisable interface implementation \{ */ bool parseFrom(NutStream & istream) override; bool writeTo(NutStream & ostream) const override; /** \} */ }; class UpsdConfigParser : public NutConfigParser { public: UpsdConfigParser(const char* buffer = nullptr); UpsdConfigParser(const std::string& buffer); void parseUpsdConfig(UpsdConfiguration* config); protected: virtual void onParseBegin() override; virtual void onParseComment(const std::string& comment) override; virtual void onParseSectionName(const std::string& sectionName, const std::string& comment = "") override; virtual void onParseDirective(const std::string& directiveName, char sep = 0, const ConfigParamList& values = ConfigParamList(), const std::string& comment = "") override; virtual void onParseEnd() override; UpsdConfiguration* _config; }; /** UPS configuration */ class UpsConfiguration : public GenericConfiguration { /* Note: key words for ups.conf are well collected from sources * by augeas lens preparation scripts. Maintainers of this class * can consume that information like this to see key words in * context of their use in sources and documentation (omit the * `continue` in grep of `nutconf.hpp` to see details of ALL * keywords and not just those not yet covered by this class * (e.g. to verify handling as str/int/bool/flag... types): :; ( cd scripts/augeas && python ./gen-nutupsconf-aug.py.in ) :; grep -E '[=|] "' scripts/augeas/nutupsconf.aug.in | awk '{print $NF}' | tr -d '"' \ | while read O ; do echo "=== $O :" ; \ grep -w '"'"$O"'"' ./include/nutconf.hpp && continue ; \ { cd ./docs/man/ && grep -A10 -w "$O" *.txt || echo '!!! UNDOCUMENTED !!!' ; } ; \ echo "-----"; { cd ./drivers && grep -A10 -w '"'"$O"'"' *.{c,h} || echo '!!! NOT USED IN CODE !!!' ; } ; \ echo "-----"; echo "" ; done | less * Arrange found new keywords into two columns (first would be * "C names" camel-cased and expanded as deemed fit) and generate * lines for code blocks below as e.g.: :; while read C O ; do \ printf '\tinline std::string get%-45sconst { return getStr(ups, "%s"); }\n' \ "$C"'(const std::string & ups)' "$O"; \ printf '\tinline void set%-75s{ setStr(ups, "%-22s val); }\n' \ "$C"'(const std::string & ups, const std::string & val)' "$O"'",' ; \ done < nutupsconf-newnames.bool | sort */ public: /** Global configuration attributes getters and setters \{ */ inline std::string getChroot() const { return getStr("chroot"); } inline std::string getDriverPath() const { return getStr("driverpath"); } inline std::string getStatePath() const { return getStr("statepath", false); } // NOTE: accept it case-insensitively inline std::string getGroup() const { return getStr("group"); } inline std::string getSynchronous() const { return getStr("synchronous"); } inline std::string getUser() const { return getStr("user"); } // Flag - if exists then "true" inline bool getNoWait() const { return getFlag("nowait"); } inline long long int getDebugMin() const { return getInt("debug_min"); } inline long long int getLibusbDebug() const { return getInt("LIBUSB_DEBUG"); } inline long long int getMaxRetry() const { return getInt("maxretry"); } inline long long int getMaxStartDelay() const { return getInt("maxstartdelay"); } inline long long int getPollInterval() const { return getInt("pollinterval", 5); } // TODO: check the default inline long long int getRetryDelay() const { return getInt("retrydelay"); } inline void setChroot(const std::string & path) { setStr("chroot", path); } inline void setDriverPath(const std::string & path) { setStr("driverpath", path); } inline void setStatePath(const std::string & path) { setStr("statepath", path); } inline void setGroup(const std::string & group) { setStr("group", group); } inline void setSynchronous(const std::string & val) { setStr("synchronous", val); } inline void setUser(const std::string & user) { setStr("user", user); } inline void setNoWait(bool val = true) { setFlag("nowait", val); } inline void setDebugMin(long long int num) { setInt("debug_min", num); } inline void setLibusbDebug(long long int num) { setInt("LIBUSB_DEBUG", num); } inline void setMaxRetry(long long int num) { setInt("maxretry", num); } inline void setMaxStartDelay(long long int delay) { setInt("maxstartdelay", delay); } inline void setPollInterval(long long int interval) { setInt("pollinterval", interval); } inline void setRetryDelay(long long int delay) { setInt("retrydelay", delay); } /** \} */ /** Generic = getter */ inline std::string getKey(const std::string & ups, const std::string & key) const { return getStr(ups, key); } /** Generic = setter */ inline void setKey(const std::string & ups, const std::string & key, const std::string & val) { setStr(ups, key, val); } /** PUZZLE: What to do about "default.*" and "override.*" * settings that apply to anything (vars!) that follows? * Maybe nest the UpsConfiguration objects, and so query * e.g. upscfg.default.getBatteryNominalVoltage() ? * Or just keep that info in ConfigParamList per section * and wrap free-style queries? */ inline std::string getDefaultStr(const std::string & ups, const std::string & key) const { return getStr(ups, "default." + key); } inline long long int getDefaultInt(const std::string & ups, const std::string & key) const { return getInt(ups, "default." + key); } inline long long int getDefaultIntHex(const std::string & ups, const std::string & key) const { return getIntHex(ups, "default." + key); } inline bool getDefaultFlag(const std::string & ups, const std::string & key) const { return getFlag(ups, "default." + key); } inline bool getDefaultBool(const std::string & ups, const std::string & key) const { return getBool(ups, "default." + key); } inline nut::BoolInt getDefaultBoolInt(const std::string & ups, const std::string & key) const { return getBoolInt(ups, "default." + key); } inline double getDefaultDouble(const std::string & ups, const std::string & key) const { return getDouble(ups, "default." + key); } inline std::string getOverrideStr(const std::string & ups, const std::string & key) const { return getStr(ups, "override." + key); } inline long long int getOverrideInt(const std::string & ups, const std::string & key) const { return getInt(ups, "override." + key); } inline long long int getOverrideIntHex(const std::string & ups, const std::string & key) const { return getIntHex(ups, "override." + key); } inline bool getOverrideFlag(const std::string & ups, const std::string & key) const { return getFlag(ups, "override." + key); } inline bool getOverrideBool(const std::string & ups, const std::string & key) const { return getBool(ups, "override." + key); } inline nut::BoolInt getOverrideBoolInt(const std::string & ups, const std::string & key) const { return getBoolInt(ups, "override." + key); } inline double getOverrideDouble(const std::string & ups, const std::string & key) const { return getDouble(ups, "override." + key); } inline void setDefaultStr(const std::string & ups, const std::string & key, const std::string & val) { setStr(ups, "default." + key, val); } inline void setDefaultInt(const std::string & ups, const std::string & key, long long int val) { setInt(ups, "default." + key, val); } inline void setDefaultIntHex(const std::string & ups, const std::string & key, long long int val) { setIntHex(ups, "default." + key, val); } inline void setDefaultFlag(const std::string & ups, const std::string & key, bool val = true) { setFlag(ups, "default." + key, val); } inline void setDefaultBool(const std::string & ups, const std::string & key, bool val) { setBool(ups, "default." + key, val); } inline void setDefaultBoolInt(const std::string & ups, const std::string & key, nut::BoolInt val) { setBoolInt(ups, "default." + key, val); } inline void setDefaultDouble(const std::string & ups, const std::string & key, double val) { setDouble(ups, "default." + key, val); } inline void setOverrideStr(const std::string & ups, const std::string & key, const std::string & val) { setStr(ups, "override." + key, val); } inline void setOverrideInt(const std::string & ups, const std::string & key, long long int val) { setInt(ups, "override." + key, val); } inline void setOverrideIntHex(const std::string & ups, const std::string & key, long long int val) { setIntHex(ups, "override." + key, val); } inline void setOverrideFlag(const std::string & ups, const std::string & key, bool val = true) { setFlag(ups, "override." + key, val); } inline void setOverrideBool(const std::string & ups, const std::string & key, bool val) { setBool(ups, "override." + key, val); } inline void setOverrideBoolInt(const std::string & ups, const std::string & key, nut::BoolInt val) { setBoolInt(ups, "override." + key, val); } inline void setOverrideDouble(const std::string & ups, const std::string & key, double val) { setDouble(ups, "override." + key, val); } /** UPS-specific configuration attributes getters and setters \{ */ inline std::string getAuthPassword(const std::string & ups) const { return getStr(ups, "authPassword"); } inline std::string getAuthProtocol(const std::string & ups) const { return getStr(ups, "authProtocol"); } inline std::string getAuthType(const std::string & ups) const { return getStr(ups, "authtype"); } inline std::string getAWD(const std::string & ups) const { return getStr(ups, "awd"); } inline std::string getBatText(const std::string & ups) const { return getStr(ups, "battext"); } inline std::string getBus(const std::string & ups) const { return getStr(ups, "bus"); } inline std::string getCommunity(const std::string & ups) const { return getStr(ups, "community"); } inline std::string getDriver(const std::string & ups) const { return getStr(ups, "driver"); } inline std::string getDescription(const std::string & ups) const { return getStr(ups, "desc"); } inline std::string getFRUID(const std::string & ups) const { return getStr(ups, "fruid"); } inline std::string getGenericGPIO_Rules(const std::string & ups) const { return getStr(ups, "rules"); } inline std::string getGenericUPS_BYPASS(const std::string & ups) const { return getStr(ups, "BYPASS"); } inline std::string getGenericUPS_CP(const std::string & ups) const { return getStr(ups, "CP"); } inline std::string getGenericUPS_LB(const std::string & ups) const { return getStr(ups, "LB"); } inline std::string getGenericUPS_OL(const std::string & ups) const { return getStr(ups, "OL"); } inline std::string getGenericUPS_RB(const std::string & ups) const { return getStr(ups, "RB"); } inline std::string getGenericUPS_SD(const std::string & ups) const { return getStr(ups, "SD"); } inline std::string getGroup(const std::string & ups) const { return getStr(ups, "group"); } inline std::string getID(const std::string & ups) const { return getStr(ups, "ID"); } inline std::string getLoadStatus(const std::string & ups) const { return getStr(ups, "load.status"); } inline std::string getLogin(const std::string & ups) const { return getStr(ups, "login"); } inline std::string getLowBatt(const std::string & ups) const { return getStr(ups, "LowBatt"); } inline std::string getLowbatt(const std::string & ups) const { return getStr(ups, "lowbatt"); } inline std::string getManufacturer(const std::string & ups) const { return getStr(ups, "manufacturer"); } inline std::string getMethodOfFlowControl(const std::string & ups) const { return getStr(ups, "methodOfFlowControl"); } inline std::string getMIBs(const std::string & ups) const { return getStr(ups, "mibs"); } inline std::string getModbus_DeviceMfr(const std::string & ups) const { return getStr(ups, "device_mfr"); } inline std::string getModbus_DeviceModel(const std::string & ups) const { return getStr(ups, "device_model"); } inline std::string getModbus_Parity(const std::string & ups) const { return getStr(ups, "parity"); } inline std::string getModbus_PortType(const std::string & ups) const { return getStr(ups, "porttype"); } inline std::string getModbus_SerParity(const std::string & ups) const { return getStr(ups, "ser_parity"); } inline std::string getModel(const std::string & ups) const { return getStr(ups, "model"); } inline std::string getModelName(const std::string & ups) const { return getStr(ups, "modelname"); } inline std::string getNotification(const std::string & ups) const { return getStr(ups, "notification"); } inline std::string getPassword(const std::string & ups) const { return getStr(ups, "password"); } inline std::string getPort(const std::string & ups) const { return getStr(ups, "port"); } inline std::string getPrefix(const std::string & ups) const { return getStr(ups, "prefix"); } inline std::string getPrivPassword(const std::string & ups) const { return getStr(ups, "privPassword"); } inline std::string getPrivProtocol(const std::string & ups) const { return getStr(ups, "privProtocol"); } inline std::string getProduct(const std::string & ups) const { return getStr(ups, "product"); } inline std::string getProductID(const std::string & ups) const { return getStr(ups, "productid"); } inline std::string getProtocol(const std::string & ups) const { return getStr(ups, "protocol"); } inline std::string getRuntimeCal(const std::string & ups) const { return getStr(ups, "runtimecal"); } inline std::string getSDType(const std::string & ups) const { return getStr(ups, "sdtype"); } inline std::string getSecLevel(const std::string & ups) const { return getStr(ups, "secLevel"); } inline std::string getSecName(const std::string & ups) const { return getStr(ups, "secName"); } inline std::string getSensorID(const std::string & ups) const { return getStr(ups, "sensorid"); } inline std::string getSerial(const std::string & ups) const { return getStr(ups, "serial"); } inline std::string getSerialNumber(const std::string & ups) const { return getStr(ups, "serialnumber"); } inline std::string getShutdownArguments(const std::string & ups) const { return getStr(ups, "shutdownArguments"); } inline std::string getSNMPversion(const std::string & ups) const { return getStr(ups, "snmp_version"); } inline std::string getSubdriver(const std::string & ups) const { return getStr(ups, "subdriver"); } inline std::string getSynchronous(const std::string & ups) const { return getStr(ups, "synchronous"); } inline std::string getTtyMode(const std::string & ups) const { return getStr(ups, "ttymode"); } inline std::string getType(const std::string & ups) const { return getStr(ups, "type"); } inline std::string getUPStype(const std::string & ups) const { return getStr(ups, "upstype"); } inline std::string getUpsId(const std::string & ups) const { return getStr(ups, "upsid"); } inline std::string getUsbBusPort(const std::string & ups) const { return getStr(ups, "busport"); } inline std::string getUsbDevice(const std::string & ups) const { return getStr(ups, "device"); } inline std::string getUSD(const std::string & ups) const { return getStr(ups, "usd"); } inline std::string getUser(const std::string & ups) const { return getStr(ups, "user"); } inline std::string getUsername(const std::string & ups) const { return getStr(ups, "username"); } inline std::string getValidationSequence(const std::string & ups) const { return getStr(ups, "validationSequence"); } inline std::string getVendor(const std::string & ups) const { return getStr(ups, "vendor"); } inline std::string getVendorID(const std::string & ups) const { return getStr(ups, "vendorid"); } inline std::string getWorkRangeType(const std::string & ups) const { return getStr(ups, "work_range_type"); } inline std::string getWUGrace(const std::string & ups) const { return getStr(ups, "wugrace"); } // Items below are "unused" - mostly set in // drivers/nutdrv_qx_masterguard.c inline std::string getFault1(const std::string & ups) const { return getStr(ups, "fault_1"); } inline std::string getFault2(const std::string & ups) const { return getStr(ups, "fault_2"); } inline std::string getFault3(const std::string & ups) const { return getStr(ups, "fault_3"); } inline std::string getFault4(const std::string & ups) const { return getStr(ups, "fault_4"); } inline std::string getFault5(const std::string & ups) const { return getStr(ups, "fault_5"); } inline std::string getInputFaultVoltage(const std::string & ups) const { return getStr(ups, "input_fault_voltage"); } inline std::string getNominalCellVoltage(const std::string & ups) const { return getStr(ups, "nominal_cell_voltage"); } inline std::string getNumberOfBatteryCells(const std::string & ups)const { return getStr(ups, "number_of_battery_cells"); } inline std::string getOutputVoltages(const std::string & ups) const { return getStr(ups, "output_voltages"); } inline std::string getRechargeTime(const std::string & ups) const { return getStr(ups, "recharge_time"); } inline std::string getRuntimeFull(const std::string & ups) const { return getStr(ups, "runtime_full"); } inline std::string getRuntimeHalf(const std::string & ups) const { return getStr(ups, "runtime_half"); } inline std::string getSeries(const std::string & ups) const { return getStr(ups, "series"); } // Items below are essentially booleans (expected values // are "enabled/disabled") -- refactoring planned per // https://github.com/networkupstools/nut/issues/2421 inline std::string getAdvancedEcoMode(const std::string & ups) const { return getStr(ups, "advanced_eco_mode"); } inline std::string getAlarmControl(const std::string & ups) const { return getStr(ups, "alarm_control"); } inline std::string getBatteryAlarm(const std::string & ups) const { return getStr(ups, "battery_alarm"); } inline std::string getBatteryOpenStatusCheck(const std::string & ups)const { return getStr(ups, "battery_open_status_check"); } inline std::string getBypassAlarm(const std::string & ups) const { return getStr(ups, "bypass_alarm"); } inline std::string getBypassForbidding(const std::string & ups) const { return getStr(ups, "bypass_forbidding"); } inline std::string getBypassWhenOff(const std::string & ups) const { return getStr(ups, "bypass_when_off"); } inline std::string getConstantPhaseAngle(const std::string & ups) const { return getStr(ups, "constant_phase_angle"); } inline std::string getConverterMode(const std::string & ups) const { return getStr(ups, "converter_mode"); } inline std::string getEcoMode(const std::string & ups) const { return getStr(ups, "eco_mode"); } inline std::string getLimitedRuntimeOnBattery(const std::string & ups)const { return getStr(ups, "limited_runtime_on_battery"); } inline std::string getSiteFaultDetection(const std::string & ups) const { return getStr(ups, "site_fault_detection"); } inline long long int getAdvOrder(const std::string & ups) const { return getInt(ups, "advorder"); } // CHECKME inline long long int getAsem_HB(const std::string & ups) const { return getInt(ups, "hb"); } inline long long int getAsem_LB(const std::string & ups) const { return getInt(ups, "lb"); } inline long long int getBatteryNumber(const std::string & ups) const { return getInt(ups, "battery_number"); } inline long long int getBatteryPercentage(const std::string & ups) const { return getInt(ups, "batteryPercentage"); } // CHECKME inline long long int getBattVoltMult(const std::string & ups) const { return getInt(ups, "battvoltmult"); } // CHECKME inline long long int getBaudRate(const std::string & ups) const { return getInt(ups, "baud_rate"); } // CHECKME inline long long int getBaudrate(const std::string & ups) const { return getInt(ups, "baudrate"); } // CHECKME inline long long int getCablePower(const std::string & ups) const { return getInt(ups, "cablepower"); } // CHECKME inline long long int getChargeTime(const std::string & ups) const { return getInt(ups, "chargetime"); } // CHECKME inline long long int getDaysOff(const std::string & ups) const { return getInt(ups, "daysoff"); } // CHECKME inline long long int getDaySweek(const std::string & ups) const { return getInt(ups, "daysweek"); } // CHECKME inline long long int getDebugMin(const std::string & ups) const { return getInt(ups, "debug_min"); } inline long long int getLibusbDebug(const std::string & ups) const { return getInt(ups, "LIBUSB_DEBUG"); } inline long long int getFrequency(const std::string & ups) const { return getInt(ups, "frequency"); } // CHECKME inline long long int getHourOff(const std::string & ups) const { return getInt(ups, "houroff"); } // CHECKME inline long long int getHourOn(const std::string & ups) const { return getInt(ups, "houron"); } // CHECKME inline long long int getI2C_address(const std::string & ups) const { return getInt(ups, "i2c_address"); } inline long long int getIdleLoad(const std::string & ups) const { return getInt(ups, "idleload"); } // CHECKME inline long long int getInputTimeout(const std::string & ups) const { return getInt(ups, "input_timeout"); } // CHECKME inline long long int getInterruptPipeNoEventsTolerance(const std::string & ups) const { return getInt(ups, "interrupt_pipe_no_events_tolerance"); } inline long long int getInterruptSize(const std::string & ups) const { return getInt(ups, "interruptsize"); } inline long long int getLineVoltage(const std::string & ups) const { return getInt(ups, "linevoltage"); } // CHECKME inline long long int getLoadpercentage(const std::string & ups) const { return getInt(ups, "loadPercentage"); } // CHECKME inline long long int getMaxLoad(const std::string & ups) const { return getInt(ups, "max_load"); } // CHECKME inline long long int getMaxPollsWithoutData(const std::string & ups) const { return getInt(ups, "max_polls_without_data"); } inline long long int getMaxStartDelay(const std::string & ups) const { return getInt(ups, "maxstartdelay"); } inline long long int getMFR(const std::string & ups) const { return getInt(ups, "mfr"); } // CHECKME inline long long int getMinCharge(const std::string & ups) const { return getInt(ups, "mincharge"); } // CHECKME inline long long int getMinRuntime(const std::string & ups) const { return getInt(ups, "minruntime"); } // CHECKME inline long long int getModbus_ByteTimeoutSec(const std::string & ups) const { return getInt(ups, "mod_byte_to_s"); } inline long long int getModbus_ByteTimeoutUsec(const std::string & ups) const { return getInt(ups, "mod_byte_to_us"); } inline long long int getModbus_CHRG_addr(const std::string & ups) const { return getInt(ups, "CHRG_addr"); } inline long long int getModbus_CHRG_noro(const std::string & ups) const { return getInt(ups, "CHRG_noro"); } inline long long int getModbus_CHRG_regtype(const std::string & ups) const { return getInt(ups, "CHRG_regtype"); } inline long long int getModbus_DISCHRG_addr(const std::string & ups) const { return getInt(ups, "DISCHRG_addr"); } inline long long int getModbus_DISCHRG_noro(const std::string & ups) const { return getInt(ups, "DISCHRG_noro"); } inline long long int getModbus_DISCHRG_regtype(const std::string & ups) const { return getInt(ups, "DISCHRG_regtype"); } inline long long int getModbus_DataBits(const std::string & ups) const { return getInt(ups, "databits"); } inline long long int getModbus_DeviceSlaveId(const std::string & ups) const { return getInt(ups, "dev_slave_id"); } inline long long int getModbus_FSD_addr(const std::string & ups) const { return getInt(ups, "FSD_addr"); } inline long long int getModbus_FSD_noro(const std::string & ups) const { return getInt(ups, "FSD_noro"); } inline long long int getModbus_FSD_pulse_duration(const std::string & ups) const { return getInt(ups, "FSD_pulse_duration"); } inline long long int getModbus_FSD_regtype(const std::string & ups) const { return getInt(ups, "FSD_regtype"); } inline long long int getModbus_HB_addr(const std::string & ups) const { return getInt(ups, "HB_addr"); } inline long long int getModbus_HB_noro(const std::string & ups) const { return getInt(ups, "HB_noro"); } inline long long int getModbus_HB_regtype(const std::string & ups) const { return getInt(ups, "HB_regtype"); } inline long long int getModbus_LB_addr(const std::string & ups) const { return getInt(ups, "LB_addr"); } inline long long int getModbus_LB_noro(const std::string & ups) const { return getInt(ups, "LB_noro"); } inline long long int getModbus_LB_regtype(const std::string & ups) const { return getInt(ups, "LB_regtype"); } inline long long int getModbus_OB_addr(const std::string & ups) const { return getInt(ups, "OB_addr"); } inline long long int getModbus_OB_noro(const std::string & ups) const { return getInt(ups, "OB_noro"); } inline long long int getModbus_OB_regtype(const std::string & ups) const { return getInt(ups, "OB_regtype"); } inline long long int getModbus_OL_addr(const std::string & ups) const { return getInt(ups, "OL_addr"); } inline long long int getModbus_OL_noro(const std::string & ups) const { return getInt(ups, "OL_noro"); } inline long long int getModbus_OL_regtype(const std::string & ups) const { return getInt(ups, "OL_regtype"); } inline long long int getModbus_RB_addr(const std::string & ups) const { return getInt(ups, "RB_addr"); } inline long long int getModbus_RB_noro(const std::string & ups) const { return getInt(ups, "RB_noro"); } inline long long int getModbus_RB_regtype(const std::string & ups) const { return getInt(ups, "RB_regtype"); } inline long long int getModbus_ResponseTimeoutMsec(const std::string & ups)const { return getInt(ups, "response_timeout_ms"); } inline long long int getModbus_ResponseTimeoutSec(const std::string & ups) const { return getInt(ups, "mod_resp_to_s"); } inline long long int getModbus_ResponseTimeoutUsec(const std::string & ups)const { return getInt(ups, "mod_resp_to_us"); } inline long long int getModbus_RioSlaveId(const std::string & ups) const { return getInt(ups, "rio_slave_id"); } inline long long int getModbus_SerBaudRate(const std::string & ups) const { return getInt(ups, "ser_baud_rate"); } inline long long int getModbus_SerDataBit(const std::string & ups) const { return getInt(ups, "ser_data_bit"); } inline long long int getModbus_SerStopBit(const std::string & ups) const { return getInt(ups, "ser_stop_bit"); } inline long long int getModbus_SlaveId(const std::string & ups) const { return getInt(ups, "slaveid"); } inline long long int getModbus_StopBits(const std::string & ups) const { return getInt(ups, "stopbits"); } inline long long int getNomBattVolt(const std::string & ups) const { return getInt(ups, "nombattvolt"); } // CHECKME inline long long int getNumOfBytesFromUPS(const std::string & ups) const { return getInt(ups, "numOfBytesFromUPS"); } // CHECKME inline long long int getOffDelay(const std::string & ups) const { return getInt(ups, "OffDelay"); } // CHECKME inline long long int getOffdelay(const std::string & ups) const { return getInt(ups, "offdelay"); } // CHECKME inline long long int getOnDelay(const std::string & ups) const { return getInt(ups, "OnDelay"); } // CHECKME inline long long int getOndelay(const std::string & ups) const { return getInt(ups, "ondelay"); } // CHECKME inline long long int getOnlineDischargeLogThrottleHovercharge(const std::string & ups)const { return getInt(ups, "onlinedischarge_log_throttle_hovercharge"); } inline long long int getOnlineDischargeLogThrottleSec(const std::string & ups)const { return getInt(ups, "onlinedischarge_log_throttle_sec"); } inline long long int getOutputPace(const std::string & ups) const { return getInt(ups, "output_pace"); } // CHECKME inline long long int getOutputPhaseAngle(const std::string & ups) const { return getInt(ups, "output_phase_angle"); } inline long long int getPinsShutdownMode(const std::string & ups) const { return getInt(ups, "pins_shutdown_mode"); } inline long long int getPollFreq(const std::string & ups) const { return getInt(ups, "pollfreq"); } // CHECKME inline long long int getPowerUp(const std::string & ups) const { return getInt(ups, "powerup"); } // CHECKME inline long long int getPrgShut(const std::string & ups) const { return getInt(ups, "prgshut"); } // CHECKME inline long long int getRebootDelay(const std::string & ups) const { return getInt(ups, "rebootdelay"); } // CHECKME inline long long int getSDOrder(const std::string & ups) const { return getInt(ups, "sdorder"); } // TODO: Is that a number? inline long long int getSDtime(const std::string & ups) const { return getInt(ups, "sdtime"); } // CHECKME inline long long int getSemistaticFreq(const std::string & ups) const { return getInt(ups, "semistaticfreq"); } inline long long int getShutdownDelay(const std::string & ups) const { return getInt(ups, "shutdown_delay"); } // CHECKME inline long long int getShutdownDuration(const std::string & ups) const { return getInt(ups, "shutdown_duration"); } inline long long int getShutdownTimer(const std::string & ups) const { return getInt(ups, "shutdown_timer"); } inline long long int getSlaveAddress(const std::string & ups) const { return getInt(ups, "slave_address"); } inline long long int getSnmpRetries(const std::string & ups) const { return getInt(ups, "snmp_retries"); } inline long long int getSnmpTimeout(const std::string & ups) const { return getInt(ups, "snmp_timeout"); } inline long long int getStartDelay(const std::string & ups) const { return getInt(ups, "startdelay"); } // CHECKME inline long long int getTestTime(const std::string & ups) const { return getInt(ups, "testtime"); } // CHECKME inline long long int getTimeout(const std::string & ups) const { return getInt(ups, "timeout"); } // CHECKME inline long long int getUPSdelayShutdown(const std::string & ups) const { return getInt(ups, "ups.delay.shutdown"); } // CHECKME inline long long int getUPSdelayStart(const std::string & ups) const { return getInt(ups, "ups.delay.start"); } // CHECKME inline long long int getVoltage(const std::string & ups) const { return getInt(ups, "voltage"); } // CHECKME inline long long int getWaitBeforeReconnect(const std::string & ups) const { return getInt(ups, "waitbeforereconnect"); } /** belkinunv: both a flag (wait for AC power) and value (also wait for charge level) */ inline long long int getWait(const std::string & ups) const { return getInt(ups, "wait"); } /** May be a flag or a number; 0 is among valid values (default -1 for unset) */ inline long long int getUsbSetAltInterface(const std::string & ups) const { return getInt(ups, "usb_set_altinterface", -1); } // CHECKME // NUT specifies these as "hexnum" values (optionally with prefixed 0x but hex anyway) inline long long int getUsbConfigIndex(const std::string & ups) const { return getIntHex(ups, "usb_config_index"); } // CHECKME inline long long int getUsbHidDescIndex(const std::string & ups) const { return getIntHex(ups, "usb_hid_desc_index"); } // CHECKME inline long long int getUsbHidRepIndex(const std::string & ups) const { return getIntHex(ups, "usb_hid_rep_index"); } // CHECKME inline long long int getUsbHidEndpointIn(const std::string & ups) const { return getIntHex(ups, "usb_hid_ep_in"); } // CHECKME inline long long int getUsbHidEndpointOut(const std::string & ups) const { return getIntHex(ups, "usb_hid_ep_out"); } // CHECKME inline double getBatteryMax(const std::string & ups) const { return getDouble(ups, "battery_max"); } inline double getBatteryMin(const std::string & ups) const { return getDouble(ups, "battery_min"); } inline double getCSHackDelay(const std::string & ups) const { return getDouble(ups, "cshdelay"); } inline double getMaxBypassFreq(const std::string & ups) const { return getDouble(ups, "max_bypass_freq"); } inline double getMaxBypassVolt(const std::string & ups) const { return getDouble(ups, "max_bypass_volt"); } inline double getMinBypassFreq(const std::string & ups) const { return getDouble(ups, "min_bypass_freq"); } inline double getMinBypassVolt(const std::string & ups) const { return getDouble(ups, "min_bypass_volt"); } // Flag - if exists then "true" inline bool getCancelShutdown(const std::string & ups) const { return getFlag(ups, "CS"); } inline bool getDumbTerm(const std::string & ups) const { return getFlag(ups, "dumbterm"); } inline bool getExplore(const std::string & ups) const { return getFlag(ups, "explore"); } inline bool getFakeLowBatt(const std::string & ups) const { return getFlag(ups, "fake_lowbatt"); } inline bool getFlash(const std::string & ups) const { return getFlag(ups, "flash"); } inline bool getIgnoreLB(const std::string & ups) const { return getFlag(ups, "ignorelb"); } inline bool getNoHang(const std::string & ups) const { return getFlag(ups, "nohang"); } inline bool getNoRating(const std::string & ups) const { return getFlag(ups, "norating"); } inline bool getNoTransferOIDs(const std::string & ups) const { return getFlag(ups, "notransferoids"); } inline bool getNoVendor(const std::string & ups) const { return getFlag(ups, "novendor"); } inline bool getNoWarnNoImp(const std::string & ups) const { return getFlag(ups, "nowarn_noimp"); } inline bool getOldMAC(const std::string & ups) const { return getFlag(ups, "oldmac"); } inline bool getPollOnly(const std::string & ups) const { return getFlag(ups, "pollonly"); } inline bool getSilent(const std::string & ups) const { return getFlag(ups, "silent"); } inline bool getStatusOnly(const std::string & ups) const { return getFlag(ups, "status_only"); } inline bool getSubscribe(const std::string & ups) const { return getFlag(ups, "subscribe"); } inline bool getUseCRLF(const std::string & ups) const { return getFlag(ups, "use_crlf"); } inline bool getUsePreLF(const std::string & ups) const { return getFlag(ups, "use_pre_lf"); } inline bool getNolock(const std::string & ups) const { return getBool(ups, "nolock"); } inline bool getCable(const std::string & ups) const { return getBool(ups, "cable"); } inline bool getFullUpdate(const std::string & ups) const { return getBool(ups, "full_update"); } inline bool getLangIDfix(const std::string & ups) const { return getBool(ups, "langid_fix"); } inline bool getLoadOff(const std::string & ups) const { return getBool(ups, "load.off"); } inline bool getLoadOn(const std::string & ups) const { return getBool(ups, "load.on"); } inline void setAuthPassword(const std::string & ups, const std::string & auth_passwd) { setStr(ups, "authPassword", auth_passwd); } inline void setAuthProtocol(const std::string & ups, const std::string & auth_proto) { setStr(ups, "authProtocol", auth_proto); } inline void setAuthType(const std::string & ups, const std::string & authtype) { setStr(ups, "authtype", authtype); } inline void setAWD(const std::string & ups, const std::string & awd) { setStr(ups, "awd", awd); } inline void setBatText(const std::string & ups, const std::string & battext) { setStr(ups, "battext", battext); } inline void setBus(const std::string & ups, const std::string & bus) { setStr(ups, "bus", bus); } inline void setCommunity(const std::string & ups, const std::string & community) { setStr(ups, "community", community); } inline void setDriver(const std::string & ups, const std::string & driver) { setStr(ups, "driver", driver); } inline void setDescription(const std::string & ups, const std::string & desc) { setStr(ups, "desc", desc); } inline void setFRUID(const std::string & ups, const std::string & fruid) { setStr(ups, "fruid", fruid); } inline void setGenericGPIO_Rules(const std::string & ups, const std::string & val) { setStr(ups, "rules", val); } inline void setGenericUPS_BYPASS(const std::string & ups, const std::string & bypass) { setStr(ups, "BYPASS", bypass); } inline void setGenericUPS_CP(const std::string & ups, const std::string & cp) { setStr(ups, "CP", cp); } inline void setGenericUPS_LB(const std::string & ups, const std::string & lb) { setStr(ups, "LB", lb); } inline void setGenericUPS_OL(const std::string & ups, const std::string & ol) { setStr(ups, "OL", ol); } inline void setGenericUPS_RB(const std::string & ups, const std::string & rb) { setStr(ups, "RB", rb); } inline void setGenericUPS_SD(const std::string & ups, const std::string & sd) { setStr(ups, "SD", sd); } inline void setGroup(const std::string & ups, const std::string & group) { setStr(ups, "group", group); } inline void setLoadStatus(const std::string & ups, const std::string & load_status) { setStr(ups, "load.status", load_status); } inline void setLogin(const std::string & ups, const std::string & login) { setStr(ups, "login", login); } inline void setLowBatt(const std::string & ups, const std::string & lowbatt) { setStr(ups, "LowBatt", lowbatt); } inline void setLowbatt(const std::string & ups, const std::string & lowbatt) { setStr(ups, "lowbatt", lowbatt); } inline void setManufacturer(const std::string & ups, const std::string & manufacturer) { setStr(ups, "manufacturer", manufacturer); } inline void setMethodOfFlowControl(const std::string & ups, const std::string & method) { setStr(ups, "methodOfFlowControl", method); } inline void setMIBs(const std::string & ups, const std::string & mibs) { setStr(ups, "mibs", mibs); } inline void setModbus_DeviceMfr(const std::string & ups, const std::string & val) { setStr(ups, "device_mfr", val); } inline void setModbus_DeviceModel(const std::string & ups, const std::string & val) { setStr(ups, "device_model", val); } inline void setModbus_Parity(const std::string & ups, const std::string & val) { setStr(ups, "parity", val); } inline void setModbus_PortType(const std::string & ups, const std::string & val) { setStr(ups, "porttype", val); } inline void setModbus_SerParity(const std::string & ups, const std::string & val) { setStr(ups, "ser_parity", val); } inline void setModel(const std::string & ups, const std::string & model) { setStr(ups, "model", model); } inline void setModelName(const std::string & ups, const std::string & modelname) { setStr(ups, "modelname", modelname); } inline void setNotification(const std::string & ups, const std::string & notification) { setStr(ups, "notification", notification); } inline void setPassword(const std::string & ups, const std::string & password) { setStr(ups, "password", password); } inline void setPort(const std::string & ups, const std::string & port) { setStr(ups, "port", port); } inline void setPrefix(const std::string & ups, const std::string & prefix) { setStr(ups, "prefix", prefix); } inline void setPrivPassword(const std::string & ups, const std::string & priv_passwd) { setStr(ups, "privPassword", priv_passwd); } inline void setPrivProtocol(const std::string & ups, const std::string & priv_proto) { setStr(ups, "privProtocol", priv_proto); } inline void setProduct(const std::string & ups, const std::string & product) { setStr(ups, "product", product); } inline void setProductID(const std::string & ups, const std::string & productid) { setStr(ups, "productid", productid); } inline void setProtocol(const std::string & ups, const std::string & protocol) { setStr(ups, "protocol", protocol); } inline void setRuntimeCal(const std::string & ups, const std::string & runtimecal) { setStr(ups, "runtimecal", runtimecal); } inline void setSDtype(const std::string & ups, const std::string & sdtype) { setStr(ups, "sdtype", sdtype); } inline void setSecLevel(const std::string & ups, const std::string & sec_level) { setStr(ups, "secLevel", sec_level); } inline void setSecName(const std::string & ups, const std::string & sec_name) { setStr(ups, "secName", sec_name); } inline void setSensorID(const std::string & ups, const std::string & sensorid) { setStr(ups, "sensorid", sensorid); } inline void setSerial(const std::string & ups, const std::string & serial) { setStr(ups, "serial", serial); } inline void setSerialNumber(const std::string & ups, const std::string & serialnumber) { setStr(ups, "serialnumber", serialnumber); } inline void setShutdownArguments(const std::string & ups, const std::string & sd_args) { setStr(ups, "shutdownArguments", sd_args); } inline void setSNMPversion(const std::string & ups, const std::string & snmp_version) { setStr(ups, "snmp_version", snmp_version); } inline void setSubdriver(const std::string & ups, const std::string & subdriver) { setStr(ups, "subdriver", subdriver); } inline void setSynchronous(const std::string & ups, const std::string & synchronous) { setStr(ups, "synchronous", synchronous); } inline void setTtyMode(const std::string & ups, const std::string & val) { setStr(ups, "ttymode", val); } inline void setType(const std::string & ups, const std::string & type) { setStr(ups, "type", type); } inline void setUPStype(const std::string & ups, const std::string & upstype) { setStr(ups, "upstype", upstype); } inline void setUpsId(const std::string & ups, const std::string & val) { setStr(ups, "upsid", val); } inline void setUsbBusPort(const std::string & ups, const std::string & val) { setStr(ups, "busport", val); } inline void setUsbDevice(const std::string & ups, const std::string & val) { setStr(ups, "device", val); } inline void setUSD(const std::string & ups, const std::string & usd) { setStr(ups, "usd", usd); } inline void setUsername(const std::string & ups, const std::string & username) { setStr(ups, "username", username); } inline void setUser(const std::string & ups, const std::string & user) { setStr(ups, "user", user); } inline void setValidationSequence(const std::string & ups, const std::string & valid_seq) { setStr(ups, "validationSequence", valid_seq); } inline void setVendor(const std::string & ups, const std::string & vendor) { setStr(ups, "vendor", vendor); } inline void setVendorID(const std::string & ups, const std::string & vendorid) { setStr(ups, "vendorid", vendorid); } inline void setWorkRangeType(const std::string & ups, const std::string & val) { setStr(ups, "work_range_type", val); } inline void setWUGrace(const std::string & ups, const std::string & wugrace) { setStr(ups, "wugrace", wugrace); } inline void setADVorder(const std::string & ups, long long int advorder) { setInt(ups, "advorder", advorder); } // CHECKME inline void setAsem_HB(const std::string & ups, long long int val) { setInt(ups, "hb", val); } inline void setAsem_LB(const std::string & ups, long long int val) { setInt(ups, "lb", val); } inline void setBatteryNumber(const std::string & ups, long long int val) { setInt(ups, "battery_number", val); } inline void setBatteryPercentage(const std::string & ups, long long int batt) { setInt(ups, "batteryPercentage", batt); } // CHECKME inline void setBattVoltMult(const std::string & ups, long long int mult) { setInt(ups, "battvoltmult", mult); } // CHECKME inline void setBaudRate(const std::string & ups, long long int baud_rate) { setInt(ups, "baud_rate", baud_rate); } // CHECKME inline void setBaudrate(const std::string & ups, long long int baudrate) { setInt(ups, "baudrate", baudrate); } // CHECKME inline void setCablePower(const std::string & ups, long long int cablepower) { setInt(ups, "cablepower", cablepower); } // CHECKME inline void setChargeTime(const std::string & ups, long long int chargetime) { setInt(ups, "chargetime", chargetime); } // CHECKME inline void setDaysOff(const std::string & ups, long long int daysoff) { setInt(ups, "daysoff", daysoff); } // CHECKME inline void setDaysWeek(const std::string & ups, long long int daysweek) { setInt(ups, "daysweek", daysweek); } // CHECKME inline void setDebugMin(const std::string & ups, long long int val) { setInt(ups, "debug_min", val); } inline void setLibusbDebug(const std::string & ups, long long int val) { setInt(ups, "LIBUSB_DEBUG", val); } inline void setFrequency(const std::string & ups, long long int frequency) { setInt(ups, "frequency", frequency); } // CHECKME inline void setHourOff(const std::string & ups, long long int houroff) { setInt(ups, "houroff", houroff); } // CHECKME inline void setHourOn(const std::string & ups, long long int houron) { setInt(ups, "houron", houron); } // CHECKME inline void setI2C_address(const std::string & ups, long long int val) { setInt(ups, "i2c_address", val); } inline void setIdleLoad(const std::string & ups, long long int idleload) { setInt(ups, "idleload", idleload); } // CHECKME inline void setInputTimeout(const std::string & ups, long long int timeout) { setInt(ups, "input_timeout", timeout); } // CHECKME inline void setInterruptPipeNoEventsTolerance(const std::string & ups, long long int val) { setInt(ups, "interrupt_pipe_no_events_tolerance", val); } inline void setInterruptSize(const std::string & ups, long long int val) { setInt(ups, "interruptsize", val); } inline void setLineVoltage(const std::string & ups, long long int linevoltage) { setInt(ups, "linevoltage", linevoltage); } // CHECKME inline void setLoadpercentage(const std::string & ups, long long int load) { setInt(ups, "loadPercentage", load); } // CHECKME inline void setMaxLoad(const std::string & ups, long long int max_load) { setInt(ups, "max_load", max_load); } // CHECKME inline void setMaxPollsWithoutData(const std::string & ups, long long int val) { setInt(ups, "max_polls_without_data", val); } inline void setMaxStartDelay(const std::string & ups, long long int delay) { setInt(ups, "maxstartdelay", delay); } inline void setMFR(const std::string & ups, long long int mfr) { setInt(ups, "mfr", mfr); } // CHECKME inline void setMinCharge(const std::string & ups, long long int mincharge) { setInt(ups, "mincharge", mincharge); } // CHECKME inline void setMinRuntime(const std::string & ups, long long int minruntime) { setInt(ups, "minruntime", minruntime); } // CHECKME inline void setModbus_ByteTimeoutSec(const std::string & ups, long long int val) { setInt(ups, "mod_byte_to_s", val); } inline void setModbus_ByteTimeoutUsec(const std::string & ups, long long int val) { setInt(ups, "mod_byte_to_us", val); } inline void setModbus_CHRG_addr(const std::string & ups, long long int val) { setInt(ups, "CHRG_addr", val); } inline void setModbus_CHRG_noro(const std::string & ups, long long int val) { setInt(ups, "CHRG_noro", val); } inline void setModbus_CHRG_regtype(const std::string & ups, long long int val) { setInt(ups, "CHRG_regtype", val); } inline void setModbus_DISCHRG_addr(const std::string & ups, long long int val) { setInt(ups, "DISCHRG_addr", val); } inline void setModbus_DISCHRG_noro(const std::string & ups, long long int val) { setInt(ups, "DISCHRG_noro", val); } inline void setModbus_DISCHRG_regtype(const std::string & ups, long long int val) { setInt(ups, "DISCHRG_regtype", val); } inline void setModbus_DataBits(const std::string & ups, long long int val) { setInt(ups, "databits", val); } inline void setModbus_DeviceSlaveId(const std::string & ups, long long int val) { setInt(ups, "dev_slave_id", val); } inline void setModbus_FSD_addr(const std::string & ups, long long int val) { setInt(ups, "FSD_addr", val); } inline void setModbus_FSD_noro(const std::string & ups, long long int val) { setInt(ups, "FSD_noro", val); } inline void setModbus_FSD_pulse_duration(const std::string & ups, long long int val) { setInt(ups, "FSD_pulse_duration", val); } inline void setModbus_FSD_regtype(const std::string & ups, long long int val) { setInt(ups, "FSD_regtype", val); } inline void setModbus_HB_addr(const std::string & ups, long long int val) { setInt(ups, "HB_addr", val); } inline void setModbus_HB_noro(const std::string & ups, long long int val) { setInt(ups, "HB_noro", val); } inline void setModbus_HB_regtype(const std::string & ups, long long int val) { setInt(ups, "HB_regtype", val); } inline void setModbus_LB_addr(const std::string & ups, long long int val) { setInt(ups, "LB_addr", val); } inline void setModbus_LB_noro(const std::string & ups, long long int val) { setInt(ups, "LB_noro", val); } inline void setModbus_LB_regtype(const std::string & ups, long long int val) { setInt(ups, "LB_regtype", val); } inline void setModbus_OB_addr(const std::string & ups, long long int val) { setInt(ups, "OB_addr", val); } inline void setModbus_OB_noro(const std::string & ups, long long int val) { setInt(ups, "OB_noro", val); } inline void setModbus_OB_regtype(const std::string & ups, long long int val) { setInt(ups, "OB_regtype", val); } inline void setModbus_OL_addr(const std::string & ups, long long int val) { setInt(ups, "OL_addr", val); } inline void setModbus_OL_noro(const std::string & ups, long long int val) { setInt(ups, "OL_noro", val); } inline void setModbus_OL_regtype(const std::string & ups, long long int val) { setInt(ups, "OL_regtype", val); } inline void setModbus_RB_addr(const std::string & ups, long long int val) { setInt(ups, "RB_addr", val); } inline void setModbus_RB_noro(const std::string & ups, long long int val) { setInt(ups, "RB_noro", val); } inline void setModbus_RB_regtype(const std::string & ups, long long int val) { setInt(ups, "RB_regtype", val); } inline void setModbus_ResponseTimeoutMsec(const std::string & ups, long long int val) { setInt(ups, "response_timeout_ms", val); } inline void setModbus_ResponseTimeoutSec(const std::string & ups, long long int val) { setInt(ups, "mod_resp_to_s", val); } inline void setModbus_ResponseTimeoutUsec(const std::string & ups, long long int val) { setInt(ups, "mod_resp_to_us", val); } inline void setModbus_RioSlaveId(const std::string & ups, long long int val) { setInt(ups, "rio_slave_id", val); } inline void setModbus_SerBaudRate(const std::string & ups, long long int val) { setInt(ups, "ser_baud_rate", val); } inline void setModbus_SerDataBit(const std::string & ups, long long int val) { setInt(ups, "ser_data_bit", val); } inline void setModbus_SerStopBit(const std::string & ups, long long int val) { setInt(ups, "ser_stop_bit", val); } inline void setModbus_SlaveId(const std::string & ups, long long int val) { setInt(ups, "slaveid", val); } inline void setModbus_StopBits(const std::string & ups, long long int val) { setInt(ups, "stopbits", val); } inline void setNomBattVolt(const std::string & ups, long long int nombattvolt) { setInt(ups, "nombattvolt", nombattvolt); } // CHECKME inline void setNumOfBytesFromUPS(const std::string & ups, long long int bytes) { setInt(ups, "numOfBytesFromUPS", bytes); } // CHECKME inline void setOffDelay(const std::string & ups, long long int offdelay) { setInt(ups, "OffDelay", offdelay); } // CHECKME inline void setOffdelay(const std::string & ups, long long int offdelay) { setInt(ups, "offdelay", offdelay); } // CHECKME inline void setOnDelay(const std::string & ups, long long int ondelay) { setInt(ups, "OnDelay", ondelay); } // CHECKME inline void setOndelay(const std::string & ups, long long int ondelay) { setInt(ups, "ondelay", ondelay); } // CHECKME inline void setOnlineDischargeLogThrottleHovercharge(const std::string & ups, long long int val) { setInt(ups, "onlinedischarge_log_throttle_hovercharge", val); } inline void setOnlineDischargeLogThrottleSec(const std::string & ups, long long int val) { setInt(ups, "onlinedischarge_log_throttle_sec", val); } inline void setOutputPace(const std::string & ups, long long int output_pace) { setInt(ups, "output_pace", output_pace); } // CHECKME inline void setOutputPhaseAngle(const std::string & ups, long long int val) { setInt(ups, "output_phase_angle", val); } inline void setPinsShutdownMode(const std::string & ups, long long int val) { setInt(ups, "pins_shutdown_mode", val); } inline void setPollFreq(const std::string & ups, long long int pollfreq) { setInt(ups, "pollfreq", pollfreq); } // CHECKME inline void setPowerUp(const std::string & ups, long long int powerup) { setInt(ups, "powerup", powerup); } // CHECKME inline void setPrgShut(const std::string & ups, long long int prgshut) { setInt(ups, "prgshut", prgshut); } // CHECKME inline void setRebootDelay(const std::string & ups, long long int delay) { setInt(ups, "rebootdelay", delay); } // CHECKME inline void setSDtime(const std::string & ups, long long int sdtime) { setInt(ups, "sdtime", sdtime); } // CHECKME inline void setSDOrder(const std::string & ups, long long int ord) { setInt(ups, "sdorder", ord); } inline void setSemistaticFreq(const std::string & ups, long long int val) { setInt(ups, "semistaticfreq", val); } inline void setShutdownDelay(const std::string & ups, long long int delay) { setInt(ups, "shutdown_delay", delay); } // CHECKME inline void setShutdownDuration(const std::string & ups, long long int val) { setInt(ups, "shutdown_duration", val); } inline void setShutdownTimer(const std::string & ups, long long int val) { setInt(ups, "shutdown_timer", val); } inline void setSlaveAddress(const std::string & ups, long long int val) { setInt(ups, "slave_address", val); } inline void setSnmpRetries(const std::string & ups, long long int val) { setInt(ups, "snmp_retries", val); } inline void setSnmpTimeout(const std::string & ups, long long int val) { setInt(ups, "snmp_timeout", val); } inline void setStartDelay(const std::string & ups, long long int delay) { setInt(ups, "startdelay", delay); } // CHECKME inline void setTestTime(const std::string & ups, long long int testtime) { setInt(ups, "testtime", testtime); } // CHECKME inline void setTimeout(const std::string & ups, long long int timeout) { setInt(ups, "timeout", timeout); } // CHECKME inline void setUPSdelayShutdown(const std::string & ups, long long int delay) { setInt(ups, "ups.delay.shutdown", delay); } // CHECKME inline void setUPSdelayStart(const std::string & ups, long long int delay) { setInt(ups, "ups.delay.start", delay); } // CHECKME inline void setVoltage(const std::string & ups, long long int voltage) { setInt(ups, "voltage", voltage); } // CHECKME inline void setWaitBeforeReconnect(const std::string & ups, long long int val) { setInt(ups, "waitbeforereconnect", val); } // Items below are "unused" - mostly set in // drivers/nutdrv_qx_masterguard.c inline void setFault1(const std::string & ups, const std::string & val) { setStr(ups, "fault_1", val); } inline void setFault2(const std::string & ups, const std::string & val) { setStr(ups, "fault_2", val); } inline void setFault3(const std::string & ups, const std::string & val) { setStr(ups, "fault_3", val); } inline void setFault4(const std::string & ups, const std::string & val) { setStr(ups, "fault_4", val); } inline void setFault5(const std::string & ups, const std::string & val) { setStr(ups, "fault_5", val); } inline void setInputFaultVoltage(const std::string & ups, const std::string & val) { setStr(ups, "input_fault_voltage", val); } inline void setNominalCellVoltage(const std::string & ups, const std::string & val) { setStr(ups, "nominal_cell_voltage",val); } inline void setNumberOfBatteryCells(const std::string & ups, const std::string & val) { setStr(ups, "number_of_battery_cells", val); } inline void setOutputVoltages(const std::string & ups, const std::string & val) { setStr(ups, "output_voltages", val); } inline void setRechargeTime(const std::string & ups, const std::string & val) { setStr(ups, "recharge_time", val); } inline void setRuntimeFull(const std::string & ups, const std::string & val) { setStr(ups, "runtime_full", val); } inline void setRuntimeHalf(const std::string & ups, const std::string & val) { setStr(ups, "runtime_half", val); } inline void setSeries(const std::string & ups, const std::string & val) { setStr(ups, "series", val); } // Items below are essentially booleans (expected values // are "enabled/disabled") -- refactoring planned per // https://github.com/networkupstools/nut/issues/2421 inline void setAdvancedEcoMode(const std::string & ups, const std::string & val) { setStr(ups, "advanced_eco_mode", val); } inline void setAlarmControl(const std::string & ups, const std::string & val) { setStr(ups, "alarm_control", val); } inline void setBatteryAlarm(const std::string & ups, const std::string & val) { setStr(ups, "battery_alarm", val); } inline void setBatteryOpenStatusCheck(const std::string & ups, const std::string & val) { setStr(ups, "battery_open_status_check", val); } inline void setBypassAlarm(const std::string & ups, const std::string & val) { setStr(ups, "bypass_alarm", val); } inline void setBypassForbidding(const std::string & ups, const std::string & val) { setStr(ups, "bypass_forbidding", val); } inline void setBypassWhenOff(const std::string & ups, const std::string & val) { setStr(ups, "bypass_when_off", val); } inline void setConstantPhaseAngle(const std::string & ups, const std::string & val) { setStr(ups, "constant_phase_angle",val); } inline void setConverterMode(const std::string & ups, const std::string & val) { setStr(ups, "converter_mode", val); } inline void setEcoMode(const std::string & ups, const std::string & val) { setStr(ups, "eco_mode", val); } inline void setLimitedRuntimeOnBattery(const std::string & ups, const std::string & val) { setStr(ups, "limited_runtime_on_battery", val); } inline void setSiteFaultDetection(const std::string & ups, const std::string & val) { setStr(ups, "site_fault_detection",val); } /** belkinunv: both a flag (wait for AC power) and value (also wait for charge level) */ inline void setWait(const std::string & ups, long long int wait) { setInt(ups, "wait", wait); } // CHECKME /** May be a flag or a number; 0 is among valid values (default -1 for unset) */ inline void setUsbSetAltInterface(const std::string & ups, long long int val = 0) { if (val >= 0) { setInt(ups, "usb_set_altinterface", val); } else { remove(ups, "usb_set_altinterface"); } } // CHECKME // NUT specifies these as "hexnum" values (optionally with prefixed 0x but hex anyway) inline void setUsbConfigIndex(const std::string & ups, long long int val) { setIntHex(ups, "usb_config_index", val); } // CHECKME inline void setUsbHidDescIndex(const std::string & ups, long long int val) { setIntHex(ups, "usb_hid_desc_index", val); } // CHECKME inline void setUsbHidRepIndex(const std::string & ups, long long int val) { setIntHex(ups, "usb_hid_rep_index", val); } // CHECKME inline void setUsbHidEndpointIn(const std::string & ups, long long int val) { setIntHex(ups, "usb_hid_ep_in", val); } // CHECKME inline void setUsbHidEndpointOut(const std::string & ups, long long int val) { setIntHex(ups, "usb_hid_ep_out", val); } // CHECKME inline void setBatteryMax(const std::string & ups, double val) { setDouble(ups, "battery_max", val); } inline void setBatteryMin(const std::string & ups, double val) { setDouble(ups, "battery_min", val); } inline void setCSHackDelay(const std::string & ups, double val) { setDouble(ups, "cshdelay", val); } inline void setMaxBypassFreq(const std::string & ups, double val) { setDouble(ups, "max_bypass_freq", val); } inline void setMaxBypassVolt(const std::string & ups, double val) { setDouble(ups, "max_bypass_volt", val); } inline void setMinBypassFreq(const std::string & ups, double val) { setDouble(ups, "min_bypass_freq", val); } inline void setMinBypassVolt(const std::string & ups, double val) { setDouble(ups, "min_bypass_volt", val); } // Flag - if exists then "true"; remove() to "unset" => "false" inline void setCancelShutdown(const std::string & ups, bool set = true) { setFlag(ups, "CS", set); } inline void setDumbTerm(const std::string & ups, bool set = true) { setFlag(ups, "dumbterm", set); } inline void setExplore(const std::string & ups, bool set = true) { setFlag(ups, "explore", set); } inline void setFakeLowBatt(const std::string & ups, bool set = true) { setFlag(ups, "fake_lowbatt", set); } inline void setFlash(const std::string & ups, bool set = true) { setFlag(ups, "flash", set); } inline void setIgnoreLB(const std::string & ups, bool set = true) { setFlag(ups, "ignorelb", set); } inline void setNoHang(const std::string & ups, bool set = true) { setFlag(ups, "nohang", set); } inline void setNoRating(const std::string & ups, bool set = true) { setFlag(ups, "norating", set); } inline void setNoTransferOIDs(const std::string & ups, bool set = true) { setFlag(ups, "notransferoids", set); } inline void setNoVendor(const std::string & ups, bool set = true) { setFlag(ups, "novendor", set); } inline void setNoWarnNoImp(const std::string & ups, bool set = true) { setFlag(ups, "nowarn_noimp", set); } inline void setOldMAC(const std::string & ups, bool set = true) { setFlag(ups, "oldmac", set); } inline void setPollOnly(const std::string & ups, bool set = true) { setFlag(ups, "pollonly", set); } inline void setSilent(const std::string & ups, bool set = true) { setFlag(ups, "silent", set); } inline void setStatusOnly(const std::string & ups, bool set = true) { setFlag(ups, "status_only", set); } // aka OPTI_MINPOLL inline void setSubscribe(const std::string & ups, bool set = true) { setFlag(ups, "subscribe", set); } inline void setUseCRLF(const std::string & ups, bool set = true) { setFlag(ups, "use_crlf", set); } inline void setUsePreLF(const std::string & ups, bool set = true) { setFlag(ups, "use_pre_lf", set); } inline void setNolock(const std::string & ups, bool set = true) { setBool(ups, "nolock", set); } inline void setCable(const std::string & ups, bool set = true) { setBool(ups, "cable", set); } inline void setFullUpdate(const std::string & ups, bool set = true) { setBool(ups, "full_update", set); } inline void setLangIDfix(const std::string & ups, bool set = true) { setBool(ups, "langid_fix", set); } inline void setLoadOff(const std::string & ups, bool set = true) { setBool(ups, "load.off", set); } inline void setLoadOn(const std::string & ups, bool set = true) { setBool(ups, "load.on", set); } /** \} */ virtual ~UpsConfiguration() override; }; // end of class UpsConfiguration /** upsd users configuration */ class UpsdUsersConfiguration : public GenericConfiguration { public: /** upsmon mode */ typedef enum { UPSMON_UNDEF = 0, /**< Unknown mode */ UPSMON_PRIMARY, /**< Primary (legacy "Master") mode */ UPSMON_SECONDARY, /**< Secondary (legacy "Slave") mode */ } upsmon_mode_t; /** User-specific configuration attributes getters and setters \{ */ inline std::string getPassword(const std::string & user) const { return getStr(user, "password"); } /** Currently valid actions include "SET" and "FSD", * but the method does not constrain the values */ inline ConfigParamList getActions(const std::string & user) const { ConfigParamList actions; get(user, "actions", actions); return actions; } /** Valid commands are "ALL" or a list of specific commands * supported by the device (NUT driver dependent) */ inline ConfigParamList getInstantCommands(const std::string & user) const { ConfigParamList cmds; get(user, "instcmds", cmds); return cmds; } upsmon_mode_t getUpsmonMode() const; inline void setPassword(const std::string & user, const std::string & passwd) { setStr(user, "password", passwd); } inline void setActions(const std::string & user, const ConfigParamList & actions) { set(user, "actions", actions); } inline void setInstantCommands(const std::string & user, const ConfigParamList & cmds) { set(user, "instcmds", cmds); } inline void addActions(const std::string & user, const ConfigParamList & actions) { add(user, "actions", actions); } inline void addInstantCommands(const std::string & user, const ConfigParamList & cmds) { add(user, "instcmds", cmds); } /** * \brief upsmon mode setter * * Note that the UPSMON_UNDEF mode isn't allowed as parameter * (logically, if you set something, it shall be defined...) * * \param mode Mode */ /* TOTHINK: Do we need a writer (other method, optional parameter * to this one) for obsolete wordings of the upsmon mode? * Note: reader in the getter accepts both old and new values. */ void setUpsmonMode(upsmon_mode_t mode); /** \} */ /** Serialisable interface implementation overload \{ */ bool parseFrom(NutStream & istream) override; bool writeTo(NutStream & ostream) const override; /** \} */ }; // end of class UpsdUsersConfiguration } /* namespace nut */ #endif /* __cplusplus */ #endif /* NUTCONF_H_SEEN */ nut-2.8.3/include/nutstream.hpp0000644000200500020050000007174514777767434013465 00000000000000/* nutstream.hpp - NUT stream Copyright (C) 2012 Eaton Author: Vaclav Krpec Copyright (C) 2024-2025 NUT Community Author: Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef nut_nutstream_h #define nut_nutstream_h #ifdef __cplusplus #include #include #include #include #include extern "C" { #include #include #include #ifndef WIN32 # include #else /* WIN32 */ # if HAVE_WINSOCK2_H # include # endif # if HAVE_WS2TCPIP_H # include # endif /* Using a private implementation in nutstream.cpp * similar to nutclient.cpp; do not call wincompat.h! * FIXME: refactor to reuse the C++ adaptation? */ #endif /* WIN32 */ } /* See include/common.h for details behind this */ #ifndef NUT_UNUSED_VARIABLE #define NUT_UNUSED_VARIABLE(x) (void)(x) #endif namespace nut { /** * \brief Data stream interface * * The interface provides character-based streamed I/O. */ class NutStream { public: /** Data store status */ typedef enum { NUTS_OK = 0, /** Operation successful */ NUTS_EOF, /** End of stream reached */ NUTS_ERROR, /** Error occurred */ } status_t; protected: /** Formal constructor */ NutStream() {} public: /** * \brief Get one character from current position * * The method provides character from current position * in the data store. * The position is not shifted (see \ref readChar for * current character consumption). * * The operation is synchronous (the call blocks if necessary). * * \param[out] ch Character * * \retval NUTS_OK on success, * \retval NUTS_EOF on end of stream, * \retval NUTS_ERROR on read error */ virtual status_t getChar(char & ch) = 0; /** * \brief Consume current character * * The method shifts position in the stream. * It shall never block (if the position gets * past-the-end of currently available data, * subsequent call to \ref getChar will block). */ virtual void readChar() = 0; /** * \brief Read characters from the stream till EoF * * The method may be used to synchronously read * whole (rest of) stream. * Note that implementation may block flow. * * \retval NUTS_OK on success, * \retval NUTS_ERROR on read error */ virtual status_t getString(std::string & str) = 0; /** * \brief Put one character to the stream end * * \param[in] ch Character * * \retval NUTS_OK on success, * \retval NUTS_ERROR on write error */ virtual status_t putChar(char ch) = 0; /** * \brief Put string to the stream end * * \param[in] str String * * \retval NUTS_OK on success, * \retval NUTS_ERROR on write error */ virtual status_t putString(const std::string & str) = 0; /** * \brief Put data to the stream end * * The difference between \ref putString and this method * is that it is able to serialize also data containing * null characters. * * \param[in] data Data * * \retval NUTS_OK on success, * \retval NUTS_ERROR on write error */ virtual status_t putData(const std::string & data) = 0; /** * \brief Flush output buffers for the stream being written * * \param[out] err_code Error code * \param[out] err_msg Error message * * \retval true if flush succeeded * \retval false if flush failed */ virtual bool flush(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif = 0; /** * \brief Flush output buffers for the stream being written * * \retval true if flush succeeded * \retval false if flush failed */ virtual bool flush() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif = 0; /** Flush output buffers for the file (or throw exception) */ virtual void flushx() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif = 0; /** Formal destructor */ virtual ~NutStream(); }; // end of class NutStream /** Memory stream */ class NutMemory: public NutStream { private: /** Implementation */ std::string m_impl; /** Position in implementation */ size_t m_pos; public: /** Constructor */ NutMemory(): m_pos(0) {} /** * \brief Constructor * * \param str Init value */ NutMemory(const std::string & str): m_impl(str), m_pos(0) {} // NutStream interface implementation status_t getChar(char & ch) override; void readChar() override; status_t getString(std::string & str) override; status_t putChar(char ch) override; status_t putString(const std::string & str) override; status_t putData(const std::string & data) override; // No-op for this class: inline bool flush (int & err_code, std::string & err_msg) override { NUT_UNUSED_VARIABLE(err_code); NUT_UNUSED_VARIABLE(err_msg); return true; } inline bool flush() override {return true;} inline void flushx() override {} }; // end of class NutMemory /** File stream */ class NutFile: public NutStream { public: /** Access mode */ typedef enum { /** Read-only, initial pos. is at the beginning */ READ_ONLY = 0, /** Write-only, with creation, clears the file if exists */ WRITE_ONLY, /** Read-write, initial pos. is at the beginning */ READ_WRITE, /** As previous, but with creation, clears the file if exists */ READ_WRITE_CLEAR, /** Read & write to end, with creation, init. pos: beginning/end for r/w */ READ_APPEND, /** Write only, with creation, initial position is at the end */ APPEND_ONLY, } access_t; /** Unnamed temp. file constructor flag */ typedef enum { ANONYMOUS, /** Anonymous temp. file flag */ } anonymous_t; private: /** Temporary files directory */ static const std::string m_tmp_dir; /** File name */ const std::string m_name; /** Implementation */ FILE *m_impl; /** Current character cache */ char m_current_ch; /** Current character cache status */ bool m_current_ch_valid; /** * \brief Convert enum access_t mode values to strings * for standard library methods * * Throws an exception on unexpected input (should never * happen with proper enum usage). * * \return Non-null "const char *" string */ const char *strAccessMode(access_t mode) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; public: /** Constructor * * \param[in] name File name */ NutFile(const std::string & name): m_name(name), m_impl(nullptr), m_current_ch('\0'), m_current_ch_valid(false) {} /** * \brief Temporary file constructor (with open) * * Anonymous temp. file (with automatic destruction) will be created. */ NutFile(anonymous_t); /** * \brief Detected temporary path name getter * * \return Path name */ inline static const std::string & tmp_dir() { return m_tmp_dir; } /** * \brief OS-dependent path separator character(s) * * \return Path separator */ inline static const std::string & path_sep() { static std::string pathsep = #ifdef WIN32 /* FIXME NUT_WIN32_INCOMPLETE : Actually modern Windows supports both slashes */ "\\"; #else /* !WIN32 */ "/"; #endif /* !WIN32 */ return pathsep; } /** * \brief File name getter * * \return File name */ inline const std::string & name() const { return m_name; } /** * \brief Check whether file exists * * \param[out] err_code Error code * \param[out] err_msg Error message * * \retval true IFF the file exists * \retval false otherwise */ bool exists(int & err_code, std::string & err_msg) const #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Check whether file exists * * \retval true IFF the file exists * \retval false otherwise */ inline bool exists() const #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return exists(ec, em); } /** * \brief Check whether file exists (or throw exception) * * \retval true IFF the file exists * \retval false otherwise */ inline bool existsx() const #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (exists(ec, em)) return true; if (ENOENT == ec || ENOTDIR == ec) return false; std::stringstream e; e << "Failed to check file " << m_name << " existence: " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Open file * * \param[in] mode File open mode * \param[out] err_code Error code * \param[out] err-msg Error message * * \retval true if open succeeded * \retval false if open failed */ bool open(access_t mode, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Open file * * \param[in] mode File open mode (read-only by default) * * \retval true if open succeeded * \retval false if open failed */ inline bool open(access_t mode = READ_ONLY) { int ec; std::string em; return open(mode, ec, em); } /** * \brief Open file (or throw exception) * * \param[in] mode File open mode (read-only by default) * * \retval true if open succeeded * \retval false if open failed */ inline void openx(access_t mode = READ_ONLY) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (open(mode, ec, em)) return; std::stringstream e; e << "Failed to open file " << m_name << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Flush output buffers for the file * * \param[out] err_code Error code * \param[out] err_msg Error message * * \retval true if flush succeeded * \retval false if flush failed */ bool flush(int & err_code, std::string & err_msg) override #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Flush output buffers for the file * * \retval true if flush succeeded * \retval false if flush failed */ inline bool flush() override #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return flush(ec, em); } /** Flush output buffers for the file (or throw exception) */ inline void flushx() override #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (flush(ec, em)) return; std::stringstream e; e << "Failed to flush file " << m_name << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Close file * * \param[out] err_code Error code * \param[out] err_msg Error message * * \retval true if close succeeded * \retval false if close failed */ bool close(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Close file * * \retval true if close succeeded * \retval false if close failed */ inline bool close() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return close(ec, em); } /** Close file (or throw exception) */ inline void closex() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (close(ec, em)) return; std::stringstream e; e << "Failed to close file " << m_name << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Remove file * * \param[out] err_code Error code * \param[out] err-msg Error message * * \retval true if \c unlink succeeded * \retval false if \c unlink failed */ bool remove(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Remove file * * \retval true if \c unlink succeeded * \retval false if \c unlink failed */ inline bool remove() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return remove(ec, em); } /** Remove file (or throw exception) */ inline void removex() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (remove(ec, em)) return; std::stringstream e; e << "Failed to remove file " << m_name << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Constructor (with open) * * Opens the file, throws exception on open error. * * \param[in] name File name * \param[in] mode File open mode */ NutFile(const std::string & name, access_t mode); /** * \brief Temporary file constructor (with open) * * Opens file in \ref m_tmp_dir. * Throws exception on open error. * Note that for temporary files, non-creation modes * don't make sense (and will result in throwing an exception). * * \param[in] name File name * \param[in] mode File open mode (r/w by default) */ NutFile(access_t mode = READ_WRITE_CLEAR); // NutStream interface implementation status_t getChar(char & ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; void readChar() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; status_t getString(std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; status_t putChar(char ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; status_t putString(const std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; status_t putData(const std::string & data) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; /** Destructor (closes the file) */ ~NutFile() override; private: /** * \brief Copy constructor * * TODO: Copying is forbidden (for now). * If required, it may be enabled, using fdup. * * \param orig Original file */ NutFile(const NutFile & orig) #if (defined __cplusplus) && (__cplusplus >= 201100) __attribute__((noreturn)) #endif { NUT_UNUSED_VARIABLE(orig); throw std::logic_error("NOT IMPLEMENTED"); } /** * \brief Assignment * * TODO: Assignment is forbidden (for now). * See copy constructor for implementation notes * (and don't forget to destroy left value, properly). * * \param rval Right value */ NutFile & operator = (const NutFile & rval) #if (defined __cplusplus) && (__cplusplus >= 201100) __attribute__((noreturn)) #endif { NUT_UNUSED_VARIABLE(rval); throw std::logic_error("NOT IMPLEMENTED"); } }; // end of class NutFile /** Socket stream */ class NutSocket: public NutStream { public: /** Socket domain */ typedef enum { NUTSOCKD_UNIX = AF_UNIX, /** Unix */ NUTSOCKD_INETv4 = AF_INET, /** IPv4 */ NUTSOCKD_INETv6 = AF_INET6, /** IPv6 */ NUTSOCKD_UNDEFINED = -1 } domain_t; /** Socket type */ typedef enum { NUTSOCKT_STREAM = SOCK_STREAM, /** Stream */ NUTSOCKT_DGRAM = SOCK_DGRAM, /** Datagram */ NUTSOCKT_UNDEFINED = -1 } type_t; /** Socket protocol */ typedef enum { NUTSOCKP_IMPLICIT = 0, /** Implicit protocol for chosen type */ } proto_t; /** Socket address */ class Address { friend class NutSocket; private: /** Implementation */ struct sockaddr *m_sock_addr; /** Length */ socklen_t m_length; /** * \brief Invalid address constructor * * Invalid address may be produced e.g. by failed DNS resolving. */ Address(): m_sock_addr(nullptr), m_length(0) {} /** * \brief Initialize UNIX socket address * * \param addr UNIX socket address * \param path Pathname */ static void init_unix(Address & addr, const std::string & path); /** * \brief Initialize IPv4 address * * \param addr IPv4 address * \param qb Byte quadruplet (MSB is at index 0) * \param port Port number */ static void init_ipv4(Address & addr, const std::vector & qb, uint16_t port); /** * \brief Initialize IPv6 address * * \param addr IPv6 address * \param hb 16 bytes of the address (MSB is at index 0) * \param port Port number */ static void init_ipv6(Address & addr, const std::vector & hb, uint16_t port); public: /** * \brief Check address validity * * \retval true if the address is valid * \retval false otherwise */ inline bool valid() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { return nullptr != m_sock_addr; } /** * \brief UNIX socket address constructor * * \param path Pathname */ Address(const std::string & path) { init_unix(*this, path); } /** * \brief IPv4 address constructor * * \param msb Most significant byte * \param msb2 Second most significant byte * \param lsb2 Second least significant byte * \param lsb Least significant byte * \param port Port number */ Address(unsigned char msb, unsigned char msb2, unsigned char lsb2, unsigned char lsb, uint16_t port); /** * \brief IP address constructor * * Creates either IPv4 or IPv6 address (depending on * how many bytes are provided via the \c bytes argument). * Throws an exception if the byte-count is invalid. * * \param bytes 4 or 16 address bytes (MSB is at index 0) * \param port Port number */ Address(const std::vector & bytes, uint16_t port) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif ; /** * \brief Copy constructor * * \param orig Original address */ Address(const Address & orig); /** * \brief Stringifisation * * \return String representation of the address */ std::string str() const; /** Stringification */ inline operator std::string() const { return str(); } /** Destructor */ ~Address(); }; // end of class Address /** Flag for socket constructor of accepted connection */ typedef enum { ACCEPT /** Accept flag */ } accept_flag_t; private: /** Socket implementation */ int m_impl; domain_t m_domain; type_t m_type; /** Current character cache */ char m_current_ch; /** Current character cache status */ bool m_current_ch_valid; /** * \brief Accept client connection on a listen socket * * \param[out] sock Socket * \param[in] listen_sock Listen socket * \param[out] err_code Error code * \param[out] err_msg Error message * * \retval true on success * \retval false otherwise */ static bool accept( NutSocket & sock, const NutSocket & listen_sock, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif ; /** * \brief Accept client connection on a listen socket * * \param[out] sock Socket * \param[in] listen_sock Listen socket * * \retval true on success * \retval false otherwise */ inline static bool accept( NutSocket & sock, const NutSocket & listen_sock) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { int ec; std::string em; return accept(sock, listen_sock, ec, em); } /** * \brief Accept client connection (or throw exception) * * \param[out] sock Socket * \param[in] listen_sock Listen socket */ inline static void acceptx( NutSocket & sock, const NutSocket & listen_sock) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error, std::runtime_error) #endif { int ec; std::string em; if (accept(sock, listen_sock, ec, em)) return; std::stringstream e; e << "Failed to accept connection: " << ec << ": " << em; throw std::runtime_error(e.str()); } public: /** * \brief Socket valid check * * \retval true if the socket is initialized * \retval false otherwise */ inline bool valid() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { return -1 != m_impl; } /** * \brief Constructor * * \param dom Socket domain * \param type Socket type * \param proto Socket protocol */ NutSocket( domain_t dom = NUTSOCKD_INETv4, type_t type = NUTSOCKT_STREAM, proto_t proto = NUTSOCKP_IMPLICIT); /** * \brief Accepted client socket constructor * * Accepts connection on a listen socket. * If the argument isn't a listen socket, exception is thrown. * The call will block until either there's an incoming connection * or the listening socket is closed or there's an error. * * \param listen_sock Listening socket */ NutSocket(accept_flag_t, const NutSocket & listen_sock, int & err_code, std::string & err_msg): m_impl(-1), m_domain(NUTSOCKD_UNDEFINED), m_type(NUTSOCKT_UNDEFINED), m_current_ch('\0'), m_current_ch_valid(false) { accept(*this, listen_sock, err_code, err_msg); } /** * \brief Accepted client socket constructor * * Accepts connection on a listen socket. * * \param listen_sock Listening socket */ NutSocket(accept_flag_t, const NutSocket & listen_sock): m_impl(-1), m_domain(NUTSOCKD_UNDEFINED), m_type(NUTSOCKT_UNDEFINED), m_current_ch('\0'), m_current_ch_valid(false) { accept(*this, listen_sock); } /** * \brief Bind socket to an address * * \param[in] addr Socket address * \param[out] err_code Error code * \param[out] err_msg Error message * * \retval true on success * \retval false on error */ bool bind(const Address & addr, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Bind socket to an address * * \param addr Socket address * * \retval true on success * \retval false on error */ inline bool bind(const Address & addr) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return bind(addr, ec, em); } /** * \brief Bind socket to an address (or throw exception) * * \param addr Socket address */ inline void bindx(const Address & addr) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (bind(addr, ec, em)) return; std::stringstream e; e << "Failed to bind socket to address " << addr.str() << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Listen on a socket * * The function sets TCP listen socket. * * \param[in] backlog Limit of pending connections * \param[out] err_code Error code * \param[out] err_msg Error message * * \retval true on success * \retval false on error */ bool listen(int backlog, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Listen on socket * * \param[in] backlog Limit of pending connections * * \retval true on success * \retval false on error */ inline bool listen(int backlog) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return listen(backlog, ec, em); } /** * \brief Listen on socket (or throw an exception) * * \param[in] backlog Limit of pending connections */ inline void listenx(int backlog) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (listen(backlog, ec, em)) return; std::stringstream e; e << "Failed to listen on socket: " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Connect to a listen socket * * \param[in] addr Remote address * \param[out] err_code Error code * \param[out] err_msg Error message * * \retval true on success * \retval false on error */ bool connect(const Address & addr, int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Connect to a listen socket * * \param[in] addr Remote address * * \retval true on success * \retval false on error */ inline bool connect(const Address & addr) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return connect(addr, ec, em); } /** * \brief Connect to a listen socket (or throw an exception) * * \param[in] addr Remote address */ inline void connectx(const Address & addr) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (connect(addr, ec, em)) return; std::stringstream e; e << "Failed to connect socket: " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Flush output data into socket * * \param[out] err_code Error code * \param[out] err-msg Error message * * \retval true if flush succeeded * \retval false if flush failed */ bool flush(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; /** * \brief Flush output data into socket * * \retval true if flush succeeded * \retval false if flush failed */ inline bool flush() override #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return flush(ec, em); } /** Flush output data into socket (or throw exception) */ inline void flushx() override #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (flush(ec, em)) return; std::stringstream e; e << "Failed to flush socket " << m_impl << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } /** * \brief Close socket * * \param[out] err_code Error code * \param[out] err-msg Error message * * \retval true if close succeeded * \retval false if close failed */ bool close(int & err_code, std::string & err_msg) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * \brief Close socket * * \retval true if close succeeded * \retval false if close failed */ inline bool close() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif { int ec; std::string em; return close(ec, em); } /** Close socket (or throw exception) */ inline void closex() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { int ec; std::string em; if (close(ec, em)) return; std::stringstream e; e << "Failed to close socket " << m_impl << ": " << ec << ": " << em; throw std::runtime_error(e.str()); } // NutStream interface implementation status_t getChar(char & ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; void readChar() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; status_t getString(std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; status_t putChar(char ch) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; status_t putString(const std::string & str) #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif override; inline status_t putData(const std::string & data) override { return putString(data); // no difference on sockets } /** Destructor (closes socket if necessary) */ ~NutSocket() override; private: /** * \brief Copy constructor * * TODO: Copying is forbidden (for now). * If required, it may be enabled, using dup. * * \param orig Original file */ NutSocket(const NutSocket & orig) #if (defined __cplusplus) && (__cplusplus >= 201100) __attribute__((noreturn)) #endif { NUT_UNUSED_VARIABLE(orig); throw std::logic_error("NOT IMPLEMENTED"); } /** * \brief Assignment * * TODO: Assignment is forbidden (for now). * See copy constructor for implementation notes * (and don't forget to destroy left value, properly). * * \param rval Right value */ NutSocket & operator = (const NutSocket & rval) { NUT_UNUSED_VARIABLE(rval); throw std::logic_error("NOT IMPLEMENTED"); } }; // end of class NutSocket } // end of namespace nut #endif /* __cplusplus */ #endif /* end of #ifndef nut_nutstream_h */ nut-2.8.3/include/state.h0000644000200500020050000000634514777767434012215 00000000000000/* state.h - Network UPS Tools common state management functions Copyright (C) 2003 Russell Kroll 2012 Arnaud Quette This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_STATE_H_SEEN #define NUT_STATE_H_SEEN 1 #include "extstate.h" #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #define ST_SOCK_BUF_LEN 512 #include "timehead.h" #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC typedef struct timespec st_tree_timespec_t; #else typedef struct timeval st_tree_timespec_t; #endif typedef struct st_tree_s { char *var; char *val; /* points to raw or safe */ char *raw; /* raw data from caller */ size_t rawsize; char *safe; /* safe data from pconf_encode */ size_t safesize; int flags; long aux; /* When was this entry last written (meaning that * val/raw/safe, flags, aux, enum or range value * was added, changed or deleted)? */ st_tree_timespec_t lastset; struct enum_s *enum_list; struct range_s *range_list; struct st_tree_s *left; struct st_tree_s *right; } st_tree_t; int state_get_timestamp(st_tree_timespec_t *now); int st_tree_node_compare_timestamp(const st_tree_t *node, const st_tree_timespec_t *cutoff); int state_setinfo(st_tree_t **nptr, const char *var, const char *val); int state_addenum(st_tree_t *root, const char *var, const char *val); int state_addrange(st_tree_t *root, const char *var, const int min, const int max); int state_setaux(st_tree_t *root, const char *var, const char *auxs); const char *state_getinfo(st_tree_t *root, const char *var); int state_getflags(st_tree_t *root, const char *var); long state_getaux(st_tree_t *root, const char *var); const enum_t *state_getenumlist(st_tree_t *root, const char *var); const range_t *state_getrangelist(st_tree_t *root, const char *var); void state_setflags(st_tree_t *root, const char *var, size_t numflags, char **flags); int state_addcmd(cmdlist_t **list, const char *cmd); void state_infofree(st_tree_t *node); void state_cmdfree(cmdlist_t *list); int state_delcmd(cmdlist_t **list, const char *cmd); int state_delinfo(st_tree_t **root, const char *var); int state_delinfo_olderthan(st_tree_t **root, const char *var, const st_tree_timespec_t *cutoff); int state_delenum(st_tree_t *root, const char *var, const char *val); int state_delrange(st_tree_t *root, const char *var, const int min, const int max); st_tree_t *state_tree_find(st_tree_t *node, const char *var); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_STATE_H_SEEN */ nut-2.8.3/include/extstate.h0000644000200500020050000000363414553676503012720 00000000000000/* extstate.h - external state structures used by things like upsd Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2007 Peter Selinger 2008 Arjen de Korte 2013 Emilien Kia 2020 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_EXTSTATE_H_SEEN #define NUT_EXTSTATE_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* this could be made dynamic if someone really needs more than this... */ #define ST_MAX_VALUE_LEN 256 /* state tree flags */ #define ST_FLAG_NONE 0x0000 #define ST_FLAG_RW 0x0001 #define ST_FLAG_STRING 0x0002 /* not STRING implies NUMBER */ #define ST_FLAG_NUMBER 0x0004 #define ST_FLAG_IMMUTABLE 0x0008 /* list of possible ENUM values */ typedef struct enum_s { char *val; struct enum_s *next; } enum_t; /* RANGE boundaries */ typedef struct range_s { int min; int max; struct range_s *next; } range_t; /* list of instant commands */ typedef struct cmdlist_s { char *name; struct cmdlist_s *next; } cmdlist_t; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_EXTSTATE_H_SEEN */ nut-2.8.3/include/attribute.h0000644000200500020050000000461314553676503013060 00000000000000/* attribute.h - portability hacks for __attribute__ usage in other header files Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2020 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_ATTRIBUTE_H_SEEN #define NUT_ATTRIBUTE_H_SEEN 1 /* To complicate matters, compilers with native support * for the keyword may expose or not expose it as a macro... * but for those that perform such courtesy, or are known * supporters, we can put up the flag. For others, someone * with those compilers should check and file PRs to NUT. */ #if (!defined HAVE___ATTRIBUTE__) || (HAVE___ATTRIBUTE__ == 0) # if ( defined(__GNUC__) && ( __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) ) ) || ( defined(__STRICT_ANSI__) && __STRICT_ANSI__ ) # ifndef __attribute__ # define __attribute__(x) # endif # ifndef HAVE___ATTRIBUTE__ # define HAVE___ATTRIBUTE__ 0 # endif # else # if defined(__clang__) || defined(__GNUC__) || defined(__SUNPRO_C) # ifndef HAVE___ATTRIBUTE__ # define HAVE___ATTRIBUTE__ 1 # endif # else # ifndef HAVE___ATTRIBUTE__ # define HAVE___ATTRIBUTE__ 0 # endif # endif # endif #endif #if (!defined HAVE___ATTRIBUTE__) || (HAVE___ATTRIBUTE__ == 0) # ifdef HAVE___ATTRIBUTE__UNUSED_ARG # undef HAVE___ATTRIBUTE__UNUSED_ARG # endif # ifdef HAVE___ATTRIBUTE__UNUSED_FUNC # undef HAVE___ATTRIBUTE__UNUSED_FUNC # endif # ifdef HAVE___ATTRIBUTE__NORETURN # undef HAVE___ATTRIBUTE__NORETURN # endif # ifdef HAVE___ATTRIBUTE__ # undef HAVE___ATTRIBUTE__ # endif #endif /* Other source files now can simply check for `ifdef HAVE___ATTRIBUTE__*` * as usual, and not bother about 0/1 values of the macro as well. */ #endif /* NUT_ATTRIBUTE_H_SEEN */ nut-2.8.3/include/nut_float.h0000644000200500020050000000511414777767434013061 00000000000000/* * nut_float.h - Network UPS Tools include files for floating point routines * and ways to compare if non-integers are close enough to assume equal * * Copyright (C) 2020 Jim Klimov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_FLOAT_H_SEEN #define NUT_FLOAT_H_SEEN 1 /* "config.h" is generated by autotools and lacks a header guard, so * we use an unambiguously named macro we know we must have, as one. * It must be the first header: be sure to know all about system config. */ #ifndef NUT_NETVERSION # include "config.h" #endif #if defined HAVE_FLOAT_H # include #endif #if defined HAVE_MATH_H # include #endif /* Modern compilers frown upon direct comparisons of floating point numbers * since their imprecise internal representations can misfire, and really we * care if they are indiscernably close. To aviod warnings like -Wfloat-equal * we prefer to compare with methods defined below. Note: despite the "floating" * name, fabs() seems to be defined over doubles or wider types, e.g.: * double fabs(double x); * float fabsf(float x); * long double fabsl(long double x); * To be on the safer side, we compare the difference to be smaller or equal to * the Epsilon for the respective numeric type, in order to be equivalent to a * zero for our needs. Various libs define it as "the next representable number * after 1.0 which is not equal to 1.0" for the discrete maths involved; no talk * about exactly comparing it to zero or whether it is the smallest representable * non-zero value... */ #define f_equal(x, y) ( fabsf((float)(x) - (float)(y)) <= FLT_EPSILON ) #define d_equal(x, y) ( fabs((double)(x) - (double)(y)) <= DBL_EPSILON ) #define ld_equal(x, y) ( fabsl((long double)(x) - (long double)(y)) <= LDBL_EPSILON ) #ifndef HAVE_STRTOF /* Use fallback from libcommon */ float strtof(const char *nptr, char **endptr); #endif #endif /* NUT_FLOAT_H_SEEN */ nut-2.8.3/include/common.h0000644000200500020050000006315614777767434012370 00000000000000/* common.h - prototypes for the common useful functions Copyright (C) 2000 Russell Kroll Copyright (C) 2021-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_COMMON_H_SEEN #define NUT_COMMON_H_SEEN 1 /* "config.h" is generated by autotools and lacks a header guard, so * we use an unambiguously named macro we know we must have, as one. * It must be the first header: be sure to know all about system config. */ #ifndef NUT_NETVERSION # include "config.h" #endif #ifdef WIN32 # ifndef __POSIX_VISIBLE /* for fcntl() and its flags in MSYS2 */ # define __POSIX_VISIBLE 200809 # endif #endif /* WIN32 */ /* Need this on AIX when using xlc to get alloca */ #ifdef _AIX #pragma alloca #endif /* _AIX */ #include #include #include #include #include /* suseconds_t among other things */ #include #ifdef HAVE_SYS_SIGNAL_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #include #ifdef HAVE_STRINGS_H #include /* for strncasecmp() and strcasecmp() */ #endif #ifdef HAVE_STRING_H #include /* for strdup() and many others */ #endif #ifndef WIN32 #include #else /* WIN32 */ #include #include #include #endif /* WIN32 */ #include /* useconds_t */ #ifndef HAVE_USECONDS_T # define useconds_t unsigned long int #endif #ifndef HAVE_SUSECONDS_T /* Note: WIN32 may have this defined as just "long" which should * hopefully be identical to the definition below, which we test * in our configure script. See also struct timeval fields for a * platform, if in doubt. */ # define suseconds_t signed long int #endif #include #include "timehead.h" #include "attribute.h" #include "proto.h" #include "str.h" #if (defined HAVE_LIBREGEX && HAVE_LIBREGEX) # include #endif #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* POSIX requires these, and most but not all systems use same * magical numbers for the file descriptors... yep, not all do! */ #ifndef STDIN_FILENO # define STDIN_FILENO 0 /* standard input file descriptor */ #endif #ifndef STDOUT_FILENO # define STDOUT_FILENO 1 /* standard output file descriptor */ #endif #ifndef STDERR_FILENO # define STDERR_FILENO 2 /* standard error file descriptor */ #endif /* porting stuff for WIN32, used by serial and SHUT codebases */ #ifndef WIN32 /* Just match three macro groups defined for WIN32 */ /* Type of what file open() and close() use, * including pipes for driver-upsd communications: */ # define TYPE_FD int # define ERROR_FD (-1) # define VALID_FD(a) (a>=0) /* Type of what NUT serial/SHUT methods juggle: */ # define TYPE_FD_SER TYPE_FD # define ERROR_FD_SER ERROR_FD # define VALID_FD_SER(a) VALID_FD(a) /* Type of what socket() returns, mostly for networked code: */ # define TYPE_FD_SOCK TYPE_FD # define ERROR_FD_SOCK ERROR_FD # define VALID_FD_SOCK(a) VALID_FD(a) #else /* WIN32 */ /* Separate definitions of TYPE_FD, ERROR_FD, VALID_FD() macros * for usual file descriptors vs. types needed for serial port * work or for networking sockets. */ # define TYPE_FD HANDLE # define ERROR_FD (INVALID_HANDLE_VALUE) # define VALID_FD(a) (a!=INVALID_HANDLE_VALUE) # ifndef INVALID_SOCKET # define INVALID_SOCKET -1 # endif # define TYPE_FD_SOCK SOCKET # define ERROR_FD_SOCK INVALID_SOCKET # define VALID_FD_SOCK(a) (a!=INVALID_SOCKET) typedef struct serial_handler_s { HANDLE handle; OVERLAPPED io_status; int overlapped_armed; unsigned int vmin_; unsigned int vtime_; unsigned int r_binary; unsigned int w_binary; } serial_handler_t; # define TYPE_FD_SER serial_handler_t * # define ERROR_FD_SER (NULL) # define VALID_FD_SER(a) (a!=NULL) /* difftime returns erroneous value so we use this macro */ # undef difftime # define difftime(t1,t0) (double)(t1 - t0) #endif /* WIN32 */ /* Two uppercase letters are more readable than one exclamation */ #define INVALID_FD_SER(a) (!VALID_FD_SER(a)) #define INVALID_FD_SOCK(a) (!VALID_FD_SOCK(a)) #define INVALID_FD(a) (!VALID_FD(a)) #define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0])) extern const char *UPS_VERSION; /* Use in code to notify the developers and quiesce the compiler that * (for this codepath) the argument or variable is unused intentionally. * void f(int x) { * NUT_UNUSED_VARIABLE(x); * ... * } * * Note that solutions which mark up function arguments or employ this or * that __attribute__ proved not portable enough for wherever NUT builds. */ #define NUT_UNUSED_VARIABLE(x) (void)(x) /** @brief Default timeout (in seconds) for network operations, as used by `upsclient` and `nut-scanner`. */ #define DEFAULT_NETWORK_TIMEOUT 5 /** @brief Default timeout (in seconds) for retrieving the result of a `TRACKING`-enabled operation (e.g. `INSTCMD`, `SET VAR`). */ #define DEFAULT_TRACKING_TIMEOUT 10 /* Returns a pointer to static internal char[] buffer with current value * of NUT_VERSION_MACRO (aka char* UPS_VERSION) and its layman description * (e.g. a "release" or "development iteration after" a certain semantically * versioned release). Returns UPS_VERSION if failed to construct a better * description. Either way, should not be free()'d by caller and does not * have an end-of-line char of its own. */ const char *describe_NUT_VERSION_once(void); /* Return a buffer with a (possibly multiline) string that can be printed * as part of program help/usage message. Caller should not free() the buffer. * Optional "progconf" allows to suggest config file(s) to study as well. * NOTE: the string in buffer starts with text and ends with one EOL char. */ const char *suggest_doc_links(const char *progname, const char *progconf); /* Based on NUT_QUIET_INIT_BANNER envvar (present and empty or "true") * hide the NUT tool name+version banners; show them by default */ int banner_is_disabled(void); /* Some NUT programs have historically printed their banner at start-up * always, and so did not print one in help()/usage() or handling `-V` * like others did. Now that we have NUT_QUIET_INIT_BANNER, we need a * way to print that banner (regardless of the flag in some cases). * The "even_if_disabled" should be 0 for initial banner of those * programs (so the envvar would hide it), 1 -V case and 2 in -h case * (for a blank line after). As before, the banner is printed to stdout. * Returns the result of printf() involved. Remembers to not print again * if the earlier printf() was successful. */ int print_banner_once(const char *prog, int even_if_disabled); /* Normally we can (attempt to) use the syslog or Event Log (WIN32), * but environment variable NUT_DEBUG_SYSLOG allows to bypass it, and * perhaps keep daemons logging to stderr (e.g. in NUT Integration Test * suite to not pollute the OS logs, or in systemd where stderr and * syslog both go into the same journal). Returns: * 0 Not disabled (NUT_DEBUG_SYSLOG not set to a value below; unset or "default" * values are handled quietly, but others emit a warning) * 1 Disabled and background() keeps stderr attached (NUT_DEBUG_SYSLOG="stderr") * 2 Disabled and background() detaches stderr as usual (NUT_DEBUG_SYSLOG="none") */ int syslog_is_disabled(void); /* get the syslog ready for us */ void open_syslog(const char *progname); /* close ttys and become a daemon */ void background(void); /* do this here to keep pwd/grp stuff out of the main files */ struct passwd *get_user_pwent(const char *name); /* change to the user defined in the struct */ void become_user(struct passwd *pw); /* drop down into a directory and throw away pointers to the old path */ void chroot_start(const char *path); /* Try to identify process (program) name for the given PID, * return NULL if we can not for any reason (does not run, * no rights, do not know how to get it on current OS, etc.) * If the returned value is not NULL, caller should free() it. * Some implementation pieces borrowed from * https://man7.org/linux/man-pages/man2/readlink.2.html and * https://github.com/openbsd/src/blob/master/bin/ps/ps.c * NOTE: Very much platform-dependent! */ char * getprocname(pid_t pid); /* Determine the base name of specified progname (may be full path) * and the location of the last "." dot character in it for extension * (caller's len and dot populated only if pointers are not NULL). */ size_t parseprogbasename(char *buf, size_t buflen, const char *progname, size_t *pprogbasenamelen, size_t *pprogbasenamedot); /* If we can determine the binary path name of the specified "pid", * check if it matches the assumed name of the current program. * Returns: * -3 Skipped because NUT_IGNORE_CHECKPROCNAME is set * -2 Could not parse a program name (ok to proceed, * risky - but matches legacy behavior) * -1 Could not identify a program name (ok to proceed, * risky - but matches legacy behavior) * 0 Process name identified, does not seem to match * 1+ Process name identified, and seems to match with * varying precision * Generally speaking, if (checkprocname(...)) then ok to proceed */ int checkprocname(pid_t pid, const char *progname); /* compareprocname() does the bulk of work for checkprocname() * and returns same values. The "pid" argument is used for logging. * Generally speaking, if (compareprocname(...)) then ok to proceed */ int compareprocname(pid_t pid, const char *procname, const char *progname); /* Helper for the above methods and some others. If it returns true (1), * work about PID-name comparison should be quickly skipped. */ int checkprocname_ignored(const char *caller); /* write a pid file - is a full pathname *or* just the program name */ void writepid(const char *name); /* parses string buffer into a pid_t if it passes * a few sanity checks; returns -1 on error */ pid_t parsepid(const char *buf); /* send a signal to another running NUT process */ #ifndef WIN32 int sendsignal(const char *progname, int sig, int check_current_progname); #else /* WIN32 */ int sendsignal(const char *progname, const char * sig, int check_current_progname); #endif /* WIN32 */ int snprintfcat(char *dst, size_t size, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); /***************************************************************************** * String methods for space-separated token lists, used originally in dstate * * NOTE: These methods are also exposed by external API (via libupsclient.h) * * with the `upscli_` prefix, to ease third-party C NUT clients' parsing of * * `ups.status` et al. * *****************************************************************************/ /* Return non-zero if "string" contains "token" (case-sensitive), * either surrounded by space character(s) or start/end of "string", * or 0 if that token is not there, or if either string is NULL or empty. */ int str_contains_token(const char *string, const char *token); /* Add "token" to end of string "tgt", if it is not yet there * (prefix it with a space character if "tgt" is not empty). * Return 0 if already there, 1 if token was added successfully, * -1 if we needed to add it but it did not fit under the tgtsize limit, * -2 if either string was NULL or "token" was empty. * NOTE: If token contains space(s) inside, recurse to treat it * as several tokens to add independently. * Optionally calls "callback_always" (if not NULL) after checking * for spaces (and maybe recursing) and before checking if the token * is already there, and/or "callback_unique" (if not NULL) after * checking for uniqueness and going to add a newly seen token. * If such callback returns 0, abort the addition of token and return -3. */ int str_add_unique_token(char *tgt, size_t tgtsize, const char *token, int (*callback_always)(char *, size_t, const char *), int (*callback_unique)(char *, size_t, const char *) ); /* Report maximum platform value for the pid_t */ pid_t get_max_pid_t(void); /* send sig to pid after some sanity checks, returns * -1 for error, or zero for a successfully sent signal */ int sendsignalpid(pid_t pid, int sig, const char *progname, int check_current_progname); /* open and get the pid * returns zero or more for successfully retrieved value, * negative for errors: * -3 PID file not found * -2 PID file not parsable */ pid_t parsepidfile(const char *pidfn); #ifndef WIN32 /* use parsepidfile() to get the pid, then send it * returns zero for successfully sent signal, * negative for errors: * -3 PID file not found * -2 PID file not parsable * -1 Error sending signal * * if executable process with that pid has suitable progname * (specified or that of the current process, depending on args: * most daemons request to check_current_progname for their other * process instancees, but upsdrvctl which manages differently * named driver programs does not request it) */ int sendsignalfn(const char *pidfn, int sig, const char *progname, int check_current_progname); #else /* WIN32 */ /* No progname here - communications via named pipe */ int sendsignalfn(const char *pidfn, const char * sig, const char *progname_ignored, int check_current_progname_ignored); #endif /* WIN32 */ const char *xbasename(const char *file); /* enable writing upslog_with_errno() and upslogx() type messages to the syslog */ void syslogbit_set(void); /* Return the default path for the directory containing configuration files */ const char * confpath(void); /* Return the default path for the directory containing state files */ const char * dflt_statepath(void); /* Return the alternate path for pid files (non-root daemons) */ const char * altpidpath(void); /* Return the main path for pid files (root daemons like upsmon) */ const char * rootpidpath(void); /* Die with a standard message if socket filename is too long */ void check_unix_socket_filename(const char *fn); /* Provide integration for systemd inhibitor interface (where available, * dummy code otherwise) implementing the pseudo-code example from * https://systemd.io/INHIBITOR_LOCKS/ * TODO: Potentially extensible to other frameworks with similar concepts?.. */ TYPE_FD Inhibit(const char *arg_what, const char *arg_who, const char *arg_why, const char *arg_mode); /* Let the service management framework proceed with its sleep mode */ void Uninhibit(TYPE_FD *fd_ptr); /* Check once if the system plans to sleep or is waking up: * -1 Same reply as before, whatever it was * 0 (false) Just after the sleep, at least as a bus signal * 1 (true) Before the sleep - we must process and un-block it */ int isPreparingForSleep(void); /* A couple of methods to reflect built-in (absent) or run-time (it depends) * support for monitoring that the OS goes to sleep and wakes up, and if we * can "inhibit" that going to sleep in order to do some house-keeping first. * -1 = do not know yet * 0 = not supported, do not bother asking in daemon loops * 1 = seems supported */ int isInhibitSupported(void); int isPreparingForSleepSupported(void); /* Send (daemon) state-change notifications to an * external service management framework such as systemd. * State types below are initially loosely modeled after * https://www.freedesktop.org/software/systemd/man/sd_notify.html */ typedef enum eupsnotify_state { NOTIFY_STATE_READY = 1, NOTIFY_STATE_READY_WITH_PID, NOTIFY_STATE_RELOADING, NOTIFY_STATE_STOPPING, NOTIFY_STATE_STATUS, /* Send a text message per "fmt" below */ NOTIFY_STATE_WATCHDOG /* Ping the framework that we are still alive */ } upsnotify_state_t; const char *str_upsnotify_state(upsnotify_state_t state); /* Note: here fmt may be null, then the STATUS message would not be sent/added */ int upsnotify(upsnotify_state_t state, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); /* upslog*() messages are sent to syslog always; * their life after that is out of NUT's control */ void upslog_with_errno(int priority, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); void upslogx(int priority, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); /* upsdebug*() messages are only logged if debugging * level is high enough. To speed up a bit (minimize * passing of ultimately ignored data trough the stack) * these are "hidden" implementations wrapped into * macros for earlier routine names spread around the * codebase, they would check debug level first and * only if logging should happen - call the routine * and pass around pointers and other data. */ void s_upsdebug_with_errno(int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); void s_upsdebugx(int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); void s_upsdebug_hex(int level, const char *msg, const void *buf, size_t len); void s_upsdebug_ascii(int level, const char *msg, const void *buf, size_t len); /* These macros should help avoid run-time overheads * passing data for messages nobody would ever see. * * Also NOTE: the "level" may be specified by callers in various ways, * e.g. as a "X ? Y : Z" style expression; to catch those expansions * transparently we hide them into parentheses as "(label)". * * For stricter C99 compatibility, all parameters specified to a macro * must be populated by caller (so we do not handle "fmt, args..." where * the args part may be skipped by caller because fmt is a fixed string). * Note it is then up to the caller (and compiler checks) that at least * one argument is provided, the format string (maybe fixed) -- as would * be required by the actual s_upsdebugx*() method after macro evaluation. */ #define upsdebug_with_errno(level, ...) \ do { if (nut_debug_level >= (level)) { s_upsdebug_with_errno((level), __VA_ARGS__); } } while(0) #define upsdebugx(level, ...) \ do { if (nut_debug_level >= (level)) { s_upsdebugx((level), __VA_ARGS__); } } while(0) #define upsdebug_hex(level, msg, buf, len) \ do { if (nut_debug_level >= (level)) { s_upsdebug_hex((level), msg, buf, len); } } while(0) #define upsdebug_ascii(level, msg, buf, len) \ do { if (nut_debug_level >= (level)) { s_upsdebug_ascii((level), msg, buf, len); } } while(0) void fatal_with_errno(int status, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))) __attribute__((noreturn)); void fatalx(int status, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))) __attribute__((noreturn)); /* Report CONFIG_FLAGS used for this build of NUT similarly to how * upsdebugx(1, ...) would do it, but not limiting the string length */ void nut_report_config_flags(void); /* Report search paths used by ltdl-augmented code to discover and * load shared binary object files at run-time (nut-scanner, DMF...) */ void upsdebugx_report_search_paths(int level, int report_search_paths_builtin); void nut_prepare_search_paths(void); /* Internal toggle for some NUT programs that deal with signal sending. * For a detailed rationale comment see common.c */ extern int nut_sendsignal_debug_level; #define NUT_SENDSIGNAL_DEBUG_LEVEL_DEFAULT 6 #define NUT_SENDSIGNAL_DEBUG_LEVEL_FOPEN_PIDFILE 5 #define NUT_SENDSIGNAL_DEBUG_LEVEL_KILL_SIG0PING 4 extern int nut_debug_level; extern int nut_log_level; void *xmalloc(size_t size); void *xcalloc(size_t number, size_t size); void *xrealloc(void *ptr, size_t size); char *xstrdup(const char *string); /**** REGEX helper methods ****/ /* helper function: version of strcmp that tolerates NULL * pointers. NULL is considered to come before all other strings * alphabetically. */ int strcmp_null(const char *s1, const char *s2); #if (defined HAVE_LIBREGEX && HAVE_LIBREGEX) /* Helper function for compiling a regular expression. On success, * store the compiled regular expression (or NULL) in *compiled, and * return 0. On error with errno set, return -1. If the supplied * regular expression is unparseable, return -2 (an error message can * then be retrieved with regerror(3)). Note that *compiled will be an * allocated value, and must be freed with regfree(), then free(), see * regex(3). As a special case, if regex==NULL, then set * *compiled=NULL (regular expression NULL is intended to match * anything). */ int compile_regex(regex_t **compiled, const char *regex, const int cflags); /* Helper function for regular expression matching. Check if the * entire string str (minus any initial and trailing whitespace) * matches the compiled regular expression preg. Return 1 if it * matches, 0 if not. Return -1 on error with errno set. Special * cases: if preg==NULL, it matches everything (no contraint). If * str==NULL, then it is treated as "". */ int match_regex(const regex_t *preg, const char *str); /* Helper function, similar to match_regex, but the argument being * matched is a (hexadecimal) number, rather than a string. It is * converted to a 4-digit hexadecimal string. */ int match_regex_hex(const regex_t *preg, const int n); #endif /* HAVE_LIBREGEX */ /* Note: different method signatures instead of TYPE_FD_SER due to "const" */ #ifndef WIN32 ssize_t select_read(const int fd, void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec); ssize_t select_write(const int fd, const void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec); #else /* WIN32 */ ssize_t select_read(serial_handler_t *fd, void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec); /* Note: currently not implemented de-facto for Win32 */ ssize_t select_write(serial_handler_t * fd, const void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec); #endif /* WIN32 */ char * get_libname(const char* base_libname); /* Buffer sizes used for various functions */ #define SMALLBUF 512 #define LARGEBUF 1024 /** @brief (Minimum) Size that a string must have to hold a UUID4 (i.e. UUID4 length + the terminating null character). */ #define UUID4_LEN 37 #define NUT_PATH_MAX SMALLBUF #if (defined(PATH_MAX)) && PATH_MAX > NUT_PATH_MAX # undef NUT_PATH_MAX # define NUT_PATH_MAX PATH_MAX #endif #if (defined(MAX_PATH)) && MAX_PATH > NUT_PATH_MAX /* PATH_MAX is the POSIX equivalent for Microsoft's MAX_PATH */ # undef NUT_PATH_MAX # define NUT_PATH_MAX MAX_PATH #endif #if (defined(UNIX_PATH_MAX)) && UNIX_PATH_MAX > NUT_PATH_MAX # undef NUT_PATH_MAX # define NUT_PATH_MAX UNIX_PATH_MAX #endif #if (defined(MAXPATHLEN)) && MAXPATHLEN > NUT_PATH_MAX # undef NUT_PATH_MAX # define NUT_PATH_MAX MAXPATHLEN #endif /* Provide declarations for getopt() global variables */ #ifdef NEED_GETOPT_H #include #else #ifdef NEED_GETOPT_DECLS extern char *optarg; extern int optind; #endif /* NEED_GETOPT_DECLS */ #endif /* HAVE_GETOPT_H */ /* logging flags: bitmask! */ #define UPSLOG_STDERR 0x0001 #define UPSLOG_SYSLOG 0x0002 #define UPSLOG_STDERR_ON_FATAL 0x0004 #define UPSLOG_SYSLOG_ON_FATAL 0x0008 #ifndef HAVE_SETEUID # define seteuid(x) setresuid(-1,x,-1) /* Works for HP-UX 10.20 */ # define setegid(x) setresgid(-1,x,-1) /* Works for HP-UX 10.20 */ #endif /* Several NUT programs define their set_exit_flag(int) methods * which accept a signal code or similar parameter. Commonly they * also accept a few negative values summarized below, to just * exit (typically after completing a processing loop) with one * of C standard exit codes. */ #define EF_EXIT_FAILURE -1 /* eventually exit(EXIT_FAILURE); */ #define EF_EXIT_SUCCESS -2 /* eventually exit(EXIT_SUCCESS); */ #ifdef WIN32 /* FIXME : this might not be the optimal mapping between syslog and ReportEvent*/ #define LOG_ERR EVENTLOG_ERROR_TYPE #define LOG_INFO EVENTLOG_INFORMATION_TYPE #define LOG_DEBUG EVENTLOG_WARNING_TYPE #define LOG_NOTICE EVENTLOG_INFORMATION_TYPE #define LOG_ALERT EVENTLOG_ERROR_TYPE #define LOG_WARNING EVENTLOG_WARNING_TYPE #define LOG_CRIT EVENTLOG_ERROR_TYPE #define LOG_EMERG EVENTLOG_ERROR_TYPE #define closelog() #define SVCNAME TEXT("Network UPS Tools") #define EVENTLOG_PIPE_NAME TEXT("nut") #define UPSMON_PIPE_NAME TEXT("upsmon") #define UPSD_PIPE_NAME TEXT("upsd") char * getfullpath(char * relative_path); #define PATH_ETC "\\..\\etc" #define PATH_VAR_RUN "\\..\\var\\run" #define PATH_SHARE "\\..\\share" #define PATH_BIN "\\..\\bin" #define PATH_SBIN "\\..\\sbin" #define PATH_LIB "\\..\\lib" #endif /* WIN32*/ /* Return a difference of two timevals as a floating-point number */ double difftimeval(struct timeval x, struct timeval y); #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) && HAVE_CLOCK_GETTIME && HAVE_CLOCK_MONOTONIC double difftimespec(struct timespec x, struct timespec y); #endif #ifndef HAVE_USLEEP /* int __cdecl usleep(unsigned int useconds); */ /* Note: if we'd need to define an useconds_t for obscure systems, * it should be an int capable of string 0..1000000 value range, * so probably unsigned long int */ int __cdecl usleep(useconds_t useconds); #endif /* HAVE_USLEEP */ #ifndef HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen); #endif /* Not all platforms support the flag; this method abstracts * its use (or not) to simplify calls in the actual codebase */ /* TODO NUT_WIN32_INCOMPLETE? : Extend for TYPE_FD and WIN32 eventually? */ void set_close_on_exec(int fd); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_COMMON_H_SEEN */ nut-2.8.3/include/wincompat.h0000644000200500020050000002543714777767434013101 00000000000000#ifndef NUT_WINCOMPAT_H #define NUT_WINCOMPAT_H 1 /* Copyright (C) 2001 Andrew Delpha (delpha@computer.org) 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. */ /* This header is provided to map Windows system calls to be compatible with the NUT code. */ #include "common.h" #include #include "nut_stdint.h" /* Used in ifdef code blocks that were not yet implemented as part of * the NUT for Windows upstreaming as a first-class citizen code base. * For more details, see: * https://github.com/networkupstools/nut/wiki/NUT-for-Windows * https://github.com/orgs/networkupstools/projects/2/views/1 * https://github.com/networkupstools/nut/issues?q=+label%3AWindows-not-on-par-with-POSIX+sort%3Aupdated-desc+ */ #define NUT_WIN32_INCOMPLETE_DETAILED(str) upsdebugx(1, "%s:%" PRIiMAX "::%s() : this method was not fully ported for WIN32: %s", __FILE__, (intmax_t)__LINE__, __func__, NUT_STRARG(str)) #define NUT_WIN32_INCOMPLETE() upsdebugx(1, "%s:%" PRIiMAX "::%s() : this method was not fully ported for WIN32", __FILE__, (intmax_t)__LINE__, __func__) #define NUT_WIN32_INCOMPLETE_LOGWARN() upslogx(LOG_WARNING, "WARNING: %s:%" PRIiMAX "::%s() : this method was not fully ported for WIN32", __FILE__, (intmax_t)__LINE__, __func__) /* These use-cases need to be revised, maybe hushed later: */ #define NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE() NUT_WIN32_INCOMPLETE_DETAILED("may be not applicable to the platform") /* This value is defined in the error.h file of the libusb-win32 sources * FIXME: Should only be relevant for builds WITH_LIBUSB_0_1 - #ifdef it so? * Conflicts with e.g. /msys64/mingw64/include/errno.h which defines it as 138 */ #ifndef ETIMEDOUT # define ETIMEDOUT 116 #endif #define random() rand() typedef const char * uid_t; struct passwd { const char *pw_name; int pw_uid; /* Fake value, alwaus set to 0 */ }; uid_t getuid(void); struct passwd *getpwuid(uid_t uid); char *getpass( const char *prompt); #define system(a) win_system(a) #define sleep(n) Sleep(1000 * n) char * strtok_r(char *str, const char *delim, char **saveptr); char * filter_path(const char * source); /* Network compatibility */ /* This is conditional because read/write are generic in unix, and this will make them network specific */ #ifdef W32_NETWORK_CALL_OVERRIDE #define close(h) sktclose(h) #define read(h,b,s) sktread(h,b,s) #define write(h,b,s) sktwrite( h ,(char *) b , s ) #define connect(h,n,l) sktconnect(h,n,l) #endif #ifndef strcasecmp #define strcasecmp(a,b) _stricmp(a,b) #endif #ifndef snprintf #define snprintf _snprintf #endif #ifndef vsnprintf #define vsnprintf _vsnprintf #endif int sktconnect(int fh, struct sockaddr * name, int len); int sktread(int fh, char *buf, int size); int sktwrite(int fh, char *buf, int size); int sktclose(int fh); #if ! HAVE_INET_NTOP /* NOTE: This fallback can get used on systems that do have inet_ntop() * but their antivirus precluded the configure-script test program linking. * A symptom of that would be: * warning: 'inet_ntop' redeclared without dllimport attribute: * previous dllimport ignored [-Wattributes] * ...and adding the attributes would cause a conflict of private fallback * and system DLL symbols. So the lesser of two evils, we use fallback. * People who see the warning should however fix their build environment * and use the native OS-provided implementation ;) */ # if (0) /* Some old winapi? or just sloppy original commits? * Why is this here at all if there's something per ws2tcpip.h - * maybe should be configure-detected? */ const char* inet_ntop(int af, const void* src, char* dst, int cnt); # else const char* inet_ntop(int af, const void* src, char* dst, size_t /* socklen_t */ cnt); # endif #endif #if ! HAVE_INET_PTON int inet_pton(int af, const char *src, void *dst); #endif /* from the MSDN getaddrinfo documentation : */ #define EAI_AGAIN WSATRY_AGAIN #define EAI_BADFLAGS WSAEINVAL #define EAI_FAIL WSANO_RECOVERY #define EAI_FAMILY WSAEAFNOSUPPORT #define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY #define EAI_NONAME WSAHOST_NOT_FOUND #define EAI_SERVICE WSATYPE_NOT_FOUND #define EAI_SOCKTYPE WSAESOCKTNOSUPPORT /* not from MS docs : */ #define EAI_SYSTEM WSANO_RECOVERY #ifndef EAFNOSUPPORT # define EAFNOSUPPORT WSAEAFNOSUPPORT #endif /* "system" function */ int win_system(const char * command); /* syslog compatibility */ void syslog(int priority, const char *fmt, ...); extern const char * EventLogName; /* Signal emulation via named pipe */ typedef struct pipe_conn_s { HANDLE handle; OVERLAPPED overlapped; char buf[LARGEBUF]; struct pipe_conn_s *prev; struct pipe_conn_s *next; } pipe_conn_t; extern pipe_conn_t *pipe_connhead; extern OVERLAPPED pipe_connection_overlapped; void pipe_create(const char * pipe_name); void pipe_connect(); void pipe_disconnect(pipe_conn_t *conn); int pipe_ready(pipe_conn_t *conn); int send_to_named_pipe(const char * pipe_name, const char * data); #define COMMAND_FSD "COMMAND_FSD" #define COMMAND_STOP "COMMAND_STOP" #define COMMAND_RELOAD "COMMAND_RELOAD" /* serial function compatibility */ int w32_setcomm ( serial_handler_t * h, int * flags ); int w32_getcomm ( serial_handler_t * h, int * flags ); int tcsendbreak (serial_handler_t * sh, int duration); typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned int tcflag_t; #define NCCS 19 struct termios { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_line; /* line discipline */ cc_t c_cc[NCCS]; /* control characters */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; serial_handler_t * w32_serial_open (const char *name, int flags); int w32_serial_close (serial_handler_t * sh); int w32_serial_write (serial_handler_t * sh, const void *ptr, size_t len); int w32_serial_read (serial_handler_t * sh, void *ptr, size_t ulen, DWORD timeout); int tcgetattr (serial_handler_t * sh, struct termios *t); int tcsetattr (serial_handler_t * sh, int action, const struct termios *t); int tcflush (serial_handler_t * sh, int queue); #define HAVE_CFSETISPEED void cfsetispeed(struct termios * t, speed_t speed); void cfsetospeed(struct termios * t, speed_t speed); speed_t cfgetispeed(const struct termios *t); speed_t cfgetospeed(const struct termios *t); #define _POSIX_VDISABLE '\0' /* c_cc characters */ #define VINTR 0 #define VQUIT 1 #define VERASE 2 #define VKILL 3 #define VEOF 4 #define VTIME 5 #define VMIN 6 #define VSWTC 7 #define VSTART 8 #define VSTOP 9 #define VSUSP 10 #define VEOL 11 #define VREPRINT 12 #define VDISCARD 13 #define VWERASE 14 #define VLNEXT 15 #define VEOL2 16 /* c_iflag bits */ #define IGNBRK 0000001 #define BRKINT 0000002 #define IGNPAR 0000004 #define PARMRK 0000010 #define INPCK 0000020 #define ISTRIP 0000040 #define INLCR 0000100 #define IGNCR 0000200 #define ICRNL 0000400 #define IUCLC 0001000 #define IXON 0002000 #define IXANY 0004000 #define IXOFF 0010000 #define IMAXBEL 0020000 #define IUTF8 0040000 /* c_oflag bits */ #define OPOST 0000001 #define OLCUC 0000002 #define ONLCR 0000004 #define OCRNL 0000010 #define ONOCR 0000020 #define ONLRET 0000040 #define OFILL 0000100 #define OFDEL 0000200 #define NLDLY 0000400 #define NL0 0000000 #define NL1 0000400 #define CRDLY 0003000 #define CR0 0000000 #define CR1 0001000 #define CR2 0002000 #define CR3 0003000 #define TABDLY 0014000 #define TAB0 0000000 #define TAB1 0004000 #define TAB2 0010000 #define TAB3 0014000 #define XTABS 0014000 #define BSDLY 0020000 #define BS0 0000000 #define BS1 0020000 #define VTDLY 0040000 #define VT0 0000000 #define VT1 0040000 #define FFDLY 0100000 #define FF0 0000000 #define FF1 0100000 /* c_cflag bit meaning */ #define CBAUD 0010017 #define B0 0000000 /* hang up */ #define B50 0000001 #define B75 0000002 #define B110 0000003 #define B134 0000004 #define B150 0000005 #define B200 0000006 #define B300 0000007 #define B600 0000010 #define B1200 0000011 #define B1800 0000012 #define B2400 0000013 #define B4800 0000014 #define B9600 0000015 #define B19200 0000016 #define B38400 0000017 #define EXTA B19200 #define EXTB B38400 #define CSIZE 0000060 #define CS5 0000000 #define CS6 0000020 #define CS7 0000040 #define CS8 0000060 #define CSTOPB 0000100 #define CREAD 0000200 #define PARENB 0000400 #define PARODD 0001000 #define HUPCL 0002000 #define CLOCAL 0004000 #define CBAUDEX 0010000 #define BOTHER 0010000 #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 #define B460800 0010004 #define B500000 0010005 #define B576000 0010006 #define B921600 0010007 #define B1000000 0010010 #define B1152000 0010011 #define B1500000 0010012 #define B2000000 0010013 #define B2500000 0010014 #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 #define CIBAUD 002003600000 /* input baud rate */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ #define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ /* c_lflag bits */ #define ISIG 0000001 #define ICANON 0000002 #define XCASE 0000004 #define ECHO 0000010 #define ECHOE 0000020 #define ECHOK 0000040 #define ECHONL 0000100 #define NOFLSH 0000200 #define TOSTOP 0000400 #define ECHOCTL 0001000 #define ECHOPRT 0002000 #define ECHOKE 0004000 #define FLUSHO 0010000 #define PENDIN 0040000 #define IEXTEN 0100000 /* tcflow() and TCXONC use these */ #define TCOOFF 0 #define TCOON 1 #define TCIOFF 2 #define TCION 3 /* tcflush() and TCFLSH use these */ #define TCIFLUSH 0 #define TCOFLUSH 1 #define TCIOFLUSH 2 /* tcsetattr uses these */ #define TCSANOW 0 #define TCSADRAIN 1 #define TCSAFLUSH 2 #define TIOCM_DTR 0x0001 #define TIOCM_RTS 0x0002 #define TIOCM_ST 0x0004 #define TIOCM_CTS MS_CTS_ON /* 0x0010*/ #define TIOCM_DSR MS_DSR_ON /* 0x0020*/ #define TIOCM_RNG MS_RING_ON /*0x0040*/ #define TIOCM_RI TIOCM_RNG /* at least that's the definition in Linux */ #define TIOCM_CD MS_RLSD_ON /*0x0080*/ #endif /* NUT_WINCOMPAT_H */ nut-2.8.3/include/Makefile.in0000644000200500020050000007504415001555011012732 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: include VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ # Optionally deliverable as part of NUT public API: @WITH_DEV_TRUE@am__append_1 = parseconf.h @WITH_DEV_LIBNUTCONF_TRUE@@WITH_DEV_TRUE@am__append_2 = nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.hpp @WITH_DEV_LIBNUTCONF_FALSE@@WITH_DEV_TRUE@am__append_3 = nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.hpp @WITH_DEV_FALSE@am__append_4 = parseconf.h nutstream.hpp nutwriter.hpp \ @WITH_DEV_FALSE@ nutipc.hpp nutconf.hpp subdir = include ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_noinst_HEADERS_DIST) \ $(am__include_HEADERS_DIST) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__dist_noinst_HEADERS_DIST = attribute.h common.h extstate.h proto.h \ state.h str.h timehead.h upsconf.h nut_bool.h nut_float.h \ nut_stdint.h nut_platform.h wincompat.h nutstream.hpp \ nutwriter.hpp nutipc.hpp nutconf.hpp parseconf.h am__include_HEADERS_DIST = parseconf.h nutstream.hpp nutwriter.hpp \ nutipc.hpp nutconf.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(includedir)" HEADERS = $(dist_noinst_HEADERS) $(include_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ include_HEADERS = $(am__append_1) $(am__append_2) dist_noinst_HEADERS = attribute.h common.h extstate.h proto.h state.h \ str.h timehead.h upsconf.h nut_bool.h nut_float.h nut_stdint.h \ nut_platform.h wincompat.h $(am__append_3) $(am__append_4) # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h CLEANFILES = nut_version.h nut_version.h.tmp* MAINTAINERCLEANFILES = Makefile.in .dirstamp all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu include/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status include/config.h $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(HEADERS) config.h installdirs: for dir in "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-includeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-includeHEADERS .MAKE: all check install install-am install-exec install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool cscopelist-am ctags ctags-am dist-hook distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-includeHEADERS install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-includeHEADERS .PRECIOUS: Makefile # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ # magic to include Git version information in NUT version string # (for builds not made from the tagged commit in a Git workspace) # NOTE: For pre-releases, SEMVER may differ from NUT_VERSION base # (e.g. a commit tagged as 2.8.3-rc5 can have its own NUT_VERSION based # on 2.8.2-something, but is assumed as a pre-release for 2.8.3 SEMVER) nut_version.h: @FORCE_NUT_VERSION@ @echo " GENERATE-HEADER $@" ; \ RES=0; \ GITREV="`$(top_srcdir)/tools/gitlog2version.sh`" || GITREV=""; \ GITREV_IS_RELEASE="`NUT_VERSION_QUERY=IS_RELEASE $(top_srcdir)/tools/gitlog2version.sh 2>/dev/null`" || GITREV_IS_RELEASE="false"; \ GITREV_IS_PRERELEASE="`NUT_VERSION_QUERY=IS_PRERELEASE $(top_srcdir)/tools/gitlog2version.sh 2>/dev/null`" || GITREV_IS_PRERELEASE="false"; \ GITREV_SEMVER="`NUT_VERSION_QUERY=SEMVER $(top_srcdir)/tools/gitlog2version.sh 2>/dev/null`" || GITREV_SEMVER=""; \ { echo '/* Autogenerated file. Do not change. */' ; \ echo '/* This file was generated by "make". */' ; \ if [ -z "$$GITREV" ]; then \ NUT_VERSION="$(PACKAGE_VERSION)"; \ echo '/* The version number is set by AC_INIT in configure.ac. */' ; \ else \ NUT_VERSION="$$GITREV"; \ echo '/* The version number is determined by Git source commit hash' ; \ echo ' * and number of commits since the most recent Git tag (if not' ; \ echo ' * building the newest tagged commit itself - then just the tag).'; \ echo ' */' ; \ fi ; \ if [ -z "$$GITREV_SEMVER" ]; then \ GITREV_SEMVER="@NUT_SOURCE_GITREV_SEMVER@"; \ fi ; \ echo "#define NUT_VERSION_MACRO \"$$NUT_VERSION\"" ; \ echo "#define NUT_VERSION_SEMVER_MACRO \"$$GITREV_SEMVER\"" ; \ if $$GITREV_IS_RELEASE ; then \ echo "#define NUT_VERSION_IS_RELEASE 1" ; \ else \ echo "#define NUT_VERSION_IS_RELEASE 0" ; \ fi ; \ if $$GITREV_IS_PRERELEASE ; then \ echo "#define NUT_VERSION_IS_PRERELEASE 1" ; \ else \ echo "#define NUT_VERSION_IS_PRERELEASE 0" ; \ fi ; \ } > "$@.tmp.$$$$" && \ echo "NUT_VERSION: \"$$NUT_VERSION\" NUT_VERSION_IS_RELEASE:$$GITREV_IS_RELEASE NUT_VERSION_IS_PRERELEASE:$$GITREV_IS_PRERELEASE NUT_VERSION_SEMVER: \"$$GITREV_SEMVER\"" && \ if test -f "$@" && test -s "$@" ; then \ if cmp -s "$@.tmp.$$$$" "$@" ; then \ echo " GENERATE-HEADER $@ did not change" ; \ else \ echo " GENERATE-HEADER $@ got changed" ; \ cp "$@.tmp.$$$$" "$@" ; \ fi ; \ else \ echo " GENERATE-HEADER $@ was absent"; \ cp "$@.tmp.$$$$" "$@" ; \ fi \ || RES=$$? ; \ rm -f "$@.tmp.$$$$" ; \ exit $$RES FORCE: # counter part of BUILT_SOURCES: since nut_version is not a direct # deps of a local target, we must clean it by ourselves before the # distribution dist-hook: $(AM_V_at)rm -f $(distdir)/nut_version.h all-libs-local: nut_version.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/include/parseconf.h0000644000200500020050000000550714777767434013054 00000000000000/* parseconf.h - state machine-driven dynamic configuration file parser Copyright (C) 2002 Russell Kroll This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef PARSECONF_H_SEEN #define PARSECONF_H_SEEN 1 #include /* Not including nut_stdint.h because this is part of end-user API */ #if defined HAVE_INTTYPES_H # include #endif #if defined HAVE_STDINT_H # include #endif #if defined HAVE_LIMITS_H # include #endif #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #define PCONF_CTX_t_MAGIC 0x00726630 #define PCONF_ERR_LEN 256 /* conservative defaults: use at most 16 KB for parsing any given line */ #define PCONF_DEFAULT_ARG_LIMIT 32 #define PCONF_DEFAULT_WORDLEN_LIMIT 512 typedef struct { FILE *f; /* stream to current file */ int state; /* current parser state */ int ch; /* last character read */ char **arglist; /* array of pointers to words */ size_t *argsize; /* list of sizes for realloc */ size_t numargs; /* max usable in arglist */ size_t maxargs; /* for reallocing arglist */ char *wordbuf; /* accumulator for current word */ char *wordptr; /* where next char goes in word */ size_t wordbufsize; /* for reallocing wordbuf */ int linenum; /* for good error reporting */ int error; /* set when an error occurred */ char errmsg[PCONF_ERR_LEN]; /* local buffer for errors */ void (*errhandler)(const char *); /* user's error handler */ int magic; /* buffer validity check */ /* these may be redefined by the caller to customize memory use */ size_t arg_limit; /* halts growth of arglist */ size_t wordlen_limit; /* halts growth of any wordbuf */ } PCONF_CTX_t; int pconf_init(PCONF_CTX_t *ctx, void errhandler(const char *)); int pconf_file_begin(PCONF_CTX_t *ctx, const char *fn); int pconf_file_next(PCONF_CTX_t *ctx); int pconf_parse_error(PCONF_CTX_t *ctx); int pconf_line(PCONF_CTX_t *ctx, const char *line); void pconf_finish(PCONF_CTX_t *ctx); char *pconf_encode(const char *src, char *dest, size_t destsize); int pconf_char(PCONF_CTX_t *ctx, char ch); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* PARSECONF_H_SEEN */ nut-2.8.3/include/proto.h0000644000200500020050000000742314777767434012236 00000000000000/* proto.h - fill in the gaps about prototypes and definitions for portability Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2006 Peter Selinger 2013 Emilien Kia 2020 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_PROTO_H_SEEN #define NUT_PROTO_H_SEEN 1 /* "config.h" is generated by autotools and lacks a header guard, so * we use an unambiguously named macro we know we must have, as one. * It must be the first header: be sure to know all about system config. */ #ifndef NUT_NETVERSION # include "config.h" #endif #include "attribute.h" #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) /* Define this as a fall through, HAVE_STDARG_H is probably already set */ #ifndef HAVE_VARARGS_H #define HAVE_VARARGS_H #endif /* varargs declarations: */ #if defined(HAVE_STDARG_H) # include # define HAVE_STDARGS /* let's hope that works everywhere (mj) */ # define VA_LOCAL_DECL va_list ap # define VA_START(f) va_start(ap, f) # define VA_SHIFT(v,t) ; /* no-op for ANSI */ # define VA_END va_end(ap) #else # if defined(HAVE_VARARGS_H) # include # undef HAVE_STDARGS # define VA_LOCAL_DECL va_list ap # define VA_START(f) va_start(ap) /* f is ignored! */ # define VA_SHIFT(v,t) v = va_arg(ap,t) # define VA_END va_end(ap) # else /*XX ** NO VARARGS ** XX*/ # endif #endif #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif #if !defined (HAVE_SNPRINTF) || defined (__Lynx__) int snprintf (char *str, size_t count, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); #endif #if !defined (HAVE_VSNPRINTF) int vsnprintf (char *str, size_t count, const char *fmt, va_list arg); #endif #endif #ifndef HAVE_SETENV int nut_setenv(const char *name, const char *value, int overwrite); static inline int setenv(const char *name, const char *value, int overwrite) { return nut_setenv(name, value, overwrite); } #endif #ifndef HAVE_UNSETENV int nut_unsetenv(const char *name); static inline int unsetenv(const char *name) { return nut_unsetenv(name); } #endif #ifdef __hpux #ifdef HAVE_SYS_MODEM_H #include #endif /* See sys/termio.h and sys/modem.h The following serial bits are not defined by HPUX. The numbers are octal like I found in BSD. TIOCM_ST is used in genericups.[ch] for the Powerware 3115. These defines make it compile, but I have no idea if it works. */ #define TIOCM_LE 0001 /* line enable */ #define TIOCM_ST 0010 /* secondary transmit */ #define TIOCM_SR 0020 /* secondary receive */ #endif #ifdef HAVE_GETPASSPHRASE #define GETPASS getpassphrase #else #define GETPASS getpass #endif #ifdef __Lynx__ /* Missing prototypes on LynxOS */ int seteuid(uid_t); int vprintf(const char *, va_list); int putenv(char *); #endif #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_PROTO_H_SEEN */ nut-2.8.3/include/nutwriter.hpp0000644000200500020050000002412714777767434013476 00000000000000/* nutwriter.hpp - NUT writer Copyright (C) 2012 Eaton Author: Vaclav Krpec Copyright (C) 2024-2025 NUT Community Author: Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef nut_nutwriter_h #define nut_nutwriter_h #ifdef __cplusplus #include "nutstream.hpp" #include "nutconf.hpp" #include namespace nut { /** * \brief NUT stream writer */ class NutWriter { public: /** NUT writer status */ typedef enum { NUTW_OK = 0, /** Writing successful */ NUTW_ERROR, /** Writing failed */ } status_t; // end of typedef enum */ protected: /** EoL separator */ static const std::string & eol; /** Output stream (by reference) */ NutStream & m_output_stream; public: /** * \brief Constructor * * Creates the writer. * The \c ostream parameter provides the writer reference * to an existing output stream; note that the stream * must exist throughout whole the writer's life. * * TBD: * The stream might actually be passed either by value * (\c NutStream implementations would have to support * copying, though, which is not implemented at the moment) * or using reference counting mechanism (smart pointers etc). * The latter is perhaps a better choice (if the stream existence * dependency is a considerable issue). * * \param ostream Output stream */ NutWriter(NutStream & ostream): m_output_stream(ostream) {} /** * \brief Write to output stream * * The method writes the provided string to the output stream. * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ inline status_t write(const std::string & str) { NutStream::status_t status = m_output_stream.putString(str); return NutStream::NUTS_OK == status ? NUTW_OK : NUTW_ERROR; } /** * \brief Write to output stream * * The method writes the provided string to the output stream. * An exception is thrown on error. */ inline void writex(const std::string & str) { NutStream::status_t status = m_output_stream.putString(str); if (NutStream::NUTS_OK != status) { std::stringstream e; e << "Failed to write to output stream: " << status; throw std::runtime_error(e.str()); } } protected: /** * \brief Write (prefixed) lines * * The method splits string to lines (by EoL) and prefix them * with specified string upon writing. * * \param str String (multi-line) * \param pref Prefix * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ status_t writeEachLine(const std::string & str, const std::string & pref); }; // end of class NutWriter /** * \brief NUT configuration writer interface (generic) */ class NutConfigWriter: public NutWriter { protected: /** Formal constructor */ NutConfigWriter(NutStream & ostream): NutWriter(ostream) {} public: /** * \brief Write comment * * \param str Comment string * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ virtual status_t writeComment(const std::string & str) = 0; /** * \brief Write section name * * \param name Section name * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ virtual status_t writeSectionName(const std::string & name) = 0; /** * \brief Write directive * * \param str Directive string * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ virtual status_t writeDirective(const std::string & str) = 0; /** Virtual destructor */ virtual ~NutConfigWriter(); }; // end of class NutConfigWriter /** * \brief NUT section-less configuration writer specialization * * Partial implementation of \ref NutConfigWriter for section-less * configuration files. */ class SectionlessConfigWriter: public NutConfigWriter { protected: /** * \brief Constructor * * \param ostream Output stream */ SectionlessConfigWriter(NutStream & ostream): NutConfigWriter(ostream) {} public: // Partial \ref NutConfigWriter interface implementation status_t writeDirective(const std::string & str) override; status_t writeComment(const std::string & str) override; private: // Section name writing is forbidden (no sections) status_t writeSectionName(const std::string & name) override; }; // end of class SectionlessConfigWriter /** * \brief \c nut.conf configuration file serializer */ class NutConfConfigWriter: public SectionlessConfigWriter { public: /** * \brief Constructor * * \param ostream Output stream */ NutConfConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} /** * \brief Serialize configuration container * * \param config Configuration * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ status_t writeConfig(const NutConfiguration & config); /* Ensure an out-of-line method to avoid "weak-vtables" warning */ virtual ~NutConfConfigWriter() override; }; // end of class NutConfConfigWriter /** * \brief \c upsmon.conf configuration file serializer */ class UpsmonConfigWriter: public SectionlessConfigWriter { public: /** * \brief Constructor * * \param ostream Output stream */ UpsmonConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} /** * \brief Serialize configuration container * * \param config Configuration * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ status_t writeConfig(const UpsmonConfiguration & config); /* Ensure an out-of-line method to avoid "weak-vtables" warning */ virtual ~UpsmonConfigWriter() override; }; // end of class UpsmonConfigWriter /** * \brief \c upsd.conf configuration file serializer */ class UpsdConfigWriter: public SectionlessConfigWriter { public: /** * \brief Constructor * * \param ostream Output stream */ UpsdConfigWriter(NutStream & ostream): SectionlessConfigWriter(ostream) {} /** * \brief Serialize configuration container * * \param config Configuration * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ status_t writeConfig(const UpsdConfiguration & config); /* Ensure an out-of-line method to avoid "weak-vtables" warning */ virtual ~UpsdConfigWriter() override; }; // end of class UpsdConfigWriter /** * \brief NUT default configuration writer ancestor * * Implements the \ref NutConfigWriter interface * and adds \c writeSection prototype to be implemented * by descendants. */ class DefaultConfigWriter: public NutConfigWriter { protected: /** * \brief Constructor * * \param ostream Output stream */ DefaultConfigWriter(NutStream & ostream): NutConfigWriter(ostream) {} public: // \ref NutConfigWriter interface implementation status_t writeComment(const std::string & str) override; status_t writeSectionName(const std::string & name) override; status_t writeDirective(const std::string & str) override; /** * \brief Write configuration section * * Serialize generic configuration section. * * \param section Configuration section * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ virtual status_t writeSection(const GenericConfigSection & section) = 0; }; // end of class DefaultConfigWriter /** * \brief NUT generic configuration writer * * Base configuration file serializer. * Implements the \ref DefaultConfigWriter \c writeSection method * and adds \c writeConfig routine for configuration file serialization. */ class GenericConfigWriter: public DefaultConfigWriter { protected: /** Default indentation of the key/value pair in section entry */ static const std::string s_default_section_entry_indent; /** Default separator of the key/value pair in section entry */ static const std::string s_default_section_entry_separator; /** * \brief Section entry serializer * * \param entry Section entry * \param indent Indentation * \param kv_sep Key/value separator * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ status_t writeSectionEntry( const GenericConfigSectionEntry & entry, const std::string & indent = s_default_section_entry_indent, const std::string & kv_sep = s_default_section_entry_separator); public: /** * \brief Constructor * * \param ostream Output stream */ GenericConfigWriter(NutStream & ostream): DefaultConfigWriter(ostream) {} // Section serializer implementation status_t writeSection(const GenericConfigSection & section) override; /** * \brief Base configuration serializer * * \param config Base configuration * * \retval NUTW_OK on success * \retval NUTW_ERROR otherwise */ status_t writeConfig(const GenericConfiguration & config); }; // end of class GenericConfigWriter /** * \brief NUT upsd.users configuration file writer * * upsd.users configuration file serializer. * Overloads the generic section serializer because of the upsmon section, * which contains an anomalous upsmon (master|slave) directive. */ class UpsdUsersConfigWriter: public GenericConfigWriter { public: /** * \brief Constructor * * \param ostream Output stream */ UpsdUsersConfigWriter(NutStream & ostream): GenericConfigWriter(ostream) {} // Section serializer overload status_t writeSection(const GenericConfigSection & section) override; }; // end of class UpsdUsersConfigWriter } // end of namespace nut #endif /* __cplusplus */ #endif /* end of #ifndef nut_nutwriter_h */ nut-2.8.3/include/nutipc.hpp0000644000200500020050000005611414777767434012736 00000000000000/* nutipc.hpp - NUT IPC Copyright (C) 2012 Eaton Author: Vaclav Krpec Copyright (C) 2024-2025 NUT Community Author: Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_NUTIPC_HPP #define NUT_NUTIPC_HPP #include #include #include #include #include #include #include extern "C" { #include #include #include #ifndef WIN32 # include #else /* WIN32 */ # include "wincompat.h" #endif /* WIN32 */ #ifdef HAVE_PTHREAD # include #endif } /* See include/common.h for details behind this */ #ifndef NUT_UNUSED_VARIABLE #define NUT_UNUSED_VARIABLE(x) (void)(x) #endif namespace nut { /** * Process-related information */ class Process { private: /** The type yields no instances */ Process() {} public: /** Get current process ID */ static pid_t getPID() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** Get parent process ID */ static pid_t getPPID() #if (defined __cplusplus) && (__cplusplus < 201100) throw() #endif ; /** * Process main routine functor prototype */ class Main { protected: /** Formal constructor */ Main() {} virtual ~Main(); public: /* Avoid implicit copy/move operator declarations */ Main(Main&&) = default; Main& operator=(const Main&) = default; //Main& operator=(Main&&) = default; /** Routine */ virtual int operator () () = 0; }; // end of class Main /** * Child process */ template class Child { private: pid_t m_pid; /**< Child PID */ bool m_exited; /**< Exited flag */ int m_exit_code; /**< Exit code */ public: /** * \brief Constructor of child process * * The constructor calls \c ::fork to create another child process. * The child executes \ref m_main functor instance operator \c (). * When the functor's \c () operator returns, the returned value * shall be used as the child exit code (and the child will exit). * * \param main Child process main routine */ Child(M main) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; /** Child PID */ inline pid_t getPID() const { return m_pid; } /** * \brief Wait for child process to exit * * The method blocks as long as the child runs. * It returns the child's exit code. * It throws an exception if executed twice * (or on other illogical usage). * * \return Child process exit code */ int wait() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif ; /** * \brief Child exit code getter * * \return Child exit code */ inline int exitCode() { return wait(); } /** * \brief Destructor * * The destructor shall wait for the child process * (unless already exited). */ ~Child() { wait(); } }; // end of class Child /** * External command executor */ class Executor: public Main { public: /** Command line arguments list */ typedef std::list Arguments; private: std::string m_bin; Arguments m_args; public: /** * \brief Constructor * * The binary path may be omitted; the implementation shall perform * the actions shell would do to search for the binary (i.e. check \c PATH * environment variable); * * Note that even option switches are command line arguments; * e.g. "tail -n 20" command has 2 arguments: "-n" and "20". * * \brief bin Binary to be executed * \brief args Command-line arguments to the binary */ Executor(const std::string & bin, const Arguments & args): m_bin(bin), m_args(args) {} /** * \brief Constructor * * This constructor form splits the command string specified * to the binary and its cmd-line arguments for the caller (by spaces). * * Note however, that the command must be a binary execution; if you want * to run a shell command, you must execute the shell, explicitly; e.g: * "/bin/sh -c ''" shall probably be what you want. * * \param command Command to be executed */ Executor(const std::string & command); /** Execution of the binary */ int operator () () #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif override; }; // end of class Executor /** * External command execution */ class Execution: public Child { public: /** * Constructor * * The binary path may be omitted; the implementation shall perform * the actions shell would do to search for the binary (i.e. check \c PATH * environment variable); * * \brief binary Binary to be executed * \brief arguments Command-line arguments to the binary */ Execution(const std::string & binary, const Executor::Arguments & arguments): Child(Executor(binary, arguments)) {} /** * Constructor * * This form of the constructor splits the command string specified * to the binary and its cmd-line arguments for the caller (by spaces). * * Note however, that the command must be a binary execution; if you want * to run a shell command, you must execute the shell, explicitly; e.g: * "/bin/sh -c ''" shall probably be what you want. * * \param command Command to be executed */ Execution(const std::string & command): Child(Executor(command)) {} }; // end of class Execution /** * \brief Execute command and wait for exit code * * \param binary Binary to be executed * \param arguments Command-line arguments to the binary * * \return Exit code */ static inline int execute(const std::string & binary, const Executor::Arguments & arguments) { Execution child(binary, arguments); return child.wait(); } /** * \brief Execute command and wait for exit code * * \param command Command to be executed * * \return Exit code */ static inline int execute(const std::string & command) { Execution child(command); return child.wait(); } }; // end of class Process template Process::Child::Child(M main) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif : m_pid(0), m_exited(false), m_exit_code(0) { #ifdef WIN32 NUT_UNUSED_VARIABLE(main); /* FIXME: Implement (for NUT processes) via pipes? * See e.g. upsdrvctl implementation. */ std::stringstream e; e << "Can't fork: not implemented on this platform yet"; /* NUT_WIN32_INCOMPLETE(); */ throw std::logic_error(e.str()); #else /* !WIN32 */ m_pid = ::fork(); if (!m_pid) ::exit(main()); #endif /* !WIN32 */ } template int Process::Child::wait() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif { #ifdef WIN32 /* FIXME: Implement (for NUT processes) via pipes? * See e.g. upsdrvctl implementation. */ std::stringstream e; e << "Can't wait for PID " << m_pid << ": not implemented on this platform yet"; /* NUT_WIN32_INCOMPLETE(); */ throw std::logic_error(e.str()); #else /* !WIN32 */ if (m_exited) return m_exit_code; pid_t wpid = ::waitpid(m_pid, &m_exit_code, 0); if (-1 == wpid) { int erno = errno; std::stringstream e; e << "Failed to wait for process " << m_pid << ": "; e << erno << ": " << strerror(erno); throw std::logic_error(e.str()); } m_exited = true; m_exit_code = WEXITSTATUS(m_exit_code); return m_exit_code; #endif /* !WIN32 */ } /** * POSIX signal * * For portability reasons, only mostly common subset of POSIX.1-2001 signals are supported. */ class Signal { public: /** Signals */ typedef enum { #ifndef WIN32 HUP = SIGHUP, /** Hangup */ INT = SIGINT, /** Interrupt */ QUIT = SIGQUIT, /** Quit */ ILL = SIGILL, /** Illegal Instruction */ TRAP = SIGTRAP, /** Trace/breakpoint trap */ ABORT = SIGABRT, /** Abort */ BUS = SIGBUS, /** Bus error (bad memory access) */ FPE = SIGFPE, /** Floating point exception */ KILL = SIGKILL, /** Kill (unmaskable) */ SEGV = SIGSEGV, /** Invalid memory reference */ PIPE = SIGPIPE, /** Broken pipe */ ALARM = SIGALRM, /** Alarm */ TERM = SIGTERM, /** Termination */ USER1 = SIGUSR1, /** User-defined signal 1 */ USER2 = SIGUSR2, /** User-defined signal 2 */ CHILD = SIGCHLD, /** Child stopped or terminated */ CONT = SIGCONT, /** Continue if stopped */ STOP = SIGSTOP, /** Stop process (unmaskable) */ TSTOP = SIGTSTP, /** Stop typed at TTY */ TTYIN = SIGTTIN, /** TTY input for background process */ TTYOUT = SIGTTOU, /** TTY output for background process */ PROF = SIGPROF, /** Profiling timer expired */ SYS = SIGSYS, /** Bad argument to routine */ URG = SIGURG, /** Urgent condition on socket */ VTALRM = SIGVTALRM, /** Virtual alarm clock */ XCPU = SIGXCPU, /** CPU time limit exceeded */ XFSZ = SIGXFSZ, /** File size limit exceeded */ #endif /* !WIN32 */ } enum_t; // end of typedef enum /** Signal list */ typedef std::list List; /** * \brief Signal handler * * Signal handler interface. */ class Handler { protected: /** Formal constructor */ Handler() {} public: /** * \brief Signal handler routine * * \param signal Signal */ virtual void operator () (enum_t signal) = 0; /** Formal destructor */ virtual ~Handler(); }; // end of class Handler private: /** Formal constructor */ Signal() {} public: /** Signal handler thread handle */ template class HandlerThread { friend class Signal; private: /** Control commands */ typedef enum { HT_QUIT = 0, /**< Shutdown the thread */ HT_SIGNAL = 1, /**< Signal obtained */ } command_t; /** Communication pipe */ static int s_comm_pipe[2]; /** POSIX thread */ pthread_t m_impl; /** * \brief Signal handler thread main routine * * The function synchronously read commands from the communication pipe. * It processes control commands on its own (e.g. the quit command). * It passes all signals to signal handler instance of \ref H * Which must implement the \ref Signal::Handler interface. * The handler is instantiated in scope of the routine. * It closes the communication pipe read end in reaction to * \ref HT_QUIT command. * * \param comm_pipe_read_end Communication pipe read end * * \retval N/A (the function never returns) */ static void * main(void * comm_pipe_read_end); /** * \brief Signal handler routine * * The actual signal handler routine executed by the OS when the process * obtains signal to be handled. * The function simply writes the signal number to the signal handler * thread communication pipe (as parameter of the \ref HT_SIGNAL command). * The signal handling itself (whatever necessary) shall be done * by the dedicated thread (to avoid possible re-entrance issues). * * Note that \c ::write is required to be an async-signal-safe function by * POSIX.1-2004; also note that up to \c PIPE_BUF bytes are written atomically * as required by IEEE Std 1003.1, 2004 Edition,\c PIPE_BUF being typically * hundreds of bytes at least (POSIX requires 512B, Linux provides whole 4KiB * page). * * \param signal Signal */ static void signalNotifier(int signal); public: /** * \brief Constructor * * At most one thread per handler instance may be created. * This limitation is both due sanity reasons (it wouldn't * make much sense to handle the same signal by multiple threads) * and because of the signal handler routine only has access * to one communication pipe write end (the static member). * This is actually the only technical reason of having the class * template (so that every instance has its own static comm. queue). * However, for different handler classes, multiple handling threads * may be created (if it makes sense) since these will be different * template instances and therefore will use different static * communication pipes. * If more than 1 instance creation is attempted, an exception is thrown. * * \param siglist List of signals that shall be handled by the thread */ HandlerThread(const Signal::List & siglist) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error, std::runtime_error) #endif ; /** * \brief Terminate the thread * * The method sends the signal handler thread the \ref QUIT signal. * It blocks until the thread is joined. * Closes the communication pipe write end. */ void quit() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; /** * \brief Destructor * * Forces the signal handler thread termination (unless already down). */ ~HandlerThread() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; }; // end of HandlerThread /** * \brief Send signal to a process * * An exception is thrown if the signal isn't implemented. * * \param signame Signal name * \param pid Process ID * * \retval 0 in case of success * \retval EPERM if the process doesn't have permission to send the signal * \retval ESRCH if the process (group) identified doesn't exist */ static int send(enum_t signame, pid_t pid) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error) #endif ; /** * \brief Send signal to a process identified via PID file * * An exception is thrown if the signal isn't implemented * or PID file read fails. * * \param signame Signal name * \param pid_file File containing process PID * * \retval 0 in case of success * \retval EPERM if the process doesn't have permission to send the signal * \retval ESRCH if the process (group) identified doesn't exist */ static int send(enum_t signame, const std::string & pid_file); }; // end of class Signal /** Initialization of the communication pipes */ template int Signal::HandlerThread::s_comm_pipe[2] = { -1, -1 }; template void * Signal::HandlerThread::main(void * comm_pipe_read_end) { int rfd = *(reinterpret_cast(comm_pipe_read_end)); H handler; for (;;) { fd_set rfds; FD_ZERO(&rfds); FD_SET(rfd, &rfds); // Poll on signal pipe // Note that a straightforward blocking read could be // also used. However, select allows specifying a // timeout, which could be useful in the future (but // is not used in the current code). int fdno = ::select(FD_SETSIZE, &rfds, nullptr, nullptr, nullptr); // -1 is an error, but EINTR means the system call was // interrupted. System calls are expected to be // interrupted on signal delivery; some systems // restart them, and some don't. Getting EINTR is // therefore not actually an error, and the standard // approach is to retry. if (-1 == fdno) { if (errno == EINTR) continue; std::stringstream e; e << "Poll on communication pipe read end "; e << rfd << " failed: " << errno; throw std::runtime_error(e.str()); } assert(1 == fdno); assert(FD_ISSET(rfd, &rfds)); // Read command int word; ssize_t read_out = ::read(rfd, &word, sizeof(word)); // TBD: again, how should we treat read error? if (-1 == read_out) { std::stringstream e; e << "Failed to read command from the command pipe: "; e << errno; throw std::runtime_error(e.str()); } // POSIX probably does not prohibit reading some but // not all of the multibyte message. However, it is // unlikely that an implementation using write and // read on int-sized or smaller objects will split // them. For now our strategy is to hope this does // not happen. assert(sizeof(word) == read_out); command_t command = static_cast(word); switch (command) { case HT_QUIT: // Close comm. pipe read end ::close(rfd); // Terminate thread ::pthread_exit(nullptr); case HT_SIGNAL: { // scoping // Read signal number read_out = ::read(rfd, &word, sizeof(word)); // TBD: again, how should we treat read error? if (-1 == read_out) { std::stringstream e; e << "Failed to read signal number "; e << "from the command pipe: " << errno; throw std::runtime_error(e.str()); } assert(sizeof(word) == read_out); Signal::enum_t sig = static_cast(word); // Handle signal handler(sig); } // scoping break; #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* Must not occur thanks to enum. * But otherwise we can see * error: 'switch' missing 'default' label [-Werror,-Wswitch-default] * from some overly zealous compilers. */ default: throw std::logic_error("INTERNAL ERROR: Unexpected default case reached"); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif } } // Pro-forma exception throw std::logic_error("INTERNAL ERROR: Unreachable code reached"); } /** * \brief Write command to command pipe * * \param fh Pipe writing end (file handle) * \param cmd Command * \param cmd_size Command size * * \retval 0 on success * \retval errno on error */ int sigPipeWriteCmd(int fh, void * cmd, size_t cmd_size) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif ; template void Signal::HandlerThread::signalNotifier(int signal) { int sig[2] = { static_cast(Signal::HandlerThread::HT_SIGNAL), }; sig[1] = signal; // TBD: The return value is silently ignored. // Either the write should've succeeded or the handling // thread is already coming down... sigPipeWriteCmd(s_comm_pipe[1], sig, sizeof(sig)); } template Signal::HandlerThread::HandlerThread(const Signal::List & siglist) #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::logic_error, std::runtime_error) #endif { #ifdef WIN32 NUT_UNUSED_VARIABLE(siglist); /* FIXME: Implement (for NUT processes) via pipes? * See e.g. upsdrvctl implementation. */ std::stringstream e; e << "Can't prepare signal handling thread: not implemented on this platform yet"; /* NUT_WIN32_INCOMPLETE(); */ throw std::logic_error(e.str()); #else /* !WIN32 */ // At most one instance per process allowed if (-1 != s_comm_pipe[1]) throw std::logic_error( "Attempt to start a duplicate of signal handling thread detected"); // Create communication pipe if (::pipe(s_comm_pipe)) { std::stringstream e; e << "Failed to create communication pipe: " << errno; throw std::runtime_error(e.str()); } // Start the thread int status = ::pthread_create(&m_impl, nullptr, &main, s_comm_pipe); if (status) { std::stringstream e; e << "Failed to start the thread: " << status; throw std::runtime_error(e.str()); } // Register signals Signal::List::const_iterator sig = siglist.begin(); for (; sig != siglist.end(); ++sig) { struct sigaction action; ::memset(&action, 0, sizeof(action)); # ifdef sigemptyset // no :: here because macro sigemptyset(&action.sa_mask); # else ::sigemptyset(&action.sa_mask); # endif action.sa_handler = &signalNotifier; int signo = static_cast(*sig); // TBD: We might want to save the old handlers... status = ::sigaction(signo, &action, nullptr); if (status) { std::stringstream e; e << "Failed to register signal handler for signal "; e << signo << ": " << errno; throw std::runtime_error(e.str()); } } #endif /* !WIN32 */ } template void Signal::HandlerThread::quit() #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { static int quit = static_cast(Signal::HandlerThread::HT_QUIT); sigPipeWriteCmd(s_comm_pipe[1], &quit, sizeof(quit)); int status = ::pthread_join(m_impl, nullptr); if (status) { std::stringstream e; e << "Failed to joint signal handling thread: " << status; throw std::runtime_error(e.str()); } if (::close(s_comm_pipe[1])) { std::stringstream e; e << "Failed to close communication pipe: " << errno; throw std::runtime_error(e.str()); } s_comm_pipe[1] = -1; } template Signal::HandlerThread::~HandlerThread #if (defined __clang__) #endif () #if (defined __cplusplus) && (__cplusplus < 201100) throw(std::runtime_error) #endif { // Stop the thread unless already stopped if (-1 != s_comm_pipe[1]) quit(); } /** NUT-specific signal handling */ class NutSignal: public Signal { public: /** * \brief Send signal to a NUT process * * The function assembles process-specific PID file name and path * and calls \ref Signal::send. * * An exception is thrown if the signal isn't implemented * or PID file read fails. * * \param signame Signal name * \param process File containing process PID * * \retval 0 in case of success * \retval EPERM if the process doesn't have permission to send the signal * \retval ESRCH if the process (group) identified doesn't exist */ static int send(enum_t signame, const std::string & process); }; // end of class NutSignal } // end of namespace nut #endif /* end of #ifndef NUT_NUTIPC_H */ nut-2.8.3/include/upsconf.h0000644000200500020050000000301114777534446012530 00000000000000/* upsconf.h - prototypes for upsconf.c Copyright (C) 2001 Russell Kroll 2005 Arnaud Quette 2013 Emilien Kia 2020 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_UPSCONF_H_SEEN #define NUT_UPSCONF_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* callback function from read_upsconf */ void do_upsconf_args(char *upsname, char *var, char *val); /* open the ups.conf, parse it, and call back do_upsconf_args() * returns -1 (or aborts the program) in case of errors; * returns 1 if processing finished successfully * See also reload_flag support in main.c for live-reload feature */ int read_upsconf(int fatal_errors); #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_UPSCONF_H_SEEN */ nut-2.8.3/include/Makefile.am0000644000200500020050000001052015001552635012716 00000000000000# Network UPS Tools: include # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ include_HEADERS = dist_noinst_HEADERS = \ attribute.h common.h extstate.h proto.h \ state.h str.h timehead.h upsconf.h \ nut_bool.h nut_float.h nut_stdint.h nut_platform.h \ wincompat.h # Optionally deliverable as part of NUT public API: if WITH_DEV include_HEADERS += parseconf.h if WITH_DEV_LIBNUTCONF include_HEADERS += nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.hpp else !WITH_DEV_LIBNUTCONF dist_noinst_HEADERS += nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.hpp endif !WITH_DEV_LIBNUTCONF else !WITH_DEV dist_noinst_HEADERS += parseconf.h dist_noinst_HEADERS += nutstream.hpp nutwriter.hpp nutipc.hpp nutconf.hpp endif !WITH_DEV # http://www.gnu.org/software/automake/manual/automake.html#Clean BUILT_SOURCES = nut_version.h CLEANFILES = nut_version.h nut_version.h.tmp* MAINTAINERCLEANFILES = Makefile.in .dirstamp # magic to include Git version information in NUT version string # (for builds not made from the tagged commit in a Git workspace) # NOTE: For pre-releases, SEMVER may differ from NUT_VERSION base # (e.g. a commit tagged as 2.8.3-rc5 can have its own NUT_VERSION based # on 2.8.2-something, but is assumed as a pre-release for 2.8.3 SEMVER) nut_version.h: @FORCE_NUT_VERSION@ @echo " GENERATE-HEADER $@" ; \ RES=0; \ GITREV="`$(top_srcdir)/tools/gitlog2version.sh`" || GITREV=""; \ GITREV_IS_RELEASE="`NUT_VERSION_QUERY=IS_RELEASE $(top_srcdir)/tools/gitlog2version.sh 2>/dev/null`" || GITREV_IS_RELEASE="false"; \ GITREV_IS_PRERELEASE="`NUT_VERSION_QUERY=IS_PRERELEASE $(top_srcdir)/tools/gitlog2version.sh 2>/dev/null`" || GITREV_IS_PRERELEASE="false"; \ GITREV_SEMVER="`NUT_VERSION_QUERY=SEMVER $(top_srcdir)/tools/gitlog2version.sh 2>/dev/null`" || GITREV_SEMVER=""; \ { echo '/* Autogenerated file. Do not change. */' ; \ echo '/* This file was generated by "make". */' ; \ if [ -z "$$GITREV" ]; then \ NUT_VERSION="$(PACKAGE_VERSION)"; \ echo '/* The version number is set by AC_INIT in configure.ac. */' ; \ else \ NUT_VERSION="$$GITREV"; \ echo '/* The version number is determined by Git source commit hash' ; \ echo ' * and number of commits since the most recent Git tag (if not' ; \ echo ' * building the newest tagged commit itself - then just the tag).'; \ echo ' */' ; \ fi ; \ if [ -z "$$GITREV_SEMVER" ]; then \ GITREV_SEMVER="@NUT_SOURCE_GITREV_SEMVER@"; \ fi ; \ echo "#define NUT_VERSION_MACRO \"$$NUT_VERSION\"" ; \ echo "#define NUT_VERSION_SEMVER_MACRO \"$$GITREV_SEMVER\"" ; \ if $$GITREV_IS_RELEASE ; then \ echo "#define NUT_VERSION_IS_RELEASE 1" ; \ else \ echo "#define NUT_VERSION_IS_RELEASE 0" ; \ fi ; \ if $$GITREV_IS_PRERELEASE ; then \ echo "#define NUT_VERSION_IS_PRERELEASE 1" ; \ else \ echo "#define NUT_VERSION_IS_PRERELEASE 0" ; \ fi ; \ } > "$@.tmp.$$$$" && \ echo "NUT_VERSION: \"$$NUT_VERSION\" NUT_VERSION_IS_RELEASE:$$GITREV_IS_RELEASE NUT_VERSION_IS_PRERELEASE:$$GITREV_IS_PRERELEASE NUT_VERSION_SEMVER: \"$$GITREV_SEMVER\"" && \ if test -f "$@" && test -s "$@" ; then \ if cmp -s "$@.tmp.$$$$" "$@" ; then \ echo " GENERATE-HEADER $@ did not change" ; \ else \ echo " GENERATE-HEADER $@ got changed" ; \ cp "$@.tmp.$$$$" "$@" ; \ fi ; \ else \ echo " GENERATE-HEADER $@ was absent"; \ cp "$@.tmp.$$$$" "$@" ; \ fi \ || RES=$$? ; \ rm -f "$@.tmp.$$$$" ; \ exit $$RES FORCE: # counter part of BUILT_SOURCES: since nut_version is not a direct # deps of a local target, we must clean it by ourselves before the # distribution dist-hook: $(AM_V_at)rm -f $(distdir)/nut_version.h all-libs-local: nut_version.h nut-2.8.3/include/nut_platform.h0000644000200500020050000001063114777767434013600 00000000000000/** * \brief Platform-specific checks * * The header performs checks to resolve the actual build platform. * It defines macra that may be later used to produce platform-tailored * code. * * Be careful when writing platform-specific code; avoid that if possible. * * References: * http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system * * \author Vaclav Krpec * \date 2012/10/12 */ #ifndef NUT_PLATFORM_H_SEEN #define NUT_PLATFORM_H_SEEN 1 /* * In case doxygen source doc isn't generated * (which is the case at time of writing this), * just check the doxygen-documented (i.e. "**" * prefixed) NUT_PLATFORM_* macra, below. */ /* Apple Mac OS X, iOS and Darwin */ #if (defined __APPLE__ && defined __MACH__) /** Apple OS based on Mach ukernel */ # define NUT_PLATFORM_APPLE_MACH /* https://stackoverflow.com/a/2339910/4715872 */ # ifndef SOEXT # define SOEXT ".dylib" # endif # include # if (defined TARGET_OS_EMBEDDED) /** iOS (implies \ref NUT_PLATFORM_APPLE_MACH) */ # define NUT_PLATFORM_APPLE_IOS # endif # if (defined TARGET_IPHONE_SIMULATOR) /** iOS simulator (implies \ref NUT_PLATFORM_APPLE_MACH) */ # define NUT_PLATFORM_APPLE_IOS_SIMULATOR # endif # if (defined TARGET_OS_IPHONE) /** iPhone (implies \ref NUT_PLATFORM_APPLE_MACH) */ # define NUT_PLATFORM_APPLE_IPHONE # endif # if (defined TARGET_OS_MAC) /** Mac OS X (implies \ref NUT_PLATFORM_APPLE_MACH) */ # define NUT_PLATFORM_APPLE_OSX # endif #endif /* * GCC AIX issue: __unix__ nor __unix are not defined in older GCC * Addressed in GCC 4.7.0, see * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39950 * Remove if no longer necessary */ #if (defined _AIX && !defined __unix__) # define __unix__ #endif /* Microsoft Windows */ #if (defined _WIN32 || defined _WIN64) /** Windows */ # define NUT_PLATFORM_MS_WINDOWS # ifndef SOEXT # define SOEXT ".dll" # endif # if (defined NTDDI_WIN8 && NTDDI_VERSION >= NTDDI_WIN8) /** Windows 8 */ # define NUT_PLATFORM_MS_WINDOWS8 # endif /* UNIX */ /* Note that Apple OSX doesn't define __unix__ nor __unix; are they ashamed or something? */ #elif (defined __unix__ || defined __unix || defined NUT_PLATFORM_APPLE_MACH) # include # include /** UNIX */ # define NUT_PLATFORM_UNIX # if (defined _POSIX_VERSION) /** POSIX (implies \ref NUT_PLATFORM_UNIX), expands to POSIX version */ # define NUT_PLATFORM_POSIX _POSIX_VERSION # endif # if (defined __linux__) /** Linux (implies \ref NUT_PLATFORM_UNIX) */ # define NUT_PLATFORM_LINUX # endif # if (defined __sun && defined __SVR4) /** Solaris (implies \ref NUT_PLATFORM_UNIX) */ # define NUT_PLATFORM_SOLARIS # endif # if (defined __hpux) /** Hewlett-Packard HP-UX (implies \ref NUT_PLATFORM_UNIX) */ # define NUT_PLATFORM_HPUX /* Note: depending on CPU arch and OS version, library file * name patterns here could have been "*.so" as well. * E.g. per * https://community.hpe.com/t5/operating-system-hp-ux/so-and-sl-files/td-p/3780528 * *.sl are used in PA-RISC (11.11) * *.so shared libraries are used in HP-UX 11.20 and upwards. * Integrity (Itanium-based) HPUX can use *.sl as well, * but it is not recommended, see ld(1) under -lx: * https://web.archive.org/web/20090925153446/http://docs.hp.com/en/B2355-60103/ld.1.html */ /* FIXME: May want to detect better the CPU or OS version * to decide the SOEXT here*/ # ifndef SOEXT # define SOEXT ".sl" # endif # endif # if (defined _AIX) /** AIX (implies \ref NUT_PLATFORM_UNIX) */ # define NUT_PLATFORM_AIX # endif /* Note that BSD is defined in sys/param.h */ # if (defined BSD) /** BSD (implies \ref NUT_PLATFORM_UNIX) */ # define NUT_PLATFORM_BSD # if (defined __DragonFly__) /** DragonFly (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ # define NUT_PLATFORM_DRAGONFLY # elif (defined __FreeBSD__) /** FreeBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ # define NUT_PLATFORM_FREEBSD # elif (defined __OpenBSD__) /** OpenBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ # define NUT_PLATFORM_OPENBSD # elif (defined __NetBSD__) /** NetBSD (implies \ref NUT_PLATFORM_UNIX, \ref NUT_PLATFORM_BSD) */ # define NUT_PLATFORM_NETBSD # endif # endif #endif /* not WIN32, not MACOS, not HPUX... */ #ifndef SOEXT # define SOEXT ".so" #endif #endif /* NUT_PLATFORM_H_SEEN */ nut-2.8.3/VERSION_DEFAULT0000644000200500020050000000003415001554777011463 00000000000000NUT_VERSION_DEFAULT='2.8.3' nut-2.8.3/docs/0000755000200500020050000000000015001555413010246 500000000000000nut-2.8.3/docs/net-protocol.txt0000644000200500020050000004514114777767434013414 00000000000000Network protocol information ============================ Since May 2002, this protocol has an official port number from IANA, which is *3493*. The old number (3305) was a relic of the original code's ancestry, and conflicted with other services. Version 0.50.0 and up use 3493 by default. This protocol runs over TCP. UDP support was dropped in July 2003. It had been deprecated for some time and was only capable of the simplest query commands as authentication is impossible over a UDP socket. A library, named libupsclient, that implement this protocol is provided in both static and shared version to help the client application development. Old command removal notice -------------------------- Before version 1.5.0, a number of old commands were supported. These have been removed from the specification. For more information, consult an older version of the software. Command reference ----------------- Multi-word elements are contained within "quotes" for easier parsing. Embedded quotes are escaped with backslashes. Embedded backslashes are also escaped by representing them as \\. This protocol is intended to be interpreted with parseconf (NUT parser) or something similar. Revision history ---------------- Here's a table to present the various changes that happened to the NUT network protocol, over the time: [options="header,autowidth",frame="topbot",grid="rows",cols="^.^,^.^,<",align="center"] |=============================================================================== |Protocol version |NUT version |Description |1.0 |< 1.5.0 |Original protocol (legacy version) |1.1 |>= 1.5.0 |Original protocol (without old commands) .2+|1.2 .2+|>= 2.6.4 |Add "LIST CLIENT" and "NETVER" commands |Add ranges of values for writable variables .4+|1.3 .4+|>= 2.8.0 |Add "cmdparam" to "INSTCMD" |Add "TRACKING" commands (GET, SET) |Add "PRIMARY" as alias to older "MASTER" (implementation tested to be backwards compatible in `upsd` and `upsmon`) |Add "PROTVER" as alias to older "NETVER" |=============================================================================== NOTE: Any new version of the protocol implies an update of `NUT_NETVERSION` in 'configure.ac' file. ERRATA: Earlier revisions of this table mistakenly mentioned `LIST CLIENTS` as added since 2.6.4. The actual added command was `LIST CLIENT` (no `S`) as documented in its section below. GET --- Retrieve a single response from the server. Possible sub-commands: NUMLOGINS ~~~~~~~~~ Form: GET NUMLOGINS GET NUMLOGINS su700 Response: NUMLOGINS NUMLOGINS su700 1 '' is the number of clients which have done LOGIN for this UPS. This is used by the upsmon in primary mode to determine how many clients are still connected when starting the shutdown process. This replaces the old "REQ NUMLOGINS" command. UPSDESC ~~~~~~~ Form: GET UPSDESC GET UPSDESC su700 Response: UPSDESC "" UPSDESC su700 "Development box" '' is the value of "desc=" from ups.conf for this UPS. If it is not set, upsd will return "Unavailable". This can be used to provide human-readable descriptions instead of a cryptic "upsname@hostname" string. VAR ~~~ Form: GET VAR GET VAR su700 ups.status Response: VAR "" VAR su700 ups.status "OL" This replaces the old "REQ" command. TYPE ~~~~ Form: GET TYPE GET TYPE su700 input.transfer.low Response: TYPE ... TYPE su700 input.transfer.low ENUM '' can be several values, and multiple words may be returned: - 'RW': this variable may be set to another value with SET - 'ENUM': an enumerated type, which supports a few specific values - 'STRING:n': this is a string of maximum length n - 'RANGE': this is an numeric, either integer or float, comprised in the range (see LIST RANGE) - 'NUMBER': this is a simple numeric value, either integer or float ENUM, STRING and RANGE are usually associated with RW, but not always. The default , when omitted, is numeric, so either integer or float. Each driver is then responsible for handling values as either integer or float. Note that float values are expressed using decimal (base 10) english-based representation, so using a dot, in non-scientific notation. So hexadecimal, exponents, and comma for thousands separator are forbidden. For example: "1200.20" is valid, while "1,200.20" and "1200,20" and "1.2e4" are invalid. This replaces the old "VARTYPE" command. DESC ~~~~ Form: GET DESC GET DESC su700 ups.status Response: DESC "" DESC su700 ups.status "UPS status" '' is a string that gives a brief explanation of the named variable. upsd may return "Unavailable" if the file which provides this description is not installed. Different versions of this file may be used in some situations to provide for localization and internationalization. This replaces the old "VARDESC" command. CMDDESC ~~~~~~~ Form: GET CMDDESC GET CMDDESC su700 load.on Response: CMDDESC "" CMDDESC su700 load.on "Turn on the load immediately" This is like DESC above, but it applies to the instant commands. This replaces the old "INSTCMDDESC" command. TRACKING ~~~~~~~~ Form: GET TRACKING (activation status of TRACKING) GET TRACKING (execution status of a command / setvar) GET TRACKING 1bd31808-cb49-4aec-9d75-d056e6f018d2 Response: ON (TRACKING feature is enabled) OFF (TRACKING feature is disabled) PENDING (command execution is pending) SUCCESS (command was successfully executed) ERR UNKNOWN (command execution failed with unknown error) ERR INVALID-ARGUMENT (command execution failed due to missing or invalid argument) ERR FAILED (command execution failed) LIST ---- The LIST functions all share a common container format. They will return "BEGIN LIST" and then repeat the initial query. The list then follows, with as many lines are necessary to convey it. "END LIST" with the initial query attached then follows. The formatting may seem a bit redundant, but it makes a different form of client possible. You can send a LIST query and then go off and wait for it to get back to you. When it arrives, you don't need complicated state machines to remember which list is which. UPS ~~~ Form: LIST UPS Response: BEGIN LIST UPS UPS "" ... END LIST UPS BEGIN LIST UPS UPS su700 "Development box" END LIST UPS '' is a name from ups.conf, and is the value of desc= from ups.conf, if available. It will be set to "Unavailable" otherwise. This can be used to determine what values of are valid before calling other functions on the server. This is also a good way to handle situations where a single upsd supports multiple drivers. Clients which perform a UPS discovery process may find this useful. VAR ~~~ Form: LIST VAR LIST VAR su700 Response: BEGIN LIST VAR VAR "" ... END LIST VAR BEGIN LIST VAR su700 VAR su700 ups.mfr "APC" VAR su700 ups.mfr.date "10/17/96" ... END LIST VAR su700 This replaces the old "LISTVARS" command. RW ~~ Form: LIST RW LIST RW su700 Response: BEGIN LIST RW RW "" ... END LIST RW BEGIN LIST RW su700 RW su700 output.voltage.nominal "115" RW su700 ups.delay.shutdown "020" ... END LIST RW su700 This replaces the old "LISTRW" command. CMD ~~~ Form: LIST CMD LIST CMD su700 Response: BEGIN LIST CMD CMD ... END LIST CMD BEGIN LIST CMD su700 CMD su700 load.on CMD su700 test.panel.start ... END LIST CMD su700 This replaces the old "LISTINSTCMD" command. ENUM ~~~~ Form: LIST ENUM LIST ENUM su700 input.transfer.low Response: BEGIN LIST ENUM ENUM "" ... END LIST ENUM BEGIN LIST ENUM su700 input.transfer.low ENUM su700 input.transfer.low "103" ENUM su700 input.transfer.low "100" ... END LIST ENUM su700 input.transfer.low This replaces the old "ENUM" command. NOTE: This does not support the old "SELECTED" notation. You must request the current value separately. RANGE ~~~~~ Form: LIST RANGE LIST RANGE su700 input.transfer.low Response: BEGIN LIST RANGE RANGE "" "" ... END LIST RANGE BEGIN LIST RANGE su700 input.transfer.low RANGE su700 input.transfer.low "90" "100" RANGE su700 input.transfer.low "102" "105" ... END LIST RANGE su700 input.transfer.low CLIENT ~~~~~~ Form: LIST CLIENT LIST CLIENT ups1 Response: BEGIN LIST CLIENT CLIENT ... END LIST CLIENT BEGIN LIST CLIENT ups1 CLIENT ups1 ::1 CLIENT ups1 192.168.1.2 END LIST CLIENT ups1 SET --- VAR ~~~ Form: SET VAR "" SET VAR su700 ups.id "My UPS" Response: OK (if TRACKING is not enabled) OK TRACKING (if TRACKING is enabled) ERR [...] (see Error responses) TRACKING ~~~~~~~~ Form: SET TRACKING SET TRACKING ON SET TRACKING OFF Response: OK ERR INVALID-ARGUMENT (if is not "ON" or "OFF") ERR USERNAME-REQUIRED (if not yet authenticated) ERR PASSWORD-REQUIRED (if not yet authenticated) INSTCMD ------- Form: INSTCMD [] INSTCMD su700 test.panel.start INSTCMD su700 load.off.delay 120 NOTE: is an additional and optional parameter for the command. Response: OK (if TRACKING is not enabled) OK TRACKING (if TRACKING is enabled) ERR [...] (see Error responses) LOGOUT ------ Form: LOGOUT Response: OK Goodbye (recent versions) Goodbye... (older versions) Used to disconnect gracefully from the server. LOGIN ----- Form: LOGIN Response: OK (upon success) or <> NOTE: This requires "upsmon secondary" or "upsmon primary" in upsd.users Use this to log the fact that a system is drawing power from this UPS. The upsmon primary will wait until the count of attached systems reaches 1 -- itself. This allows the secondaries to shut down first. NOTE: You probably shouldn't send this command unless you are upsmon, or a upsmon replacement. PRIMARY (since NUT 2.8.0) or MASTER (deprecated) ------------------------------------------------ NOTE: This command was renamed in NUT 2.8.0 to "PRIMARY" with the older name "MASTER" kept as deprecated alias for compatibility. Form: MASTER Response: OK MASTER-GRANTED (upon success) Form: PRIMARY Response: OK PRIMARY-GRANTED (upon success) or <> NOTE: This requires "upsmon primary" in upsd.users NOTE: Previously documented response was just `OK` -- clients checking that server reply *starts with* that keyword would handle all cases. This function doesn't do much by itself. It is used by upsmon to make sure that primary-mode functions like FSD are available if necessary. FSD --- Form: FSD Response: OK FSD-SET (success) or <> NOTE: This requires "upsmon primary" in upsd.users, or "FSD" action granted in upsd.users upsmon in primary mode is the primary user of this function. It sets this "forced shutdown" flag on any UPS when it plans to power it off. This is done so that secondary systems will know about it and shut down before the power disappears. Setting this flag makes "FSD" appear in a STATUS request for this UPS. Finding "FSD" in a status request should be treated just like a "OB LB". It should be noted that FSD is currently a latch -- once set, there is no way to clear it short of restarting upsd or dropping then re-adding it in the ups.conf. This may cause issues when upsd is running on a system that is not shut down due to the UPS event. Note also that certain drivers can propagate the "FSD" state declared by the smarter UPSes themselves, e.g. when an UPS is charging after an outage and its battery level is below the "safe for load" threshold configured on the device itself. In this case the device usually does not power up its outlets automatically, but it can be forced by the systems administrator. The rationale behind such FSD during charging allows enough power to be guaranteed for systems to both boot and shut down safely, if the wall power disappears again, trading off prolonged unavailability of the shut down servers for the safety of their data. In such cases, administrators should be ready to disarm their upsmon clients until the batteries are charged, to avoid quick shutdowns of quickly restored servers -- but only if they are sure about the wall power being restored for good (e.g. outage was due to maintenance). PASSWORD -------- Form: PASSWORD Response: OK (upon success) or <> Sets the password associated with a connection. Used for later authentication for commands that require it. USERNAME -------- Form: USERNAME Response: OK (upon success) or <> Sets the username associated with a connection. This is also used for authentication, specifically in conjunction with the upsd.users file. STARTTLS -------- Form: STARTTLS Response: OK STARTTLS or <> This tells upsd to switch to TLS mode internally, so all future communications will be encrypted. You must also change to TLS mode in the client after receiving the OK, or the connection will be useless. Other commands -------------- - HELP: lists the commands supported by this server - VER: shows the version of the server currently in use - NETVER: shows the version of the network protocol currently in use (aliased as PROTVER since NUT v2.8.0, or formal protocol version 1.3) These three are not intended to be used directly by programs. Humans can make use of this program by using telnet or netcat. If you use telnet, make sure you don't have it set to negotiate extra options. upsd doesn't speak telnet and will probably misunderstand your first request due to the extra junk in the buffer. [[np-errors]] Error responses --------------- An error response has the following format: ERR [...] is always one element; it never contains spaces. This may be used to allow additional information () in the future. can have the following values: - 'ACCESS-DENIED' + The client's host and/or authentication details (username, password) are not sufficient to execute the requested command. - 'UNKNOWN-UPS' + The UPS specified in the request is not known to upsd. This usually means that it didn't match anything in ups.conf. - 'VAR-NOT-SUPPORTED' + The specified UPS doesn't support the variable in the request. + This is also sent for unrecognized variables which are in a space which is handled by upsd, such as server.*. - 'CMD-NOT-SUPPORTED' + The specified UPS doesn't support the instant command in the request. - 'INVALID-ARGUMENT' + The client sent an argument to a command which is not recognized or is otherwise invalid in this context. This is typically caused by sending a valid command like GET with an invalid subcommand. - 'INSTCMD-FAILED' + upsd failed to deliver the instant command request to the driver. No further information is available to the client. This typically indicates a dead or broken driver. - 'SET-FAILED' + upsd failed to deliver the set request to the driver. This is just like INSTCMD-FAILED above. - 'READONLY' + The requested variable in a SET command is not writable. - 'TOO-LONG' + The requested value in a SET command is too long. - 'FEATURE-NOT-SUPPORTED' + This instance of upsd does not support the requested feature. This is only used for TLS/SSL mode (STARTTLS) at the moment. - 'FEATURE-NOT-CONFIGURED' + This instance of upsd hasn't been configured properly to allow the requested feature to operate. This is also limited to STARTTLS for now. - 'ALREADY-SSL-MODE' + TLS/SSL mode is already enabled on this connection, so upsd can't start it again. - 'DRIVER-NOT-CONNECTED' + upsd can't perform the requested command, since the driver for that UPS is not connected. This usually means that the driver is not running, or if it is, the ups.conf is misconfigured. - 'DATA-STALE' + upsd is connected to the driver for the UPS, but that driver isn't providing regular updates or has specifically marked the data as stale. upsd refuses to provide variables on stale units to avoid false readings. + This generally means that the driver is running, but it has lost communications with the hardware. Check the physical connection to the equipment. - 'ALREADY-LOGGED-IN' + The client already sent LOGIN for a UPS and can't do it again. There is presently a limit of one LOGIN record per connection. - 'INVALID-PASSWORD' + The client sent an invalid PASSWORD -- perhaps an empty one. - 'ALREADY-SET-PASSWORD' + The client already set a PASSWORD and can't set another. This also should never happen with normal NUT clients. - 'INVALID-USERNAME' + The client sent an invalid USERNAME. - 'ALREADY-SET-USERNAME' + The client has already set a USERNAME, and can't set another. This should never happen with normal NUT clients. - 'USERNAME-REQUIRED' + The requested command requires a username for authentication, but the client hasn't set one. - 'PASSWORD-REQUIRED' + The requested command requires a passname for authentication, but the client hasn't set one. - 'UNKNOWN-COMMAND' + upsd doesn't recognize the requested command. + This can be useful for backwards compatibility with older versions of upsd. Some NUT clients will try GET and fall back on REQ after receiving this response. - 'INVALID-VALUE' + The value specified in the request is not valid. This usually applies to a SET of an ENUM type which is using a value which is not in the list of allowed values. Future ideas ------------ Dense lists ~~~~~~~~~~~ The LIST commands may be given the ability to handle options some day. For example, `LIST VARS +DESC` would return the current value like now, but it would also append the description of that variable. Get collection ~~~~~~~~~~~~~~ Allow to request only a subtree, which can be a collection, or a sub collection. nut-2.8.3/docs/asciidoc-vars.conf0000644000200500020050000001661114777767434013624 00000000000000ifndef::asciidoc-vars-nut-included[] :asciidoc-vars-nut-included: true // NOTE: The big block of comments and definitions below comes from // NUT::docs/asciidoc-vars.conf and is included into top-level document // sources by maintenance recipes directly (`make maintainer-asciidocs`), // due to current limitations of the GitHub Web UI asciidoc renderer. // Hopefully it can be dropped in favor of compact include definitions // (see README.adoc for anticipated example) after this issue is resolved // on their side: // * https://github.com/github/markup/issues/1095 // // This file should be included into NUT documentation sources to consistently // define certain expandable attributes, with contents defined based on the // rendition target (e.g. GitHub Web UI, plain text, locally built HTML/PDF...) // Note that currently GitHub Web UI references lead to nut-website (as of // last built and published revision), not to neighboring documents in the // source browser (which would make sense for branch revisions, etc.) due // to certain complexity about referencing other-document sections with a // partially functional rendering engine there. Exploration and fixes are // welcome (actually working links like // https://github.com/networkupstools/nut/tree/master#installing or // https://github.com/networkupstools/nut/blob/master/UPGRADING.adoc#changes-from-274-to-280 // do seem promising)! // // Since the GitHub UI does not allow use of custom asciidoc configuration // files, or generally does not process the `include:` requests at this time, // clumsy expandable attributes had to be used (usually a set including a // prefix with meaningful name, and one or more separators and/or a suffix // with shortened names). For our classic documentation renditions, they // should resolve to properly defined macros from `docs/asciidoc.conf` // (usually named same as the variables defined here, for simplicity): // * `linksrcdoc` allows to refer to a source of documentation file // relative to the root of NUT code base. // * `linkdoc` allows to refer to a file under `docs/` directory (or // its nut-website rendition). // * `xref` substitutes the asciidoc shorthand '<< >>' syntax with // attributes that conditionally expand to: // - links on GitHub (references can point at most to a section of // level docs/common.xsl's ), or // - xref asciidoc macros when generating docs. // * `linksingledoc` guarantees that, when chunked HTML is generated, // the link always points to a non-chunked file. // * `linkman2` allows to support different names for the manpage and // the command shown. This is also needed to properly display links // to manpages in both GitHub and generated docs without defining an // attribute for each manpage. // * `linkmanext` and `linkmanext2` macros repeat the behavior of the default ones. // These macros are intended for system man pages (e.g. HTML links might lead // to a generic internet site, or possibly to a distro-provided library // online or locally). // // Optional attributes set by callers: // * `website-url` (defaulted below) may be used for "historic website" // snapshot builds... hopefully // * `website` is used as a boolean toggle in our recipes for nut-website // vs. offline documentation renditions // * `env-github` is used as a boolean toggle, set by GitHub Web-UI renderer // * `(top_)srcdir` and `(top_)builddir` can be set by `Makefile.am` // calling the `a2x` tool, since some of the files with the asciidoc // mark-up are only generated or post-processed during build and // (due to `make dist` restrictions) being build products, they may // not reside in same directory as static source text files which // reference or include them. Note that the non-`top` paths would // normally differ based on location of the `Makefile` involved // (e.g. workspace root, or the `docs`, or `docs/man` directories). // These variables are expected to be absolute paths, or ones relative // to asciidoc-selected `:base_dir`, and to end with a relevant path // separator, or be empty -- so in all cases letting the resulting // string resolve meaningfully in the filesystem during docs build. // // Please keep the remaining comments and definitions as one big block // so it does not become a series of empty paragraphs in the rendered // documents! // ifndef::website-url[] :website-url: https://www.networkupstools.org/ endif::website-url[] // ifndef::srcdir[] :srcdir: endif::srcdir[] // ifndef::builddir[] :builddir: endif::builddir[] // ifndef::top_srcdir[] :top_srcdir: endif::top_srcdir[] // ifndef::top_builddir[] :top_builddir: endif::top_builddir[] // // // Address links on GitHub vs. docs // (note: 'env-github' attribute is set on GitHub) // // - when generating docs: ifndef::env-github[] // * xref -> xref // syntax: {xref}{x-s}[] // -> xref:[] :xref: xref: :x-s: // * link to doc -> our macro // syntax: {linksrcdoc} // -> linksrcdoc:[] :linksrcdoc: linksrcdoc: // * link to doc -> our macro (optional 2/3/4 args) // syntax: {linkdoc}{ld-s}[{,{,{,}}}] // -> linkdoc:[{,{,{,}}}] :linkdoc: linkdoc: :ld-s: // * link to single doc -> our macro // syntax: {linksingledoc}{lsd-s}[] // -> linksingledoc:[] :linksingledoc: linksingledoc: :lsd-s: // * link to manpage -> our macro // syntax: {linkman2}{lm-s}{lm-c}{lm-e} // -> linkman2:[,] :linkman2: linkman2: :lm-s: [ :lm-c: , :lm-e: ] :linkmanext: https://www.die.net/search/?q= :linkmanext2: https://www.die.net/search/?q= endif::env-github[] // // - on GitHub: ifdef::env-github[] // In our normal builds, Makefile variables convey the needed paths // (used relatively below as `image:images/ci/...png` etc.) :imagesdir: docs // * xref -> link // syntax: {xref}{x-s}[] // In order for it to work, can reference at most a section of // level docs/common.xsl's // -> {website-url}docs/user-manual.chunked/.html[] :xref: {website-url}docs/user-manual.chunked/ :x-s: .html // * link to doc -> our macro // syntax: {linksrcdoc} // -> link:[] :linksrcdoc: link:{top_srcdir}/ // * link to doc -> link (FIXME: ignore or use 2/3/4 args; currently they are all pasted as contents!) // syntax: {linkdoc}{ld-s}[{,{,{,}}}] // -> {website-url}docs/.chunked/index.html[] :linkdoc: {website-url}docs/ :ld-s: .chunked/index.html // * link to single doc -> link // syntax: {linksingledoc}{lsd-s}[] // -> {website-url}docs/.html[] :linksingledoc: {website-url}docs/ :lsd-s: .html // * link to manpage -> link // syntax: {linkman2}{lm-s}{lm-c}{lm-e} // All the fields are mandatory. // -> {website-url}docs/man/.html[()] :linkman2: {website-url}docs/man/ :lm-s: .html[ :lm-c: ( :lm-e: )] :linkmanext: https://www.die.net/search/?q= :linkmanext2: https://www.die.net/search/?q= endif::env-github[] endif::asciidoc-vars-nut-included[] // nut-2.8.3/docs/nut-versioning.adoc0000644000200500020050000005235515001552635014022 00000000000000NUT versioning ============== Historic note ------------- Historically, the Network UPS Tools project release and interim iterations code base versions were identified by three or four numeric components, roughly following the Semantic Versioning (SEMVER) traditions, later codified as a formal standard at link:https://semver.org/[semver.org]: * NUT uses the GNU autotools suite for recipe orchestration, and the version string is specified in the `configure.ac` file an `AC_INIT` macro, which further generates variables like `PACKAGE_VERSION`, `PACKAGE_URL` and others used (substituted) in the actual code base, often via `nut_version.h` file. * NUT releases were identified by a `MAJOR.MINOR.PATCH` triplet, which was not strictly following the standard in that while the "major" part did reflect architectural/design changes, and "minor" part reflected some significant development milestones or API changes, the "patch" part did not correspond to post-release fixes but reflected iterative development, of which releases were the better-reviewed snapshots. Such a triplet was only spelled in `AC_INIT` for the commit tagged as that release. * Until NUT v2.6.x, the odd values of the `MINOR` component meant development code trees, and even values meant the stable tree. This approach was skipped (or effectively abandoned, as over a decade passed) with the move to Git branches for development -- as numerous NUT v2.7.x based releases were produced, and development continued into NUT v2.8.x. * NUT development versions were specified by the next commit after a release was published, spelling an `AC_INIT` macro argument like `MAJOR.MINOR.PATCH.1` to provide a fourth component -- which is logically "greater than" `MAJOR.MINOR.PATCH` for comparisons, so that the developed version can formally be installed over a preceding release (e.g. from custom testing packages). This configuration with a single development version (`.1`) was not very helpful for the faster pace of iterations, especially as the Git workflow and pull requests were adopted as the way of iterating the NUT development. This did not really help identify the build being tested by CI or reported by a community member, nor quickly determine if one custom build is "newer" than another (e.g. can be a recommended upgrade from the previously installed snapshot to check if some bug was fixed). Some experiments were done adding the `git describe` output to version banners reported by programs. These provide the number of commits since the most-recent known git tag, as well as the git hash of the NUT sources involved. This made the builds better identifiable, but did not help compare the feature branches and the main trunk of development: any code committed after a release has its own count of commits since that tag, this one number does not really suffice. Current NUT SEMVER definition ----------------------------- Since NUT v2.8.3, the definition which goes into `AC_INIT` and further into the code was extended in a manner similar to what `git describe` produces, but with added numbers after the common triplet of semantically versioned numbers: `X.Y.Z(.T(.B(-C+H(+R))))` or `X.Y.Z(.T(.B(-R)))` * Standard semver (used in releases): + NOTE: Historically NUT did not *diligently* follow the standard semver triplet, primarily because a snapshot of trunk is tested and released, and work moves on with the PATCH part (rarely MINOR one) incremented; no actual patches are released to some sustaining track of an older release lineage. There were large re-designs that got MAJOR up to 2, though. - `X`: MAJOR - incompatible API changes - `Y`: MINOR - major new features and/or API evolution - `Z`: PATCH - bug fixes (and new features like added drivers) * Extended semver (for snapshots of trunk): - T: (optional) Commits on trunk since previous release tag * Extended semver (for features branched off trunk): - B: (optional) Commits on branch since nearest ancestor which is on trunk The optional suffix (only for commits which are not git tags themselves) is provided by `git describe`: * C: Commits on branch since previous release tag * H: (Short) Git hash (prefixed by "g" character) of the described commit The pre-release information (if provided/known) would either follow the optional suffix detailed above, or it would be the suffix itself: * R: If this commit has a non-release tag, it can be optionally reported so we know that a commit some '1234' iterations after release 'N' is also a release candidate for 'N+1'. Note that any dash in that tag value will be replaced by a plus, e.g. `2.8.2.2878.1-2879+g882dd4b00+v2.8.3+rc6` The numeric part of NUT SEMVER definition mostly follows https://semver.org/ except that for development iterations the base version may have up to five dot-separated numeric components (SEMVER triplet for base release, and additional data described above). Unlike standard semver provisions for "pre-release versions" (separated by a minus sign after the triplet), which are "less than" that release for comparisons, the fourth and fifth components (if present) are "greater than" that release and any preceding development iterations made after it. Helper script `tools/gitlog2version.sh` is used to determine the project version from packager-provided override files (or equivalents provided by `make dist` in a snapshot/release tarball), git metadata from the current workspace, or built-in fallback defaults. Occasionally there may be tagged pre-releases, which follow the standard semver markup, like `v2.8.0-rc3` (in git), however they would be converted to NUT SEMVER here (as a number of commits since previous release) by default. Using gitlog2version.sh ----------------------- The script can be controlled by environment variables, including some sourced from configuration files. It identifies a number of data items, and reports the one specified by `NUT_VERSION_QUERY` on `stdout`. NOTE: It does not currently have a query to report "everything" in a manner that can be processed by `eval` in calling shell scripts (or `Makefile` rule implementations). .Environment variables that can be used for external configuration [opts="header",cols="1,3,2a"] |========================================================================= |Variable | Description | Example |`abs_top_srcdir` | Top source directory | `/home/abuild/nut` |`abs_top_builddir` | Top build directory (defaults to `abs_top_srcdir`) | `/home/abuild/.builds/linux/nut` |`NUT_VERSION_FORCED` | Set `NUT_VERSION_DEFAULT` (extended NUT SEMVER, may be just a triplet) to this value and enforce `NUT_VERSION_PREFER_GIT=false`. Usually sourced from `${abs_top_srcdir}/VERSION_FORCED` (if present) | `2.8.2.2379` `2.8.3-rc3` `2.8.2.2878.3-2881+g45029249f+v2.8.3+rc6` |`NUT_VERSION_FORCED_SEMVER` | Set `SEMVER` (exactly a triplet) to this value regardless of `NUT_VERSION_PREFER_GIT` setting. Usually sourced from `${abs_top_srcdir}/VERSION_FORCED_SEMVER` (if present) | `2.8.3` |`NUT_VERSION_DEFAULT` | Usually sourced from either `${abs_top_builddir}/VERSION_DEFAULT` (if present) or `${abs_top_srcdir}/VERSION_DEFAULT` (if present), in which case the script also defaults `NUT_VERSION_PREFER_GIT=false` (unless it is already specified as `true` or `${abs_top_srcdir}/.git` exists). If no value was provided, a hard-coded value is used (updated as part of maintainers' release rituals). | `2.8.2.2379.2-2381+g1faa9945d` |`NUT_VERSION_PREFER_GIT` | If not provided by caller, or sourced files, or defaulted with `NUT_VERSION_FORCED` or `NUT_VERSION_DEFAULT` as described above, as a `false` value, then becomes `true` if `${abs_top_srcdir}/.git` exists or `false` otherwise (tarball builds) | `true` |`NUT_WEBSITE` | Default website URL, extended for historic sub-sites for a release | `https://www.networkupstools.org/` |`NUT_VERSION_GIT_TRUNK` | Git branch name to use for calculation of current codebase distance from main development (as known in local workspace index); by default, the newest branch named like `master` is located (any competition is same or ancestor) | `origin/master` |`NUT_VERSION_GIT_ALL_TAGS` | If `true`, consider usual (not "annotated") tags too | `false` |`NUT_VERSION_GIT_ALWAYS_DESC` | If `true`, tell git to return just a commit hash if no tag was matched in index. | `false` |========================================================================= .Intermediate variables in Git workspace processing [opts="header",cols="1,3,2a"] |========================================================================= |Variable | Description | Example (development and release) |`DESC` | Originates from `git describe`, filtered for releases (`vX.Y.Z`) and ignoring various `rc`, `alpha`, `beta` etc. tags. This yields the tag name, followed by number of commits added to current `HEAD` history since that tag, and the current commit hash. In the resulting string, the git hash is separated by a "plus" sign (as semver build metadata) rather than the "minus" returned by the tool. | `v2.8.2-2381+g1faa9945d` |`TAG` | Nearest (annotated by default) tag preceding the `HEAD` in history: the part of `DESC` before the commit count and hash. | `v2.8.2` |`BASE` | The `git merge-base` of current commit and `NUT_VERSION_GIT_TRUNK` (see above). How much of the known trunk history is in current HEAD? This may be "all of it" when we are on that branch or PR made from its tip, "some of it" if looking at a historic snapshot, or "nothing" if looking at the tagged commit (it is the merge base for itself and any of its descendants) | `e9a48c9afeb4e06c758a3f4215977445c0f64780` |`SUFFIX` | Commit count since the tag and hash of the `HEAD` commit; empty e.g. when `HEAD` is the tagged commit | `-2381+g1faa9945d` |`VER5` | Full 5-component version, note we strip leading `v` from the expected `TAG` value | `2.8.2.2379.2` |`DESC5` | Full 5-component version `VER5` concatenated with `SUFFIX` | `2.8.2.2379.2-2381+g1faa9945d` |`VER50` | `VER5` without trailing `.0` in fifth or fourth component | * dev: `2.8.2.2379.2` * trunk: `2.8.2.2379.0` => `2.8.2.2379` * release: `2.8.2.0.0` => `2.8.2` |`DESC50` | `VER50` concatenated with `SUFFIX` | * release: `2.8.2-2381-g1faa9945d` |`SEMVER` | Exactly three leading numeric components. Either `NUT_VERSION_FORCED_SEMVER` (if provided by caller or configuration files), or derived from `VER5` (removing fourth and fifth numbers) | `2.8.0` |========================================================================= .Intermediate variables in default (non-git -- tarball or forced) processing [opts="header",cols="1,3,2a"] |========================================================================= |Variable | Description | Example (development and release) |`NUT_VERSION_DEFAULT_DOTS` | Processed from `NUT_VERSION_DEFAULT` (see above) to count just the dot characters | * dev: `....` * trunk: `...` * release: `..` |`NUT_VERSION_DEFAULT5_DOTS` | Grows from `NUT_VERSION_DEFAULT_DOTS`, used to construct `NUT_VERSION_DEFAULT5` | `....` |`NUT_VERSION_DEFAULT5` | Constructed from `NUT_VERSION_DEFAULT`, adding `.0` numeric components as needed, to have *at least 5* of them | `2.8.2.0.0` |`NUT_VERSION_DEFAULT3_DOTS` | Decreases from `NUT_VERSION_DEFAULT_DOTS`, used to construct `NUT_VERSION_DEFAULT3` | `..` |`NUT_VERSION_DEFAULT3` | Constructed from `NUT_VERSION_DEFAULT`, adding `.0` numeric components as needed or dropping extras, to have *exactly 3* of them | `2.8.0` |`SUFFIX` | Empty, unless `NUT_VERSION_DEFAULT` had a suffix for pre-release information roughly matching the `-(rc|alpha|beta)[0-9]*` regular expression | `""` `-rc6` |`VER5` | Full 5-component version, `NUT_VERSION_DEFAULT5` | `2.8.2.2379.2` |`DESC5` | Constructed as `${VER5}${SUFFIX}` | `2.8.2.2379.2` `2.8.3.0.0-rc6` |`VER50` | `NUT_VERSION_DEFAULT` as provided by caller or defaulted, may be with or without trailing `.0` in fifth or fourth components | `2.8.2.1` |`DESC50` | Constructed as `${VER50}${SUFFIX}` | `2.8.2.1` `2.8.3-rc6` |`BASE` | Empty (no known common commits with no trunk) | `""` |`SEMVER` | Exactly three leading numeric components. Either `NUT_VERSION_FORCED_SEMVER` (if provided by caller or configuration files), or `NUT_VERSION_DEFAULT3` (see above) | `2.8.0` |`TAG` | Constructed as `v${NUT_VERSION_DEFAULT3}${SUFFIX}` | `v2.8.0` `v2.8.3-rc6` |========================================================================= The majority of identified values can be reported for debugging to `stderr`, currently as a single line (wrapped for readability in the sample below): ---- :; ./tools/gitlog2version.sh SEMVER=2.8.2; TRUNK='master'; BASE='e9a48c9afeb4e06c758a3f4215977445c0f64780'; DESC='v2.8.2-2381+g1faa9945d' => TAG='v2.8.2' + SUFFIX='-2381+g1faa9945d' => VER5='2.8.2.2379.2' => VER50='2.8.2.2379.2' => DESC50='2.8.2.2379.2-2381+g1faa9945d' ---- .Values reported via `NUT_VERSION_QUERY` [opts="header",cols="1,3,2a"] |========================================================================= |`NUT_VERSION_QUERY` | Description | Example (development and release) |`DESC5` | Full 5-component version (concatenated with `SUFFIX` for git) | * dev: `2.8.2.2379.2-2381+g1faa9945d` * snapshot tarball: `2.8.2.2379.2` |`DESC50` | 3-to-5 non-zero component version (concatenated with `SUFFIX` for git) | * dev: `2.8.2.2381-2381+g1faa9945d` * snapshot tarball: `2.8.2.1` |`VER5` | Full 5-component version | * dev: `2.8.2.2379.2` * snapshot tarball: `2.8.2.1.0` |`VER50` | 3-to-5 non-zero component version | * dev: `2.8.2.2379.2` * release tarball: `2.8.0` |`SEMVER` | Exactly three leading numeric components | `2.8.2` |`IS_RELEASE` | `true` if `SEMVER`==`VER50`, `false` otherwise | * dev: `false` * rel: `true` |`IS_PRERELEASE` | `true` if `SUFFIX_PRERELEASE` is not empty, `false` otherwise | * dev: `false` * rel/RC: `true` |`TAG` | GIT: Nearest (annotated by default) tag preceding the `HEAD` in history. DEFAULT: Constructed from `SEMVER` | `v2.8.2` |`TAG_PRERELEASE` | GIT: if the `HEAD` itself has a tag matching the `-(rc|alpha|beta)[0-9]*` regular expression. DEFAULT: Constructed from `NUT_VERSION_DEFAULT3` and `SUFFIX_PRERELEASE`. Empty for not-pre-releases. | `v2.8.2-rc3` `""` |`TRUNK` | GIT: Branch name used for calculation of current codebase distance from main development. DEFAULT: empty. | `master` |`SUFFIX` | GIT: Commit count since the tag and hash of the `HEAD` commit DEFAULT: empty for non-prerelease `NUT_VERSION_DEFAULT` values, or either value of `SUFFIX_PRERELEASE` with a leading dash for `NUT_VERSION_DEFAULT` values without git offset info (e.g. `2.8.3.5-rc6` => `-rc6`), or the whole tail with git and pre-release tag info. | * dev: `-2381+g1faa9945d` * RC git: `-2381+g1faa9945d+v2.8.3+rc6` * RC default: `-rc6` |`SUFFIX_PRERELEASE` | GIT: Constructed from `TAG_PRERELEASE` replacing any dash with a plus character. DEFAULT: empty unless `NUT_VERSION_DEFAULT` has a suffix matching the `-(rc|alpha|beta)[0-9]*` regular expression, or git info followed by the pre-release tag. NOTE: No leading dash in this value (unlike `SUFFIX`). | * RC git: `v2.8.3+rc6` * RC default: `rc6` |`BASE` | GIT: Newest common commit of development `TRUNK` and the `HEAD` commit (their `git merge-base`). DEFAULT: empty. | `e9a48c9afeb4e06c758a3f4215977445c0f64780` |`URL` | Clarify the project website URL -- particularly historically frozen snapshots made for releases | * dev: `https://www.networkupstools.org/` (default development) * rel: `https://www.networkupstools.org/historic/v2.8.2/index.html` |`UPDATE_FILE` | Used in `autogen.sh` and top-level `Makefile.am` to update the `VERSION_DEFAULT` file that goes into "dist" tarballs; prints its contents | `NUT_VERSION_DEFAULT='2.8.2.2379.2-2381+g1faa9945d'` |`UPDATE_FILE_GIT_RELEASE` | Used in maintainer rituals (requires git) to update the `VERSION_FORCED` and `VERSION_FORCED_SEMVER` files that go into "dist" tarballs; prints their contents | `NUT_VERSION_FORCED='2.8.2.2878.3-2881+g45029249f+v2.8.3+rc6'` `NUT_VERSION_FORCED_SEMVER='2.8.3'` |default | Report `DESC50` | `v2.8.2-2381-g1faa9945d` |========================================================================= Variables propagated by configure.ac ------------------------------------ .Values reported via `NUT_VERSION_QUERY` [opts="header",cols="1,3,2a"] |========================================================================= |Variable | Description | Example (development and release) |`PACKAGE_VERSION` | Argument to `AC_INIT` determined by `NUT_VERSION_QUERY=VER50 gitlog2version.sh` | * dev: `2.8.2.695.1` * trunk: `2.8.2.695` * release: `2.8.2` |`PACKAGE_URL` | Argument to `AC_INIT` determined by `NUT_VERSION_QUERY=URL gitlog2version.sh` | * dev/trunk: `https://www.networkupstools.org/` * release: `https://www.networkupstools.org/historic/v2.8.2/index.html` |`NUT_WEBSITE_BASE` | Derived from `PACKAGE_URL` without a trailing slash nor `index.html` (prefixed to documentation file URLs, etc.) | * dev/trunk: `https://www.networkupstools.org` * release: `https://www.networkupstools.org/historic/v2.8.2` |`NUT_SOURCE_GITREV` | Determined by `NUT_VERSION_QUERY=DESC50 gitlog2version.sh` | `2.8.2.695.1-696+g0e00f0777` |`NUT_SOURCE_GITREV_SEMVER` | Determined by `NUT_VERSION_QUERY=SEMVER gitlog2version.sh` | `2.8.2` |`NUT_SOURCE_GITREV_NUMERIC` | Determined by `NUT_SOURCE_GITREV` leaving only the numbers, e.g. for PyPI uploads (currently without the total commit count) | `2.8.2.695.1'` |`NUT_SOURCE_GITREV_IS_RELEASE` | Determined by `NUT_VERSION_QUERY=IS_RELEASE gitlog2version.sh` | `true` or `false` |`NUT_SOURCE_GITREV_IS_PRERELEASE` | Determined by `NUT_VERSION_QUERY=IS_PRERELEASE gitlog2version.sh` | `true` or `false` |`NUT_SOURCE_GITREV_DEVREL` | String determined by `NUT_SOURCE_GITREV_IS_RELEASE` | `"release"` or `"development iteration"` |========================================================================= Variables propagated by nut_version.h ------------------------------------- .Values encoded via `include/nut_version.h`, generated by `include/Makefile.am` [opts="header",cols="1,3,2a"] |========================================================================= |Variable | Description | Example (development and release) |`#define NUT_VERSION_MACRO "$NUT_VERSION"` | Determined by default `gitlog2version.sh` (no `NUT_VERSION_QUERY`) at the moment of latest build, or (as fallback) `PACKAGE_VERSION` set during the last run of `configure` script | `2.8.2.695.1` |`#define NUT_VERSION_SEMVER_MACRO "$GITREV_SEMVER"` | Determined by `NUT_VERSION_QUERY=SEMVER gitlog2version.sh` at the moment of latest build, or (as fallback) `NUT_SOURCE_GITREV_SEMVER` set during the last run of `configure` script | `2.8.2` |`#define NUT_VERSION_IS_RELEASE <0-or-1>` | Determined by `NUT_VERSION_QUERY=IS_RELEASE gitlog2version.sh` (falls back to `false` if that query fails) | * `1` if `$GITREV_IS_RELEASE` * `0` otherwise |`#define NUT_VERSION_IS_PRERELEASE <0-or-1>` | Determined by `NUT_VERSION_QUERY=IS_PRERELEASE gitlog2version.sh` (falls back to `false` if that query fails) | * `1` if `$GITREV_IS_PRERELEASE` * `0` otherwise |========================================================================= Use in C code ------------- common.c ~~~~~~~~ * The `NUT_VERSION_MACRO` is used in `common/common.c` and further made known to all code base as a static string `UPS_VERSION` linked via `libcommon*.la` internal libraries. * Method `describe_NUT_VERSION_once()` prepares the string which combines the `NUT_VERSION_MACRO` with comments that it is either a `release` or a `(development iteration after $NUT_VERSION_SEMVER_MACRO)`, based on the value of `NUT_VERSION_IS_RELEASE`. + It is used from a number of other methods, such as `print_banner_once()`, `nut_report_config_flags()`, and so ends up in version reports of programs via their `help()`/`usage()` methods. * Method `suggest_doc_links()` prepares a uniform bit of text for driver and tool programs to report in their `help()`/`usage()` methods, to refer to their manual page under the `NUT_WEBSITE_BASE`. Man pages ~~~~~~~~~ * Manual pages and other documentation consume the `PACKAGE_VERSION`, `PACKAGE_VERSION` and `NUT_WEBSITE_BASE` as `asciidoc` attributes when rendering HTML/PDF/man document formats. * The `NUT_WEBSITE_BASE` is also substituted instead of literal `https://www.networkupstools.org/*` which follows a `home page:` prefix (so that the pages rendered for a release refer to the historic website). systemd and SMF manifests ~~~~~~~~~~~~~~~~~~~~~~~~~ Service manifests include references to documentation for the tools they wrap, including published pages under the `NUT_WEBSITE_BASE` for the development or historic variants of the NUT website. NUT-Monitor (Python UI) and PyNUTClient ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * The `PACKAGE_VERSION` and `NUT_WEBSITE_BASE` are reported in the About dialog. * Version information is propagated into PyPI packages for the `PyNUTClient` module. nut-2.8.3/docs/outlets.txt0000644000200500020050000000670714553676503012457 00000000000000[[outlet_management]] NUT outlets management and PDU notes ==================================== NUT supports advanced outlets management for any kind of device that proposes it. This chapter introduces how to manage outlets in general, and how to take advantage of the provided features. Introduction ------------ Outlets are the core of Power Distribution Units. They allow you to turn on, turn off or cycle the load on each outlet. Some UPS models also provide manageable outlets (Eaton, MGE, Powerware, Tripplite, ...) that help save power in various ways, and manage loads more intelligently. Finally, some devices can be managed in a PDU-like way. Consider blade systems: the blade chassis can be controlled remotely to turn on, turn off or cycle the power on individual blade servers. NUT allows you to control all these devices! NUT outlet data collection -------------------------- NUT provides a complete and uniform integration of outlets related data, through the 'outlet' collection. First, there is a special outlet, called 'main outlet'. You can access it through 'outlet.{id, desc, ...}' without any index. Any modification through the 'main outlet' will affect *all* outlets. For example, calling the command 'outlet.load.cycle' will cycle all outlets. Next, outlets index starts from *1*. Index '0' is implicitly reserved to the 'main outlet'. So the first outlet is 'outlet.1.*'. For a complete list of outlet data and commands, refer to the <>. An example upsc output (data/epdu-managed.dev) is available in the source archive. NOTE: The variables supported depend on the exact device type. Outlets on PDU -------------- Smart Power Distribution Units provide at least various meters, related to current, power and voltage. Some more advanced devices also provide control through the 'load.off', 'load.on' and 'load.cycle' commands. Outlets on UPS -------------- Some advanced Uninterruptible Power Supplies provide smart outlet management. This allows to program a limited backup time to non-critical loads in order to keep the maximum of the battery reserve for critical equipment. This also allows the same remote electrical management of devices provided by PDUs, which can be very interesting in Data Centers. For example, on small setup, you can plug printers, USB devices, hubs, (...) into managed outlets. Depending on your UPS's capabilities, you will be able to turn off those loads: - after some minutes of back-up time using 'outlet.n.delay.start', - when reaching a percentage battery charge using 'outlet.n.autoswitch.charge.low'. This will ensure a maximum runtime for the computer. On bigger systems, with bigger UPSs, this is the same thing with servers instead of small devices. NOTE: If you need the scheduling function and your device doesn't support it, you can still use <>. WARNING: don't plug the UPS's communication cable (USB or network) on a managed outlet. Otherwise, all computers will be stopped as soon as the communication is lost. Other type of devices --------------------- As mentioned in the introduction, some other devices can be considered and managed like PDUs. This is the case in most blade systems, where the blade chassis offers power management services. This way, you can control remotely each blade server as if it were a PDU outlet. This category of devices is generally called Remote Power Controls -- or "RPC" in NUT. nut-2.8.3/docs/snmp.txt0000644000200500020050000000270314777767434011741 00000000000000Desc: Information about SNMP and Network UPS Tools File: snmp.txt Date: 16 March 2003 Auth: Arnaud Quette or This document presents interactions between SNMP and Network UPS Tools. This work is mostly sponsored by: MGE UPS SYSTEMS There are two part in NUT for SNMP support: 1) the agent or server side An SNMP agent provides information for its hardware. In general, agents are embedded in SNMP card. This part has to be implemented as a Net-SNMP sub agent, acting as a NUT middleware (upsd level). Such software make a bridge between NUT data and SNMP, thus allowing to monitor, through SNMP, standard point to point UPSs (serial and USB). This is part of the "UPS Sub-Agent" project with Net-SNMP team. 2) the client side * Introduction An SNMP client communicates with an agent to acquire data. This part, which has to be a NUT driver, is implemented by snmp-ups. snmp-ups acts as a bridge from SNMP to NUT, thus allowing to monitor in NUT any SNMP Agent (embedded or on a host). The new snmp-ups driver now support multiple MIBS (SNMP structures declaration). For more information on snmp-ups, have a look at its man page (man 8 snmp-ups). * Extending existing mib2nut information To be written... * Adding new mib2nut information To be written... References: - NUT SNMP Protocols Library Available at: https://www.networkupstools.org/ups-protocols.html#_snmp nut-2.8.3/docs/nutdrv_qx-subdrivers.txt0000644000200500020050000012062214777767434015205 00000000000000How to make a new subdriver to support another Q* UPS ----------------------------------------------------- Overall concept ~~~~~~~~~~~~~~~ The NUT "*nutdrv_qx*" driver is a meta-driver that handles Q* UPS devices. It consists of a core driver that handles most of the work of talking to the hardware, and several sub-drivers to handle specific UPS manufacturers. Adding support for a new UPS device is easy, because it requires only the creation of a new sub-driver. [NOTE] ====== Due to historic reasons, there is a bit of a mess with terminology here: among the set of driver parameters passed on command-line or via `ups.conf`, the `subdriver` value is for Serial-over-USB dialect ("usbsubdriver" in code), and the `protocol` value is for Qx dialect (but referred to as "subdriver" in most of the documentation, and variable names in the code itself).. An additional set of source code files named `nutdrv_qx_subdrivername.{c,h}` defines a `subdriver_t` entry that is listed as in `subdrivers_list` array in the main `nutdrv_qx.c` file. However, in `ups.conf` this entity is referred to via the communication `protocol` keyword, if the end-user wants to pick one explicitly (bypassing auto-detection). Confusingly, there *is* also an optional USB `subdriver` setting (available when the driver is built with USB support), for "Serial-over-USB subdriver selection", corresponding to entries in the `usbsubdriver` array and several `usbsubdrvname_command()` methods defined directly in `nutdrv_qx.c`. There are also methods called `usbsubdrvname_subdriver()` which are called via `qx_usb_id[]` array for USB VendorID/ProductID/iManufacturer/iProduct based matching, and typically set the `subdriver_command` variable to point to the corresponding `usbsubdrvname_command()` method when auto-detection happens. Otherwise, this variable is set according to a text name requested in the `subdriver` driver parameter. ====== Creating a subdriver ~~~~~~~~~~~~~~~~~~~~ In order to develop a new subdriver for a specific UPS you have to know the "idiom" (dialect of the protocol) spoken by that device. This kind of devices speaks idioms that can be summed up as follows: - We send the UPS a query for one or more information * If the query is supported by the device, we'll get a reply that is mostly of a fixed length, therefore, in most cases, each information starts and ends always at the same indexes - We send the UPS a command * If the command is supported by the device, the UPS will either take action without any reply or reply us with a device-specific answer signaling that the command has been accepted (e.g. +ACK+) - If the query/command isn't supported by the device we'll get either the query/command echoed back or a device-specific reply signaling that it has been rejected (e.g. +NAK+) To be supported by this driver the idiom spoken by the UPS must comply to these conditions. Writing a subdriver ~~~~~~~~~~~~~~~~~~~ You have to fill the +subdriver_t+ structure: ---- typedef struct { const char *name; int (*claim)(void); item_t *qx2nut; void (*initups)(void); void (*initinfo)(void); void (*makevartable)(void); const char *accepted; const char *rejected; #ifdef TESTING testing_t *testing; #endif /* TESTING */ } subdriver_t; ---- Where: *+name+*:: Name of this subdriver: name of the +protocol+ that will need to be set in the +ups.conf+ file to use this subdriver plus the internal version of it separated by a space (e.g. "++Megatec 0.01++"). *+claim+*:: This function allows the subdriver to "claim" a device: return +1+ if the device is supported by this subdriver, else +0+. *+qx2nut+*:: Main table of vars and instcmds: an array of +item_t+ mapping a UPS idiom to NUT. *+initups+* (optional):: Subdriver-specific +upsdrv_initups+. This function will be called at the end of nutdrv_qx's own +upsdrv_initups+. *+initinfo+* (optional):: Subdriver-specific +upsdrv_initinfo+. This function will be called at the end of nutdrv_qx's own +upsdrv_initinfo+. *+makevartable+* (optional):: Function to add subdriver-specific +ups.conf+ vars and flags. Make sure not to collide with other subdrivers' vars and flags. *+accepted+* (optional):: String to match if the driver is expecting a reply from the UPS on instcmd/setvar in case of success. This comparison is done after the answer we got back from the UPS has been processed to get the value we are searching, so you don't have to include the trailing carriage return (+\r+) and you can decide at which index of the answer the value should start or end setting the appropriate +from+ and +to+ in the +item_t+ (see <<_mapping_an_idiom_to_nut,Mapping an idiom to NUT>>). *+rejected+* (optional):: String to match if the driver is expecting a reply from the UPS in case of error. Note that this comparison is done on the answer we got back from the UPS before it has been processed, so include also the trailing carriage return (+\r+) and whatever character is expected. *+testing+*:: Testing table (an array of +testing_t+) that will hold the commands and the replies used for testing the subdriver. + -- +testing_t+: ---- typedef struct { const char *cmd; const char answer[SMALLBUF]; const int answer_len; } testing_t; ---- Where: *+cmd+*:: Command to match. *+answer+*:: Answer for that command. + NOTE: If +answer+ contains inner ++\0++s, in order to preserve them, +answer_len+ as well as an +item_t+'s +preprocess_answer()+ function must be set. *+answer_len+*:: Answer length: + - if set to +-1+ -> auto calculate answer length (treat +answer+ as a null-terminated string), - otherwise -> use the provided length (if reasonable) and preserve inner ++\0++s (treat +answer+ as a sequence of bytes till the +item_t+'s +preprocess_answer()+ function gets called). For more information, see <<_mapping_an_idiom_to_nut,Mapping an idiom to NUT>>. -- Mapping an idiom to NUT ~~~~~~~~~~~~~~~~~~~~~~~ If you understand the idiom spoken by your device, you can easily map it to NUT variables and instant commands, filling +qx2nut+ with an array of +item_t+ data structure: ---- typedef struct item_t { const char *info_type; const int info_flags; info_rw_t *info_rw; const char *command; char answer[SMALLBUF]; const int answer_len; const char leading; char value[SMALLBUF]; const int from; const int to; const char *dfl; unsigned long qxflags; int (*preprocess_command)(struct item_t *item, char *command, const size_t commandlen); int (*preprocess_answer)(struct item_t *item, const int len); int (*preprocess)(struct item_t *item, char *value, const size_t valuelen); } item_t; ---- Where: *+info_type+*:: NUT variable name, otherwise, if +QX_FLAG_NONUT+ is set, name to print to logs and if both +QX_FLAG_NONUT+ and +QX_FLAG_SETVAR+ are set, name of the var to retrieve from +ups.conf+. *+info_flags+*:: NUT flags (+ST_FLAG_*+ values to set in +dstate_addinfo+). *+info_rw+*:: + -- An array of +info_rw_t+ to handle r/w variables: - If +ST_FLAG_STRING+ is set in +info_flags+ it'll be used to set the length of the string (in +dstate_setaux+) - If +QX_FLAG_ENUM+ is set in +qxflags+ it'll be used to set enumerated values (in +dstate_addenum+) - If +QX_FLAG_RANGE+ is set in +qxflags+ it'll be used to set range boundaries (in +dstate_addrange+) NOTE: If +QX_FLAG_SETVAR+ is set the value given by the user will be checked against these infos. +info_rw_t+: ---- typedef struct { char value[SMALLBUF]; int (*preprocess)(char *value, const size_t len); } info_rw_t; ---- Where: *+value+*:: Value for enum/range, or length for +ST_FLAG_STRING+. *+preprocess(value, len)+*:: Optional function to preprocess range/enum +value+. + This function will be given +value+ and its +size_t+ and must return either +0+ if +value+ is supported or +-1+ if not supported. -- *+command+*:: Command sent to the UPS to get answer, or to execute an instant command, or to set a variable. *+answer+*:: Answer from the UPS, filled at runtime. + NOTE: If you expect a non-valid C string (e.g.: inner ++\0++s) or need to perform actions before the answer is used (and treated as a null-terminated string), you should set a +preprocess_answer()+ function. *+answer_len+*:: Expected minimum length of the answer. Set it to +0+ if there's no minimum length to look after. *+leading+*:: Expected leading character of the answer (optional), e.g. +#+, +(+ ... *+value+*:: Value from the answer, filled at runtime (i.e. +answer+ in the interval [+from+ to +to+]). *+from+*:: Position of the starting character of the info we're after in the answer. *+to+*:: Position of the ending character of the info we're after in the answer: use +0+ if all the remaining of the line is needed. *+dfl+*:: printf format to store value from the UPS in NUT variables. Set it either to +%s+ for strings or to a floating point specifier (e.g. +%.1f+) for numbers. + -- Otherwise: - If +QX_FLAG_ABSENT+ -> default value - If +QX_FLAG_CMD+ -> default command value -- + *+qxflags+*:: Driver's own flags. + -- [cols="m,",options="autowidth",frame="topbot",grid="rows"] |==== |QX_FLAG_STATIC |Retrieve this variable only once. |QX_FLAG_SEMI_STATIC |Retrieve this info smartly, i.e. only when a command/setvar is executed and we expect that data could have been changed. |QX_FLAG_ABSENT |Data is absent in the device, use default value. |QX_FLAG_QUICK_POLL |Mandatory vars. |QX_FLAG_CMD |Instant command. |QX_FLAG_SETVAR |The var is settable and the actual item stores info on how to set it. |QX_FLAG_TRIM |This var's value need to be trimmed of leading/trailing spaces/hashes. |QX_FLAG_ENUM |Enum values exist. |QX_FLAG_RANGE |Ranges for this var are available. |QX_FLAG_NONUT |This var doesn't have a corresponding var in NUT. |QX_FLAG_SKIP |Skip this var: this item won't be processed. |==== [NOTE] ==== The driver will run a so-called +QX_WALKMODE_INIT+ in +initinfo+ walking through all the items in +qx2nut+, adding instant commands and the like. From then on it'll run a so-called +QX_WALKMODE_QUICK_UPDATE+ just to see if the UPS is still there and then it'll do a so-called +QX_WALKMODE_FULL_UPDATE+ to update all the vars. If there's a problem with a var in +QX_WALKMODE_INIT+, the driver will automagically set +QX_FLAG_SKIP+ on it and then it'll skip that item in +QX_WALKMODE_QUICK_UPDATE+/+QX_WALKMODE_FULL_UPDATE+, provided that the item has not the flag +QX_FLAG_QUICK_POLL+ set, in that case the driver will set +datastale+. ==== -- *+preprocess_command(item, command, commandlen)+*:: Last chance to preprocess the command to be sent to the UPS (e.g. to add CRC, ...). This function is given the currently processed item (+item+), the command to be sent to the UPS (+command+) and its size_t (+commandlen+). Return +-1+ in case of errors, else +0+. +command+ must be filled with the actual command to be sent to the UPS. *+preprocess_answer(item, len)+*:: Function to preprocess the answer we got from the UPS before we do anything else (e.g. for CRC, decoding, ...). This function is given the currently processed item (+item+) with the answer we got from the UPS unmolested and already stored in +item+'s +answer+ and the length of that answer (+len+). Return +-1+ in case of errors, else the length of the newly allocated +item+'s +answer+ (from now on, treated as a null-terminated string). *+preprocess(item, value, valuelen)+*:: Function to preprocess the data from/to the UPS: you are given the currently processed item (+item+), a char array (+value+) and its +size_t+ (+valuelen+). Return +-1+ in case of errors, else +0+. + -- - If +QX_FLAG_SETVAR+/+QX_FLAG_CMD+ is set then the item is processed before the command is sent to the UPS so that you can fill it with the value provided by the user. + NOTE: In this case +value+ must be filled with the command to be sent to the UPS. - Otherwise the function will be used to process the value we got from the answer of the UPS before it'll get stored in a NUT variable. + NOTE: In this case +value+ must be filled with the processed value already compliant to NUT standards. -- IMPORTANT: You must provide an +item_t+ with +QX_FLAG_SETVAR+ and its boundaries set for both +ups.delay.start+ and +ups.delay.shutdown+ to map the driver variables +ondelay+ and +offdelay+, as they will be used in the shutdown sequence. TIP: In order to keep the data flow at minimum you should keep together the items in +qx2nut+ that need data from the same query (i.e. +command+): doing so the driver will send the query only once and then every +item_t+ processed after the one that got the answer, provided that it's filled with the same +command+ and that the answer wasn't +NULL+, will get that +answer+. Examples ~~~~~~~~ The following examples are from the +voltronic+ subdriver. Simple vars ^^^^^^^^^^^ We know that when the UPS is queried for status with +QGS\r+, it replies with something like +(234.9 50.0 229.8 50.0 000.0 000 369.1 ---.- 026.5 ---.- 018.8 100000000001\r+ and we want to access the output voltage (the third token, in this case +229.8+). ---- > [QGS\r] < [(234.9 50.0 229.8 50.0 000.0 000 369.1 ---.- 026.5 ---.- 018.8 100000000001\r] 0123456789012345678901234567890123456789012345678901234567890123456789012345 0 1 2 3 4 5 6 7 ---- Here's the +item_t+: ---- { "output.voltage", 0, NULL, "QGS\r", "", 76, '(', "", 12, 16, "%.1f", 0, NULL, NULL, NULL }, ---- [horizontal] +info_type+:: +output.voltage+ +info_flags+:: +0+ +info_rw+:: +NULL+ +command+:: +QGS\r+ +answer+:: Filled at runtime +answer_len+:: +76+ +leading+:: +(+ +value+:: Filled at runtime +from+:: +12+ -> the index at which the info (i.e. +value+) starts +to+:: +16+ -> the index at which the info (i.e. +value+) ends +dfl+:: +%.1f+ + We are expecting a number, so at first the core driver will check if it's made up entirely of digits/points/spaces, then it'll convert it into a double. Because of that we need to provide a floating point specifier. +qxflags+:: +0+ +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +NULL+ Mandatory vars ^^^^^^^^^^^^^^ Also from +QGS\r+, we want to process the 9th status bit +10000000+*`0`*+001+ that tells us whether the UPS is shutting down or not. ---- > [QGS\r] < [(234.9 50.0 229.8 50.0 000.0 000 369.1 ---.- 026.5 ---.- 018.8 100000000001\r] 0123456789012345678901234567890123456789012345678901234567890123456789012345 0 1 2 3 4 5 6 7 ---- Here's the +item_t+: ---- { "ups.status", 0, NULL, "QGS\r", "", 76, '(', "", 71, 71, "%s", QX_FLAG_QUICK_POLL, NULL, NULL, voltronic_status }, ---- [horizontal] +info_type+:: +ups.status+ +info_flags+:: +0+ +info_rw+:: +NULL+ +command+:: +QGS\r+ +answer+:: Filled at runtime +answer_len+:: +76+ +leading+:: +(+ +value+:: Filled at runtime +from+:: +71+ -> the index at which the info (i.e. +value+) starts +to+:: +71+ -> the index at which the info (i.e. +value+) ends +dfl+:: +%s+ + Since a +preprocess+ function is defined for this item, this could have been +NULL+, however, if we want -- like here -- we can use it in our +preprocess+ function. +qxflags+:: +QX_FLAG_QUICK_POLL+ -> this item will be polled every time the driver will check for updates. Since this item is mandatory to run the driver, if a problem arises in +QX_WALKMODE_INIT+ the driver won't skip it and it will set +datastale+. +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +voltronic_status+ + This function will be called *after* the +command+ has been sent to the UPS and we got back the +answer+ and stored the +value+ in order to process it to NUT standards: in this case we will convert the binary +value+ to a NUT status. Settable vars ^^^^^^^^^^^^^ So your UPS reports its battery type when queried for +QBT\r+; we are expecting an answer like +(01\r+ and we know that the values can be mapped as follows: +00+ -> "Li", +01+ -> "Flooded" and +02+ -> "AGM". ---- > [QBT\r] < [(01\r] <- 00="Li", 01="Flooded" or 02="AGM" 0123 0 ---- Here's the +item_t+: ---- { "battery.type", ST_FLAG_RW, voltronic_e_batt_type, "QBT\r", "", 4, '(', "", 1, 2, "%s", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM, NULL, NULL, voltronic_p31b }, ---- [horizontal] +info_type+:: +battery.type+ +info_flags+:: +ST_FLAG_RW+ -> this is a r/w var +info_rw+:: +voltronic_e_batt_type+ + The values stored here will be added to the NUT variable, setting its boundaries: in this case +Li+, +Flooded+ and +AGM+ will be added as enumerated values. +command+:: +QBT\r+ +answer+:: Filled at runtime +answer_len+:: +4+ +leading+:: +(+ +value+:: Filled at runtime +from+:: +1+ -> the index at which the info (i.e. +value+) starts +to+:: +2+ -> the index at which the info (i.e. +value+) ends +dfl+:: +%s+ + Since a +preprocess+ function is defined for this item, this could have been +NULL+, however, if we want -- like here -- we can use it in our +preprocess+ function. +qxflags+:: +QX_FLAG_SEMI_STATIC+ -> this item changes -- and will therefore be updated -- only when we send a command/setvar to the UPS + +QX_FLAG_ENUM+ -> this r/w variable is of the enumerated type and the enumerated values are listed in the +info_rw+ structure (i.e. +voltronic_e_batt_type+) +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +voltronic_p31b+ + This function will be called *after* the +command+ has been sent to the UPS and we got back the +answer+ and stored the +value+ in order to process it to NUT standards: in this case we will check if the value is in the range and then publish the human readable form of it (i.e. +Li+, +Flooded+ or +AGM+). We also know that we can change battery type with the +PBTnn\r+ command; we are expecting either +(ACK\r+ if the command succeeded or +(NAK\r+ if the command is rejected. ---- > [PBTnn\r] nn = 00/01/02 < [(ACK\r] 01234 0 ---- Here's the +item_t+: ---- { "battery.type", 0, voltronic_e_batt_type, "PBT%02.0f\r", "", 5, '(', "", 1, 4, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM, NULL, NULL, voltronic_p31b_set }, ---- [horizontal] +info_type+:: +battery.type+ +info_flags+:: +0+ +info_rw+:: +voltronic_e_batt_type+ + The value provided by the user will be automagically checked by the core nutdrv_qx driver against the enumerated values already set by the non setvar item (i.e. +Li+, +Flooded+ or +AGM+), so this could have been +NULL+, however if we want -- like here -- we can use it in our +preprocess+ function. +command+:: +PBT%02.0f\r+ +answer+:: Filled at runtime +answer_len+:: +5+ <- either +(NAK\r+ or +(ACK\r+ +leading+:: +(+ +value+:: Filled at runtime +from+:: +1+ -> the index at which the info (i.e. +value+) starts +to+:: +3+ -> the index at which the info (i.e. +value+) ends +dfl+:: Not used for +QX_FLAG_SETVAR+ +qxflags+:: +QX_FLAG_SETVAR+ -> this item is used to set the variable +info_type+ (i.e. +battery.type+) + +QX_FLAG_ENUM+ -> this r/w variable is of the enumerated type and the enumerated values are listed in the +info_rw+ structure (i.e. +voltronic_e_batt_type+) +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +voltronic_p31b_set+ + This function will be called *before* the +command+ is sent to the UPS so that we can fill +command+ with the value provided by the user: in this case the function will simply translate the human readable form of battery type (i.e. +Li+, +Flooded+ or +AGM+) to the UPS compliant type (i.e. +00+, +01+ and +02+) and then fill +value+ (the second argument passed to the +preprocess+ function). Instant commands ^^^^^^^^^^^^^^^^ We know that we have to send to the UPS +Tnn\r+ or +T.n\r+ in order to start a battery test lasting +nn+ minutes or +.n+ minutes: we are expecting either +(ACK\r+ on success or +(NAK\r+ if the command is rejected. ---- > [Tnn\r] < [(ACK\r] 01234 0 ---- Here's the +item_t+: ---- { "test.battery.start", 0, NULL, "T%s\r", "", 5, '(', "", 1, 4, NULL, QX_FLAG_CMD, NULL, NULL, voltronic_process_command }, ---- [horizontal] +info_type+:: +test.battery.start+ +info_flags+:: +0+ +info_rw+:: +NULL+ +command+:: +T%s\r+ +answer+:: Filled at runtime +answer_len+:: +5+ <- either +(NAK\r+ or +(ACK\r+ +leading+:: +(+ +value+:: Filled at runtime +from+:: +1+ -> the index at which the info (i.e. +value+) starts +to+:: +3+ -> the index at which the info (i.e. +value+) ends +dfl+:: Not used for +QX_FLAG_CMD+ +qxflags+:: +QX_FLAG_CMD+ -> this item is an instant command that will be fired when +info_type+ (i.e. +test.battery.start+) is called +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +voltronic_process_command+ + This function will be called *before* the +command+ is sent to the UPS so that we can fill +command+ with the value provided by the user: in this case the function will check if the value is in the accepted range and then fill +value+ (the second argument passed to the +preprocess+ function) with +command+ and the given value. Information absent in the device ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In order to set the server-side var +ups.delay.start+, that will be then used by the driver, we have to provide the following +item_t+: ---- { "ups.delay.start", ST_FLAG_RW, voltronic_r_ondelay, NULL, "", 0, 0, "", 0, 0, "180", QX_FLAG_ABSENT | QX_FLAG_SETVAR | QX_FLAG_RANGE, NULL, NULL, voltronic_process_setvar }, ---- [horizontal] +info_type+:: +ups.delay.start+ +info_flags+:: +ST_FLAG_RW+ -> this is a r/w var +info_rw+:: +voltronic_r_ondelay+ + The values stored here will be added to the NUT variable, setting its boundaries: in this case +0+ and +599940+ will be set as the minimum and maximum value of the variable's range. Those values will then be used by the driver to check the user provided value. +command+:: Not used for +QX_FLAG_ABSENT+ +answer+:: Not used for +QX_FLAG_ABSENT+ +answer_len+:: Not used for +QX_FLAG_ABSENT+ +leading+:: Not used for +QX_FLAG_ABSENT+ +value+:: Not used for +QX_FLAG_ABSENT+ +from+:: Not used for +QX_FLAG_ABSENT+ +to+:: Not used for +QX_FLAG_ABSENT+ +dfl+:: +180+ <- the default value that will be set for this variable +qxflags+:: +QX_FLAG_ABSENT+ -> this item isn't available in the device + +QX_FLAG_SETVAR+ -> this item is used to set the variable +info_type+ (i.e. +ups.delay.start+) + +QX_FLAG_RANGE+ -> this r/w variable has a settable range and its boundaries are listed in the +info_rw+ structure (i.e. +voltronic_r_ondelay+) +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +voltronic_process_setvar+ + This function will be called, in setvar, before the driver stores the value in the NUT var: here it's used to truncate the user-provided value to the nearest settable interval. Information not yet available in NUT ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If your UPS reports some data items that are not yet available as NUT variables and you need to process them, you can add them in +item_t+ data structure adding the +QX_FLAG_NONUT+ flag to its +qxflags+: the info will then be printed to the logs. So we know that the UPS reports actual input/output phase angles when queried for +QPD\r+: ---- > [QPD\r] < [(000 120\r] <- Input Phase Angle -- Output Phase Angle 012345678 0 ---- Here's the +item_t+ for input phase angle: ---- { "input_phase_angle", 0, NULL, "QPD\r", "", 9, '(', "", 1, 3, "%03.0f", QX_FLAG_STATIC | QX_FLAG_NONUT, NULL, NULL, voltronic_phase }, ---- [horizontal] +info_type+:: +input_phase_angle+ + This information will be used to print the value we got back from the UPS in the logs. +info_flags+:: +0+ +info_rw+:: +NULL+ +command+:: +QPD\r+ +answer+:: Filled at runtime +answer_len+:: +9+ +leading+:: +(+ +value+:: Filled at runtime +from+:: +1+ -> the index at which the info (i.e. +value+) starts +to+:: +3+ -> the index at which the info (i.e. +value+) ends +dfl+:: +%03.0f+ + If there's no +preprocess+ function, the format is used to print the value to the logs. Here instead it's used by the +preprocess+ function. +qxflags+:: +QX_FLAG_STATIC+ -> this item doesn't change + +QX_FLAG_NONUT+ -> this item doesn't have yet a NUT variable +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +voltronic_phase+ + This function will be called *after* the +command+ has been sent to the UPS so that we can parse the value we got back and check it. Here's the +item_t+ for output phase angle: ---- { "output_phase_angle", ST_FLAG_RW, voltronic_e_phase, "QPD\r", "", 9, '(', "", 5, 7, "%03.0f", QX_FLAG_SEMI_STATIC | QX_FLAG_ENUM | QX_FLAG_NONUT, NULL, NULL, voltronic_phase }, ---- [horizontal] +info_type+:: +output_phase_angle+ + This information will be used to print the value we got back from the UPS in the logs. +info_flags+:: +ST_FLAG_RW+ + This could also be +0+ (it's not really used by the driver), but it's set to +ST_FLAG_RW+ for cohesion with other rw vars -- also, if ever a NUT variable would become available for this item, it'll be easier to change this item and its +QX_FLAG_SETVAR+ counterpart to use it. +info_rw+:: +voltronic_e_phase+ + Enumerated list of available value (here: +000+, +120+, +240+ and +360+). Since +QX_FLAG_NONUT+ is set the driver will print those values to the logs, plus you could use it in the +preprocess+ function to check the value we got back from the UPS (as done here). +command+:: +QPD\r+ +answer+:: Filled at runtime +answer_len+:: +9+ +leading+:: +(+ +value+:: Filled at runtime +from+ :: +5+ -> the index at which the info (i.e. +value+) starts +to+:: +7+ -> the index at which the info (i.e. +value+) ends +dfl+:: +%03.0f+ + If there's no +preprocess+ function, the format is used to print the value to the logs. Here instead it's used by the +preprocess+ function. +qxflags+:: +QX_FLAG_SEMI_STATIC+ -> this item changes -- and will therefore be updated -- only when we send a command/setvar to the UPS + +QX_FLAG_ENUM+ -> this r/w variable is of the enumerated type and the enumerated values are listed in the +info_rw+ structure (i.e. +voltronic_e_phase+). + +QX_FLAG_NONUT+ -> this item doesn't have yet a NUT variable +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +voltronic_phase+ + This function will be called *after* the +command+ has been sent to the UPS so that we can parse the value we got back and check it. Here it's used also to store a var that will then be used to check the value in setvar's preprocess function. If you need also to change some values in the UPS you can add a +ups.conf+ var/flag in the subdriver's own +makevartable+ and then process it adding to its +qxflags+ both +QX_FLAG_NONUT+ and +QX_FLAG_SETVAR+: this item will be processed only once in +QX_WALKMODE_INIT+. The driver will check if the var/flag is defined in +ups.conf+: if so, it'll then call +setvar+ passing to this item the defined value, if any, and then it'll print the results in the logs. We know we can set output phase angle sending +PPDnnn\r+ to the UPS: ---- > [PPDn\r] n = (000, 120, 180 or 240) < [(ACK\r] 01234 0 ---- Here's the +item_t+ ---- { "output_phase_angle", 0, voltronic_e_phase, "PPD%03.0f\r", "", 5, '(', "", 1, 4, NULL, QX_FLAG_SETVAR | QX_FLAG_ENUM | QX_FLAG_NONUT, NULL, NULL, voltronic_phase_set }, ---- [horizontal] +info_type+:: +output_phase_angle+ + This information will be used to print the value we got back from the UPS in the logs and to retrieve the user-provided value in +ups.conf+. So, name it after the variable you created to use in +ups.conf+ in the subdriver's own +makevartable+. +info_flags+:: +0+ +info_rw+:: +voltronic_e_phase+ + Enumerated list of available values (here: +000+, +120+, +240+ and +360+). The value provided by the user will be automagically checked by the core nutdrv_qx driver against the enumerated values stored here. +command+:: +PPD%03.0f\r+ +answer+:: Filled at runtime +answer_len+:: +5+ <- either +(NAK\r+ or +(ACK\r+ +leading+:: +(+ +value+:: Filled at runtime +from+:: +1+ -> the index at which the info (i.e. +value+) starts +to+:: +3+ -> the index at which the info (i.e. +value+) ends +dfl+:: Not used for +QX_FLAG_SETVAR+ +qxflags+:: +QX_FLAG_SETVAR+ -> this item is used to set the variable +info_type+ (i.e. +output_phase_angle+) + +QX_FLAG_ENUM+ -> this r/w variable is of the enumerated type and the enumerated values are listed in the +info_rw+ structure (i.e. +voltronic_e_phase+). + +QX_FLAG_NONUT+ -> this item doesn't have yet a NUT variable +preprocess_command+:: +NULL+ +preprocess_answer+:: +NULL+ +preprocess+:: +voltronic_phase_set+ + This function will be called *before* the +command+ is sent to the UPS so that we can check user-provided value and fill +command+ with it and then fill +value+ (the second argument passed to the +preprocess+ function). Support functions ~~~~~~~~~~~~~~~~~ You are already given the following functions: *+int instcmd(const char *cmdname, const char *extradata)+*:: Execute an instant command. In detail: + -- - look up the given +cmdname+ in the qx2nut data structure (if not found, try to fallback to commonly known commands); - if +cmdname+ is found, call its preprocess function, passing to it +extradata+, if any, otherwise its +dfl+ value, if any; - send the command to the device and check the reply. -- + Return +STAT_INSTCMD_INVALID+ if the command is invalid, +STAT_INSTCMD_FAILED+ if it failed, +STAT_INSTCMD_HANDLED+ on success. *+int setvar(const char *varname, const char *val)+*:: Set r/w variable to a value after it has been checked against its +info_rw+ structure. Return +STAT_SET_HANDLED+ on success, otherwise +STAT_SET_UNKNOWN+. *+item_t *find_nut_info(const char *varname, const unsigned long flag, const unsigned long noflag)+*:: Find an item of +item_t+ type in +qx2nut+ data structure by its +info_type+, optionally filtered by its +qxflags+, and return it if found, otherwise return +NULL+. - +flag+: flags that have to be set in the item, i.e. if one of the flags is absent in the item it won't be returned. - +noflag+: flags that have to be absent in the item, i.e. if at least one of the flags is set in the item it won't be returned. *+int qx_process(item_t *item, const char *command)+*:: Send +command+ (a null-terminated byte string) or, if it is +NULL+, send the command stored in the +item+ to the UPS and process the reply, saving it in +item+'s +answer+. Return +-1+ on errors, +0+ on success. *+int ups_infoval_set(item_t *item)+*:: Process the value we got back from the UPS (set status bits and set the value of other parameters), calling the +item+-specific +preprocess+ function, if any, otherwise executing the standard preprocessing (including trimming if +QX_FLAG_TRIM+ is set). Return +-1+ on failure, +0+ for a status update and +1+ in all other cases. *+int qx_status(void)+*:: Return the currently processed status so that it can be checked with one of the +status_bit_t+ passed to the +STATUS()+ macro (see +nutdrv_qx.h+). *+void update_status(const char *nutvalue)+*:: If you need to edit the current status call this function with one of the NUT status (all but +OB+ are supported, simply set it as not +OL+); prefix them with an exclamation mark if you want to clear them from the status (e.g. +!OL+). Armac Subdriver ~~~~~~~~~~~~~~~ Armac subdriver is based on reverse engineering of Power Manager II software by Richcomm Technologies written in 2005 that is still (as of 2023) being distributed as a valid software for freshly sold UPS of various manufacturers. It uses commands as defined for Megatec protocol - but has a different communication mechanism. It uses two types of USB interrupt transfers: - 4 bytes to send a command (usually single transfer). - 6 byte chunk to read a reply (multiple transfers). Transfers are similar to those of the richcomm nut driver, but the transferred data is not short binary commands. Instead, serial text data is overlaid in these transfers in a way that creates a badly made USB serial interface. UPS reply looks similar to this: 0 1 2 3 4 5 HL 00 00 00 00 00 HL is a control byte. Its high nibble meaning is unknown. It changes between two possible values during transmission. Low nibble encodes number of bytes that have a meaning in the transaction. For example there are 5 bytes that might contain ASCII serial data, but only some might be valid, and other might be random, stale buffer data, etc. What follows is set of observed transmissions by various UPSes gathered from Github issues. Transfer dumps ^^^^^^^^^^^^^^ #### Vultech V2000 ---- 419.987514 [D4] armac command Q1 419.988307 [D4] armac cleanup ret i=0 ret=6 ctrl=c0 420.119402 [D4] read: ret 6 buf 81: 28 30 31 30 30 >(0100< 420.130383 [D4] read: ret 6 buf c1: 32 30 31 30 30 >20100< 420.141408 [D4] read: ret 6 buf 82: 33 33 31 30 30 >33100< 420.152201 [D4] read: ret 6 buf c3: 2e 30 20 30 30 >.0 00< 420.153237 [D4] read: ret 6 buf 82: 30 30 20 30 30 >00 00< 420.164299 [D4] read: ret 6 buf c1: 30 30 20 30 30 >00 00< 420.175293 [D4] read: ret 6 buf 82: 2e 30 20 30 30 >.0 00< 420.186358 [D4] read: ret 6 buf c3: 20 32 33 30 30 > 2300< 420.190322 [D4] read: ret 6 buf 83: 33 2e 30 30 30 >3.000< 420.194323 [D4] read: ret 6 buf c1: 20 2e 30 30 30 > .000< 420.205358 [D4] read: ret 6 buf 81: 30 2e 30 30 30 >0.000< 420.216318 [D4] read: ret 6 buf c2: 31 34 30 30 30 >14000< 420.227445 [D4] read: ret 6 buf 83: 20 34 39 30 30 > 4900< 420.228334 [D4] read: ret 6 buf c2: 2e 30 39 30 30 >.0900< 420.239461 [D4] read: ret 6 buf 81: 20 30 39 30 30 > 0900< 420.250411 [D4] read: ret 6 buf c2: 32 37 39 30 30 >27900< 420.261405 [D4] read: ret 6 buf 83: 2e 30 20 30 30 >.0 00< 420.265468 [D4] read: ret 6 buf c3: 32 30 2e 30 30 >20.00< 420.269465 [D4] read: ret 6 buf 81: 38 30 2e 30 30 >80.00< 420.280322 [D4] read: ret 6 buf c1: 20 30 2e 30 30 > 0.00< 420.291469 [D4] read: ret 6 buf 82: 30 30 2e 30 30 >00.00< 420.302465 [D4] read: ret 6 buf c3: 30 30 31 30 30 >00100< 420.303511 [D4] read: ret 6 buf 82: 00 30 31 30 30 > <- This has 0x00 and '0', will be read as "00" 420.303515 [D3] found null byte in status bits at 43 byte, assuming 0. 420.314425 [D4] read: ret 6 buf c1: 31 30 31 30 30 >10100< <- this has '1' 420.325432 [D4] read: ret 6 buf 81: 0d 30 31 30 30 >.0100< <- and this finishes with `\r`. 420.325442 [D3] armac command Q1 response read: '(233.0 000.0 233.0 014 49.0 27.0 20.8 00001001' ---- ---- 1.185164 [D4] armac command ID 1.316257 [D4] read: ret 6 buf c1: 23 31 00 30 30 >#1 1.327309 [D4] read: ret 6 buf 81: 20 31 00 30 30 > 1 1.338264 [D4] read: ret 6 buf c2: 20 20 00 30 30 > 1.349151 [D4] read: ret 6 buf 83: 20 20 20 30 30 > 00< 1.360277 [D4] read: ret 6 buf c2: 20 20 20 30 30 > 00< 1.371322 [D4] read: ret 6 buf 83: 20 20 20 30 30 > 00< 1.382265 [D4] read: ret 6 buf c3: 20 20 20 30 30 > 00< 1.393156 [D4] read: ret 6 buf 82: 20 20 20 30 30 > 00< 1.404324 [D4] read: ret 6 buf c3: 20 20 20 30 30 > 00< 1.415342 [D4] read: ret 6 buf 83: 20 20 20 30 30 > 00< 1.426292 [D4] read: ret 6 buf c2: 20 20 20 30 30 > 00< 1.437203 [D4] read: ret 6 buf 83: 20 20 20 30 30 > 00< 1.448328 [D4] read: ret 6 buf c3: 56 34 2e 30 30 >V4.00< 1.459293 [D4] read: ret 6 buf 82: 31 30 2e 30 30 >10.00< 1.470274 [D4] read: ret 6 buf c3: 20 20 20 30 30 > 00< 1.481208 [D4] read: ret 6 buf 82: 20 20 20 30 30 > 00< 1.492261 [D4] read: ret 6 buf c1: 0d 20 20 30 30 > 1.492270 [D3] armac command ID response read: '# V4.10 ' ---- ---- 4.749667 [D4] armac command F 4.876638 [D4] read: ret 6 buf 81: 23 31 00 30 30 >#1 4.887614 [D4] read: ret 6 buf c1: 32 31 00 30 30 >21 4.898644 [D4] read: ret 6 buf 82: 32 30 00 30 30 >20 4.909595 [D4] read: ret 6 buf c3: 2e 30 20 30 30 >.0 00< 4.920648 [D4] read: ret 6 buf 82: 30 30 20 30 30 >00 00< 4.931629 [D4] read: ret 6 buf c3: 35 20 32 30 30 >5 200< 4.942601 [D4] read: ret 6 buf 83: 34 2e 30 30 30 >4.000< 4.953666 [D4] read: ret 6 buf c2: 30 20 30 30 30 >0 000< 4.964535 [D4] read: ret 6 buf 83: 35 30 2e 30 30 >50.00< 4.975540 [D4] read: ret 6 buf c2: 30 0d 2e 30 30 >0 4.975546 [D3] armac command F response read: '#220.0 005 24.00 50.0' ---- #### Armac R/2000I/PSW ---- 112.966856 [D4] armac command Q1 112.968197 [D4] armac cleanup ret i=0 ret=6 ctrl=c0 <- Cleanups required. 113.091193 [D4] read: ret 6 buf 81: 28 30 0d 2e 30 >(0 <- Usually 1-3 bytes available in transfer. 113.103211 [D4] read: ret 6 buf c1: 30 30 0d 2e 30 >00 113.115180 [D4] read: ret 6 buf 82: 30 30 0d 2e 30 >00 113.117144 [D4] read: ret 6 buf c3: 2e 30 20 2e 30 >.0 .0< 113.120150 [D4] read: ret 6 buf 81: 31 30 20 2e 30 >10 .0< 113.132178 [D4] read: ret 6 buf c1: 34 30 20 2e 30 >40 .0< 113.144159 [D4] read: ret 6 buf 82: 30 2e 20 2e 30 >0. .0< 113.146149 [D4] read: ret 6 buf c3: 30 20 32 2e 30 >0 2.0< 113.149173 [D4] read: ret 6 buf 81: 32 20 32 2e 30 >2 2.0< 113.161167 [D4] read: ret 6 buf c1: 37 20 32 2e 30 >7 2.0< 113.173159 [D4] read: ret 6 buf 82: 2e 30 32 2e 30 >.02.0< 113.175157 [D4] read: ret 6 buf c3: 20 30 30 2e 30 > 00.0< 113.178158 [D4] read: ret 6 buf 81: 32 30 30 2e 30 >200.0< 113.190157 [D4] read: ret 6 buf c1: 20 30 30 2e 30 > 00.0< 113.202161 [D4] read: ret 6 buf 82: 30 30 30 2e 30 >000.0< 113.204154 [D4] read: ret 6 buf c3: 2e 30 20 2e 30 >.0 .0< 113.207150 [D4] read: ret 6 buf 81: 34 30 20 2e 30 >40 .0< 113.219174 [D4] read: ret 6 buf c1: 36 30 20 2e 30 >60 .0< 113.231165 [D4] read: ret 6 buf 82: 2e 38 20 2e 30 >.8 .0< 113.233157 [D4] read: ret 6 buf c3: 20 35 36 2e 30 > 56.0< 113.237149 [D4] read: ret 6 buf 81: 2e 35 36 2e 30 >.56.0< 113.249168 [D4] read: ret 6 buf c1: 30 35 36 2e 30 >056.0< 113.261155 [D4] read: ret 6 buf 83: 20 31 30 2e 30 > 10.0< 113.263151 [D4] read: ret 6 buf c2: 30 30 30 2e 30 >000.0< 113.266152 [D4] read: ret 6 buf 81: 31 30 30 2e 30 >100.0< 113.278161 [D4] read: ret 6 buf c1: 30 30 30 2e 30 >000.0< <- No Null bytes. 113.290155 [D4] read: ret 6 buf 82: 30 30 30 2e 30 >000.0< 113.292159 [D4] read: ret 6 buf c1: 0d 30 30 2e 30 > 113.292169 [D3] armac command Q1 response read: '(000.0 140.0 227.0 002 00.0 46.8 56.0 10001000' ---- Next query would return 0x80 control byte - 0 available bytes. This used to terminate transmission, but some UPS don't work like that. #### Armac R/3000I/PF1 ---- 0.083301 [D4] armac command Q1 0.164847 [D4] read: ret 6 buf a6: 28 32 34 31 2e >(241.< 0.184839 [D4] read: ret 6 buf 86: 35 20 30 30 30 >5 000< 0.205851 [D4] read: ret 6 buf a6: 2e 30 20 32 33 >.0 23< 0.226849 [D4] read: ret 6 buf 86: 30 2e 33 20 30 >0.3 0< 0.247859 [D4] read: ret 6 buf a6: 30 30 20 34 39 >00 49< 0.268862 [D4] read: ret 6 buf 86: 2e 39 20 32 2e >.9 2.< 0.289857 [D4] read: ret 6 buf a6: 32 35 20 34 38 >25 48< 0.309866 [D4] read: ret 6 buf 86: 2e 30 20 30 30 >.0 00< 0.330863 [D4] read: ret 6 buf a6: 30 30 30 30 30 >00000< 0.827913 [D4] read: ret 6 buf 83: 31 0d 30 30 30 >1 000< 0.827927 [D3] armac command Q1 response read: '(241.5 000.0 230.3 000 49.9 2.25 48.0 00000001' 0.827954 [D4] armac command ID 1.394985 [D4] read: ret 6 buf a5: 4e 41 4b 0d 30 >NAK < 1.395001 [D3] armac command ID response read: 'NAK' ---- This UPS sends higher nibble set to 6 often, which exceeds available bytes. Maybe means that more are available. Its serial-USB bridge is probably faster. We read 5 bytes in case 6 nibble is sent. End of transmission is marked by `\r`, no 0 nibble is sent. Notes ~~~~~ You must put the generated files into the +drivers/+ subdirectory, with the name of your subdriver preceded by +nutdrv_qx_+, and update +nutdrv_qx.c+ by adding the appropriate +#include+ line and by updating the definition of +subdriver_list+. Please, make sure to add your driver in that list in a smart way: if your device supports also the basic commands used by the other subdrivers to claim a device, add something that is unique (i.e. not supported by the other subdrivers) to your device in your claim function and then add it on top of the slightly supported ones in that list. You must also add the subdriver to +NUTDRV_QX_SUBDRIVERS+ list variable in the +drivers/Makefile.am+ and call "++autoreconf++" and/or "++./configure++" from the top level NUT directory. You can then recompile +nutdrv_qx+, and start experimenting with the new subdriver. For more details, have a look at the currently available subdrivers: - +nutdrv_qx_bestups.+{+c+,+h+} - +nutdrv_qx_innovart31.+{+c+,+h+} - +nutdrv_qx_masterguard.+{+c+,+h+} - +nutdrv_qx_mecer.+{+c+,+h+} - +nutdrv_qx_megatec.+{+c+,+h+} - +nutdrv_qx_megatec-old.+{+c+,+h+} - +nutdrv_qx_mustek.+{+c+,+h+} - +nutdrv_qx_q1.+{+c+,+h+} - +nutdrv_qx_q2.+{+c+,+h+} - +nutdrv_qx_q6.+{+c+,+h+} - +nutdrv_qx_voltronic.+{+c+,+h+} - +nutdrv_qx_voltronic-qs.+{+c+,+h+} - +nutdrv_qx_voltronic-qs-hex.+{+c+,+h+} - +nutdrv_qx_zinto.+{+c+,+h+} - +nutdrv_qx_ablerex.+{+c+,+h+} nut-2.8.3/docs/nut-qa.txt0000644000200500020050000001661614777767434012201 00000000000000NUT Quality Assurance --------------------- Recognizing the critical nature of NUT, the NUT Quality Assurance (NQA) effort has been established to improve NUT where necessary, and to maintain software quality as high as it should be. NQA is present in many aspects and areas of NUT. Documentation ~~~~~~~~~~~~~ The documentation toolchain uses link:https://asciidoc.org/[AsciiDoc] to output both HTML pages and manual pages (troff). This single point of control fills many gaps, suppresses many redundancies, and optimizes documentation management in general. - The NUT website and HTML documentation are tested for W3C XHTML 1.1 and CSS compliance. This can be counter verified by clicking the W3C XHTML 1.1 and CSS icons, at the bottom of each page. //////////////////////////////////////////////////////////////////////////////// - the manual pages conformance is tested with link:http://catb.org/~esr/doclifter/index.html[doclifter] (outdated) //////////////////////////////////////////////////////////////////////////////// - Documentation source files are spell checked, using link:http://aspell.net[Aspell], both interactively (using 'make spellcheck-interactive') and automatically in NUT CI farm runs (using 'make spellcheck'). NOTE: A NUT dictionary is also available (as `docs/nut.dict` in NUT sources), providing a glossary of terms related to power devices and management, as well as partial terms, technical jargon and author names. Source code ~~~~~~~~~~~ Use of standards ^^^^^^^^^^^^^^^^ NUT promotes and uses many standards, such as: - the variable names standard used in NUT, - the coding rules and best practices for developers, - the use of a software architecture limiting developments to the very minimum, - the use of standard Free and OpenSource Software components, like: * the USB library, * the Net SNMP project, * the Neon library, * the OpenSSL library (to be replaced by NSS, which is more license compliant with NUT and can be FIPS 140 certified), * the TCP Wrappers library. QA tools and metrics ^^^^^^^^^^^^^^^^^^^^ NUT's quality is constantly monitored using many tools, like: - a Revision Control System (link:https://github.com/networkupstools/nut[Git]) to track development and ease regression fixes. //////////////////////////////////////////////////////////////////////////////// Any modification on the NUT source trees are reported on the link:http://lists.alioth.debian.org/mailman/listinfo/nut-commits[NUT Commits] mailing list. //////////////////////////////////////////////////////////////////////////////// - OBSOLETE: link:http://buildbot.networkupstools.org/public/nut/[Buildbot] for older take on multi-platform builds, and the - new dedicated Jenkins incarnation of the NUT CI Farm with "legacy UI" for link:https://ci.networkupstools.org/job/nut/job/nut/job/master/[main branch] and link:https://ci.networkupstools.org/job/nut/job/nut/view/change-requests/[PRs], also accessible at the slower but slicker-looking Blue Ocean user interface for link:https://ci.networkupstools.org/blue/organizations/jenkins/nut%2Fnut/activity/[activity], link:https://ci.networkupstools.org/blue/organizations/jenkins/nut%2Fnut/branches/[branches] and link:https://ci.networkupstools.org/blue/organizations/jenkins/nut%2Fnut/pr/[PRs], are all used to automate the compile/test cycle, using numerous platforms, target distributions, C/C++ revisions, compiler toolkits and make program implementations. Any build failure is caught early, and fixed quickly. Also we get to see if incoming pull requests (as well as Git branch HEADs) do not have code (or recipe) that is instantly faulty and can not build on one of the platforms we track even with relaxed warnings. //////////////////////////////////////////////////////////////////////////////// reported through the link:http://lists.alioth.debian.org/mailman/listinfo/nut-commits[NUT Commits] mailing list, and fixed quickly. //////////////////////////////////////////////////////////////////////////////// - a project portal with trackers for bugs, feature request, patches and tasks, currently at GitHub - CodeQL (previously LGTM.COM) automatically checking C/C++ and Python code - Static code analysis: * link:https://scan.coverity.com/projects/networkupstools-nut[Coverity Scan overview of NUT] * status: image:https://scan.coverity.com/projects/8829/badge.svg[Coverity Scan Build Status] * cppcheck as part of NUT CI farm builds and reports NUT QA also relies on external tools and trackers, like: //////////////////////////////////////////////////////////////////////////////// FIXME (POST): - integrate static code analysis - consider splint, Frama-C, BLAST and Clang, and choose one. - only use coverity?! - point other distro BTS (use Launchpad as an aggregator?!) //////////////////////////////////////////////////////////////////////////////// - Clang - the Debian QA tools, available through the link:https://tracker.debian.org/pkg/nut[NUT Package Tracking System]: * Lintian general QA checks, * link:http://piuparts.debian.org/sid/source/n/nut.html[piuparts] automates the installation, upgrade and removal testing processes. - a runtime testing suite, which automates the inter-layer communication testing (driver -- upsd -- upsmon / clients), that is part of Ubuntu. link:https://git.launchpad.net/ubuntu/+source/nut/tree/debian/tests/test-nut.py[The NUT testing script] is available in the link:https://code.edge.launchpad.net/qa-regression-testing[Ubuntu QA Regression Testing suite]. + It installs NUT packages, configures it with the dummy-ups driver, changes a few data points and checks that these are well propagated with upsc. - similar approach is explored in NIT (NUT Integration Testing) suite, which is part of the codebase and automated with `make check-NIT`; it can also be added to default `make check` activities by running `configure --enable-check-NIT` * Note that developers updating components which directly impact NIT runs may benefit from `make check-NIT-devel` target, to rebuild the `upsd`, `dummy-ups`, `cppnit` and other programs used in the test as they iterate. - link:https://bugzilla.redhat.com/buglist.cgi?component=nut[Redhat / Fedora Bug tracker] - link:https://www.openhub.net/p/nut[Black Duck Open Hub] (formerly Ohloh.net) provides metrics on NUT source code base and activity. Runtime quality ^^^^^^^^^^^^^^^ - NUT provides many linkdoc:user-manual[security features,NUT_Security,docs/security.txt] to ensure a maximum runtime security level. - Packages use several link:http://wiki.debian.org/Hardening[Hardening methods] to protect NUT binaries. //////////////////////////////////////////////////////////////////////////////// FIXME (POST): - write a code conformance checker (nut-lint) - write a § on driver maintenance status - consider using [http://forge.novell.com/modules/xfmod/project/?opensuse OpenSUSE Build Service tools] - provide software metrics and evolution over the time * [http://www.flossmetrics.org/ FlossMetrics] * [http://en.wikipedia.org/wiki/Software_metric Wikipedia] * [http://cccc.sourceforge.net/ CCCC - C and C++ Code Counter] * [http://open.ncsu.edu/se/tutorials/metrics/ Metrics with Eclipse] - Code documentation, for the core architecture (client and drivers are already documented) * [http://doxygen.org/ Doxygen] * [http://naturaldocs.org/ NaturalDocs] //////////////////////////////////////////////////////////////////////////////// nut-2.8.3/docs/solaris-usb.txt0000644000200500020050000004140414777767434013230 00000000000000NUT USB setup in modern Solaris-like systems (OpenSolaris descendants) ====================================================================== Local-media device setup for use with NUT has some nuances with numerous descendants of the OpenSolaris project, including both the commercial Sun/Oracle Solaris 11 and illumos-based open source distributions such as OpenIndiana and OmniOS. Recommendations below may also apply to other related operating systems, possibly to older releases as well. Change the OS driver binding: use UGEN -------------------------------------- Like other hardware, USB devices are interfaced to the operating system by OS drivers, and often there are several suitable drivers with different capabilities. In Solaris and related systems, this mapping is detailed in the `/etc/driver_aliases` file and properly managed by dedicated tools. By default, USB devices can be captured by the generic USB HID driver, or none at all; however an "UGEN" driver can behave better with the libusb library used on Solaris. NOTE: Operations below would need running as `root` or elevating the privileges (via `pfexec`, `sudo`, etc.) Connect the power device using its USB port to your computer. Run `prtconf -v | less` to see the details of device connections, and search for its probable strings (vendor, model, serial number). Two examples follow: * In this example, no suitable driver was attached "out of the box": + ---- :; prtconf -v ... input (driver not attached) Hardware properties: name='driver-minor' type=int items=1 value=00000000 name='driver-major' type=int items=1 value=00000002 name='low-speed' type=boolean name='usb-product-name' type=string items=1 value='Eaton 9PX' name='usb-vendor-name' type=string items=1 value='EATON' name='usb-serialno' type=string items=1 value='G202E02032' name='usb-raw-cfg-descriptors' type=byte items=34 value=09.02.22.00.01.01.00.a0.0a.09.04.00.00.01.03.00.00.00.09.21.10.01.21.01.22.10.0d.07.05.81.03.08.00.14 name='usb-dev-descriptor' type=byte items=18 value=12.01.10.01.00.00.00.08.63.04.ff.ff.00.01.01.02.04.01 name='usb-release' type=int items=1 value=00000110 name='usb-num-configs' type=int items=1 value=00000001 name='usb-revision-id' type=int items=1 value=00000100 name='usb-product-id' type=int items=1 value=0000ffff name='usb-vendor-id' type=int items=1 value=00000463 name='compatible' type=string items=9 value='usb463,ffff.100' + 'usb463,ffff' + 'usbif463,class3.0.0' + 'usbif463,class3.0' + 'usbif463,class3' + 'usbif,class3.0.0' + 'usbif,class3.0' + 'usbif,class3' + 'usb,device' name='reg' type=int items=1 value=00000002 name='assigned-address' type=int items=1 value=00000003 ---- * In the following example, a "hid power" driver was attached, giving some usability to the device although not enough for NUT to interact well (at least, according to the helpful notes in the https://web.archive.org/web/20140126045707/http://barbz.com.au/blog/?p=407 blog entry): + ---- :; prtconf -v ... input, instance #1 Driver properties: name='pm-components' type=string items=3 dev=none value='NAME= hid1 Power' + '0=USB D3 State' + '3=USB D0 State' Hardware properties: name='driver-minor' type=int items=1 value=00000000 name='driver-major' type=int items=1 value=00000002 name='low-speed' type=boolean name='usb-product-name' type=string items=1 value='USB to Serial' name='usb-vendor-name' type=string items=1 value='INNO TECH' name='usb-serialno' type=string items=1 value='20100826' name='usb-raw-cfg-descriptors' type=byte items=34 value=09.02.22.00.01.01.03.80.32.09.04.00.00.01.03.00.00.04.09.21.00.01.00.01.22.1b.00.07.05.81.03.08.00.20 name='usb-dev-descriptor' type=byte items=18 value=12.01.10.01.00.00.00.08.65.06.61.51.02.00.01.02.03.01 name='usb-release' type=int items=1 value=00000110 name='usb-num-configs' type=int items=1 value=00000001 name='usb-revision-id' type=int items=1 value=00000002 name='usb-product-id' type=int items=1 value=00005161 name='usb-vendor-id' type=int items=1 value=00000665 name='compatible' type=string items=9 value='usb665,5161.2' + 'usb665,5161' + 'usbif665,class3.0.0' + 'usbif665,class3.0' + 'usbif665,class3' + 'usbif,class3.0.0' + 'usbif,class3.0' + 'usbif,class3' + 'usb,device' name='reg' type=int items=1 value=00000003 name='assigned-address' type=int items=1 value=00000005 Device Minor Nodes: dev=(108,2) dev_path=/pci@0,0/pci8086,7270@1d/hub@1/input@3:hid_0_1 spectype=chr type=minor dev_link=/dev/usb/hid0 ---- You can also check with `cfgadm` if the device is at least somehow visible (if not, there can be hardware issues in play). For example, if there is a physical link but no recognized driver was attached, the device would show up as "unconfigured": ---- :; cfgadm | grep usb- usb8/1 usb-input connected unconfigured ok ---- If you conclude that a change is needed, you would need to unload the existing copy of the "ugen" driver and set it up to handle the device patterns that you find in 'compatible' values from `prtconf`. For example, to monitor the devices from listings above, you would run: ---- :; rem_drv ugen :; add_drv -i '"usb463,ffff.100"' -m '* 0666 root sys' ugen ---- or ---- :; rem_drv ugen :; add_drv -i '"usb665,5161.2"' -m '* 0666 root sys' ugen ---- Note that there are many patterns in the 'compatible' line which allow for narrower or wider catchment. It is recommended to match with the narrowest fit, to avoid potential conflict with other devices from same vendor (especially if the declared identifiers are for a generic USB chipset). Also note that the `add_drv` definition above lists the POSIX access metadata for the device node files that would be generated when the device is plugged in and detected. In the examples above, it would be owned by `root:sys` but accessible for reads and writes (`0666`) to anyone on the system. On shared systems you may want to constrain this access to the account that the NUT driver would run as. After proper driver binding, `cfgadm` should expose the details: ---- # cfgadm -lv ... usb8/1 connected configured ok Mfg: EATON Product: Eaton 9PX NConfigs: 1 Config: 0 unavailable usb-input n /devices/pci@0,0/pci103c,1309@1d,2:1 ... ---- Usually the driver mapping should set up the "friendly" device nodes under `/dev/` tree as well (symlinks to real entries in `/devices/`) so for NUT drivers you would specify a `port=/dev/usb/463.ffff/0` for your new driver section in `ups.conf`. NOTE: As detailed in link:config-notes.txt[], the "natively USB" drivers (including `usbhid-ups` and `nutdrv_qx`) match the device by ID and/or strings it reports, and so effectively require but ignore the `port` option -- so it is commonly configured as `port=auto`. Drivers used for SHUT or serial protocols do need the device path. For some serial-to-USB converter chips however it was noted that while the device driver is attached, and the `/device/...` path is exposed in the `dmesg` output (saved to `/var/adm/messages`) the `/dev/...` symlinks are not created. In this case you can pass the low-level name of the character-device node as the "port" option, e.g.: ---- ./mge-shut -s 9px-ser -DDDDD -d2 -u root \ -x port=/devices/pci@0,0/pci103c,1309@1a,2/device@1:0 ---- libusb version and binary ------------------------- Until NUT release 2.7.4 the only option to build NUT drivers for USB connectivity was to use libusb-0.1 or a distribution's variant of it; the original Sun Solaris releases and later related systems provided their customized version for example (packaged originally as `SUNWlibusbugen`, `SUNWugen{,u}` and `SUNWusb{,s,u,vc}`). However, libusb-0.1 consuming programs had some stability issues reported when running with long-term connections to devices (such as an UPS), especially when using USB hubs and chips where hardware vendors had cut a few corners too many, which were addressed in a newer rewrite of the library as libusb-1.0. Subsequently just as at least the illumos-based distributions evolved to include the new library and certain patches for it, and the library itself matured, the NUT project also added an ability to build with libusb-1.0 either directly or using its 0.1-compat API (available since NUT 2.8.0 release). If your "standard" build of NUT has problems connecting to your USB UPS (libusb binary variant should be visible in driver debug messages), consider re-building NUT from source with the other option using the recent library build as available for your distribution. In this context, note the OpenIndiana libusb-1 package pull requests with code which was successfully used when developing this documentation: * https://github.com/OpenIndiana/oi-userland/pull/5382 * (TO CHECK) https://github.com/OpenIndiana/oi-userland/pull/5277 Binaries from builds made in OpenIndiana using the recipe from https://github.com/OpenIndiana/oi-userland/pull/5382[PR #5382] above were successfully directly used on contemporary OmniOS CE as well. Troubleshooting and reconnecting -------------------------------- So... your setup worked nicely, and then one day you see the console flooded with messages like the following: Broadcast Message from nut (???) on n54l Mon May 9 12:05:59... Communications with UPS innotech@localhost lost Broadcast Message from nut (???) on n54l Mon May 9 12:10:55... UPS innotech@localhost is unavailable Unfortunately, some devices "get stuck" on USB level (whether in the chips, in the OS driver layer, libusb or NUT driver) and their NUT drivers have to be restarted to regain monitoring, as opposed to intermittent losses of connectivity that software recovers from automatically. As in all systems, you should stop all programs using the connection, including NUT driver instances that might have been started beside the wrapping service (SMF). It may be possible to just start the new driver instance at this point, but if it still does not see the device -- you have to re-initialize the connection on the OS level. As a symptom, attempts to start the NUT driver with elevated debug verbosity would not even see the device details: ---- 0.000606 [D1] Saving PID 5187 into /var/run/nut/nutdrv_qx-innotech.pid 0.000727 [D1] upsdrv_initups... 0.012065 [D2] Checking device 1 of 2 (0665/5161) 0.012303 [D1] Failed to open device (0665/5161), skipping: Other error 0.012394 [D2] Checking device 2 of 2 (099A/610A) ... 0.020364 [D2] Trying to match device 0.020586 [D3] match_function_regex: matching a device... 0.020839 [D2] match_function_regex: failed match of VendorID: 99a 0.021061 [D2] Device does not match - skipping 0.021371 [D2] libusb1: No appropriate HID device found Network UPS Tools - Generic Q* USB/Serial driver 0.32 (2.8.0-20-g535395363) USB communication driver (libusb 1.0) 0.43 0.021720 libusb1: Could not open any HID devices: insufficient permissions on everything 0.021821 No supported devices found. Please check your device availability with 'lsusb' and make sure you have an up-to-date version of NUT. If this does not help, try running the driver with at least 'subdriver', 'vendorid' and 'productid' options specified. Please refer to the man page for details about these options (man 8 nutdrv_qx). Driver failed to start (exit status=1) Network UPS Tools - UPS driver controller 2.8.0-20-g535395363 [ May 9 03:10:01 Method "start" exited with status 1. ] ---- NOTE: Details of the service instance life-cycle for the NUT driver may be seen in its SMF log, e.g. by `less /var/svc/log/*innotech*log`, and to see in-vivo debugs as the service starts in production mode, use `debug_min = 3` in the `/etc/nut/ups.conf` file (in global context or in driver section). Recycle the USB connection ~~~~~~~~~~~~~~~~~~~~~~~~~~ In case of Solaris/illumos systems, first stop the respective nut-driver instance, e.g.: ---- :; svcadm disable -ts nut-driver:innotech :; ps -ef | grep -Ei 'nut|ups' ; svcs -p innotech root 10522 1 0 May 06 ? 0:00 /usr/sbin/upsmon root 16927 1 0 Feb 25 ? 1:20 /usr/lib/nut/bin/nutdrv_qx -a innotech nut 10257 1 0 May 06 ? 0:39 /usr/sbin/upsd root 16985 15379 0 11:27:36 pts/1 0:00 grep -Ei nut|ups nut 10524 10522 0 May 06 ? 0:25 /usr/sbin/upsmon STATE STIME FMRI offline 11:26:49 svc:/system/power/nut-driver:innotech # In the ps listing above, a driver daemon is seen that was started as # the root user beside the actual service. It has to be stopped too: :; kill -9 16927 ---- To unconfigure and disconnect the USB link on the OS level, you will need its attachment point identifier. If you don't know your system's current layout (it can change with device re-enumeration due to hot plugging and/or reboots), you can execute `cfgadm -lv`, look for the "Information" field resembling your UPS brand, and make note of its "Ap_Id". You can also query a single device to confirm a guess or your earlier records: ---- :; cfgadm -lv usb10/1 Ap_Id Receptacle Occupant Condition Information When Type Busy Phys_Id usb10/1 connected configured ok Mfg: INNO TECH Product: USB to Serial NConfigs: 1 Config: 0 : 20100826 unavailable usb-input n /devices/pci@0,0/pci103c,1609@13:1 ---- Disconnect the device; note that if something (typically a program with an open connection) still has a hold on the device, the system would fail to complete the command: ---- :; cfgadm -c disconnect usb10/1 Disconnect the device: /devices/pci@0,0/pci103c,1609@13:1 This operation will suspend activity on the USB device Continue (yes/no)? yes cfgadm: Hardware specific failure: Cannot issue devctl to ap_id: /devices/pci@0,0/pci103c,1609@13:1 ---- If that is the case, run `ps` per above and make sure all NUT driver daemons are stopped (the data server `upsd` and client upsmon should be inconsequential in this regard). Normally, the reconnection should work like this: ---- :; cfgadm -c unconfigure usb10/1 Unconfigure the device: /devices/pci@0,0/pci103c,1609@13:1 This operation will suspend activity on the USB device Continue (yes/no)? yes :; cfgadm -c disconnect usb10/1 Disconnect the device: /devices/pci@0,0/pci103c,1609@13:1 This operation will suspend activity on the USB device Continue (yes/no)? yes :; cfgadm -lv usb10/1 Ap_Id Receptacle Occupant Condition Information When Type Busy Phys_Id usb10/1 disconnected unconfigured ok unavailable unknown n /devices/pci@0,0/pci103c,1609@13:1 :; cfgadm -c configure usb10/1 cfgadm: Hardware specific failure: Cannot issue devctl to ap_id: /devices/pci@0,0/pci103c,1609@13:1 # Despite the error above, the device is seen now: :; cfgadm -lv usb10/1 Ap_Id Receptacle Occupant Condition Information When Type Busy Phys_Id usb10/1 connected configured ok Mfg: INNO TECH Product: USB to Serial NConfigs: 1 Config: 0 : 20100826 unavailable usb-input n /devices/pci@0,0/pci103c,1609@13:1 # ... and the driver can start: :; svcadm enable innotech ---- When everything gets recovered, you should see it: Broadcast Message from nut (???) on n54l Mon May 9 12:12:30... Communications with UPS innotech@localhost established and `upsc innotech@localhost` would tell you what it sees :) Regular auto-recovery via crontab ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Additional tricks that can help involve `crontab` for regular automated checks if the device got lost. One is just an attempt to "clear" the service if its earlier startup failed (repetitively) so SMF gave up: ---- * * * * * svcadm clear innotech 2>&1 | grep -v 'is not in a maintenance' ---- Another is more complicated and involves some custom scripting: ---- 0,5,10,15,20,25,30,35,40,45,50,55 * * * * MODE=optional /etc/nut/reset-ups-usb-solaris.sh ---- ...where the script would be a copy (customized to your device(s) and connection points!) of `reset-ups-usb-solaris.sh.sample` from either `scripts/Solaris/` directory in the NUT sources, or a copy which may be available in your system, e.g. under the `/usr/share/nut/solaris-init/` data directory. nut-2.8.3/docs/snmp-subdrivers.txt0000644000200500020050000002536414777767434014137 00000000000000How to make a new subdriver to support another SNMP device ---------------------------------------------------------- Overall concept ~~~~~~~~~~~~~~~ The SNMP protocol allow for a common way to interact with devices over the network. The NUT "snmp-ups" driver is a meta-driver that handles many SNMP devices, such as UPS and PDU. It consists of a core driver that handles most of the work of talking to the SNMP agent, and several sub-drivers to handle specific device manufacturers. Adding support for a new SNMP device is easy, because it requires only the creation of a new sub-driver. SNMP data Tree ~~~~~~~~~~~~~~ From the point of view of writing an SNMP subdriver, an SNMP device consists of a bunch of variables, called OIDs (for Object IDentifiers). Some OIDs (such as the current input voltage) are read-only, whereas others (such as the beeper enabled/disabled/muted status) can be read and written. OID are grouped together and arranged in a hierarchical tree shape, similar to directories in a file system. OID components are separated by ".", and can be expressed in numeric or textual form. For example: .iso.org.dod.internet.mgmt.mib-2.system.sysObjectID is equivalent to: .1.3.6.1.2.1.1.2.0 Here is an excerpt tree, showing only two OIDs, sysDescr and sysObjectID: .iso .org .dod .internet .mgmt .mib-2 .system .sysDescr.0 = STRING: Dell UPS Tower 1920W HV .sysObjectID.0 = OID: .iso.org.dod.internet.private.enterprises.674.10902.2 (...) .upsMIB .upsObjects .upsIdent .upsIdentModel = STRING: "Dell UPS Tower 1920W HV" (...) .private .enterprises .674 .10902 .2 .100 .1.0 = STRING: "Dell UPS Tower 1920W HV" (...) As you can see in the above example, the device name is exposed three times, through three different MIBs: - Generic MIB-II (RFC 1213): .iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0 = STRING: Dell UPS Tower 1920W HV .1.3.6.1.2.1.1.1.0 = STRING: Dell UPS Tower 1920W HV - UPS MIB (RFC 1628): .iso.org.dod.internet.mgmt.mib-2.upsMIB.upsObjects.upsIdent.upsIdentModel = STRING: "Dell UPS Tower 1920W HV" .1.3.6.1.2.1.33.1.1.2.0 = STRING: "Dell UPS Tower 1920W HV" - DELL SNMP UPS MIB: .iso.org.dod.internet.private.enterprises.674.10902.2.100.1.0 = STRING: "Dell UPS Tower 1920W HV" But only the two last can serve useful data for NUT. An highly interesting OID is *sysObjectID*: its value is an OID that refers to the main MIB of the device. In the above example, the device points us at the Dell UPS MIB. *sysObjectID*, also called "sysOID" is used by snmp-ups to find the right mapping structure. For more information on SNMP, refer to the link:http://en.wikipedia.org/wiki/Simple_Network_Management_Protocol[Wikipedia] article, or browse the Internet. To be able to convert values, NUT SNMP subdrivers need to provide: - manufacturer-specific sysOID, to determine which lookup structure applies to which devices, - a mapping of SNMP variables to NUT variables, - a mapping of SNMP values to NUT values. Moreover, subdrivers might have to provide additional functionality, such as custom implementations of specific instant commands (load.off, shutdown.restart), and conversions of manufacturer specific data formats. At the time of writing this document, snmp-ups doesn't provide such mechanisms (only formatting ones), but it is planned in a future release. Creating a subdriver ~~~~~~~~~~~~~~~~~~~~ In order to create a subdriver, you will need the following: - the "MIB definition file. This file has a ".mib" extension, and is generally available on the accompanying disc, or on the manufacturer website. It should either be placed in a system directory (/usr/share/mibs/ or equivalent), or pointed using *-M* option, - a network access to the device - OR information dumps. You can create an initial "stub" subdriver for your device by using the helper script *scripts/subdriver/gen-snmp-subdriver.sh*. Note that this only creates a "stub" which MUST be customized to be useful (see CUSTOMIZATION below). You have two options to run gen-snmp-subdriver.sh: mode 1: get SNMP data from a real agent ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This method requires to have a network access to the device, in order to automatically retrieve the needed information. You have to specify the following parameters: - *-H* host address: is the SNMP host IP address or name - *-c* community: is the SNMP v1 community name (default: public)" For example: $ gen-snmp-subdriver.sh -H W.X.Y.Z -c foobar -n .mib mode 2: get data from files ^^^^^^^^^^^^^^^^^^^^^^^^^^^ This method does not require direct access to the device, at least not for the one using gen-snmp-subdriver.sh. The following SNMP data need to be dumped first: - sysOID value: for example '.1.3.6.1.4.1.705.1' - a numeric SNMP walk (OIDs in dotted numeric format) of the tree pointed by sysOID. For example: snmpwalk -On -c foobar W.X.Y.Z .1.3.6.1.4.1.705.1 > snmpwalk-On.log - a textual SNMP walk (OIDs in string format) of the tree pointed by sysOID. For example: snmpwalk -Os -c foobar W.X.Y.Z .1.3.6.1.4.1.705.1 > snmpwalk-Os.log NOTE: If the OID are only partially resolved (i.e, there are still parts expressed in numeric form), then try using *-M* to point your .mib file. Then call the script using: $ gen-snmp-subdriver.sh -s For example: $ gen-snmp-subdriver.sh -s .1.3.6.1.4.1.705.1 snmpwalk-On.log snmpwalk-Os.log This script prompts you for a name for the subdriver if you don't provide it with *-n*. Use only letters and digits, and use natural capitalization such as "Camel" (not "camel" or "CAMEL", apart if it natural). The script may prompt you for additional information. Integrating the subdriver with snmp-ups ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Beside of the mandatory customization, there are a few things that you have to do, as mentioned at the end of the script: - edit drivers/snmp-ups.h and add #include ".h", where is the name of the header file, with the *.h* extension, - edit drivers/snmp-ups.c and bump DRIVER_VERSION by adding "0.01". - also add "&" to snmp-ups.c:mib2nut[] list, where is the lower case driver name - add "-mib.c" to snmp_ups_SOURCES in drivers/Makefile.am - add "-mib.h" to dist_noinst_HEADERS in drivers/Makefile.am - copy "-mib.c" and "-mib.h" to ../drivers/ - finally call the following, from the top level directory, to test compilation: $ autoreconf && configure && make You can already start experimenting with the new subdriver; but all data will be prefixed by "unmapped.". You will now have to customize it. CUSTOMIZATION ^^^^^^^^^^^^^ The initially generated subdriver code is only a stub (mainly a big C structure to be precise), and will not implement any useful functionality (in particular, it will be unable to shut down the UPS). In the beginning, it simply attempts to monitor some UPS variables. To make this driver useful, you must examine the NUT variables of the form "unmapped.*" in the hid_info_t data structure (commonly wrapped into `snmp_info_default()` macros for portability), and map them to actual NUT variables and instant commands. There are currently no step-by-step instructions for how to do this. Please look at the source files to see how the currently implemented SNMP subdrivers are written: - apc-mib.c/h - baytech-mib.c/h - bestpower-mib.c/h - compaq-mib.c/h - cyberpower-mib.c/h - eaton-*-mib.c/h - ietf-mib.c/h - mge-mib.c/h - netvision-mib.c/h - powerware-mib.c/h - raritan-pdu-mib.c - huawei-mib.c/h To help you, above each entry in -mib.c, there is a comment that displays the textual OID name. For example, the following entry: /* upsMIB.upsObjects.upsIdent.upsIdentModel = STRING: "Dell UPS Tower 1920W HV" */ snmp_info_default("ups.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.1.1.0", NULL, SU_FLAG_OK, NULL), Many times, only the first field will need to be modified, to map to an actual NUT variable name. Check the <> section first to find a name that matches the OID name (closest fit). If nothing matches, contact the upsdev list, and we'll figure it out. In the above example, the right NUT variable is obviously "device.model". The MIB definition file (.mib) also contains some description of these OIDs, along with the possible enumerated values. NOTE: To test existing data points (including those not yet translated to standard NUT mappings conforming to <>), you can use custom drivers built after you `./configure --with-unmapped-data-points`. Production driver builds must not include any non-standard names. //////////////////////////////////////////////////////////////////////////////// FIXME: Shutting down the UPS ~~~~~~~~~~~~~~~~~~~~~ It is desirable to support shutting down the UPS. Usually (for devices that follow the HID Power Device Class specification), this requires sending the UPS two commands. One for shutting down the UPS (with an 'offdelay') and one for restarting it (with an 'ondelay'), where offdelay < ondelay. The two NUT commands for which this is relevant, are 'shutdown.return' and 'shutdown.stayoff'. Since the one-to-one mapping above doesn't allow sending two HID commands to the UPS in response to sending one NUT command to the driver, this is handled by the driver. In order to make this work, you need to define the following four NUT values: ups.delay.start (variable, R/W) ups.delay.shutdown (variable, R/W) load.off.delay (command) load.on.delay (command) If the UPS supports it, the following variables can be used to show the countdown to start/shutdown: ups.timer.start (variable, R/O) ups.timer.shutdown (variable, R/O) The `load.on` and `load.off` commands will be defined implicitly by the driver (using a delay value of '0'). Define these commands yourself, if your UPS requires a different value to switch on/off the load without delay. Note that the driver expects the `load.off.delay` and `load.on.delay` to follow the HID Power Device Class specification, which means that the `load.on.delay` command should NOT switch on the load in the absence of mains power. If your UPS switches on the load regardless of the mains status, DO NOT define this command. You probably want to define the `shutdown.return` and/or `shutdown.stayoff` commands in that case. Commands defined in the subdriver will take precedence over the ones that are composed in the driver. When running the driver with the '-k' flag, it will first attempt to send a `shutdown.return` command and if that fails, will fallback to `shutdown.reboot`. //////////////////////////////////////////////////////////////////////////////// nut-2.8.3/docs/contact-closure.txt0000644000200500020050000001117114553676503014054 00000000000000Contact closure hardware information ------------------------------------ This is a collection of notes that apply to contact closure UPS hardware, specifically those monitored by the genericups driver. Definitions ~~~~~~~~~~~ "Contact closure" refers to a situation where one line is connected to another inside UPS hardware to indicate some sort of situation. These can be relays, or some other form of switching electronics. The generic idea is that you either have a signal on a line, or you don't. Think binary. Usually, the source for a signal is the host PC. It provides a high (logic level 1) from one of its outgoing lines, and the UPS returns it on one or more lines to communicate. The rest of the time, the UPS either lets it float or connects it to the ground to indicate a 0. Other equipment generates the high and low signals internally, and does not require cable power. These signals just appear on the right lines without any special configuration on the PC side. Bad levels ~~~~~~~~~~ Some evil cabling and UPS equipment uses the transmit or receive lines as their reference points for these signals. This is not sufficient to register as a high signal on many serial ports. If you have problems reading certain signals on your system, make sure your UPS isn't trying to do this. Signals ~~~~~~~ Unlike their smarter cousins, this kind of UPS can only give you very simple yes/no answers. Due to the limited number of serial port lines that can be used for this purpose, you typically get two pieces of data: 1. "On line" or "on battery" 2. "Battery OK" or "Low battery" That's it. Some equipment actually swaps the second one for a notification about whether the battery needs to be replaced, which makes life interesting for those users. Most hardware also supports an outgoing signal from the PC which means "shut down the load immediately". This is generally implemented in such a way that it only works when running on battery. Most hardware or cabling will ignore the shutdown signal when running on line power. New genericups types ~~~~~~~~~~~~~~~~~~~~ If none of the existing types in the genericups driver work completely, make a note of which ones (if any) manage to work partially. This can save you some work when creating support for your hardware. Use that information to create a list of where the signals from your UPS appear on the serial port at the PC end, and whether they are active high or active low. You also need to know what outgoing lines, if any, need to be raised in order to supply power to the contacts. This is known as cable power. Finally, if your UPS can shut down the load, that line must also be identified. There are only 4 incoming and 2 outgoing lines, so not many combinations are left. The other lines on a typical 9 pin port are transmit, receive, and the ground. Anything trying to do a high/low signal on those three is beyond the scope of the genericups driver. The only exception is an outgoing BREAK, which we already support. When editing the genericups.h, the values have the following meanings: Outgoing lines: - line_norm = what to set to make the line "normal" -- i.e. cable power - line_sd = what to set to make the UPS shut down the load Incoming lines: - line_ol = flag that appears for on line / on battery - val_ol = value of that flag when the UPS is on battery - line_bl = flag that appears for low battery / battery OK - val_bl = value of that flag when the battery is low - line_rb = flag that appears for battery health - val_rb = value of that flag when the battery needs a replacement - line_bypass = flag that appears for battery bypass / battery protection active - val_bypass = value of that flag when the battery is bypassed / missing This may seem a bit confusing to have two variables per value that we want to read, but here's how it works. If you set line_ol to TIOCM_RNG, then the value of TIOCM_RNG (0x080 on my box) will be anded with the value of the serial port whenever a poll occurs. If that flag exists, then the result of the and will be 0x80. If it does not exist, the result will be 0. So, if line_ol = foo, then val_ol can only be foo or 0. As a general case, if 'line_ol == val_ol', then the value you're reading is active high. Otherwise, it's active low. Check out the guts of upsdrv_updateinfo() to see how it really works. Custom definitions ~~~~~~~~~~~~~~~~~~ Late in the 1.3 cycle, a feature was merged which allows you to create custom monitoring settings without editing the model table. Just set upstype to something close, then use settings in ups.conf to adjust the rest. See the linkman:genericups[8] man page for more details. nut-2.8.3/docs/ChangeLog.txt0000644000200500020050000000113114777534445012577 00000000000000:titles.underlines: "__","==","--","~~","^^" Network UPS Tools Change Log ____________________________ :Author: NUT_project_community_contributors Introduction ============ The primary goal of the Network UPS Tools (NUT) project is to provide support for Power Devices, such as Uninterruptible Power Supplies, Power Distribution Units and Solar Controllers. [[Change_Log]] Very detailed Change Log ======================== This document intends to detail the change log for relatively recent work (roughly since the source code was tracked in Git). include::{builddir}../ChangeLog.adoc-parsed[] nut-2.8.3/docs/scheduling.txt0000644000200500020050000002650314777534446013110 00000000000000Advanced usage and scheduling notes =================================== upsmon can call out to a helper script or program when the device changes state. The example upsmon.conf has a full list of which state changes are available -- ONLINE, ONBATT, LOWBATT, and more. There are two options, that will be presented in details: - the simple approach: create your own helper, and manage all events and actions yourself, - the advanced approach: use the NUT provided helper, called 'upssched'. The simple approach, using your own script ------------------------------------------ How it works relative to upsmon ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Your command will be called with the full text of the message as one argument. For the default values, refer to the sample upsmon.conf file. The environment string NOTIFYTYPE will contain the type string of whatever caused this event to happen -- ONLINE, ONBATT, LOWBATT, ... Making this some sort of shell script might be a good idea, but the helper can be in any programming or scripting language. NOTE: Remember that your helper must be *executable*. If you are using a script, make sure the execution flags are set. For more information, refer to linkman:upsmon[8] and linkman:upsmon.conf[5] manual pages. Setting up everything ~~~~~~~~~~~~~~~~~~~~~ - Set EXEC flags on various things in linkman:upsmon.conf[5]: + NOTIFYFLAG ONBATT EXEC NOTIFYFLAG ONLINE EXEC + If you want other things like WALL or SYSLOG to happen, just add them: + NOTIFYFLAG ONBATT EXEC+WALL+SYSLOG + You get the idea. - Tell upsmon where your script is NOTIFYCMD /path/to/my/script - Make a simple script like this at that location: #! /bin/bash echo "$*" | sendmail -F"ups@mybox" bofh@pager.example.com - Restart upsmon, pull the plug, and see what happens. That approach is bare-bones, but you should get the text content of the alert in the body of the message, since upsmon passes the alert text (from NOTIFYMSG) as an argument. Using more advanced features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Your helper script will be run with a few environment variables set. - UPSNAME: the name of the system that generated the change. + This will be one of your identifiers from the MONITOR lines in upsmon.conf. - NOTIFYTYPE: this will be ONLINE, ONBATT, or whatever event took place which made upsmon call your script. You can use these to do different things based on which system has changed state. You could have it only send pages for an important system while totally ignoring a known trouble spot, for example. Suppressing notify storms ~~~~~~~~~~~~~~~~~~~~~~~~~ upsmon will call your script every time an event happens that has the EXEC flag set. This means a quick power failure that lasts mere seconds might generate a notification storm. To suppress this sort of annoyance, use upssched as your NOTIFYCMD program, and configure it to call your command after a timer has elapsed. The advanced approach, using upssched ------------------------------------- upssched is a helper for upsmon that will invoke commands for you at some interval relative to a UPS event. It can be used to send pages, mail out notices about things, or even shut down the box early. There will be examples scattered throughout. Change them to suit your pathnames, UPS locations, and so forth. How upssched works relative to upsmon ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When an event occurs, upsmon will call whatever you specify as a 'NOTIFYCMD' in your upsmon.conf, if you also enable the 'EXEC' in your 'NOTIFYFLAGS'. In this case, we want upsmon to call upssched as the notifier, since it will be doing all the work for us. So, in the upsmon.conf: NOTIFYCMD /usr/local/ups/sbin/upssched Then we want upsmon to actually _use_ it for the notify events, so again in the upsmon.conf we set the flags: NOTIFYFLAG ONLINE SYSLOG+EXEC NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC ... and so on. For the purposes of this document I will only use those three, but you can set the flags for any of the valid notify types. Setting up your upssched.conf ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Once upsmon has been configured with the NOTIFYCMD and EXEC flags, you're ready to deal with the upssched.conf details. In this file, you specify just what will happen when a given event occurs on a particular UPS. First you need to define the name of the script or program that will handle timers that trigger. This is your CMDSCRIPT, and needs to be above any AT defines. There's an example provided with the program, so we'll use that here: CMDSCRIPT /usr/local/ups/bin/upssched-cmd Then you have to define the variables PIPEFN and LOCKFN; the former sets the file name of the FIFO that will pass communications between processes to start and stop timers, while the latter sets the file name for a temporary file created by upssched in order to avoid a race condition under some circumstances. Please see the relevant comments in upssched.conf for additional information and advice about these variables. Now you can tell your CMDSCRIPT what to do when it is called by upsmon. The big picture ^^^^^^^^^^^^^^^ The design in a nutshell is: upsmon ---> calls upssched ---> calls your CMDSCRIPT Ultimately, the CMDSCRIPT does the actual useful work, whether that's initiating an early shutdown with 'upsmon -c fsd', sending a page by calling sendmail, or opening a subspace channel to V'ger. Establishing timers ^^^^^^^^^^^^^^^^^^^ Let's say that you want to receive a notification when any UPS has been running on battery for 30 seconds. Create a handler that starts a 30 second timer for an ONBATT condition. AT ONBATT * START-TIMER onbattwarn 30 This means "when any UPS (the *) goes on battery, start a timer called onbattwarn that will trigger in 30 seconds". We'll come back to the onbattwarn part in a moment. Right now we need to make sure that we don't trigger that timer if the UPS happens to come back before the time is up. In essence, if it goes back on line, we need to cancel it. So, let's tell upssched that. AT ONLINE * CANCEL-TIMER onbattwarn NOTE: Timers are pure in-memory mechanisms, specific to upssched. Conversely to other mechanisms found in NUT, such as upsmon->POWERDOWNFLAG, there is no file created on the filesystem. Executing commands immediately ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As an example, consider the scenario where a UPS goes onto battery power. However, the users are not informed until 30 seconds later -- using a timer as described above. Whilst this may let the *logged in* users know that the UPS is on battery power, it does not inform any users subsequently logging in. To enable this we could, at the same time, create a file which is read and displayed to any user trying to login whilst the UPS is on battery power. If the UPS comes back onto utility power within 30 seconds, then we can cancel the timer and remove the file, as described above. However, if the UPS comes back onto utility power say 5 minutes later then we do not want to use any timers but we still want to remove the file. To do this we could use: AT ONLINE * EXECUTE ups-back-on-power This means that when upsmon detects that the UPS is back on utility power it will signal upssched. Upssched will see the above command and simply pass 'ups-back-on-power' as an argument directly to CMDSCRIPT. This occurs immediately, there are no timers involved. Writing the command script handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OK, now that upssched knows how the timers are supposed to work, let's give it something to do when one actually triggers. The name of the example timer is onbattwarn, so that's the argument that will be passed into your CMDSCRIPT when it triggers. This means we need to do some shell script writing to deal with that input. -------------------------------------------------------------------------------- #! /bin/sh case $1 in onbattwarn) # Send a notification mail echo "The UPS has been on battery for awhile" \ | mail -s"UPS monitor" bofh@pager.example.com # Create a flag-file on the filesystem, for your own processing /usr/bin/touch /some/path/ups-on-battery ;; ups-back-on-power) # Delete the flag-file on the filesystem /bin/rm -f /some/path/ups-on-battery ;; *) logger -t upssched-cmd "Unrecognized command: $1" ;; esac -------------------------------------------------------------------------------- This is a very simple script example, but it shows how you can test for the presence of a given trigger. With multiple ATs creating various timer names, you will need to test for each possibility and handle it according to your desires. NOTE: You can invoke just about anything from inside the CMDSCRIPT. It doesn't need to be a shell script, either -- that's just an example. If you want to write a program that will parse argv[1] and deal with the possibilities, that will work too. Early Shutdowns ~~~~~~~~~~~~~~~ One thing that gets requested a lot is early shutdowns in upsmon. With upssched, you can now have this functionality. Just set a timer for some length of time at ONBATT which will invoke a shutdown command if it elapses. Just be sure to cancel this timer if you go back ONLINE before then. The best way to do this is to use the upsmon callback feature. You can make upsmon set the "forced shutdown" (FSD) flag on the upsd so your secondary systems shut down early too. Just do something like this in your CMDSCRIPT: /sbin/upsmon -c fsd NOTE: the path to `upsmon` must be provided. The default for an installation built from sources is `/usr/local/ups` (so `/usr/local/ups/sbin/upsmon`), while packaged installations will generally comply to link:http://refspecs.linuxfoundation.org/fhs.shtml[FHS -- Filesystem Hierarchy Standard] (so `/sbin/upsmon`). It's not a good idea to call your system's shutdown routine directly from the CMDSCRIPT, since there's no synchronization with the secondary systems hooked to the same UPS. FSD is the primary's way of saying "we're shutting down *now* like it or not, so you'd better get ready". Background ~~~~~~~~~~ This program was written primarily to fulfill the requests of users for the early shutdown scenario. The "outboard" design of the program (relative to upsmon) was intended to reduce the load on the average system. Most people don't have the requirement of shutting down after n seconds on battery, since the usual OB+LB testing is sufficient. This program was created separately so those people don't have to spend CPU time and RAM on something that will never be used in their environments. The design of the timer handler is also geared towards minimizing impact. It will come and go from the process list as necessary. When a new timer is started, a process will be forked to actually watch the clock and eventually start the CMDSCRIPT. When a timer triggers, it is removed from the queue. Canceling a timer will also remove it from the queue. When no timers are present in the queue, the background process exits. This means that you will only see upssched running when one of two things is happening: 1. There's a timer of some sort currently running 2. upsmon just called it, and you managed to catch the brief instance The final optimization handles the possibility of trying to cancel a timer when there's none running. If there's no process already running, there are no timers to cancel, and furthermore there is no need to start a clock-watcher. As a result, it skips that step and exits sooner. nut-2.8.3/docs/qa-guide.adoc0000644000200500020050000005736014777767434012560 00000000000000NUT Quality Assurance and Build Automation Guide ================================================ :Author: Jim_Klimov :Author Initials: JK :top_srcdir: .. :docinfo: docinfo-since-v2.8.3.xml WARNING: This is a Work In Progress document. ///////////////////// // Note on use of ":leveloffset: N" with absolute values below // // While docs recommend relative offsets or using them as parameters // to the include macro, this is a feature of asciidoctor - not asciidoc-py // (older implementation) that we rely on in most operating systems: // https://docs.asciidoctor.org/asciidoc/latest/directives/include-with-leveloffset/ // // So we resort to absolute offsets (as explicitly not recommended) in the // document itself, that `Title.level` handling in the older code base supports: // https://github.com/asciidoc-py/asciidoc-py/blob/main/asciidoc/asciidoc.py#L1775 ///////////////////// Abstract -------- The aim of this document is to describe the different ways we ensure and maintain the source code quality of Network UPS Tools, its portability to various platforms, and non-regression. Previous NUT releases may have included parts of this documentation in the developer guide or user manual. Most of this information can be applied to both automated testing environments and local development workflows. [[nut-qa]] include::nut-qa.txt[] Code and recipe analysis ------------------------ GNU Autotools distcheck ~~~~~~~~~~~~~~~~~~~~~~~ [[CI_distcheck]] The Network UPS Tools project code base is managed by the link:https://www.gnu.org/software/automake/manual/html_node/GNU-Build-System.html[GNU Build System] colloquially known as "The Autotools", which include `autoconf`, `automake` and many other components. Some of their important roles are to generate the portable shell `configure` script to detect build environment capabilities and other nuances, and to help actually build the project with `Makefile` recipes (supported by many implementations of the standard POSIX `make` tool) generated from the `Makefile.am` templates by the `automake` tool. Among the many standard recipes promulgated by the Autotools, `make dist` handles creation of archive files with a release (or other) snapshot of a software project, which "distribute" all the original or generated files needed to build and install that project on a minimally capable end-user system (should have a compiler, `make`, and dependency libraries/headers, but is not required to have autotools, manual page generation tools, etc.) The `make distcheck` goal allows to validate that the constructed archive is in fact sufficient for such a build (includes all required files), and also that the code structure and its recipes properly support out-of-tree builds (as used on multi-platform and cross-build environments) without contaminating the source code directory structure. NUT's root `Makefile.am` defines the `DISTCHECK_FLAGS` eventually passed to the `configure` script executed as part of `distcheck` validation, and the default set of the flags requires to build everything. This in turn constrains the set of systems where this validation can be performed to build environments that have all dependency projects installed, have the documentation generation tools, etc. in order to make sure that for all files that are compiled or otherwise processed by the build routine, we actually distribute the sources (implicitly as calculated by programs' listed sources, or via explicit `EXTRA_DIST` and similar statements) regardless of features enabled or not to be built in the original run. To avoid this constraint and allow the relevant `distcheck`-like validation to happen on environments without "everything and a kitchen sink" installed, further recipes are defined by NUT, such as: * `distcheck-light`: does not *require* the optional features to be built, but just allow them (using `--with-all=auto --with-ssl=auto --with-doc=auto` etc. flags); * `distcheck-light-man`: similar to the above, but require validation that manual pages can all be built (do not build PDF or HTML formats, though); * `distcheck-fake-man`: for formal validation on systems without documentation processing tools used by NUT recipes, populate the distribution archive with "PLACEHOLDER" contents of missing pre-generated manual pages (such an archive SHOULD NOT be delivered to end-users as a fully functional release), so the validation of *recipes* around pre-built documentation installation can be performed; * `distcheck-ci`: based on current build circumstances, dispatch to standard strict `distcheck` or to `distcheck-fake-man`. Other recipes based on this concept are also defined, including: * `distcheck-valgrind`: build whatever code we can, and do not waste time on documentation processing (`--with-all=auto --with-ssl=auto --with-doc=skip`), to run the NUT test programs (`make check` in the built environment) through the <> memory-checking tool. Valgrind checks ~~~~~~~~~~~~~~~ [[CI_VALGRIND]] NUT sources include a helper script and a suppression file which allow developers and CI alike to easily run built programs through the popular link:https://valgrind.org/[Valgrind] tool and check for memory leaks, un-closed file descriptors, and more. One use-case to cover the population of <> (and the common code they pull in from NUT libraries and drivers) is automated as the `make distcheck-valgrind` goal. :leveloffset: 3 include::{top_srcdir}/scripts/valgrind/README.adoc[] :leveloffset: 0 cppcheck ~~~~~~~~ [[CI_cppcheck]] The root `Makefile.am` includes a recipe to run a special build of NUT analyzed by the `cppcheck` tool (if detected by `configure` script) and produce a `cppcheck.xml` report for further tools to use, e.g. visualize it by the Jenkins Warnings plugin. Static analysis by compilers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [[CI_compiler_warnings]] As compilers like GCC and LLVM/CLANG evolve, so do their built-in code analyzers and warnings. In fact, this is a large part of the reasoning behind using a vast array of systems along with the compilers they have (many points of view on the same code discover different issues in it), and on another -- behind the certain complexity pattern in NUT's own code base, where code recommended by one compiler seems offensive to another (so stacks of `pragma` expressions are used to quiesce certain warnings around certain lines). Pre-set warning options ^^^^^^^^^^^^^^^^^^^^^^^ The options chosen into pre-sets that can be selected by `configure` script options are ones we use for different layers of CI tests. Values to note include: * `--enable-Werror(=yes/no)` -- make warnings fatal; * `--enable-warnings(=.../no)` -- enable certain warning presets: ** `gcc-hard`, `clang-hard`, `gcc-medium`, `clang-medium`, `gcc-minimal`, `clang-minimal`, `all` -- actual definitions that are compiler-dependent (the latter just adds `-Wall` which may be relatively portable); ** `hard`, `medium` or `minimal` -- if current compiler is detected as CLANG or GCC, apply corresponding setting from above (or `all` otherwise); ** `gcc` or `clang` -- apply the set of options (regardless of detected compiler) with default "difficulty" hard-coded in `configure` script, to tweak as our codebase becomes cleaner; ** `yes`/`auto` (also takes effect if `--enable-warnings` is requested without an `=ARG` part) -- if current compiler is detected as CLANG or GCC, apply corresponding setting with default "difficulty" from above (or `all` otherwise). Note that for backwards-compatibility reasons and to help filter out introduction of blatant errors, builds with compilers that claim GCC compatibility can enable a few easy warning presets by default. This can be avoided with an explicit argument to `--disable-warnings` (or `--enable-warnings=no`). All levels of warnings pre-sets for GCC in particular do not enforce the `-pedantic` mode for builds with C89/C90/ANSI standard revision (as guesstimated by `CFLAGS` content), because nowadays it complains more about the system and third-party library headers, than about NUT codebase quality (and "our offenses" are mostly something not worth fixing in this era, such as the use of `__func__` in debug commands). If there still are practical use-cases that require builds of NUT on pre-C99 compiler toolkits, pull requests are of course welcome -- but the maintainer team does not intend to spend much time on that. Hopefully this warnings pre-set mechanism is extensible enough if we would need to add more compilers and/or "difficulty levels" in the future. Finally, note that such pre-set warnings can be mixed with options passed through `CFLAGS` or `CXXFLAGS` values to your local `configure` run, but it is up to your compiler how it interprets the resulting mix. Shell script checks ~~~~~~~~~~~~~~~~~~~ [[CI_shellcheck]] The `make shellcheck` recipe finds files which the `file` tool determines to be POSIX or Bourne-Again shell scripts, and runs them through respective interpreter's (`bash` or system `/bin/sh`) test mode to validate the syntax works. Given that the `/bin/sh` implementation varies wildly on different systems (e.g. Korn shell, BASH, DASH and many others), this goal performed by CI on a large number of available platforms makes sure that the lowest-denominator syntax we use is actually understood everywhere. NOTE: At a later time additional tests, perhaps using the `shellcheck` tool, can be introduced into the stack. The `make shellcheck-nde` recipe calls `tests/nut-driver-enumerator-test.sh` to self-test the `scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in` against an array of `SHELL_PROGS` (e.g. a list of interpreters provided by specific CI agents), and make sure that shell-script based processing of `ups.conf` in various interpreters provides the exact spelling of expected results. Documentation spelling checks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [[CI_spellcheck]] NUT recipes rely on the `aspell` tool (with `aspell-en` dictionary, default but different on numerous platforms), and a custom maintained dictionary file (specified in `Makefile` variables as `NUT_SPELL_DICT` -- by default, it is `${top_srcdir}/docs/nut.dict`) for additional words either unique to NUT or quite common but absent in older standard dictionaries on some systems. Operations are done according to `LANG` and `LC_ALL` values, both specified in `Makefile` variables as `ASPELL_ENV_LANG`, by default `en.UTF-8`. The "nut-website" generation has similar recipes and relies on integration with those provided by the main NUT code base, but maintains its own custom dictionary for words only present in the website sources. The root `Makefile.am` includes recipes which allow developers and maintainers to check spelling of all documentation (and/or update the custom dictionary), while recipes in numerous subdirectories (where `README.adoc` or other specific documentation files exist) have similar goals to check just their files. The actual implementation of the goals is in `docs/Makefile.am`, and either calls the tool if it was detected by the `configure` script, or skips work. For each checked file, a `*-spellchecked` touch-file is created in respective `${builddir}`, so it is not re-checked until the source document, the custom dictionary, or the `Makefile` recipe is updated. The ecosystem of `Makefile.am` files includes the following useful recipes: * `spellcheck`: passively check that all used words are in some dictionary known to this system, or report errors for unknown words; * `spellcheck-interactive`: actively check the documents, and for unknown words start the interactive mode of `aspell` so you can either edit the source text (replace typos with suggested correct spelling), update the custom dictionary, or ignore the hit (to rephrase the paragraph later, etc.) + NOTE: This recipe can update the timestamp of the custom dictionary file, causing all documents to become fair game for re-checks of their spelling. * `spellcheck-sortdict`: make sure the custom dictionary file is sorted alphanumerically (helpful in case of manual edits) and the word count in the heading line is correct (helpful in case of manual edits or git branch merges). The root `Makefile.am` also provides some aids for maintainers: * `spellcheck-interactive-quick`: runs "passive" `spellcheck` in parallel `make` mode, and only if it errors out -- runs `spellcheck-interactive`; * `spellcheck-report-dict-usage`: prepares a `nut.dict.usage-report` file to validate that words used in a custom dictionary are actually present in any NUT documentation source file. Test automation --------------- :leveloffset: 2 [[CI_BUILD_SH]] include::{top_srcdir}/ci_build.adoc[] :leveloffset: 0 Test programs in NUT codebase ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [[CI_NUT_SELFTESTS]] FIXME: Write the chapter text. For now, investigate files in the `tests/` directory contents in NUT sources. ///////////////////////////// // end of CI_NUT_SELFTESTS // ///////////////////////////// :leveloffset: 2 [[NIT]] include::{top_srcdir}/tests/NIT/README.adoc[] :leveloffset: 0 Continuous Integration (NUT CI farm) technologies ------------------------------------------------- [[NUTCI_farm_technologies]] CI Farm configuration notes ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [[CI_Farm_Notes]] NOTE: This chapter contains information about NUT CI farm setup tricks that were applied at different times by the maintainer team to ensure regular builds and tests of the codebase. Whether these are used in daily production today or not, similar setup should be possible locally on developer and contributor machines. Multiple FOSS CI providers and technologies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ While there are many FOSS-friendly CI offerings, they are usually (and reasonably) focused on the OS market leaders -- offering recent releases of Linux, Windows and MacOS build agents, and sometimes a way to "bring your own device" to cover other systems. The NUT CI farm does benefit from those offerings as well, using GitHub Actions with CodeQL for Linux code quality inspection, AppVeyor CI for Windows, and CircleCI for MacOS, to name a few. But on the other hand, being a massively multi-platform effort (and aiming to support older boxes that are still alive even if their vendors and/or distro versions are not), a comprehensive NUT CI approach requires many machines running uncommon operating systems. This is where custom virtual machines help, and more so -- a core set of those hosted in the cloud and dedicated to the project, rather than only some resources intermittently contributed by community members which come and go. NOTE: Community-provided builders running on further systems are also welcome, and the option is of course supported, as managed by the link:https://github.com/networkupstools/jenkins-dynamatrix[Jenkins-Dynamatrix] effort which appeared due to such need, and runs the core NUT CI farm. We have also had historic experience with FOSS CI providers (and community members' machines) disappearing, so having NUT CI farm goals covered by multiple independent implementations is also a feature beyond having yet another set of digital eyes looking at our code quality (which is also a goal in itself). Jenkins is the way ~~~~~~~~~~~~~~~~~~ * https://stories.jenkins.io/user-story/jenkins-is-the-way-for-networkupstools/ * https://github.com/jenkins-infra/stories/blob/main/src/user-story/jenkins-is-the-way-for-networkupstools/index.yaml The jenkins-dynamatrix library ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [[Jenkins_Dynamatrix_Library]] FIXME: Write the chapter text. For now, see https://github.com/networkupstools/jenkins-dynamatrix sources (note the README and large comments at start of files may be obsolete, as of this writing -- documenting the initial ideas, but the implementation might differ from that over time). Jenkinsfile-dynamatrix cases in NUT sources ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [[Jenkins_Dynamatrix_Pipeline]] FIXME: Write the chapter text. For now, see the `Jenkinsfile-dynamatrix` in the NUT sources (maybe only git), e.g. https://github.com/networkupstools/nut/blob/master/Jenkinsfile-dynamatrix for the practical pipeline preparation and hand-off to library implementation. Jenkins CI ^^^^^^^^^^ [[NUT_CI_JENKINS]] Since mid-2021, the NUT CI farm is implemented by several virtual servers courteously provided originally by link:http://fosshost.org[Fosshost] and later by link:https://www.digitalocean.com/?refcode=d2fbf2b9e082&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge[DigitalOcean]. These run various operating systems as build agents, and a Jenkins instance to orchestrate the builds of NUT branches and pull requests on those agents. This is driven by `Jenkinsfile-dynamatrix` and a Jenkins Shared Library called link:https://github.com/networkupstools/jenkins-dynamatrix[jenkins-dynamatrix] which prepares a matrix of builds across as many operating systems, bitnesses/architectures, compilers, make programs and C/C++ revisions as it can -- based on the population of currently available build agents and capabilities which they expose as agent labels. This hopefully means that people interested in NUT can contribute to the build farm (and ensure NUT is and remains compatible with their platform) by running a Jenkins Swarm agent with certain labels, which would dial into https://ci.networkupstools.org/ controller. Please contact the NUT maintainer if you want to participate in this manner. The `Jenkinsfile-dynamatrix` recipe allows NUT CI farm to run different sets of build scenarios based on various conditions, such as the name of branch being built (or PR'ed against), changed files (e.g. C/C++ sources vs. just docs), and some build combinations may be not required to succeed. For example, the main development branch and pull requests against it must cleanly pass all specified builds and tests on various platforms with the default level of warnings specified in the `configure` script. These are balanced to not run too many build scenarios overall, but just a quick and sufficiently representative set. As another example, there is special handling for "fightwarn" pattern in the branch names to run many more builds with varying warning levels and more variants of intermediate language revisions, and so expose concerns deliberately missed by default warnings levels in "master" branch builds (the bar moves over time, as some classes of warnings become extinct from our codebase). Further special handling for branches named like `fightwarn.*89.*` regex enables more intensive warning levels for a GNU89 build specifically (which are otherwise disabled as noisy yet not useful for supported C99+ builds), and is intended to help develop fixes for support of this older language revision, if anyone would dare. Many of those unsuccessful build stages are precisely the focus of the "fightwarn" effort, and are currently marked as "may fail", so they end up as "UNSTABLE" (seen as orange bubbles in the Jenkins BlueOcean UI, or orange cells in the tabular list of stages in the legacy UI), rather than as "FAILURE" (red bubbles) for build scenarios that were not expected to fail and usually represent higher-priority problems that would block a PR. Developers whose PR builds (or attempts to fix warnings) did not succeed in some cell of such build matrix, can look at the individual logs of that cell. Beside indication from the compiler about the failure, the end of log text includes the command which was executed by CI worker and can be reproduced locally by the developer, e.g.: ---- 22:26:01 FINISHED with exit-code 2 cmd: ( 22:26:01 [ -x ./ci_build.sh ] || exit 22:26:01 22:26:01 eval BUILD_TYPE="default-alldrv" BUILD_WARNOPT="hard" \ BUILD_WARNFATAL="yes" MAKE="make" CC=gcc-10 CXX=g++-10 \ CPP=cpp-10 CFLAGS='-std=gnu99 -m64' CXXFLAGS='-std=gnu++11 -m64' \ LDFLAGS='-m64' ./ci_build.sh 22:26:01 ) ---- or for autotools-driven scenarios (which prep, configure, build and test in separate stages -- so for reproducing a failed build you should also look at its configuration step separately): ---- 22:28:18 FINISHED with exit-code 0 cmd: ( [ -x configure ] || exit; \ eval CC=clang-9 CXX=clang++-9 CPP=clang-cpp-9 CFLAGS='-std=c11 -m64' \ CXXFLAGS='-std=c++11 -m64' LDFLAGS='-m64' time ./configure ) ---- To re-run such scenario locally, you can copy the line from `eval` (but without the `eval` keyword itself) up to and including the executed script or tool, into your shell. Depending on locally available compilers, you may have to tweak the `CC`, `CXX` and `CPP` arguments; note that a `CPP` may be specified as `/path/to/CC -E` for GCC and CLANG based toolkits at least, if they lack a standalone preprocessor program (e.g. IntelCC). NOTE: While NUT recipes do not currently recognize a separate `CXXCPP`, it would follow similar semantics. Some further details about the NUT CI farm workers are available in linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] and linkdoc:qa-guide[Custom NUT CI farm build agents: LXC multi-arch containers,CI_LXC,docs/ci-farm-lxc-setup.txt] documentation. AppVeyor CI ~~~~~~~~~~~ [[NUT_CI_APPVEYOR]] Primarily used for building NUT for Windows on Windows instances provided in the cloud -- and so ensure non-regression as well as downloadable archives with binary installation prototype area, intended for enthusiastic testing (proper packaging to follow). NUT for Windows build-ability was re-introduced soon after NUT 2.8.0 release. This relies on a few prerequisite packages and a common NUT configuration, as coded in the `appveyor.yml` file in the NUT codebase. CircleCI ~~~~~~~~ [[NUT_CI_CIRCLE]] Primarily used for building NUT for MacOS on instances provided in the cloud, and so ensure non-regression across several Xcode releases. This relies on a few prerequisite packages and a common NUT configuration, as coded in the `.circleci/config.yml` file in the NUT codebase. Travis CI ~~~~~~~~~ [[NUT_CI_TRAVIS]] See the `.travis.yml` file in project sources for a detailed list of third party dependencies and a large matrix of `CFLAGS` and compiler versions last known to work or to not (yet) work on operating systems available to that CI solution. [NOTE] ====== The cloud Travis CI offering became effectively defunct for open-source projects in mid-2021, so the `.travis.yml` file in NUT codebase is not actively maintained. Local private deployments of Travis CI are possible, so if anybody does use it and has updated markup to share, they are welcome to post PRs. ====== The NUT project on GitHub had integration with Travis CI to test a large set of compiler and option combinations, covering different versions of gcc and clang, C standards, and requiring to pass builds at least in a mode without warnings (and checking the other cases where any warnings are made fatal). CodeQL ~~~~~~ [[NUT_CI_CODEQL]] (Earlier this role was performed by LGTM.com) Run GitHub Actions for static analysis of C, C++ and Python code and recipes, to produce suggestions based on common coding flaws and best-practice security patterns. Continuous Integration (NUT CI farm) build agent preparation ------------------------------------------------------------ [[NUTCI_farm_agents]] Custom NUT CI farm build agents: VMs on DigitalOcean ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [[CI_VM_DigitalOcean]] This section details Installation of VMs on Digital Ocean. :leveloffset: 1 include::ci-farm-do-setup.adoc[] :leveloffset: 0 Custom NUT CI farm build agents: LXC multi-arch containers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [[CI_LXC]] This section details configuration of LXC containers as build environments for NUT CI farm; this approach can also be used on developer workstations. :leveloffset: 1 include::ci-farm-lxc-setup.txt[] :leveloffset: 0 Prerequisites for building NUT on different OSes ------------------------------------------------ [[NUT_Config_Prereqs]] :leveloffset: 1 include::config-prereqs.txt[] :leveloffset: 0 nut-2.8.3/docs/common.xsl0000644000200500020050000001035714553676503012233 00000000000000 1 0 images/icons/ 0 0 #E0E0E0 images/icons/ margin-left: 0; margin-right: 10%; article toc,title book toc,title,figure,table,example,equation chapter toc,title part toc,title preface toc,title qandadiv toc qandaset toc reference toc,title sect1 toc sect2 toc sect3 toc sect4 toc sect5 toc section toc set toc,title article nop book nop nut-2.8.3/docs/ci-farm-lxc-setup.txt0000644000200500020050000010700014777767434014220 00000000000000Setting up the multi-arch Linux LXC container farm for NUT CI ------------------------------------------------------------- Due to some historical reasons including earlier personal experience, the Linux container setup implemented as described below was done with persistent LXC containers wrapped by LIBVIRT for management. There was no particular use-case for systems like Docker (and no firepower for a Kubernetes cluster) in that the build environment intended for testing non-regression against a certain release does not need to be regularly updated -- its purpose is to be stale and represent what users still running that system for whatever reason (e.g. embedded, IoT, corporate) have in their environments. Common preparations ~~~~~~~~~~~~~~~~~~~ * Example list of packages for Debian-based systems may include (not necessarily is limited to): + ---- :; apt install lxc lxcfs lxc-templates \ ipxe-qemu qemu-kvm qemu-system-common qemu-system-data \ qemu-system-sparc qemu-system-x86 qemu-user-static qemu-utils \ virt-manager virt-viewer virtinst ovmf \ libvirt-daemon-system-systemd libvirt-daemon-system \ libvirt-daemon-driver-lxc libvirt-daemon-driver-qemu \ libvirt-daemon-config-network libvirt-daemon-config-nwfilter \ libvirt-daemon libvirt-clients # TODO: Where to find virt-top - present in some but not all releases? # Can fetch sources from https://packages.debian.org/sid/virt-top and follow # https://www.linuxfordevices.com/tutorials/debian/build-packages-from-source # Be sure to use 1.0.x versions, since 1.1.x uses a "better-optimized API" # which is not implemented by libvirt/LXC backend. ---- + NOTE: This claims a footprint of over a gigabyte of new packages when unpacked and installed to a minimally prepared OS. Much of that would be the graphical environment dependencies required by several engines and tools. * Prepare LXC and LIBVIRT-LXC integration, including an "independent" (aka "masqueraded) bridge for NAT, following https://wiki.debian.org/LXC and https://wiki.debian.org/LXC/SimpleBridge ** For dnsmasq integration on the independent bridge (`lxcbr0` following the documentation examples), be sure to mention: *** `LXC_DHCP_CONFILE="/etc/lxc/dnsmasq.conf"` in `/etc/default/lxc-net` *** `dhcp-hostsfile=/etc/lxc/dnsmasq-hosts.conf` in/as the content of `/etc/lxc/dnsmasq.conf` *** `touch /etc/lxc/dnsmasq-hosts.conf` which would list simple `name,IP` pairs, one per line (so one per container) *** `systemctl restart lxc-net` to apply config (is this needed after setup of containers too, to apply new items before booting them?) *** For troubleshooting, see `/var/lib/misc/dnsmasq.lxcbr0.leases` (in some cases you may have to rename it away and reboot host to fix IP address delegation) * Install qemu with its `/usr/bin/qemu-*-static` and registration in `/var/lib/binfmt` * Prepare an LVM partition (or preferably some other tech like ZFS) as `/srv/libvirt` and create a `/srv/libvirt/rootfs` to hold the containers * Prepare `/home/abuild` on the host system (preferably in ZFS with lightweight compression like lz4 -- and optionally, only if the amount of available system RAM permits, with deduplication; otherwise avoid it); account user and group ID numbers are `399` as on the rest of the CI farm (historically, inherited from OBS workers) ** It may help to generate an ssh key without a passphrase for `abuild` that it would trust, to sub-login from CI agent sessions into the container. Then again, it may be not required if CI logs into the host by SSH using `authorized_keys` and an SSH Agent, and the inner ssh client would forward that auth channel to the original agent. + ------ abuild$ ssh-keygen # accept defaults abuild$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys abuild$ chmod 640 ~/.ssh/authorized_keys ------ * Edit the root (or whoever manages libvirt) `~/.profile` to default the virsh provider with: + ------ LIBVIRT_DEFAULT_URI=lxc:///system export LIBVIRT_DEFAULT_URI ------ * If host root filesystem is small, relocate the LXC download cache to the (larger) `/srv/libvirt` partition: + ------ :; mkdir -p /srv/libvirt/cache-lxc :; rm -rf /var/cache/lxc :; ln -sfr /srv/libvirt/cache-lxc /var/cache/lxc ------ ** Maybe similarly relocate shared `/home/abuild` to reduce strain on rootfs? Setup a container ~~~~~~~~~~~~~~~~~ Note that completeness of qemu CPU emulation varies, so not all distros can be installed, e.g. "s390x" failed for both debian10 and debian11 to set up the `openssh-server` package, or once even to run `/bin/true` (seems to have installed an older release though, to match the outdated emulation?) While the `lxc-create` tool does not really specify the error cause and deletes the directories after failure, it shows the pathname where it writes the log (also deleted). Before re-trying the container creation, this file can be watched with e.g. `tail -F /var/cache/lxc/.../debootstrap.log` [NOTE] ====== You can find the list of LXC "template" definitions on your system by looking at the contents of the `/usr/share/lxc/templates/` directory, e.g. a script named `lxc-debian` for the "debian" template. You can see further options for each "template" by invoking its help action, e.g.: ------ :; lxc-create -t debian -h ------ ====== Initial container installation (for various guest OSes) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Install containers like this: + ------ :; lxc-create -P /srv/libvirt/rootfs \ -n jenkins-debian11-mips64el -t debian -- \ -r bullseye -a mips64el ------ ** to specify a particular mirror (not everyone hosts everything -- so if you get something like `"E: Invalid Release file, no entry for main/binary-mips/Packages"` then see https://www.debian.org/mirror/list for details, and double-check the chosen site to verify if the distro version of choice is hosted with your arch of choice): + ------ :; MIRROR="http://ftp.br.debian.org/debian/" \ lxc-create -P /srv/libvirt/rootfs \ -n jenkins-debian10-mips -t debian -- \ -r buster -a mips ------ ** ...or for EOLed distros, use the Debian Archive server. *** Install the container with Debian Archive as the mirror like this: + ------ :; MIRROR="http://archive.debian.org/debian-archive/debian/" \ lxc-create -P /srv/libvirt/rootfs \ -n jenkins-debian8-s390x -t debian -- \ -r jessie -a s390x ------ *** Note you may have to add trust to their (now expired) GPG keys for packaging to verify signatures made at the time the key was valid, by un-symlinking (if appropriate) the debootstrap script such as `/usr/share/debootstrap/scripts/jessie`, commenting away the `keyring /usr/share/keyrings/debian-archive-keyring.gpg` line and setting `keyring /usr/share/keyrings/debian-archive-removed-keys.gpg` instead. You may further have to edit `/usr/share/debootstrap/functions` and/or `/usr/share/lxc/templates/lxc-debian` to honor that setting (the `releasekeyring` was hard-coded in version I had installed), e.g. in the latter file ensure such logic as below, and re-run the installation: + ------ ... # If debian-archive-keyring isn't installed, fetch GPG keys directly releasekeyring="`grep -E '^keyring ' "/usr/share/debootstrap/scripts/$release" | sed -e 's,^keyring ,,' -e 's,[ #].*$,,'`" 2>/dev/null if [ -z $releasekeyring ]; then releasekeyring=/usr/share/keyrings/debian-archive-keyring.gpg fi if [ ! -f $releasekeyring ]; then ... ------ ** ...Alternatively, other distributions can be used (as supported by your LXC scripts, typically in `/usr/share/debootstrap/scripts`), e.g. Ubuntu: + ------ :; lxc-create -P /srv/libvirt/rootfs \ -n jenkins-ubuntu1804-s390x -t ubuntu -- \ -r bionic -a s390x ------ ** For distributions with a different packaging mechanism from that on the LXC host system, you may need to install corresponding tools (e.g. `yum4`, `rpm` and `dnf` on Debian hosts for installing CentOS and related guests). You may also need to pepper with symlinks to taste (e.g. `yum => yum4`), or find a `pacman` build to install Arch Linux or derivative, etc. Otherwise, you risk seeing something like this: + ------ root@debian:~# lxc-create -P /srv/libvirt/rootfs \ -n jenkins-centos7-x86-64 -t centos -- \ -R 7 -a x86_64 Host CPE ID from /etc/os-release: 'yum' command is missing lxc-create: jenkins-centos7-x86-64: lxccontainer.c: create_run_template: 1616 Failed to create container from template lxc-create: jenkins-centos7-x86-64: tools/lxc_create.c: main: 319 Failed to create container jenkins-centos7-x86-64 ------ + Note also that with such "third-party" distributions you may face other issues; for example, the CentOS helper did not generate some fields in the `config` file that were needed for conversion into libvirt "domxml" (as found by trial and error, and comparison to other `config` files): + ------ lxc.uts.name = jenkins-centos7-x86-64 lxc.arch = x86_64 ------ + Also note the container/system naming without underscore in "x86_64" -- the deployed system discards the character when assigning its hostname. Using "amd64" is another reasonable choice here. + ** For Arch Linux you would need `pacman` tools on the host system, so see https://wiki.archlinux.org/title/Install_Arch_Linux_from_existing_Linux#Using_pacman_from_the_host_system for details. On a Debian/Ubuntu host, assumed ready for NUT builds per linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt], it would start like this: + ------ :; apt-get update :; apt-get install meson ninja-build cmake # Some dependencies for pacman itself; note there are several libcurl builds; # pick another if your system constraints require you to: :; apt-get install libarchive-dev libcurl4-nss-dev gpg libgpgme-dev :; git clone https://gitlab.archlinux.org/pacman/pacman.git :; cd pacman # Iterate something like this until all needed dependencies fall # into line (note libdir for your host architecture): :; rm -rf build; mkdir build && meson build --libdir=/usr/lib/x86_64-linux-gnu :; ninja -C build # Depending on your asciidoc version, it may require that `--asciidoc-opts` are # passed as equation to a vale (not space-separated from it). Then apply this: # diff --git a/doc/meson.build b/doc/meson.build # - '--asciidoc-opts', ' '.join(asciidoc_opts), # + '--asciidoc-opts='+' '.join(asciidoc_opts), # and re-run (meson and) ninja. # Finally when all succeeded: :; sudo ninja -C build install :; cd ------ + You will also need `pacstrap` and Debian `arch-install-scripts` package does not deliver it. It is however simply achieved: + ------ :; git clone https://github.com/archlinux/arch-install-scripts :; cd arch-install-scripts :; make && sudo make PREFIX=/usr install :; cd ------ + It will also want an `/etc/pacman.d/mirrorlist` which you can populate for your geographic location from https://archlinux.org/mirrorlist/ service, or just fetch them all (don't forget to uncomment some `Server =` lines): + ------ :; mkdir -p /etc/pacman.d/ :; curl https://archlinux.org/mirrorlist/all/ > /etc/pacman.d/mirrorlist ------ + And to reference it from your host `/etc/pacman.conf` by un-commenting the `[core]` section and `Include` instruction, as well as adding `[community]` and `[extra]` sections with same reference, e.g.: + ------ [core] ### SigLevel = Never SigLevel = PackageRequired Include = /etc/pacman.d/mirrorlist [extra] ### SigLevel = Never SigLevel = PackageRequired Include = /etc/pacman.d/mirrorlist [community] ### SigLevel = Never SigLevel = PackageRequired Include = /etc/pacman.d/mirrorlist ------ + And just then you can proceed with LXC: + ------ :; lxc-create -P /srv/libvirt/rootfs \ -n jenkins-archlinux-amd64 -t archlinux -- \ -a x86_64 -P openssh,sudo ------ + In my case, it had problems with GPG keyring missing (using one in host system, as well as the package cache outside the container, it seems) so I had to run `pacman-key --init; pacman-key --refresh-keys` on the host itself. Even so, `lxc-create` complained about updating some keyring entries and I had to go one by one picking key servers (serving different metadata) like this: + ------ :; pacman-key --keyserver keyserver.ubuntu.com --recv-key 6D1655C14CE1C13E ------ + In the worst case, see `SigLevel = Never` for `pacman.conf` to not check package integrity (seems too tied into thinking that host OS is Arch)... + It seems that pre-fetching the package databases with `pacman -Sy` on the host was also important. Initial container-related setup ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Add the "name,IP" line for this container to `/etc/lxc/dnsmasq-hosts.conf` on the host, e.g.: + ------ jenkins-debian11-mips,10.0.3.245 ------ + NOTE: Don't forget to eventually `systemctl restart lxc-net` to apply the new host reservation! * Convert a pure LXC container to be managed by LIBVIRT-LXC (and edit config markup on the fly -- e.g. fix the LXC `dir:/` URL schema): + ------ :; virsh -c lxc:///system domxml-from-native lxc-tools \ /srv/libvirt/rootfs/jenkins-debian11-armhf/config \ | sed -e 's,dir:/srv,/srv,' \ > /tmp/x && virsh define /tmp/x ------ + NOTE: You may want to tune the default generic 64MB RAM allocation, so your launched QEMU containers are not OOM-killed as they exceeded their memory `cgroup` limit. In practice they do not eat *that much* resident memory, just want to have it addressable by VMM, I guess (swap is not very used either), at least not until active builds start (and then it depends on compiler appetite and `make` program parallelism level you allow, e.g. by pre-exporting `MAXPARMAKES` environment variable for `ci_build.sh`, and on the number of Jenkins "executors" assigned to the build agent). + ** It may be needed to revert the generated "os/arch" to `x86_64` (and let QEMU handle the rest) in the `/tmp/x` file, and re-try the definition: + ------ :; virsh define /tmp/x ------ * Then execute `virsh edit jenkins-debian11-armhf` (and same for other containers) to bind-mount the common `/home/abuild` location, adding this tag to their "devices": + ------ ------ ** Note that generated XML might not conform to current LXC schema, so it fails validation during save; this can be bypassed with `i` when it asks. One such case was however with indeed invalid contents, the "dir:" schema removed by example above. Shepherd the herd ~~~~~~~~~~~~~~~~~ * Monitor deployed container rootfs'es with: + ------ :; du -ks /srv/libvirt/rootfs/* ------ + (should have non-trivial size for deployments without fatal infant errors) * Mass-edit/review libvirt configurations with: + ------ :; virsh list --all | awk '{print $2}' \ | grep jenkins | while read X ; do \ virsh edit --skip-validate $X ; done ------ ** ...or avoid `--skip-validate` when markup is initially good :) * Mass-define network interfaces: + ------ :; virsh list --all | awk '{print $2}' \ | grep jenkins | while read X ; do \ virsh dumpxml "$X" | grep "bridge='lxcbr0'" \ || virsh attach-interface --domain "$X" --config \ --type bridge --source lxcbr0 ; \ done ------ * Verify that unique MAC addresses were defined (e.g. `00:16:3e:00:00:01` tends to pop up often, while `52:54:00:xx:xx:xx` are assigned to other containers); edit the domain definitions to randomize, if needed: + ------ :; grep 'mac add' /etc/libvirt/lxc/*.xml | awk '{print $NF" "$1}' | sort ------ * Make sure at least one console device exists (end of file, under the network interface definition tags), e.g.: + ------ ------ * Populate with `abuild` account, as well as with the `bash` shell and `sudo` ability, reporting of assigned IP addresses on the console, and SSH server access complete with envvar passing from CI clients by virtue of `ssh -o SendEnv='*' container-name`: + ------ :; for ALTROOT in /srv/libvirt/rootfs/*/rootfs/ ; do \ echo "=== $ALTROOT :" >&2; \ grep eth0 "$ALTROOT/etc/issue" || ( printf '%s %s\n' \ '\S{NAME} \S{VERSION_ID} \n \l@\b ;' \ 'Current IP(s): \4{eth0} \4{eth1} \4{eth2} \4{eth3}' \ >> "$ALTROOT/etc/issue" ) ; \ grep eth0 "$ALTROOT/etc/issue.net" || ( printf '%s %s\n' \ '\S{NAME} \S{VERSION_ID} \n \l@\b ;' \ 'Current IP(s): \4{eth0} \4{eth1} \4{eth2} \4{eth3}' \ >> "$ALTROOT/etc/issue.net" ) ; \ groupadd -R "$ALTROOT" -g 399 abuild ; \ useradd -R "$ALTROOT" -u 399 -g abuild -M -N -s /bin/bash abuild \ || useradd -R "$ALTROOT" -u 399 -g 399 -M -N -s /bin/bash abuild \ || { if ! grep -w abuild "$ALTROOT/etc/passwd" ; then \ echo 'abuild:x:399:399::/home/abuild:/bin/bash' \ >> "$ALTROOT/etc/passwd" ; \ echo "USERADDed manually: passwd" >&2 ; \ fi ; \ if ! grep -w abuild "$ALTROOT/etc/shadow" ; then \ echo 'abuild:!:18889:0:99999:7:::' >> "$ALTROOT/etc/shadow" ; \ echo "USERADDed manually: shadow" >&2 ; \ fi ; \ } ; \ if [ -s "$ALTROOT/etc/ssh/sshd_config" ]; then \ grep 'AcceptEnv \*' "$ALTROOT/etc/ssh/sshd_config" || ( \ ( echo "" ; \ echo "# For CI: Allow passing any envvars:"; \ echo 'AcceptEnv *' ) \ >> "$ALTROOT/etc/ssh/sshd_config" \ ) ; \ fi ; \ done ------ + Note that for some reason, in some of those other-arch distros `useradd` fails to find the group anyway; then we have to "manually" add them. * Let the host know and resolve the names/IPs of containers you assigned: + ------ :; grep -v '#' /etc/lxc/dnsmasq-hosts.conf \ | while IFS=, read N I ; do \ getent hosts "$N" >&2 || echo "$I $N" ; \ done >> /etc/hosts ------ Further setup of the containers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ See linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] about dependency package installation for Debian-based Linux systems. It may be wise to not install e.g. documentation generation tools (or at least not the full set for HTML/PDF generation) in each environment, in order to conserve space and run-time stress. Still, if there are significant version outliers (such as using an older distribution due to vCPU requirements), it can be installed fully just to ensure non-regression -- e.g. that when adapting `Makefile` rule definitions or compiler arguments to modern toolkits, we do not lose the ability to build with older ones. For this, `chroot` from the host system can be used, e.g. to improve the interactive usability for a population of Debian(-compatible) containers (and to use its networking, while the operating environment in containers may be not yet configured or still struggling to access the Internet): ------ :; for ALTROOT in /srv/libvirt/rootfs/*/rootfs/ ; do \ echo "=== $ALTROOT :" ; \ chroot "$ALTROOT" apt-get install \ sudo bash vim mc p7zip p7zip-full pigz pbzip2 git \ ; done ------ Similarly for `yum`-managed systems (CentOS and relatives), though specific package names can differ, and additional package repositories may need to be enabled first (see linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] for more details such as recommended package names). Note that technically `(sudo) chroot ...` can also be used from the CI worker account on the host system to build in the prepared filesystems without the overhead of running containers as complete operating environments with any standard services and several copies of Jenkins `agent.jar` in them. Also note that externally-driven set-up of some packages, including the `ca-certificates` and the JDK/JRE, require that the `/proc` filesystem is usable in the chroot environment. This can be achieved with e.g.: ------ :; for ALTROOT in /srv/libvirt/rootfs/*/rootfs/ ; do \ for D in proc ; do \ echo "=== $ALTROOT/$D :" ; \ mkdir -p "$ALTROOT/$D" ; \ mount -o bind,rw "/$D" "$ALTROOT/$D" ; \ done ; \ done ------ TODO: Test and document a working NAT and firewall setup for this, to allow SSH access to the containers via dedicated TCP ports exposed on the host. Arch Linux containers ^^^^^^^^^^^^^^^^^^^^^ Arch Linux containers prepared by procedure above include only a minimal footprint, and if you missed the `-P pkg,list` argument, they can lack even an SSH server. Suggestions below assume this path to container: ------ :; ALTROOT=/srv/libvirt/rootfs/jenkins-archlinux-amd64/rootfs/ ------ Let `pacman` know current package database: ------ :; grep 8.8.8.8 $ALTROOT/etc/resolv.conf || (echo 'nameserver 8.8.8.8' > $ALTROOT/etc/resolv.conf) :; chroot $ALTROOT pacman -Syu :; chroot $ALTROOT pacman -S openssh sudo :; chroot $ALTROOT systemctl enable sshd :; chroot $ALTROOT systemctl start sshd ------ This may require that you perform bind-mounts above, as well as "passthrough" the `/var/cache/pacman/pkg` from host to guest environment (in `virsh edit`, and bind-mount for `chroot` like for `/proc` et al above). It is possible that `virsh console` would serve you better than `chroot`. Note you may have to first `chroot` to set the `root` password anyhow. Troubleshooting ~~~~~~~~~~~~~~~ * Q: Container won't start, its `virsh console` says something like: + ------ Failed to create symlink /sys/fs/cgroup/net_cls: Operation not permitted ------ + A: According to https://bugzilla.redhat.com/show_bug.cgi?id=1770763 (skip to the end for summary) this can happen when a newer Linux host system with `cgroupsv2` capabilities runs an older guest distro which only knows about `cgroupsv1`, such as when hosting a CentOS 7 container on a Debian 11 server. + ** One workaround is to ensure that the guest `systemd` does not try to "join" host facilities, by setting an explicit empty list for that: + ------ :; echo 'JoinControllers=' >> "$ALTROOT/etc/systemd/system.conf" ------ + ** Another approach is to upgrade `systemd` related packages in the guest container. This may require additional "backport" repositories or similar means, possibly maintained not by distribution itself but by other community members, and arguably would logically compromise the idea of non-regression builds in the old environment "as is". * Q: Server was set up with ZFS as recommended, and lots of I/O hit the disk even when application writes are negligible + A: This was seen on some servers and generally derives from data layout and how ZFS maintains the tree structure of blocks. A small application write (such as a new log line) means a new empty data block allocation, an old block release, and bubble up through the whole metadata tree to complete the transaction (grouped as TXG to flush to disk). + ** One solution is to use discardable build workspaces in RAM-backed storage like `/dev/shm` (`tmpfs`) on Linux, or `/tmp` (`swap`) on illumos hosting systems, and only use persistent storage for the home directory with `.ccache` and `.gitcache-dynamatrix` directories. ** Another solution is to reduce the frequency of TXG sync from modern default of 5 sec to conservative 30-60 sec. Check how to set the `zfs_txg_timeout` on your platform. Connecting Jenkins to the containers ------------------------------------ To properly cooperate with the https://github.com/networkupstools/jenkins-dynamatrix[jenkins-dynamatrix] project driving regular NUT CI builds, each build environment should be exposed as an individual agent with labels describing its capabilities. Agent Labels ~~~~~~~~~~~~ With the `jenkins-dynamatrix`, agent labels are used to calculate a large "slow build" matrix to cover numerous scenarios for what can be tested with the current population of the CI farm, across operating systems, `make`, shell and compiler implementations and versions, and C/C++ language revisions, to name a few common "axes" involved. Labels for QEMU ^^^^^^^^^^^^^^^ Emulated-CPU container builds are CPU-intensive, so for them we define as few capabilities as possible: here CI is more interested in checking how binaries behave on those CPUs, *not* in checking the quality of recipes (distcheck, Make implementations, etc.), shell scripts or documentation, which is more efficient to test on native platforms. Still, we are interested in results from different compiler suites, so specify at least one version of each. NOTE: Currently the NUT `Jenkinsfile-dynamatrix` only looks at various `COMPILER` variants for `qemu-nut-builder` use-cases, disregarding the versions and just using one that the environment defaults to. The reduced set of labels for QEMU workers looks like: ------ qemu-nut-builder qemu-nut-builder:alldrv NUT_BUILD_CAPS=drivers:all NUT_BUILD_CAPS=cppunit OS_FAMILY=linux OS_DISTRO=debian11 GCCVER=10 CLANGVER=11 COMPILER=GCC COMPILER=CLANG ARCH64=ppc64le ARCH_BITS=64 ------ Labels for native builds ^^^^^^^^^^^^^^^^^^^^^^^^ For contrast, a "real" build agent's set of labels, depending on presence or known lack of some capabilities, looks something like this: ------ doc-builder nut-builder nut-builder:alldrv NUT_BUILD_CAPS=docs:man NUT_BUILD_CAPS=docs:all NUT_BUILD_CAPS=drivers:all NUT_BUILD_CAPS=cppunit=no OS_FAMILY=bsd OS_DISTRO=freebsd12 GCCVER=10 CLANGVER=10 COMPILER=GCC COMPILER=CLANG ARCH64=amd64 ARCH_BITS=64 SHELL_PROGS=sh SHELL_PROGS=dash SHELL_PROGS=zsh SHELL_PROGS=bash SHELL_PROGS=csh SHELL_PROGS=tcsh SHELL_PROGS=busybox MAKE=make MAKE=gmake PYTHON=python2.7 PYTHON=python3.8 ------ Generic agent attributes ~~~~~~~~~~~~~~~~~~~~~~~~ * Name: e.g. `ci-debian-altroot--jenkins-debian10-arm64` (note the pattern for "Conflicts With" detailed below) * Remote root directory: preferably unique per agent, to avoid surprises; e.g.: `/home/abuild/jenkins-nut-altroots/jenkins-debian10-armel` ** Note it may help that the system home directory itself is shared between co-located containers, so that the `.ccache` or `.gitcache-dynamatrix` are available to all builders with identical contents ** If RAM permits, the Jenkins Agent working directory may be placed in a temporary filesystem not backed by disk (e.g. `/dev/shm` on modern Linux distributions); roughly estimate 300Mb per executor for NUT builds. * Usage: "Only build jobs with label expressions matching this node" * Node properties / Environment variables: ** `PATH+LOCAL` => `/usr/lib/ccache` Where to run agent.jar ~~~~~~~~~~~~~~~~~~~~~~ Depending on circumstances of the container, there are several options available to the NUT CI farm: * Java can run in the container, efficiently (native CPU, different distro) => the container may be exposed as a standalone host for direct SSH access (usually by NAT, exposing SSH on a dedicated port of the host; or by first connecting the Jenkins controller with the host as an SSH Build Agent, and then calling SSH to the container as a prefix for running the agent; or by using Jenkins Swarm agents), so ultimately the build `agent.jar` JVM would run in the container. Filesystem for the `abuild` account may be or not be shared with the host. * Java can not run in the container (crashes on emulated CPU, or is too old in the agent container's distro -- currently Jenkins requires JRE 17+, but eventually will require 21+) => the agent would run on the host, and then the host would `ssh` or `chroot` (networking not required, but bind-mount of `/home/abuild` and maybe other paths from host would be needed) called for executing `sh` steps in the container environment. Either way, home directory of the `abuild` account is maintained on the host and shared with the guest environment, user and group IDs should match. * Java is inefficient in the container (operations like un-stashing the source succeed but take minutes instead of seconds) => either of the above NOTE: As time moves on and Jenkins core and its plugins get updated, support for some older run-time features of the build agents can get removed (e.g. older Java releases, older Git tooling). While there are projects like Temurin that provide Java builds for older systems, at some point a switch to "Jenkins agent on new host going into older build container" approach can become unavoidable. One clue to look at in build logs is failure messages like: ---- Caused by: java.lang.UnsupportedClassVersionError: hudson/slaves/SlaveComputer$SlaveVersion has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0 ---- Using Jenkins SSH Build Agents ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is a typical use-case for tightly integrated build farms under common management, where the Jenkins controller can log by SSH into systems which act as its build agents. It injects and launches the `agent.jar` to execute child processes for the builds, and maintains a tunnel to communicate. Methods below involving SSH assume that you have configured a password-less key authentication from the host machine to the `abuild` account in each guest build environment container. This can be an `ssh-keygen` result posted into `authorized_keys`, or a trusted key passed by a chain of ssh agents from a Jenkins Credential for connection to the container-hoster into the container. The private SSH key involved may be secured by a pass-phrase, as long as your Jenkins Credential storage knows it too. Note that for the approaches explored below, the containers are not directly exposed for log-in from any external network. * For passing the agent through an SSH connection from host to container, so that the `agent.jar` runs inside the container environment, configure: ** Launch method: "Agents via SSH" ** Host, Credentials, Port: as suitable for accessing the container-hoster + NOTE: The container-hoster should have accessed the guest container from the account used for intermediate access, e.g. `abuild`, so that its `.ssh/known_hosts` file would trust the SSH server on the container. ** Prefix Start Agent Command: content depends on the container name, but generally looks like the example below to report some info about the final target platform (and make sure `java` is usable) in the agent's log. Note that it ends with un-closed quote and a space char: + ------ ssh jenkins-debian10-amd64 '( java -version & uname -a ; getconf LONG_BIT; getconf WORD_BIT; wait ) && ------ ** Suffix Start Agent Command: a single quote to close the text opened above: ------ ' ------ * The other option is to run the `agent.jar` on the host, for all the network and filesystem magic the agent does, and only execute shell steps in the container. The solution relies on overridden `sh` step implementation in the `jenkins-dynamatrix` shared library that uses a magic `CI_WRAP_SH` environment variable to execute a pipe into the container. Such pipes can be `ssh` or `chroot` with appropriate host setup described above. + NOTE: In case of ssh piping, remember that the container's `/etc/ssh/sshd_config` should `AcceptEnv *` and the SSH server should be restarted after such configuration change. ** Launch method: "Agents via SSH" ** Host, Credentials, Port: as suitable for accessing the container-hoster ** Prefix Start Agent Command: content depends on the container name, but generally looks like the example below to report some info about the final target platform (and make sure it is accessible) in the agent's log. Note that it ends with a space char, and that the command here should not normally print anything into stderr/stdout (this tends to confuse the Jenkins Remoting protocol): + ------ echo PING > /dev/tcp/jenkins-debian11-ppc64el/22 && ------ ** Suffix Start Agent Command: empty * Node properties / Environment variables: ** `CI_WRAP_SH` => + ------ ssh -o SendEnv='*' "jenkins-debian11-ppc64el" /bin/sh -xe ------ Using Jenkins Swarm Agents ^^^^^^^^^^^^^^^^^^^^^^^^^^ This approach allows remote systems to participate in the NUT CI farm by dialing in and so defining an agent. A single contributing system may be running a number of containers or virtual machines set up following the instructions above, and each of those would be a separate build agent. Such systems should be "dedicated" to contribution in the sense that they should be up and connected for days, and sometimes tasks would land. Configuration files maintained on the Swarm Agent system dictate which labels or how many executors it would expose, etc. Credentials to access the NUT CI farm Jenkins controller to register as an agent should be arranged with the farm maintainers, and currently involve a GitHub account with Jenkins role assignment for such access, and a token for authentication. The https://github.com/networkupstools/jenkins-swarm-nutci[jenkins-swarm-nutci] repository contains example code from such setup with a back-up server experiment for the NUT CI farm, including auto-start method scripts for Linux systemd and upstart, illumos SMF, and OpenBSD rcctl. Sequentializing the stress ~~~~~~~~~~~~~~~~~~~~~~~~~~ Running one agent at a time ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Another aspect of farm management is that emulation is a slow and intensive operation, so we can not run all agents and execute builds at the same time. The current solution relies on https://github.com/jimklimov/conflict-aware-ondemand-retention-strategy-plugin to allow co-located build agents to "conflict" with each other -- when one picks up a job from the queue, it blocks neighbors from starting; when it is done, another may start. Containers can be configured with "Availability => On demand", with shorter cycle to switch over faster (the core code sleeps a minute between attempts): * In demand delay: `0`; * Idle delay: `0` (Jenkins may change it to `1`); * Conflicts with: `^ci-debian-altroot--.*$` assuming that is the pattern for agent definitions in Jenkins -- not necessarily linked to hostnames. Also, the "executors" count should be reduced to the amount of compilers in that system (usually 2) and so avoid extra stress of scheduling too many emulated-CPU builds at once. Sequentializing the git cache access ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As part of the `jenkins-dynamatrix` optional optimizations, the NUT CI recipe invoked via `Jenkinsfile-dynamatrix` maintains persistent git reference repositories that can be used to cache NUT codebase (including the tested commits) and so considerably speed up workspace preparation when running numerous build scenarios on the same agent. Such `.gitcache-dynamatrix` cache directories are located in the build workspace location (unique for each agent), but on a system with numerous containers these names can be symlinks pointing to a shared location. To avoid collisions with several executors updating the same cache with new commits, critical access windows are sequentialized with the use of https://github.com/jenkinsci/lockable-resources-plugin[Lockable Resources plugin]. On the `jenkins-dynamatrix` side this is facilitated by labels: ------ DYNAMATRIX_UNSTASH_PREFERENCE=scm-ws:nut-ci-src DYNAMATRIX_REFREPO_WORKSPACE_LOCKNAME=gitcache-dynamatrix:SHARED_HYPERVISOR_NAME ------ * The `DYNAMATRIX_UNSTASH_PREFERENCE` tells the `jenkins-dynamatrix` library code which checkout/unstash strategy to use on a particular build agent (following values defined in the library; `scm-ws` means SCM caching under the agent workspace location, `nut-ci-src` names the cache for this project); * The `DYNAMATRIX_REFREPO_WORKSPACE_LOCKNAME` specifies a semi-unique string: it should be same for all co-located agents which use the same shared cache location, e.g. guests on the same hypervisor; and it should be different for unrelated cache locations, e.g. different hypervisors and stand-alone machines. nut-2.8.3/docs/macros.txt0000644000200500020050000000514114777767434012247 00000000000000NUT-specific autoconf macros ---------------------------- The following NUT-specific autoconf macros are defined in the `m4/` directory. *NUT_TYPE_SOCKLEN_T*:: *NUT_TYPE_UINT8_T*:: *NUT_TYPE_UINT16_T*:: Check for the corresponding type in the system header files, and `#define` a replacement if necessary. *NUT_CHECK_LIBGD*:: *NUT_CHECK_LIBNEON*:: *NUT_CHECK_LIBNETSNMP*:: *NUT_CHECK_LIBPOWERMAN*:: *NUT_CHECK_LIBOPENSSL*:: *NUT_CHECK_LIBNSS*:: *NUT_CHECK_LIBUSB*:: *NUT_CHECK_LIBWRAP*:: *et al*:: Determine the compiler flags for the corresponding library. On success, set `nut_have_libxxx="yes"` and set `LIBXXX_CFLAGS` and `LIBXXX_LDFLAGS`. On failure, set `nut_have_libxxx="no"`. This macro can be run multiple times, but will do the checking only once. Here "xxx" should of course be replaced by the respective library name. + The checks for each library grow organically to compensate for various bugs in the libraries, pkg-config, etc. This is why we have a separate macro for each library. *NUT_CHECK_IPV6*:: Check for various features required to compile the IPv6 support. Define a preprocessor symbol for each individual feature (`HAVE_GETADDRINFO`, `HAVE_FREEADDRINFO`, `HAVE_STRUCT_ADDRINFO`, `HAVE_SOCKADDR_STORAGE`, `SOCKADDR_IN6`, `IN6_ADDR`, `HAVE_IN6_IS_ADDR_V4MAPPED`, `HAVE_AI_ADDRCONFIG`). + Also set the shell variable `nut_have_ipv6=yes` if all the required features are present. Set `nut_have_ipv6=no` otherwise. *NUT_CHECK_OS*:: Check for the exact system name and type. This was only used in the past to determine the packaging rule to be used through the `OS_NAME` variable, but may be useful for other purposes in the future. *NUT_REPORT_FEATURE(FEATURE, VALUE, VARIABLE, DESCRIPTION)*:: Schedule a line for the end-of-configuration feature summary. The 'FEATURE' is a descriptive string such that the sentence "Checking whether to FEATURE" makes sense, and 'VALUE' describes the decision taken (typically 'yes' or 'no'). The feature is also reported to the terminal. + Also use 'VARIABLE' and 'DESCRIPTION' for defining `AM_CONDITIONAL` and `AC_DEFINE` (only if `VALUE = "yes"`). The 'VARIABLE' is of the form `WITH_`. *NUT_REPORT(FEATURE, VALUE)*:: Schedule a line for the end-of-configuration feature summary, without printing anything to the terminal immediately. *NUT_PRINT_FEATURE_REPORT*:: Print out a list of the features that have been reported by previous `NUT_REPORT_FEATURE` macro calls. *NUT_ARG_WITH(FEATURE, DESCRIPTION, DEFAULT)*:: Declare a simple `--with-FEATURE` option with the given 'DESCRIPTION' and 'DEFAULT'. Sets the variable `nut_with_FEATURE`. nut-2.8.3/docs/release-notes.txt0000644000200500020050000000233614777534446013527 00000000000000:titles.underlines: "__","==","--","~~","^^" Network UPS Tools Release Notes _______________________________ :Author: Russell_Kroll,_Arnaud_Quette,_Arjen_de_Korte,_Charles_Lepple_and_Jim_Klimov :Author Initials: RK, AQ, ADK, CL & JK Introduction ============ The primary goal of the Network UPS Tools (NUT) project is to provide support for Power Devices, such as Uninterruptible Power Supplies, Power Distribution Units and Solar Controllers. This document intends to report high-level changes delivered by NUT project releases, as well as practical nuances for packagers and end-users who would be upgrading their NUT deployments. It DOES NOT intend to detail the change log: it is very large and complicated to render properly, so is better served by another document artifact. If you wish to discover how everything came together, have a look at the <>. [[NUT_Release_Notes]] NUT Release Notes (and other feature details) ============================================= include::{builddir}../NEWS.adoc-parsed[] [[NUT_Upgrading_Notes]] NUT Upgrading Notes =================== include::{builddir}../UPGRADING.adoc-parsed[] [[Project_History]] Project history =============== include::history.txt[] nut-2.8.3/docs/user-manual.txt0000644000200500020050000002207414777767434013220 00000000000000:titles.underlines: "__","==","--","~~","^^" Network UPS Tools User Manual _____________________________ :Author: Russell_Kroll,_Arnaud_Quette,_Arjen_de_Korte_and_Jim Klimov :Author Initials: RK, AQ, ADK & JK Introduction ============ The primary goal of the Network UPS Tools (NUT) project is to provide support for Power Devices, such as Uninterruptible Power Supplies, Power Distribution Units and Solar Controllers. NUT provides many control and monitoring <>, with a uniform control and management interface. More than 170 different manufacturers, and several thousands of models are <>. This software is the combined effort of many <>. This document intend to describe how to install software support for your <> (UPS, PDU, ...), and how to use the NUT project. It is not intended to explain what are, nor distinguish the different technologies that exist. For such information, have a look at the <>. If you wish to discover how everything came together, have a look at the <>. [[Overview]] include::../README.adoc[] [[Features]] include::features.txt[] Compatibility information ------------------------- Hardware ~~~~~~~~ The current list of hardware supported by NUT can be viewed <>. Operating systems ~~~~~~~~~~~~~~~~~ This software has been reported to run on: - Linux distributions, - the BSDs, - Apple's OS X, - Sun Solaris and illumos, - SGI IRIX, - HP/UX, - Tru64 Unix, - AIX, - Windows: * There is an older port of the client-side monitoring to Windows called WinNUT. Windows users may be able to build it directly with Cygwin. * Note there are also numerous third-party projects named WinNUT-Client or similar, made over decades by different enthusiasts and community members with a number of technologies underneath. If you run a program that claims such a name, locate and ask its creators for support related to the client. * Since NUT v2.8.1, there is an on-going effort to integrate older platform development of NUT for Windows into the main code base -- allowing to run the whole stack of NUT drivers, data server and same clients as on POSIX platforms (for fancy GUI clients, see linkman:NUT-Monitor[8] or third-party projects). Still, as of NUT release v2.8.3, installation is complicated and there are other known imperfections (not all WIN32 code has equivalents to POSIX); for current details see NUT issues tracked on GitHub under https://github.com/orgs/networkupstools/projects/2/views/1 NUT is also often embedded into third-party projects like OpenWRT (or similar) based routers, NAS and other appliances, monitoring systems like Home Assistant, and provided or suggested by some UPS vendors as their software companion. Your system will probably run it too. You just need a good C compiler and possibly some more packages to gain access to the serial ports. Other features, such as USB / SNMP / whatever, will also need extra software installed. Success reports are welcomed to keep this list accurate. Given its core position at the heart of your systems' lifecycle, we make it a point to have current NUT building and running anywhere, especially where older releases did work before (including "abandonware" like the servers and OSes from the turn of millennium): if those boxes are still alive and in need of power protection, they should be able to get it. [TIP] ===== If you like how the NUT project helps protect your systems from power outages, please consider sponsoring or at least "starring" it on GitHub at https://github.com/networkupstools/nut/ - these stars are among metrics which the larger potential sponsors consider when choosing how to help FOSS projects. Keeping the lights shining in such a large non-regression build matrix is a big undertaking! ifndef::pdf_format[] image:https://api.star-history.com/svg?repos=networkupstools/nut&type=Date[link="https://star-history.com/#networkupstools/nut&Date" alt="NUT GitHub Star History Chart"] endif::pdf_format[] See <> for an overview of the shared effort. ===== As a FOSS project, for over a quarter of a century we welcome contributions of both core code (drivers and other features), build recipes and other integration elements to make it work on your favourite system, documentation revisions to make it more accessible to newcomers, as well as hardware vendor cooperation with first-hand driver and protocol submissions, and just about anything else you can think of. NUT Support Policy ~~~~~~~~~~~~~~~~~~ The Network UPS Tools project is a community-made open-source effort, primarily made and maintained by people donating their spare time. The support channels are likewise open, with preferred ones being link:https://github.com/networkupstools/nut/issues[the NUT project issue tracker on GitHub] and the NUT Users mailing list, as detailed at https://networkupstools.org/support.html page. Please keep in mind that any help is provided by community members just like yourself, as a best effort, and subject to their availability and experience. It is expected that you have read the Frequently Asked Questions, looked at the link:https://github.com/networkupstools/nut/wiki[NUT wiki], and have a good grasp about the three-layer design and programs involved in a running deployment of NUT, for a discussion to be constructive and efficient. Be patient, polite, and prepare to learn and provide information about your NUT deployment (version, configuration, OS...) and the device, to collect logs, and to answer any follow-up questions about your situation. Finally, note that NUT is packaged and delivered by packaging into numerous operating systems, appliances and monitoring projects, and may be bundled with third-party GUI clients. It may be wise of end-users to identify such cases and ask for help on the most-relevant forum (or several, including the NUT support channels). It is important to highlight that the NUT project releases have for a long time been essentially snapshots of better-tested code, and we do not normally issue patches to "hot-fix" any older releases. Any improvements of NUT itself are made in the current code base, same as any other feature development, so to receive desired fixes on your system (and/or to check that they do solve your particular issue), expect to be asked to build the recent development iteration from GitHub or work with your appliance vendor to get a software upgrade. Over time, downstream OS packaging or other integrations which use NUT, may issue patches as new package revisions, or new baseline versions of NUT, according to *their* release policies. It is not uncommon for distributions, especially "stable" flavours, to be a few years behind upstream projects. [[Download_instructions]] include::download.txt[] [[_installation_instructions]] include::{builddir}../INSTALL.nut.adoc-parsed[] [[Configuration_notes]] include::config-notes.txt[] [[Advanced_usage_scheduling_notes]] include::scheduling.txt[] include::outlets.txt[] [[daisychain]] NUT daisychain support notes ============================ include::daisychain.txt[] [[NUT_Security]] include::security.txt[] Appendix A: Glossary ==================== This section document the various acronyms used throughout the present documentation. [template="glossary",id="terms"] ATS:: Automatic Transfer Switch. NUT:: Network UPS Tools. PDU:: Power Distribution Unit. PSU:: Power Supply Units. SCD:: Solar Controller Device. UPS:: Uninterruptible Power Supply. [[Acknowledgements]] Appendix B: Acknowledgements / Contributions ============================================ include::acknowledgements.txt[Acknowledgements / Contributions] [[nut-names]] Appendix C: NUT command and variable naming scheme ================================================== include::nut-names.txt[] [[HCL]] Appendix D: Hardware Compatibility List ======================================= Refer to the link:https://www.networkupstools.org/stable-hcl.html[online HCL]. Appendix E: Documentation ========================= include::documentation.txt[] [[Support_Request]] Appendix F: Support instructions ================================ include::support.txt[] [[Cables_information]] Appendix G: Cables information ============================== include::cables.txt[] [[Configure_options]] Appendix H: Configure options ============================= NOTE: For more information about build environment setup, see chapters about linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] and linkdoc:qa-guide[Custom NUT CI farm build agents: LXC multi-arch containers,CI_LXC,docs/ci-farm-lxc-setup.txt]. include::configure.txt[] [[Upgrading_notes]] Appendix I: Upgrading notes =========================== include::{builddir}../UPGRADING.adoc-parsed[] [[Project_History]] Appendix J: Project history =========================== include::history.txt[] nut-2.8.3/docs/asciidoc.conf0000644000200500020050000001661714777767434012661 00000000000000## NUT macros: linkman, linkman2, linkdoc, linksingledoc # # Usage: linkman:command[manpage-section] # This macro allows to handle variable manpage location, depending on the # document type # Usage: linkman2:command-page[displayed-command,manpage-section] # Just like linkman macro, but supports different names for the page and the # command shown. # # Note: # - in linkman, {0} is the manpage section, while {target} is the command. # - in linkman2, {0} is the whole list of attributes, {1} is the command to be # shown, {2} is the manpage section, while {target} is the command page. # - linkmanext and linkmanext2 macros repeat the behavior of the default ones. # These macros are intended for system man pages (e.g. HTML links might lead # to a generic internet site, or possibly to a distro-provided library # online or locally). # # Example: # linkman:ups.conf[5] # linkman2:ups_conf[ups.conf,5] # linkmanext:chroot[2] # # Show NUT link as: (
); if section is defined, else just show # the command. # ################################################################################ # # Usage: linksrcdoc:document[] # Mark-up a reference to a document source file in NUT code base; # NOTE: its "document" path is assumed to be relative to source root! # Usage: suggestsrcdoc:document[] # This macro allows to recommend a document in NUT source code base # to consult the most up-to-date version of a quickly evolving text. # It wraps the above into a prepared message, to name the source file # as an "up-to-date" alternative to a link generated by other macros. # # Usage: linkdoc:document[display title[,anchor[,source path[,chunk name]]]] # This macro allows to handle variable NUT documentation location, depending # on the document type. NOTE: its "document" path is assumed to be relative to # the rendered (HTML, PDF) document location; adding "../" for chunked HTML. # Usage: linksingledoc:document[display title[,anchor[,source path]]] # Just like linkdoc macro, but, when chunked HTML is generated, this one always # points to a non-chunked file # # Note, {1} is the display title, {2} is the optional anchor name, # {3} is an optional path to source document in NUT code base # (recommended for parts of documentation which expect significant # change over time, so a reference can be provided to current text), # {4} is an optional name of the HTML Chunk (typically anchor name in the # root document text file, e.g. "[[Overview]]" section of "user-manual.txt"), # (ignored in non-chunked formats), # {0} is the whole set of args ({1}...{n}) and {target} is the # base document name. # Example: # linkdoc:user-manual[user manual,NUT_Security] # linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] # linkdoc:developer-guide[developer guide,_status_data] # linksingledoc:FAQ[shopping tips,_which_ups_should_i_buy] [macros] # From asciidoc-py docs at https://asciidoc-py.github.io/chunked/ch21.html : # =[=#[=+[ # Delete the existing macro with this . # * is a Python regular expression and is the name of # a markup template. # * If is omitted then it is the value of the regular expression # match group named "name". # * The optional [linkman):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Plinkman2):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Plinkmanext):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Plinkmanext2):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Plinkdoc):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Plinksingledoc):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Psuggestsrcdoc):(?P\S*?)\[(?P.*?)\]= # FIXME: find a way to use "link:" or xref, at least for GitHub renders. (?su)[\\]?(?Plinksrcdoc):(?P\S*?)\[(?P.*?)\]= ifdef::basebackend-docbook[] # AsciiDoc <= ~8.6.9 tests the wrong attribute and, as a consequence # of that, it produces both and . # To workaround this issue, implement the xref macro by ourselves. [xref-inlinemacro] {0} {0%} [suggestsrcdoc-inlinemacro] (or linksrcdoc:{target}[] in NUT sources for up-to-date information) ifdef::xhtml11_format[] [linkman-inlinemacro] {target}{0?({0})} [linkman2-inlinemacro] {1={target}}{2?({2})} # FIXME: Allow to define external man page URL structure and whether # sections should change via configure script options: [linkmanext-inlinemacro] {target}{0?({0})} [linkmanext2-inlinemacro] {1={target}}{2?({2})} [linkdoc-inlinemacro] {1}{3?suggestsrcdoc:{3}[]} [linksingledoc-inlinemacro] {1}{3?suggestsrcdoc:{3}[]} [linksrcdoc-inlinemacro] {target} endif::xhtml11_format[] # NOTE: linkdoc does not support 'anchor' if generating with classic # asciidoc numbered chapters, but it is not a problem when the anchor # value becomes the file name (allowing for persistent links unless # the chapter is renamed - but surviving reshuffled ordering) ifdef::chunked_format[] [linkman-inlinemacro] {target}{0?({0})} [linkman2-inlinemacro] {1={target}}{2?({2})} # FIXME: Allow to define external man page URL structure and whether # sections should change via configure script options: [linkmanext-inlinemacro] {target}{0?({0})} [linkmanext2-inlinemacro] {1={target}}{2?({2})} [linkdoc-inlinemacro] {1}{3?suggestsrcdoc:{3}[]} [linksingledoc-inlinemacro] {1}{3?suggestsrcdoc:{3}[]} [linksrcdoc-inlinemacro] {target} endif::chunked_format[] # PDF output points online versions ifdef::pdf_format[] [linkman-inlinemacro] {target}{0?({0})} [linkman2-inlinemacro] {1={target}}{2?({2})} # FIXME: Allow to define external man page URL structure and whether # sections should change via configure script options: [linkmanext-inlinemacro] {target}{0?({0})} [linkmanext2-inlinemacro] {1={target}}{2?({2})} [linkdoc-inlinemacro] {1}{3?suggestsrcdoc:{3}[]} [linksingledoc-inlinemacro] {1}{3?suggestsrcdoc:{3}[]} [linksrcdoc-inlinemacro] {target} endif::pdf_format[] endif::basebackend-docbook[] nut-2.8.3/docs/docinfo.xml0000644000200500020050000001476215001555033012341 00000000000000 2.8.3 2025-04-07 JK Some changes to docs and recipes, libusbclient API and functionality. Updated NUT SEMVER definition and added scripting around it. Groundwork for vendor-defined status and INSTCMD buzzwords like "ECO". Fixed some regressions and added improvements for certain new device series. 2.8.2 2024-04-01 JK Some changes to docs and recipes, libnutscan API and functionality. Added nutconf (library and tool). Fixed some regressions and added improvements for certain new device series. 2.8.1 2023-10-31 JK Some changes to API, docs and recipes, in particular to simplify local builds and tests (e.g. to help end-users check if current NUT codebase trunk has already fixed an issue they see with a packaged installation). Revived NUT for Windows effort, further improved other OS integrations. NUT became reference for "UPS management protocol", Informational RFC 9271. Documentation files refactored to ease maintenance. More drivers and new driver categories introduced. 2.8.0 2022-04-26 JK Change of maintainer. Many changes to API, docs (both style and content), and recipes, with a stress on non-regression test-ability, run-time debug-ability, general codebase maintainability, as well as OS integrations (notably nut-driver-enumerator for systemd and SMF service instance maintenance). Added a lot in area of CI support and documented pre-requisite package lists for numerous platforms, and CI agent set-up. Added libusb-1.x support and many new driver categories (and drivers), and daisychain device connection support. Instant commands enhanced with TRACKING to enable protocol-based waiting for completion of a particular INSTCMD or SET operation. 2.7.4 2016-03-09 AQ NUT variables namespace updated, in particular for outlet groups, alarms and thresholds, ATS devices, and battery.charger.status to supersede CHRG and DISCHRG flags published in ups.status readings. NUT network protocol extended with NUMBER type; some API changes. 2.7.3 2015-04-22 AQ Documentation revised, including some API changes. Added NUT DDL links. NUT variables namespace updated. 2.7.2 2014-04-17 AQ The nut-website project was offloaded into a separate repository. FreeDesktop HAL support was removed (obsoleted in GNOME consumer). Introduced nutdrv_atcl_usb driver. 2.7.1 2013-11-19 CL NUT source codebase migrated from SVN to Git (and from Debian infrastructure to GitHub source code hosting). jNut binding split into a separate project. Introduced libnutclient (C++ binding), al175, apcupsd-ups and nutdrv_qx drivers, Mozilla NSS support for simpler licensing than OpenSSL, and a newer apcsmart implementation. Documentation support enhanced with a spell checker, contents massively updated to reflect project changes. 2.6.5 2012-08-08 AQ New macosx-ups driver, new implementation of mge-shut driver. NUT variables namespace updated. Docs cleaned up and revised. 2.6.4 2012-05-31 AQ New NUT network protocol commands (LIST CLIENTS, LIST RANGE and NETVER), and socket protocol commands (ADDRANGE, DELRANGE). NUT variables namespace updated. Introduced nut-recorder tool. 2.6.3 2012-01-04 AQ No substantial changes to documentation. 2.6.2 2011-09-15 AQ Introduced nut-scanner tool and nut-ipmipsu driver, systemd support, and a new apcsmart implementation. 2.6.1 2011-06-01 AQ Introduced default.* and override.* optional settings in ups.conf, an ups.efficiency report, and outlet.0 special handling. 2.6.0 2011-01-14 AQ First release of AsciiDoc documentation for Network UPS Tools (NUT). nut-2.8.3/docs/ci-farm-do-setup.adoc0000644000200500020050000006756514777767434014150 00000000000000Setting up the non-standard VM farm for NUT CI on DigitalOcean -------------------------------------------------------------- Since 2023 the Network UPS Tools project employs virtual machines, hosted and courteously sponsored as part of FOSS support program by link:https://www.digitalocean.com/?refcode=d2fbf2b9e082&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge[DigitalOcean], for a significant part of the NUT CI farm based on a custom link:https://www.jenkins.io/[Jenkins] setup. Use of complete machines, virtual or not, in the NUT CI farm allows our compatibility and non-regression testing to be truly multi-platform, spanning various operating system technologies and even (sometimes emulated) CPU architectures. To that extent, while it is easy to deploy common OS images and manage the resulting VMs, there are only so many images and platforms that are officially supported by the hosting as general-purpose "DigitalOcean VPS Droplets", and work with other operating systems is not easy. But not impossible, either. In particular, while there is half a dozen Linux distributions offered out of the box, official FreeBSD support was present earlier but abandoned shortly before NUT CI farm migration from the defunct Fosshost.org considered this hosting option. Still, there were community reports of various platforms including *BSD and illumos working in practice (sometimes with caveats), which just needed some special tinkering to run and to manage. This chapter details how the NUT CI farm VMs were set up on DigitalOcean. ////////// // Originally documented at https://github.com/networkupstools/nut/issues/2192 ////////// Design trade-offs ~~~~~~~~~~~~~~~~~ Note that some design choices were made because equivalent machines existed earlier on Fosshost.org hosting, and filesystem content copies or ZFS snapshot transfers were the least disruptive approach (using ZFS wherever possible also allows to keep the history of system changes as snapshots, easily replicated to offline storage). It is further important to note that DigitalOcean VMs in recovery mode apparently must use the one ISO image provided by DigitalOcean. At the time of this writing it was based on Ubuntu 18.04 LTS with ZFS support -- so the ZFS pools and datasets on VMs that use them should be created *AND* kept with options supported by that version of the filesystem implementation. Another note regards pricing: resources that "exist" are billed, whether they run or not (e.g. turned-off VMs still reserve CPU/RAM to be able to run on demand, dormant storage for custom images is used even if they are not active filesystems, etc.) As of this writing, the hourly prices are applied for resources spawned and destroyed within a calendar month. After a monthly-rate total price for the item is reached, that is applied instead. OS images ^^^^^^^^^ Some links will be in OS-specific chapters below; further reading for this effort included: * link:https://www.digitalocean.com/blog/custom-images[] * link:https://ptribble.blogspot.com/2021/04/running-tribblix-on-digital-ocean.html[] -- notes on custom image creation, may involve link:https://github.com/illumos/metadata-agent[] * link:https://bsd-cloud-image.org/[] -- A collection of pre-built *BSD cloud images According to the fine print in the scary official docs, DigitalOcean VMs can only use "custom images" in one of a number of virtual HDD formats, which should carry an ext3/ext4 filesystem for DigitalOcean addons to barge into for management. In practice, uploading other images (OpenIndiana Hipster "cloud" image, OmniOS, FreeBSD) from your workstation or by providing an URL to an image file on the Internet (see links in this document for some collections) sort of works. While the upload status remained "pending", a VM could often be made with it soon... but in other cases you have to wait a surprisingly long time, some 15-20 minutes, and additional images suddenly become "Uploaded". * The initial theory was that we exceeded some limit and after ending the setups with one custom image, it can be nuked and then another used in its place; in practice this seems to be not true -- just the storage information refresh (perhaps propagation from cache to committed) can lag. * Note that your budget would be invoiced for storage of custom images too. If you use stock ISOs once, it makes sense to remove them later. * There is also an option to use pre-installed operating systems, so you can dynamically create and destroy VMs with minimal work after creation (e.g. with Jenkins cloud plugins to spawn workers according to labels); in this case you may want to retain (eventually update) the golden image. * It may be that not *all* non-standard images are supported, but those with `cloud-init` or similar tools (see https://www.digitalocean.com/blog/custom-images for details). Networking ^^^^^^^^^^ FIXME: Private net, DO-given IPs One limitation seen with "custom images" is that IPv6 is not offered to those VMs. Generally all VMs get random (hopefully persistent) public IPv4 addresses from various subnets. It is possible to also request an interconnect VLAN for one project's VMs co-located in same data center and have it attached (with virtual IP addresses) to an additional network interface on each of your VMs: it is supposed to be faster and free (regarding traffic quotas). * For the Jenkins controller which talks to the world (and enjoys an off-hosting backup at a maintainer's home server) having substantial monthly traffic quota is important. * For the set of builders hosted on DigitalOcean, which would primarily talk to the controller in the common VLAN -- not so much (just OS upgrades? maybe GitHub?) One more potential caveat: while DigitalOcean provides VPC network segments for free inter-communications of a group of droplets, it assigns IP addresses to those and does not let any others be used by the guest. This causes some hassle when importing a set of VMs which used different IP addresses on their inter-communications VLAN originally (on another hosting). Common notes for illumos VMs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The original OpenIndiana Hipster and OmniOS VMs were configured with the https://github.com/jimklimov/illumos-splitroot-scripts methodology and scripting, so there are quite a few datasets dedicated to their purposes instead of a large one. There are known issues about VM reboot: * Per https://www.illumos.org/issues/14526 and personal and community practice, it seems that "slow reboot" for illumos VMs on QEMU-6.x (and on DigitalOcean) misbehaves and hangs, ultimately the virtual hardware is not power-cycled. * A power-off/on cycle through UI (and probably REST API) does work. * It took about 2 hours for `rebooting...` to take place in fact. At least, the machine would not be stuck for eternity in case of unattended crashes. * Other kernels (Linux, BSD, ...) are not impacted by this, it seems. Wondering if there are QEMU HW watchdogs on DigitalOcean that we could use... Using the DigitalOcean Recovery ISO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As noted above, for installation and subsequent management DigitalOcean's recovery ISO must be used when booting the VM, which is based on Ubuntu and includes ZFS support. It was used a lot both initially and over the years, so deserves a dedicated chapter. To boot into the recovery environment, you should power off the VM (see the Power left-menu item in DigitalOcean web dashboard, and "Turn off Droplet"), then go into the Recovery menu and select "Boot from Recovery ISO" and power on the Droplet. When you are finished with recovery mode operations, repeat this routine but select "Boot from Hard Drive" instead. NOTE: Sometimes you might be able to change the boot device in advance (it takes time to apply the setting change) and power-cycle the VM later. The recovery live image allows to install APT packages, such as `mc` (file manager and editor) and `mbuffer` (to optimize `zfs-send`/`zfs-recv` traffic). When the image boots, it offers a menu which walks through adding SSH public keys (can import ones from e.g. GitHub by username). Note that if your client system uses `screen`, `tmux` or `byobu`, the new SSH connections would get the menu again. To get a shell right away, interactive or for scripting like `rsync` and `zfs recv` counterparts, you should `export TERM=vt220` from your `screen` session (the latter proved useful in any case for independence of the long replication run from connectivity of my laptop to Fosshost/DigitalOcean VMs). * SSH keys can be imported with a `ssh-import-id-gh` helper script provided in the image: + ---- #recovery# ssh-import-id-gh jimklimov 2023-12-10 21:32:18,069 INFO Already authorized ['2048', 'SHA256:Q/ouGDQn0HUZKVEIkHnC3c+POG1r03EVeRr81yP/TEoQ', 'jimklimov@github/10826393', '[RSA]'] ... ---- * More can be pasted into `~/.ssh/authorized_keys` later; * The real SSH session is better than the (VNC-based web-wrapped) Rescue Console, which is much less responsive and also lacks mouse and copy-paste integration with your browser; * On your SSH client side (e.g. in the `screen` session on original VM which would send a lot of data), you can add non-default (e.g. one-time) keys of the SSH server of the recovery environment with: + ---- #origin# eval `ssh-agent` #origin# ssh-add ~/.ssh/id_rsa_custom_key ---- Make the recovery userland convenient: ---- #recovery# apt install mc mbuffer ---- * `mc`, `mcview` and `mcedit` are just very convenient to manage systems and to manipulate files; * ZFS send/receive traffic is quite bursty, with long quiet times as it investigates the source or target pools respectively, and busy streaming times with data. + Using an `mbuffer` on at least one side (ideally both to smooth out network latency) is recommended to have something useful happen when at least one of the sides has the bulk data streaming phase. OpenIndiana ~~~~~~~~~~~ Helpful links for this part of the quest: * https://openindiana.org/downloads/ => see link:https://dlc.openindiana.org/isos/hipster/20231027/OI-hipster-cloudimage.img.gz[] -- OI distro-provided cloud images (detailed at link:https://www.openindiana.org/announcements/openindiana-hipster-2023-04-announcement/[] release notes, though not at later ones) DO-NUT-CI-OI VM creation ^^^^^^^^^^^^^^^^^^^^^^^^ Initial attempt, using the OpenIndiana cloud image ISO: The OI image could be loaded... but that's it -- the logo is visible on the DigitalOcean Recovery Console, as well as some early boot-loader lines ending with a list of supported consoles. I assume it went into the `ttya` (serial) console as one is present in the hardware list, but DigitalOcean UI does not make it accessible and I did not find quickly if there are any REST API or SSH tunnel into serial ports. NOTE: The web console did not come up quickly enough after a VM (re-)boot for any interaction with the early seconds of ISO image loader's uptime, if it even offers any. It *probably* booted and auto-installed, since I could see an `rpool/swap` twice the size of VM RAM later on, and the `rpool` occupied the whole VM disk (created with auto-sizing). The VM can however be rebooted with a (DO-provided) Recovery ISO, based at that time on Ubuntu 18.04 LTS with ZFS support -- which was sufficient to send over the existing VM contents from original OI VM on Fosshost. See above about booting and preparing that environment. DO-NUT-CI-OI VM OS transfer ^^^^^^^^^^^^^^^^^^^^^^^^^^^ As the practically useful VM already existed at Fosshost.org, and a quick shot failed at making a new one from scratch, in order to only transfer local zones (containers), a decision was made to transfer the whole ZFS pool via snapshots using the Recovery ISO. First, following up from the first experiment above: I can import the ZFS pool created by cloud-OI image into the Linux Recovery CD session: * Check known pools: + ---- #recovery# zpool import pool: rpool id: 7186602345686254327 state: ONLINE status: The pool was last accessed by another system. action: The pool can be imported using its name or numeric identifier and the `-f' flag. see: http://zfsonlinux.org/msg/ZFS-8000-EY config: rpool ONLINE vda ONLINE ---- * Import without mounting (`-N`), using an alternate root if we decide to mount something later (`-R /a`), and ignoring possible markers that the pool was not unmounted so might be used by another storage user (`-f`): + ---- #recovery# zpool import -R /a -N -f rpool ---- * List what we see here: + ---- #recovery# zfs list NAME USED AVAIL REFER MOUNTPOINT rpool 34.1G 276G 204K /rpool rpool/ROOT 1.13G 276G 184K legacy rpool/ROOT/c936500e 1.13G 276G 1.13G legacy rpool/export 384K 276G 200K /export rpool/export/home 184K 276G 184K /export/home rpool/swap 33.0G 309G 104K - ---- The import and subsequent inspection above showed that the kernel core-dump area was missing, compared to the original VM... so adding per best practice: * Check settings wanted by the installed machine for the `rpool/dump` dataset: + ---- #origin# zfs get -s local all rpool/dump NAME PROPERTY VALUE SOURCE rpool/dump volsize 1.46G local rpool/dump checksum off local rpool/dump compression off local rpool/dump refreservation none local rpool/dump dedup off local ---- * Apply to the new VM: + ---- #recovery# zfs create -V 2G -o checksum=off -o compression=off \ -o refreservation=none -o dedup=off rpool/dump ---- To receive ZFS streams from the running OI into the freshly prepared cloud-OI image, it wanted the ZFS features to be enabled (all were disabled by default) since some are used in the replication stream: * Check what is there initially (on the new VM): + ---- #recovery# zpool get all NAME PROPERTY VALUE SOURCE rpool size 320G - rpool capacity 0% - rpool altroot - default rpool health ONLINE - rpool guid 7186602345686254327 - rpool version - default rpool bootfs rpool/ROOT/c936500e local rpool delegation on default rpool autoreplace off default rpool cachefile - default rpool failmode wait default rpool listsnapshots off default rpool autoexpand off default rpool dedupditto 0 default rpool dedupratio 1.00x - rpool free 318G - rpool allocated 1.13G - rpool readonly off - rpool ashift 12 local rpool comment - default rpool expandsize - - rpool freeing 0 - rpool fragmentation - - rpool leaked 0 - rpool multihost off default rpool feature@async_destroy disabled local rpool feature@empty_bpobj disabled local rpool feature@lz4_compress disabled local rpool feature@multi_vdev_crash_dump disabled local rpool feature@spacemap_histogram disabled local rpool feature@enabled_txg disabled local rpool feature@hole_birth disabled local rpool feature@extensible_dataset disabled local rpool feature@embedded_data disabled local rpool feature@bookmarks disabled local rpool feature@filesystem_limits disabled local rpool feature@large_blocks disabled local rpool feature@large_dnode disabled local rpool feature@sha512 disabled local rpool feature@skein disabled local rpool feature@edonr disabled local rpool feature@userobj_accounting disabled local ---- * Enable all features this pool knows about (list depends on both ZFS module versions which created the pool and which are running now): + ---- #recovery# zpool get all | grep feature@ | awk '{print $2}' | \ while read F ; do zpool set $F=enabled rpool ; done ---- On the original VM, stop any automatic snapshot services like link:https://www.znapzend.org[ZnapZend] or `zfs-auto-snapshot`, and manually snapshot all datasets recursively so that whole data trees can be easily sent over (note that we then remove some snaps like for `swap`/`dump` areas which otherwise waste a lot of space over time with blocks of obsolete swap data held by the pool for possible dataset rollback): ---- #origin# zfs snapshot -r rpool@20231210-01 #origin# zfs destroy rpool/swap@20231210-01& #origin# zfs destroy rpool/dump@20231210-01& ---- On the receiving VM, move existing cloudy `rpool/ROOT` out of the way, if we would not use it anyway, so the new one from the original VM can land (for kicks, we can `zfs rename` the cloud-image's boot environment back into the fold after replication is complete). Also prepare to maximally compress the received root filesystem data, so it does not occupy too much in the new home (this is not something we write too often, so slower `gzip-9` writes can be tolerated): ---- #recovery# zfs rename rpool/ROOT{,x} ; \ while ! zfs set compression=gzip-9 rpool/ROOT ; do sleep 0.2 || break ; done ---- Send over the data (from the prepared `screen` session on the origin server); first make sure all options are correct while using a dry-run mode, e.g.: ---- ### Do not let other work of the origin server preempt the replication #origin# renice -n -20 $$ #origin# zfs send -Lce -R rpool/ROOT@20231210-01 | mbuffer | \ ssh root@recovery "mbuffer | zfs recv -vFnd rpool" ---- * Then remove `-n` from `zfs recv` after initial experiments confirm it would receive what you want and where you want it, and re-run. With sufficiently large machines and slow source hosting, expect some hours for the transfer. * I saw 4-8Mb/s in the streaming phase for large increments, and quite a bit of quiet time during enumeration of even almost-empty regular snapshots made by link:https://www.znapzend.org[ZnapZend] -- low-level work with ZFS metadata has a cost. Note that one of the benefits of ZFS (and the non-automatic snapshots used here) is that it is easy to catch-up later to send the data which the original server would generate and write *during* the replication. You can keep it actually working until the last minutes of the migration. After the large initial transfers complete, follow-up with a pass to stop the original services (e.g. whole `zones` either from OS default grouping or as wrapped by https://github.com/jimklimov/illumos-smf-zones scripting) and replicate any new information created on origin server during this transfer (and/or human outage for the time it would take you to focus on this task again, after the computers were busy for many hours...) NOTE: The original VM had ZnapZend managing regular ZFS snapshots and their off-site backups. As the old machine would no longer be doing anything of consequence, keep the service there disable and also turn off the tunnel to off-site backup -- this serves to not confuse your remote systems as an admin. The new VM clone would just resume the same snapshot history, poured to the same off-site backup target. * `rsync` the `rpool/boot/` from old machine to new, which is a directory right in the `rpool` dataset and has boot-loader configs; update `menu.lst` for GRUB boot-loader settings; * run `zpool set bootfs=...` to enable the transplanted root file system; * `touch reconfigure` in the new rootfs (to pick up changed hardware on boot); * be ready to fiddle with `/etc/dladm/datalink.conf` (if using virtual links, etherstubs, etc.), as well as `/etc/hostname*`, `/etc/defaultrouter` etc. * revise the loader settings regarding the console to use (should be `text` first here on DigitalOcean) -- see in `/boot/solaris/bootenv.rc` and/or `/boot/defaults/loader.conf` * reboot into production mode to see if it all actually "works" :) If the new VM does boot correctly, log into it and: * Revive the `znapzend` retention schedules: they have a configuration source value of `received` in ZFS properties of the replica, so are ignored by the tool. See `znapzendzetup list` on the original machine to get a list of datasets to check on the replica, e.g.: + ---- :; zfs get -s received all rpool/{ROOT,export,export/home/abuild/.ccache,zones{,-nosnap}} \ | grep znapzend | while read P K V S ; do zfs set $K="$V" $P & done ---- * re-enable `znapzend` and `zones` SMF services on the new VM; * check about `cloud-init` integration services; the `metadata-agent` seems buildable and installable, it logged the SSH keys on console after service manifest import (details elaborated in links above). DO-NUT-CI-OI VM preparation as build agent ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As of this writing, the NUT CI Jenkins controller runs on DigitalOcean -- and feels a lot snappier in browsing and SSH management than the older Fosshost.org VMs. Despite the official demise of the platform, they were alive and used as build agents for the newly re-hosted Jenkins controller for over a year until somebody or something put them to rest: the container with the old production Jenkins controller was set to not-auto-booting, and container with worker was attached to the new controller. The Jenkins SSH Build Agent setups involved here were copied on the controller (as XML files) and then updated to tap into the different "host" and "port" (so that the original definitions can in time be used for replicas on DO), and due to trust settings -- the `~jenkins/.ssh/known_hosts` file on the new controller had to be updated with the "new" remote system fingerprints. Otherwise, the migration went smooth. Similarly, existing Jenkins swarm agents from community PCs had to be taught the new DNS name (some had it in `/etc/hosts`), but otherwise connected OK. OmniOS ~~~~~~ Helpful links for this part of the quest: * https://omnios.org/download => see link:https://downloads.omnios.org/media/lts/omnios-r151046.cloud.vmdk[] (LTS) or link:https://downloads.omnios.org/media/stable/omnios-r151048.cloud.vmdk[] (recent stable) or daily "bloody" images like link:https://downloads.omnios.org/media/bloody/omnios-bloody-20231209.cloud.vmdk[] DO-NUT-CI-OO VM preparation ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Added replicas of more existing VMs: OmniOS (relatively straightforward with the OI image). The original OmniOS VM used ZFS, so its contents were sent-received similarly to the OI VM explained above. FreeBSD ~~~~~~~ Helpful links for this part of the quest: * https://www.adminbyaccident.com/freebsd/how-to-upload-a-freebsd-custom-image-on-digitalocean/ DO-NUT-CI-FREEBSD VM preparation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Added replicas of more existing VMs: FreeBSD 12 (needed to use a seed image, tried an OpenIndiana image first but did not cut it -- the ZFS options in its `rpool` were too new, so the older build of the BSD loader was not too eager to find the pool). The original FreeBSD VM used ZFS, so its contents were sent-received similarly to the OI VM explained above. * The (older version of?) FreeBSD loader rejected a `gzip-9` compressed `zroot/ROOT` location, so care had to be taken to first disable compression (only on the original system's tree of root filesystem datasets). The last applied ZFS properties are used for the replication stream. OpenBSD ~~~~~~~ Helpful links for this part of the quest: * link:https://dev.to/nabbisen/custom-openbsd-droplet-on-digitalocean-4a9o[] -- how to piggyback OpenBSD via FreeBSD images (no longer offered by default on DO) DO-NUT-CI-OPENBSD VM creation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Added a replica of OpenBSD 6.5 VM as an example of relatively dated system in the CI farm, which went decently well as a `dd` stream of the local VM's vHDD into DO recovery console session: ---- #tgt-recovery# mbuffer -4 -I 12340 > /dev/vda #src# dd if=/dev/rsd0c | time nc myHostingIP 12340 ---- ...followed by a reboot and subsequent adaptation of `/etc/myname` and `/etc/hostname.vio*` files. I did not check if the DigitalOcean recovery image can directly mount BSD UFS partitions, as it sufficed to log into the pre-configured system. One caveat was that it was originally installed with X11, but DigitalOcean web-console did not pass through the mouse nor advanced keyboard shortcuts. So `rcctl disable xenodm` (to reduce the attack surface and resource waste). FWIW, `openbsd-7.3-2023-04-22.qcow2` "custom image" did not seem to boot. At least, no activity on display and the IP address did not go up. Linux ~~~~~ Helpful links for this part of the quest: * link:https://openzfs.github.io/openzfs-docs/Getting%20Started/Debian/Debian%20Bookworm%20Root%20on%20ZFS.html[] -- first steps for moving our older Linux VM onto ZFS root DO-NUT-CI-LINUX VM creation ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Spinning up the Debian-based Linux builder (with many containers for various Linux systems) with ZFS, to be consistent across the board, was an adventure. * DigitalOcean rescue CD is Ubuntu 18.04 based, it has an older ZFS version so instructions from https://openzfs.github.io/openzfs-docs/Getting%20Started/Debian/Debian%20Stretch%20Root%20on%20ZFS.html have to be used particularly to `zpool create bpool` (with the dumbed-down options for GRUB to be able to read that boot-pool); * For the rest of the system, https://openzfs.github.io/openzfs-docs/Getting%20Started/Debian/Debian%20Bookworm%20Root%20on%20ZFS.html is relevant for current distro (Debian 12) and is well-written; * Note that while in many portions the "MBR or (U)EFI" boot is a choice of either one command to copy-paste or another, the spot about installing GRUB actually requires both (MBR for disk to be generally bootable, and EFI to proceed with that implementation); * If the (recovery) console with the final OS is too "tall" in the Web-UI, so the lower rows are hidden by the DO banner with IP address, and you can't see the commands you are typing, try `clear ; stty size` to check the current display size (was 128x48 for me) and `stty rows 45` to reduce it a bit. Running a full-screen program like `mc` helps gauge if you got it right. DO-NUT-CI-LINUX VM OS transfer ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ After the root pool was prepared and the large tree of datasets defined to handle the numerous LXC containers, `abuild` home directory, and other important locations of the original system, `rsync -avPHK` worked well to transfer the data. DO-NUT-CI-LINUX VM preparation as build agent ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Numerous containers with an array of Linux distributions are used as either Jenkins SSH build agents or swarm agents, as documented in chapters about LXC containers. nut-2.8.3/docs/documentation.txt0000644000200500020050000002053314777767434013636 00000000000000ifdef::website[] Documentation ============= endif::website[] User Documentation ------------------ ifdef::website[] - FAQ - Frequently Asked Questions (link:docs/FAQ.html[online]) (link:docs/FAQ.pdf[PDF]) - NUT User Manual (link:docs/user-manual.chunked/index.html[online]) (link:docs/user-manual.pdf[PDF]) - Cables information (link:cables.html[online]) (link:docs/cables.pdf[PDF]) - link:docs/man/index.html#User_man[User manual pages] - link:ddl/index.html#_supported_devices[Devices Dumps Library (DDL)]: Provides information on how devices are supported; see also link:stable-hcl.html[the HCL] - link:docs/solaris-usb.html[Notes on NUT monitoring of USB devices in Solaris and related operating systems] endif::website[] ifndef::website[] - link:../FAQ.html[FAQ - Frequently Asked Questions] - linkdoc:user-manual[NUT user manual] - <> - link:../man/index.html#User_man[User manual pages] - link:https://www.networkupstools.org/ddl/index.html#_supported_devices[Devices Dumps Library (DDL)]: Provides information on how devices are supported; see also link:https://www.networkupstools.org/stable-hcl.html[the HCL] - link:../solaris-usb.html[Notes on NUT monitoring of USB devices in Solaris and related operating systems] endif::website[] - link:https://github.com/networkupstools/ConfigExamples/releases/latest/download/ConfigExamples.pdf[NUT Configuration Examples] book maintained by Roger Price - link:https://github.com/networkupstools/nut/wiki[NUT GitHub Wiki] Developer Documentation ----------------------- ifdef::website[] - NUT Developer Guide (link:docs/developer-guide.chunked/index.html[online]) (link:docs/developer-guide.pdf[PDF]) - NUT Quality Assurance Guide (link:docs/qa-guide.chunked/index.html[online]) (link:docs/qa-guide.pdf[PDF]) - NUT Packager Guide (link:docs/packager-guide.chunked/index.html[online]) (link:docs/packager-guide.pdf[PDF]) - NUT Release Notes (link:docs/release-notes.chunked/index.html[online]) (link:docs/release-notes.pdf[PDF]) - NUT Change Log (link:docs/ChangeLog.chunked/index.html[online]) (link:docs/ChangeLog.pdf[PDF]) - link:ups-protocols.html[UPS protocols library] - link:docs/man/index.html#Developer_man[Developer manual pages] - link:nut-qa.html[NUT Quality Assurance] - link:ddl/index.html[Devices Dumps Library (DDL)]: Provides simulation data to the linkman:dummy-ups[8] driver endif::website[] ifndef::website[] - linkdoc:developer-guide[NUT Developer Guide] - linkdoc:qa-guide[NUT Quality Assurance and Build Automation Guide] - linkdoc:packager-guide[NUT Packager Guide] - linkdoc:release-notes[NUT Release Notes] - linkdoc:ChangeLog[NUT Change Log] - link:ups-protocols.html[UPS protocols library] - link:../man/index.html#Developer_man[Developer manual pages] - link:nut-qa.html[NUT Quality Assurance] - link:https://www.networkupstools.org/ddl/index.html[Devices Dumps Library (DDL)]: Provides simulation data to the linkman:dummy-ups[8] driver endif::website[] Data dumps for the DDL ---------------------- Note: both developers contributing a driver and users using an existing driver for device not previously documented as supported by it, are welcome to report new data for the Devices Dumps Library (DDL) mentioned above. Best of all such "data dump" reports can be prepared by the ifdef::website[] link:https://raw.githubusercontent.com/networkupstools/nut/master/tools/nut-ddl-dump.sh[`tools/nut-ddl-dump.sh`] endif::website[] ifndef::website[] `./tools/nut-ddl-dump.sh` endif::website[] script from the main NUT codebase, and reported on the NUT mailing list or via link:https://github.com/networkupstools/nut/issues[NUT issues on GitHub] or as a pull request against the link:https://github.com/networkupstools/nut-ddl[NUT Devices Dumps Library] following the naming and other rules described in the DDL documentation page. Data dumps collected by the tools above, or by `upsc` client, or by drivers in exploratory data-dumping mode (with `-d 1` argument), can be compared by ifdef::website[] link:https://raw.githubusercontent.com/networkupstools/nut/master/tools/nut-dumpdiff.sh[`tools/nut-dumpdiff.sh`] endif::website[] ifndef::website[] `./tools/nut-dumpdiff.sh` endif::website[] script from the main NUT codebase, which strips away lines with only numeric values (aiming to minimize the risk of losing meaningful changes like counters). Offsite Links ------------- [[general_powerdev_info]] These are general information about UPS, PDU, ATS, PSU and SCD: - link:http://tldp.org/HOWTO/UPS-HOWTO/[UPS HOWTO] (The Linux Documentation Project) - link:http://en.wikipedia.org/wiki/Uninterruptible_power_supply[UPS on Wikipedia] - link:http://en.wikipedia.org/wiki/Power_distribution_unit[PDU on Wikipedia] - link:https://en.wikipedia.org/wiki/Transfer_switch[Automatic Transfer Switch] - link:https://en.wikipedia.org/wiki/Power_supply_unit_%28computer%29[Power Supply Units] - link:http://en.wikipedia.org/wiki/Solar_controller[Solar controller on Wikipedia] - link:http://www.pcguide.com/ref/power/ext/ups/over.htm[UPS on The PC Guide] These are writeups by users of the software. - link:http://rogerprice.org/NUT[NUT Configuration Examples and helper scripts] '(Roger Price)' (sources replicated in NUT GitHub organization as link:https://github.com/networkupstools/ConfigExamples[ConfigExamples], link:https://github.com/networkupstools/TLS-UPSmon[TLS-UPSmon], and link:https://github.com/networkupstools/TLS-Shims[TLS-Shims]) - link:https://dan.langille.org/2020/09/10/nut-testing-the-shutdown-mechanism/[nut – testing the shutdown mechanism] '(Dan Langille)' - link:http://www.dimat.unina2.it/LCS/MonitoraggioUpsNutUbuntu10-eng.htm[Deploying NUT on an Ubuntu 10.04 cluster] '(Stefano Angelone)' - link:http://blog.shadypixel.com/monitoring-a-ups-with-nut-on-debian-or-ubuntu-linux[Monitoring a UPS with nut on Debian or Ubuntu Linux] '(Avery Fay)' - link:http://linux.developpez.com/cours/upsusb/[Installation et gestion d'un UPS USB en réseau sous linux] '(Olivier Van Hoof, french)' - link:https://github.com/networkupstools/nut/wiki/NUT-on-Mac-OS-X[Network UPS Tools (NUT) on Mac OS X (10.4.10)] '(Andy Poush)' - link:http://www.llondel.org/ups.shtml[Interfacing a Contact-Closure UPS to Mac OS X and Linux] '(David Hough)' - link:http://fedoranews.org/contributors/kazutoshi_morioka/nut/[How to use UPS with nut on RedHat / Fedora Core] '(Kazutoshi Morioka)' - link:http://people.freebsd.org/~thierry/nut_FreeBSD_HowTo.txt[FreeBSD installation procedure] '(Thierry Thomas, from FreeBSD)' - link:http://www.usebox.net/jjm/ups-obsd/[Gestionando un SAI desde OpenBSD con NUT] '(Juan J. Martinez, spanish)' - link:http://forums.gentoo.org/viewtopic-p-2663684.html[HOWTO: MGE Ellipse 300 on gentoo] '(nielchiano)' - link:http://deschis.blogspot.com/2006/07/cum-se-configureaz-un-ups-apollo-seria.html[Cum se configurează un UPS Apollo seria 1000F pe Linux] '(deschis, Romanian)' - link:http://buffalo.nas-central.org/wiki/Install_a_UPS_%28nut%29[Install a UPS (nut) on a Buffalo NAS] '(various authors)' - link:http://blog.pointbre.com/2903/nutnetwork-ups-tool-korean-guidebook.html[NUT Korean GuideBook] '(PointBre)' - link:https://www.jamesridgway.co.uk/monitoring-eaton-5sc-ups-scripts-and-integration-network-tools-home-assistant/amp/[USB UPS, notifications, and Home Assistant] '(James Ridgway)' - link:https://www.hirschler.solutions/posts/2022/06/powerwalker-ups-on-fedora-server-36[PowerWalker UPS on Fedora Server 36] '(Michael Hirschler)' Video articles are also available: - link:https://www.youtube.com/watch?v=vyBP7wpN72c[Network UPS Tools (NUT Server) Ultimate Guide] '(Techno Tim)' - link:https://www.jeffgeerling.com/blog/2025/nut-on-my-pi-so-my-servers-dont-die[NUT on my Pi, so my servers don't die] '(Jeff Geerling)' also including Home Assistant (HA) examples * link:https://www.youtube.com/watch?v=fLt5YhOubxk&t=207s[Jeff's lab tour due to an outage] * link:https://youtu.be/yFnItLSRpLI[Save your servers! NUT on a Raspberry Pi!] * link:https://github.com/geerlingguy/pi-nut[Ansible PiNUT project] and link:https://github.com/geerlingguy/ansible-role-nut_client[`geerlingguy.nut_client` Ansible role] News articles and Press releases -------------------------------- - link:http://www.crn.com/news/channel-programs/199000818/linux-ups-without-tears.htm[Linux UPS Without Tears] '(A. Lizard)' - link:http://www.enterprisenetworkingplanet.com/netsysm/article.php/3295841/Graceful-UPS-Shutdowns-on-Linux.htm[Graceful UPS shutdowns on Linux] '(Carla Schroder)' nut-2.8.3/docs/images/0000755000200500020050000000000015001555412011512 500000000000000nut-2.8.3/docs/images/note.png0000644000200500020050000000467614553676503013142 00000000000000PNG  IHDR00W IDAThYlW{'^4i I IMKB[, PX$P RA< E<"AE J )%bgqIܱ=fqc(h͌=sgw_} \y-FFFlxxzzzdžmdd?ZV͛7}y&8Ʊ)>^aՇ>Ɩ-[dm}QyIa[D: {&`_Z2z=H (U1hp8W|ࡇ*6E%E`ǎte"Y !KZƎ;1` YPe1T*'u ":8xMDsg}$ i^S8u7_88:y%Y( ׽ %~hQ'%,EUiIQD RB=xWlkmp,'rooI?Ў1 8' 0WhhH(`iJ:SEx~-7峻+Lo#25h\NH3 4;@R4!\Ц!qOG‡]O3ͦr=dzL=_##G)'D74 R @xOp޸5Cl>A=ܶaZdf8!Mp +NFZW4\+*sUySHG4.Ҍ^|NNM;LGGFU:g u"sKl0. shBBQ*EŸsj^fzX$ f\Q;+4Eɿ`s3S\Xd1zDD)d(TIpN\h 7#B I2ipDEQHǩf":OJPgI0ЅPVQUT'X9 FI@&@[; ) H7!- -(#ΑG!$')1QU:b4P-F{WL*?}W,]Mww{yQwcN5-yQcVrݺyz?.p L~Po7=;+yj?y;n-6YNMUY|kV/ Ћg^* W\чHbs5W3* t&&&xբF 8h4fEq$izSV/dYoX(!ᛊE*Ry~y2[ߘsjRqM #hDv8M-"AJhTǙ5^<ΐ$j\ ӔK.> W !F8(fJ<*y.=8).M:F)ZJdalݺնm5v; כшH1iCdk 4+YliAC4EAC(411sR\(&3|5*($R|֜TQ-ITcY貎;;w Sp,DÈ4=+R$dDDKEQ f9j4ff{/_]Ԧ`9xp^㯻0y8=HG{]]m\5kV!EX?k9̌d1*ʂ(NU>9r;VN[bV\>9y7ԉÔm q!]{}}>O8ɣ1V4'631288H^GDذaގ7vJ<ϙEUVl߾6<|[8gլZkKe Q*Λ^VיfffZFf5k6s̘9̨Cs$IHRFUkq6C~w!"[CS$< / [^r˿dvIENDB`nut-2.8.3/docs/images/bizarre.png0000644000200500020050000014673714553676503013640 00000000000000PNG  IHDR.9.`sRGBgAMA a pHYs oytIDATx^]v=B!!k)uB)PCJHk@)Zwנ!rɹݭ73{{wɑ䒐_͛73~}Omx\v6 !|?@:'CCy 92W_ m {wY 9M **|Ɂ|ʂd>h][`^ĵ;5o?CHn 5I_A,X`aYjϟ4ǝ+k4.ꕐ@ރZ Ă %F]g iւ 7ANL>r/3 7֕Y`^^rȻA4e:? 5r3-Rc?xFiixb5A|<'~cXK<oƢ-h% 5746*+*o PY)"@Dx7^ -g!_to%xBb}_| DTR|j=$t&0p(vcxIǖe(v!lcks,8XyޯUv{#9cXK$i --ښ~{X@¡|H84oz1H̤ 4qfѐA )!p8ddd3##t9NgXF3nqdilW@7GsRԮFbIpBS4wylNkÈ3G@!Ex;Ml6XGY3fWv"΅NlH9mH֧"ۧ~ɟkwm8̳9-#*]r'>ra P0dGi97#-^õh{N=/`"S .(,ճJp mxuunzٲeu%__sX=zt &ȴ#/"?qɎRS]g~~muuuiʼ;S8$0FTt:!l&6v\F*9o_'/_̟ "J%&6趈pY.dåI~i)Qθ]Q8PYJ^o-5oG?U٧l7tSS l6˸q뤹/-͸>|x̰KVvH.>77+@ QTyEu?֯B7~t_W$#N9G#@a؟tIyU^MtrC ĐIW_U!]?ngikÜxEu!k $8fx-UUp ^ #y2c ;wSH]J^~qRnv" Cs1[#⢅P_ݴqCG;KUx LȖ!S:%XDNگtjfJMchS?nC/,Y`,UX'~^Fg4ͥDQ%@^{ _T\"g}BaNp:?KQ3QHDu6|Yyyzi隡̞_< `9 .7;\1C ZܐΎM .e-n~\ufJҺ93NikoJ1IRyPoJ]k:V׼Cf,"1X5dgKXA$6J <0'HT}B ²֭͒Kz#}~Cda2t~a gdMZ ;`Ν7_0geZh^ x^q(?< ىmNlx0?dtg ntT@+YP8Ц'Ci]9.X״cؤb3Mz6v/~k \õAiY3;T:ʸ ZBn%nqAv/w !WAz@8e'dwi] !0O܌st8-D`^\ ? > aN v"*9}%ؤɰAV rGřU)Z7⒬*[-6#.K!=*mÜNn{nN?y""F>xVx;*& kJR80mS4ݠ8Cq; C v ȍ1}Gt >G@x8 BZp$!ۜrg8QoA@C~d do9qe !~/Kfd0K *!mHKB 9|AZ<1[ _:U?nX\P[+(vzD?pU:6MZ«cum+qN v[M2m2t-偭zdk? jT#pfIxDؤ"/|&\I~h ğo.S~L{a¼?_w#ǽMs@a٧+*'f kEpP?ׇ~hvb?' SGH }wo(d3'c#'`4I^4I^#g9~pl=|XC᫮rA ,H`Q0N 1oB8@xܹ{Krb6Z"?,xC Wշo)/OJ-6|X+ %rd=Jz-eԵZPx)8ߜb`qof-Kz_g| 8Ԝ9z8_֗Xbm9w Un bE4gT𵛛ĥN,x m>֐vMΣxL;ok^P Ew@Ұ=KF-,[%?$/>xH^~al8Yb?Z;anE Y!އd>5&1g.CdF#^G<;\ !nWĕ#%%Ea՗k\ǵkV˴iZFȽx,_@S { NSMYҲJgb^ qagiXw@~1c&ئIy2lTγFss^;&\SZ !*o|m+T:|)GM@u0*4q  q(8Fծb0nHs_; lu!NGyBa-"N$~pW!q@tU,[D PPj>;Ym qvٴqȔ1q)=U(F'^{9 49~zS)[w{lJP;.A XLqPdر,|{޻w3%꿡AjOy%WHm#\xމdҳW~.ZWKܦ6u=m_e_ ^ӄE:bʺ&Qq&mޏҎ :)?],t1_5n&{n;&,}&+)p9@tPLnUk硴y8Wy +ۦ2s; ɦN/`W:YJ;v=oGȰ#TW"N3Fh--h!f4L4ER~{X +u7{یShĵ>$ѮBUgo Ɵ' Q!x~%^tz3K;C =vqVH&3y$4cM푓;ś1_Ss6m̝LzmF6J |wĥVW5a22ₘdi6qܝ *98 ?dD[8XwDdqMP,];ɍkUE5r:yb]Y>" v]CX[ CooJh䟴mN)ɡ5R83Č{>kܾTФ35U {1V)EZ`q1YNޑf]8(-m *ʅd-t1NZ_yy} T;C>p=_. ~pQ'h9M5 =wFM!Pn(nM lOsqE#./NXAjCٸa464ȸGpÒ<_+Iv˖ĊFɢeMxE,QVw4ǣ?P7dGoxHl|윆Y,,eAh?JU[pϐ˗<#I͎>IT iz eŊeh-Ç% }[;x9^cr,W1́P=ZkdBHHBv@Qi EU1v9=\m\BC:r MHgìi0Q1 ũ 3_}=ڱDZ:J(5$6 -RAp,aqCNE341z#t&Q1Sy-.FhF n~},Js(g"r|Y6'DN!4jj%]%y5e ,#.x@,Js83el-KX͍(mt-CaϒDTc*tL@t#KS'H*hJNgv@eFNWЫy)`\SYĥk d(.!Zǁ78P^>Gqt,.ޏjCNH*ja&.mliikm#VVsS5:M\MMMi&YfZZV\)We˖ҥKeɒ%hbYp_@͛/sΓ9s@J`xlW@+qq՟uy BP]1 Z5!frJhHIi ,~*W|iҞv9 "Ԛ$lՉQZm-ۥ%%rȐ!C`"qi4 !TbyڀbsbQk=G]\.Dϥt!;~pʩIQʅFEZM҉}f|]]<2p`y(Q.}>.SzپuJJK%//W\.~U8gegqe r%;&.޸{OJB{O\v}嗿eUWsed:דj'wVs%̰~Gl"-%7kSs?=ğȊlҞ1GJWG>Z7$п&RCG SdA4O9aEu/ˆ"K&~Wu,8i7ɇ]'u|2"  kKW>TѮ /_/L{`(YU^Z_i%l C1Klq8\8qb?Cڲ*óGCamFh-fؼ^| v5e>h}O{eKնgi*ȮZ!>O/?$;+SV޹s|޻2t0ݯI[׉vCK8.('-M7iF٢[= !O/b-O>uJYYYE+M Rͺ؇I!<]^p^9OskLi>5N Xh7* x~蒊r3SV +jVK9aH^Ǘ^*99d˻"-//) 6\-Q[ &/z6TL5$#آ՝qr%3+'p9ׯ[G7uqiݺ ^$N_aFWCoLW8 "} @WP%wAZ\KIp];!6P,oxJflsa>;؎[O6@s9'deL樓GOS8C?$9rQ2j?`ȪiHUvn.,CQa( ̔۸\VBh "I&.r8=3/jn1O!B\XT'26n̺S\ʾ Jg{{7I7'LJohu\CWde&-#AvB&WVvO U0G~|9sYpZB6_e 4>fB|(xXuTqaƱ3Lx88w|hXnleҪz[-X#!q6B"!BRL}!EޖnKޟ);n= W_ʙ}]2w?i\veq+-4e5Jeě$< .mbB8QSW:E<{D\I1V3g]d@!֍-kܪ;rHJ-~VscfVfb- ?nwsxa!eJv:ɭ\B\־!=!?;`!`!}t~/{C7wzqZN?L{dr}qǟ ?r9j ;n _M7ʊ4:Ӆ tHZ)dEM1<z%Vo-)gTʊc:@[\VxMtU1m-3*ٓ+L@C$V=K=~soy7֛N<`j0X ),{\أAZ􉣹NlMGcȋP{L`q`[R*!Jq)7IV Z g+{%%CPYCCM^:naQMe*;2ufYtL@Y `ɚpΫ|w ڢ2pl mE+nC~Ij%]ǵnkq6Yӭ[7Ӎ8-3dsa;}]+ALE(QzvGEӻȎ;d-i Džzv3G:  p:͛7ɊeKIsmg`y{/v4~`u\nHWa jyF=d ٶv~`={>:~9/?g ^?s}Źη>ӟ(';'{RfV拰Xee}U"طhjNT+ѽxm!ڵ5ȩצՒ&,`4"YYzvؑ#q_ +Sue}z{&,K!slݬ {]eSƪ,<_o¢xaaQ$ plp|NGݞ`pGee+.#/;zsm޽ZzC ,7nDk,/ =(@$dUa:YjL:M>ZبHDNE ZUUU%u^z!QNحxu׉S5mڴ6ĵqF.k%cƎ/B\@ɧ%~|򜪣H%z]=kM7"8]mO9xw<6; ( Hbj{Pp. FRYmMK~}w53H'3ZZZJ:Cb֭WɑGM%db"ʔ,iK0D["Y03ߒeJbѣlۺvKbk L\lqVA6;YowKNf^IУGou&uq]׏\ΌG{l7W$R ϋ~{,V}4ڼSN`)yC0<+ DsՅAW˶n+Q3W؋21l MZ"(W--ՖRܾ ɫ Ge1߿j͂tn7&A\3ц(4u}QT=$%jפJ\/WSYxqYqmanje<,e1̷d^xӫ{G}-j ^UZkCJuSe P}oߦbhjI>e=T'H|U\SU;$\Sn8j$7C:,?=i=n뚫I3VdJ\ *u[3I\5x$믿"4[okxdlvHLܱm|0qmݺE/_M=cԩo{ )-~p$>}ZsÑm2@W9l5Y򕫤[ij9P!Q}5eV FRp D+q-B{{7%.pM)**+2[-q_Sw13M$R5Ζn"Cf̰m3b""P@b*ԓ$0wYf"]2h۷~Tk(IwPx(-[6x%K?n+T31F#}G\իw||Lg+HDܱCI]$.Z.۶mdggV]GW/lڰQ*h:ӝWǸ=2ymrLtٹssz%jjdƍ{)K&WJId32pGaXag>ĕWJ @VfӷđիYq= ^y 6zx<ȥ=^)pM(GLL%';W;0aRPT$L3>%Keݺ)ܶ&GTTuU7Za$92a%K˼ d'쪊rIL͕|jDJ$Aҍõpe;dXF"Y 7Yι~95_{'}vɉid7䮻k~s,X^ -??װ` >XЮ+~n-N9d=Ef4441gZqJViya<&_>>m۶WٶmXzM7Y!x o 22 ^x dJbM^ +i";"aV;ċrEKܼpe Lʥ|oi9L GuTNFFA9Yt)<8gy~u~ :Sk2o|9dy|\uU_%-}l|ߕE | `\/B/|n"C wo<[sr˂z#v kJכ2A,?L , _VX˗N8d`zٱ\  Be2h@? g"^( h5RTX .C֬Y'ݺ<2Ժl5oWn7ӣHb7ؑ-Y:e1~~a2l60]\?V*ne^dׯS9#֭czsrAT t.A#\:)Y#O!aѝVvVnό~䊖ߥ>f-|ML\o]:G\SG1Y.˗-^3Y}x` vhn|-IUYYzJ`k;|[08hXa1 .v:EA t˱\xzX/WV& h #ƏW{R^QF+QJ԰ڤF6'*/K˃:-Z#p (6u-QX=5vns}u/)U=U#HVziY!/H@@ٚ8wBݫrOׯ_lTȓamm"x<s9]-^gۓnM}u˗/̎i$zw5e^OO"cƪ:Oq}l5S̝;_= l[ikN9R~)1kff-chBoݲy_T nf{aa͵k}{< qurn-i;昙:z 﫪jd5ʍ͖tETƍC’ LR$*)g%R 7l!2ی '˭ӌK/  `dJ,5_JJq 2d|.]h}f\+44`L*чC.b9jڑ//!>P]s@P$*XR|}(O, *~@l\f\~ǻκPRT9cX*jpÇ pU LGo>2<1/UƗ?_J*q)mذol G~i=y7?"9QjrH ߃y:_(nXX7oQ}ggCU7a}8e#\'VEVФI>ep7ٝ|ÝdgM7ŪW Rvv-^&e;TӠKZ |~}$ * :`yG²}[KX2̎;K/,+W(ӭ[wUaZyͷ|_|YݷK-lzt`^V_g_rEּG|٧?Hs|ͅEE ҟ\::쳒,.KKJ;U%* ,+WVa#]~^K=芊z1lZ^]][oMY\θCpPa Kp,1Β+?U?D녅492i "UTVOwYKcG>re…H?^d%]s HQq>Lr@46j;[P|U<*@Eȧޯ~}*r;NJwd+bǧ]k׮N^O+'cGT,shXj|_U}(vRigPX1o5,)gǕ{ٳ=;iaO*y{$7/H_|1~'sQdc&]ǵnkqfڈ@emQ_cÝzs>v !xiQI=s`= $5raҽ{"+WE> xl3`@bND6V학3$۶Jrki ܜ徭YJl '#ۘ03)IZR ۶oւkZAo|9~@4j<,쀪<륲3`uW}qJVo7~w|tC2˯\yK/}<덍0ϗQށ4RiU:qkcaE`q@A뽜/YũFeU?,2`]ڣWwluQӧ:\m93Z;'iSfѰ=FYa"Bޕ.@V`XG rDΧ+/{dӏT =llniQ-;^B֯USqlEcEmIɧU`I!--*]Aa5py]Om !qY 4-X]'wSR|1AN?4QHB#Ɂdz;v…wsΝ 1r.YsgPcF2*ON̮EhDFNvfczU%VqB^͍Z+IR5UЬ26VZ޻ `;v \LLmA 9s8vc`yMSYNvӎ:p)H5Еx9T]В2"IuDTѺGrboyIrAR-6Y]w{k ßBocʫ\NlRwg"-ē/qGx'"@@^0-!s #HaZpA*r4Zaܸ% n+2$ǵa!א/Vaӭ?9+bٽ9T?&vY7nL<UCr*7 wQi=>^Vv`q3I#)ZRj]Daǝwr(: Z?+h u^ Chp$ZGdQXZa>&hqݤBcUgD5^Ά@?Ka!ʼn4C zW?Շ$B›"p[>_]ImPFRFAT~` Nv2=e̬Os~㣏Τ@:߅Z@.FLtiI`ߎ~ˡvOdsO Ɓ0L-'p<ߥǁ .bwtlcΑZIE{uO| j2Iʀy3;=,׹ \6F|eCZ#H_zNjIe(q]Aq8P5dȐ\=cv߁GN4I 1W:mHv=,ܬG^] iPCgq8PE ?t'. NW^5{{'C6[[ݩ-XSݼv1xJC}]K$IyJJJ?3`OMj%Kz|6S-=hRNk}u[qc֚V,=oq}b̡;|v H;Fv ?;,`k[}@AP]]_Ⱦbg_a _/  M bٍ]= BBiDo|@NLУ@FBУ sc,iWXe b-ssmm.YF/] NŵR:P[! ?ۿp!^:qA1/˂8b `v⏈2m3zZN?ap1xۈcUb#Q,`mUi6 "@1:H=c9=p7At߆~Xhp,X+ TDeA8 7=€6mo @nd353?/g} iU` _plэ /ZP!˻*v0|_s.֛Alر;e$A⚥,`k+Ũ8N7$@_  oc6 M͡ Ⱥc9lgmRAZV7Xe $- ح4ӻC@j#޼$>k,XDŠӡZ?ld-VxB_)^߫v^y)!j( AV , %f`};p^Lq t⌇1O'Aσ{gA8K%$^p%Nz?C[`as}*> e6+hNr vdmق E q+`bNωHbf'B>pA ,5:K\U9 K@K.4:-*dU ,XktBr58(2P\=zAׂ %@+9r{β_{Gs: !C^ `F D d5$FuT ׁbCE@]]]Z E\8:K\֚P00L0ZM։}V{Lǩ>p( H @0(1K@VJ S;2zj&S6t8♯aXu+㜰.i_b 8gs љj{Bu7O8ܜ=awٴySzT:*QlkqڃWNm3?㒛>j2h(ڎ/p-g-%:M\+@Vg]IKg}|B H8"hDsxI#0d2K#a0㓈O$sn/RWh q=̳c?/(,ճ_%xpղ~:ٲu+^D$"ȬpLm'5]R\$'LgKJ"Icc(kxSO/žooinqF\|Mbp祉=g̏l(ذf |W~hPNs0>S\f~Ih 8:Z:wԶ uׇl6etpD\7tcE|zD\Dԩf5A|󉯡AՋ%9r$//Orˑ‚)MQ0U `H**uga <éE\sx."FtuQ2ZG|n BEqL5Sh:?fء!}<:J %AAdPl":8 )su|HLOYEee|O?Ogy6Oݐmkڴig=o;@"X0H0D ʍ?ffY2YQwװ뭷-Io!^[|yhY=:K\{uukēH@'B̤k30imay$~/g[ssYŗ^ZrE=vGLl% +o~Sf5Mk ,U vrUIJJ>/NKwt[ZYf-b`OQs|9gs ۷oJ_=]鸜tg8(k\scA8 }VvK4aBk9IXp0Ztm}xLNǸmv7K.5kh#q$ǝ!}2<#=26-`#a͆[o3O?#f}lkii\L},' c-iH7/~IyEʺ\np픸!d|lYd1\7{}wY%H靺[%7'Gz){9s9!W( ,d'J`p& iWZ2Q%ykI$8]zy[K|*I镴/V96Ƿ^[uKzwa,j{FzzQSƍ ǎF.G!Æʀ_ҧOoѳt+-E.ǏʛSZy.z.VrVlB)O~ cU8s\q# WB!?Btb0?BBxEKΊXq3 pbn3A p_Cn8C ƹ~9 4umey (,.-¯|MGB})a"\jib:֜Gj^ӵY$v;_fw<$6_@67:R򜭷2 31"[hkjZt#XbÂ7S5fHaqt]z-|V6ժvX^,-W ķ'|4ѻS!iS$.|y&i~״Ŝc)p65!q]f"H0leԾ .uR@nVn ݮaZ[佴i=^W}Jx8]:-'Bkǐk`Y*DD+!\0ۿjޯW! Cn~ ;BHH9&ȇ pbN%>mANDo"k-$ι'@( +&tGa5!t ךMW$)_ub|J/$7dX\Ⱦ!.<3-W!nE^]p-}_tnF2^a} d-WEE[NIk ,gZ.uTl50X*oo?] ac`ZMfp_SEɸ\P͕@tκ,o Ӧ>^+w2ߺWnW(z-.<(JA 1Z:=};<ɗqH‰cSPytt9iVWfqT}*@]GBpIۭ߸3!KCY^$;HsG* *c?\992u^}PwC:hάz;K3 ݺ!{8jsRˁt BBh̿_41@g iɱ65-bXn Bi@ 'KICc G~9 ~,+K*C#K1"(ܳ}*idh0~Kk;Q^WI^Aq|H;5q.Kz%zlP\ߗbgd\C84A2acr?s1!'CzZ y䚓Ƶpѐ먱M uo$oAf@hI-;I5IG›mVyeeCΎ x-vǡic!} u jR~4؛&! Y_Ӊ86)I:< 3IZ\ƹ<$)Mwi,Tax1oOh֬jO+sr> bN߃¨zл\uYYrTv@_ZnP -Jk]}K͋؍iX\Fg<>a-ΒÏRot:ڍr24 \%d|L'(]ױcMy mӗrԩG/g͂uUP ܱy >BA4+ÔCkqMt1Bk8y̛3WݯiUY٩<hkCo{w{ m`)ȏ,1s# pL64ev_^,m/ sOk徕 ft_qLH*Zj\ 8n!yF#No#.%u)D?ନt:!KhctvjUל`G ;v\N[XĕH".=f`&hچ, ~yo{ {vO_瓇4S}&yg[YTu!YG>D‹!9Ⱦ)h]HZ:z^ݞUTt!2opbزDR-mgffgXL,ҵ!ߑh[԰ \o+qD()SIj%PS*I%4ZsA\ +r⿎D8c*v\V".|&al%< u^A+g}+$$jc; * I%ڰ!⊶%,M41+awh6#[qkNT(M6ƍe ~zYn]V֬Y#VVɊ+dt2YTWx`[J\'? ld14KGTr2tGkβB)՞n#Eyz`uyb@Zt4r ֆd{9sv=&۶myu7,%q RhnQVApY.>X!~0 (DVHT)dI)kАT!)Fhq=oikm<޲4thq=cbJ9 4I8nqÓGkH ˰xi tIrYg7;vпnׯAGHyKFyZGEzvu)O@)5ncDіYRU?q̘9SYBauujhh{^@2|455iִlJΝjaT?A/[*٥Sņ B.qmX^~uc#G烼 n`i :".>jL\E2CvHaYH~W;tMR]&vdU}+=Q )Y1ɧUR{Z)jEvmu<2h`5juM_w])_~_\e;$t ̗QN)=1giU\L1pIR iq\V&/n1Y+a͛7O:Qp"i["phő#65q_X=%p[LWLU !kx<ʔ,)sk8ćy4 Ty38].RKeƌ|_ƹrʩH>$//֙O6oڤT>(cv'4G?Soޡ0+*E00ѭ";0dqԯ|̠{[M$cµG>BF[<;HFt'\hfݵ\.60ٳw}f?rg}S<3 + '[ܝd*) ]DU0҇aK6 9pyş%,0O7B-]&ýs^•%nYɈ-$a)ޢF3&WiRW>g_8d=0Fng [~A!]֗cfP&inGp"r~ ./xwGVry7@\äpk󥹾V", {r$ɕ9Hs$ܯ䤓N9gKn^ߞ|ѫťv۪CC aeUq[3)w]P;c廣 س!{❡OCHvÉ^pOS]d.~* w:Us},b*EٽJI?RE=]DĹ}n'}V+^A@PHV{|Pz a>,j~,(πmݾ2#TIM{Ι".zZgӉM3.:)uHVSZWqq5#_}DEwLz* 2;ddE2a 9ֶF=g<%(ʢf b֗;cqP7@N] AH&.{ VAcv˼n%_+24noFɮ^);Iֶz*rt.Yy 68cΉ'կѿDN1M89ȣ˘1dARX\&}*;woaXU\T$ERXP 'y#9leR-/:N6 oz-صslu,_c#Aq6WBm̺ ]\Hwt3s=ۤ[7J^Ez~)e0[MsaN"H˼?ቴ*C+]A`;eu֢ d۷mJ ؆IpH5=s--ܐm9Ѝ #ffj(@?|{E\M퀅UIv2{[-yJz~}-={'=> XLLz@.8T)&w䎿Ufs_QCaQdJꐬ̤ +M)^rZU b| WX5n`Y\1bO2Ğ{2Ƀ~e*n?!33`q#iT #)idBʩ_'yK`Ru _߻7Kwo In> E'ސlXIu8laÆɕuL;jV[6+/$o#ƒ'Y阬!-s5 .}Zk|hð?1t_ wm" Ds(NVfÎKp%\;y7Ҫ}sͫ{o֟ ?IwXH%ş=$󞖼H֦٢,=ys䱇#˖.=֛o *ivq'SΖ_]+o}Gr@``S| t5,,ϑ)w;Qȅjb`%<Ɵ yǟ|*wúu}d=]Z7µ)㩰-/RPT-**Z gddNgltcHao(/rݞq5AHĦxomOsΤwm[%e܄#@tZ׈u}w)}] m/P%믿^|$.L=rZ E6m,~xW+)g47B5%H2qEA_޽7I7 2-g0zr~Gܟ 8Q_AAHR( $)*.VcI&a^ϒ{ǻRtw=fw}SWh4@dΐugefYlL8I/q+q? *ey\9RSzլ;ւqW^y)-wK\:O״iJ\6lP((cǎ/-N7Z^M\B}c/ ѣG7צqq3M-&It߸{ٷH]f@H /(,E<o7ݮ:ߟ wj8)ٳ"M6ƍdÖMG[Z;Xcs/ B#I0_oe2qinE׳A/nmv<[&G|M>|!j y%wkjW^B\u*m=巿M;: B / KŐ:i*ϻ64RQA8U3t\xjvzowqIIp8yf/^\ۧwoݧf˞A\lr-tHbuO>'`Ѱ21i7kҔ#n$7xnq:RUYA⊼ :5[kԈk3h( Z_%Q)/U+qϯW:XxiF\đO _0@G߻?T#%J*(uF\n7,%Gnr](`볲.UV__?+wqm޴aڭz@տ}p2DLzJr4x\MbbcB4B3P>]2RsK^j=l0FD*˃ ٽ[kụ٤ABkmȉqOK:l֭9(NH.+'gde0,reҵحŵaoc=}?`($Xd$`ݺv*5F4 KwfII(r%X̑p\BHsG2cֽlݼŗ^(TvK\W_u:32< + Ku \ qY.}qmݲc9xVaaܦQc\f7JwȖ,{ԩS۟}<+ 6 o\xoQGτW%%> S4cojhV\+dʕ n+Tvc5о#ʊr_~aWzwdffՀ:"ںZ?SDl"fv^<&==G8kF~99y"ݻu tb%<jjkaqF_dgfE𸓤jwJd7HV<p8( bg{vNyb_:A\qU#E\{Ε[R7#*6 :װ[}u] %Eil&7mx}]m4 5Uzmwo{闱K\pݳrWSSuL^n~!#hͺKwK\/A#O8AF:):`!T~qTq6mF\dް"v }gmWĵiF8hZD`C?9GQȉ֍džCĔjJ>Bx儜dRYUZPA;++G LaeufډQ8D}k֬74,+.*ꚫ>kw}]pşg5BΖ̬l)P8_|덍 ߿+S}[/H\ N8D  @\ey~W_Íq*GN?jf;`8 OtIEUjһɁhMM >;PðBBt,6t K@,F`:Y|YV`AM8Q"^}a9,PsG> ;'8F +9R!3;Ν;Oj+++ޛglRڭۉ^W233A}pmTw5HGܹ3`]v~gnWqBlL>]}z|<LXqѯo?7[._!tz+^)el S<yu<ҥR]U-C SUf#ɄqyRMqqMD<| 5W.#fn+t5?caǕWӿ)f%f%[nZIҕH壏86ܦL4i'q.65ShkStTh)-^P*wJaaDGYq)֓2oK_WvYnr6HfA G" Lwu2I0\k )hg'>Xf} yUR^n 2Do=!]%VEണO:YMVX5={ʄ Ł))u\5:hVR*~G!UU_(׬?\((}*{?#2k,Uիg%DsF`"W |<.uÇSg?XWWk[zQq翖}}}Ŭ }I#y+_=ɮLa G{reWȋ/HWQYn!pr)2H\5ԖUHP_~ =L:Ma/[ zzsfFŕ|/K{&Ga·tzt?\ ݫKV[o-Yy7ߔd̙r7!?O`ʠA@tx\jUMq&))))'Sd`8 blp23=z~3'reQLv(W^I 8Oqc=` 8_̞Zs{]oi\Rw[|AYd,X֒SM!L;o\e |?.s:c(ckqt (yy}= oy-x_yu\?O qڙgaiu\}00_2zhygWWUeB9o/ϤISWBKy#W[oMqkZxqUW]Vl9n挂˼\.w [Mu"njի֨SG,{_$U<ĕ%M-8H>ҫp\iira} eTc3d *Yw0ua({_Pܪnrr+7kz+V&ѕ:d)VS۷kRuj];%V Ɩ{/=ՁZ< =? 7E"яo냤n6qmE O.IgA\ 2+3G0Tp\ea#]Qa@ڲi$4^%GC2}XAaGWedfWuHugp']ȓ-9lQUI7JSs]ո}#s;H".,?͞=V\ڴirHr"1i+985R$wz}ee(ӯ3v 2nRr綢b'kaCAl^t d5ljEt!]DS*7nlܸq 2TFs⅋AZ2nc4+yXȆ!w ߂0} )E\y]ZT\>}:DE`}FM+b ׊N2jhlRuEIe1.+ˎe ‚|e#-_bvGµc}-)VΓ`ؚzU[iEKTy}rm9DRT-Hj)g\.#ov'ǰ+q}%޽g_GdN>z|s -*c2 :U=y$)MYcº1ܼsAF~˂xޱk+YM"2u +V[j6 vwEL{:Qѭq!԰`nV ,ARek "TX1tࠗz{v=U};&;N*%ťj + C+마'>;gI \Sf}4Jd'"ʕLr$fѭaFERO#I#e_CcҜYCBǐp]1] KU~b{\_6?!߂-={TY-"TXr d4[w){ 4Xać| ={PI\u[,lۺMuC_}'j8LA=Vړ(I$֊\# !GUsaÆ*"QUVV* AP%e#e[?'@nqXO- ރUu;ウY}VE$M;)/d 7d= f Ir$/~@_ɒ$II5"ހx>. 2q]fZĕ  IpۯQY4~2v85[يǎddƍjs]>Cb2*50;HrTs-KрˠnCh)-0퓐 m)!,@ 'sٷ$B8a,ꯐ@!0˼x-] Ra^u~Aa}s{23UΨ0id9[.u6vm<`bҬFE]!1F.rLv!.ݷk"4r>!~´.sAH:8Q?ݿ֍$aIe*qE> UgKv I.iCt!,JE\{ ݻڧo?-jcgOZJٰӜTKs= ƻ\Ngqs7!YL7s#z\3)HO7H\!93qѽ"pAb$k B&"-eEĉXuV\#H{'t"TXĵO0dGzsQ>}b'Rcp1g47F5Ș^-։@PP< rQ=l:We*ԹVrE/0~.h+hIĽͼ~56d8Zuld-3!Y_"._a"TXĵ0|tcJ ʨ4'aCb gܼ*}?xFm׃(j1_Xĕ 2f8i]Ҝ IC'Hu~`gAm;q"} Wp{<599/deg^+qYpL\c s{ Ϋ],X8ȀB?p\/=1ȧF˂\yAP!3=~T `9-| \a߮AzCCNԣO |%M,؁0 a>GьH&u ,`  >-{8(.LfagVqYl/l*!ӿ&8  ¾\!qUR}=v)O"d}>xx 9Ϗ0#sXeX@=9V{̿"`QZhJ% ͎0nf/wp%ı):sɎn=#ɒ YCxpŜ׻a Hj-©c831pXthqqGGKiDYOfZWm'8$VLvcZCKNc&χ|B; } ,X8!=> q  +w3F7!n:.(xAZiXpHz$'ZS6ǐL r/QuXHA-д~chE]0{kspJu4tp9,`HT$ZPA Hh7 xNʩi~@6'8O֖A>g8Ϛ bt`B^1N$O྅:Z84͜A .v5 @$N(ȩf@|)X!@j"s6gA5+FԌq8-·a{G:Zpp㏐D] i@H@\iqN9L`;%K#8g!NN8x˂ U<kf˦c.E\,@7.zZS+G.XeJ,`BDd_". ,|` v˂ _;Xe,`qYowm,t1!?Dy7.Oq\"bH<&a\}'W3a m5HUX,EIh9@ki7X+XcXe"M7zrPZMh L3v(__A/n`;Γ2lGAX#EG>MȾ&FGnBJEȫ9 oΝ$Ɛ$ $,JEK¡h4bꐼ3t{>X,.@@-~?ڋvrqXtB2Vs398̅nzT b01#ëO+C\ 4؈p3-uk׭_p"T֪`00\ #P[ }*6лAd$ I(/@JHT q0ǩO㸿0Z.,;&Yi=Bӊb®E55~SO9.u kv :X4*QVб(( Z$}INKrrXz.ݺu,f C H %51'Hvq{T! Ra4JNf&"SdG3dj ;KM\E"M]W_ _cTm<{A08]1]w.K,$_¡tPWL'x^UpJ8,-m8DqMi)ҝaC).;%DuIZե.eYcG|)z2Gpaq"]7?ox<2S?DDDRDOKh`o/WJ\ynu4! $* BCAq$֜ r06n"ʪ*L'm3AT*tWڱIZKѺ0cKSHQ/Uc4 SWRtFDZBfO5 VȓtӵY:7%x mCCpRIuTTQ8@DY\t@洸h؆+VשH);O)³0L,)bXnkAYQ-G(Jz6I'5MdAAE"pZ->4~ⴘ$ӛ%Yz!jh&-mҿv|竮;Rueؤg+v{g+WC]|u5 0 F :X-]Ng[5i%ZZ\yJJ)N H\t=7`R7ĕ:4/v>#{4f~0q]y3,Jc4|(bb}RWZ' x xc)<^D:ƥsh\\B2qEmt{AjʛZS5eDN$Y`Ӯ+ćF`Ė-[Q,.jZohEP ݖPVřy(m=t".)ڴJձqfUlڧdKτ{ B2[UFY8<4)JcX4ō!6H: EYiUuoҘĈS:9KMM4|MKOpr^뀪-"T2 ǨpԵOV T8.j]3ebB9vP7XtsKZ ) *+hgUUV$l *52`Of1+k1lf1Ǧ3#)IEσt Qcr^#/W!I\nK\N7Ԛpjw@F"'/fyn75],/"ѨZv(-6˛;rylmY׆&V%*AX&A^, Z HKtR:]$y!'긴r]BY:"hR4L:%=E̖F&:quDN퐔1ijqܢb_(P봄E\i)HpL["1,@Xs+N"W`KY ֶfp . چln $R FE!9A'rns1WĨ_מœ+"LMtDR 1$,.rkCBAh]AhH N-RHGq9@\\`5A\P+VCcJQk Gc:̏c{),JsT(hg=%n&CXH䫐T>mEXg"D}̚[_Ï ,)+́°[I F`4drjua0rq)bbT+Ig}3p! ^niް!p۽ąrVEtOpvGRIfh1j>pS *eNwcv\hz"A->~CVvvX4܀۾%.>aqui M"b+1!Ojm&$2MnBqXmDT}+ l*KUЛ r H%w1!$Tj ݦ7=DJڷ 2cW3l',:;$;T3<F7hOV=DL"[هJPd&T>ve{)څEMpxƁZq8D}kxo%Sc=/ 4znZ!X]"Vb'QOgI*Ub>IWJ"67Fј".hU@e-Z}7z k1D+qXE' C 6;2+* 7D"( YJLc0LT;Exڶs< ~i>9>%-"bBmCAӂg@Βhb ]BymQH)eqE jW )ꎈͰꁙ9Idoi@Ҋ@Zh"smY3O״ Otp ʯ{S>kgĪԺ?aO[C^TqުGS鿽8=HJOmDJȸ#'@@{B'VBN3zyge2lHilhTc!NDLilMMmM7a,[DzI2__ryWdС2p븭)(y H dxş'GZ\yΕf~s KH`ϮbM:f!AZNqXٞx{k0WLqt6t*p}]wעW {+{e3ͥk'?L22i1\\yM0?`J~g.i,͑-Ḋ Di)_IN:T=sZx~8 ?maRcgA>H%Ug'KIS̈́K#o>{691 s=.B2$#P--P/MܾNJܧd)o,%|5iW=īh/t[asx$}ݑQUSCO|QY 'kA%r'˄ euZ&6[Z/KXu0-. ~i:z۽L} !a`d+U27Hvr+#ޕeHW0AHQWdeH{DkˌrrڙgI&g̔'HHUkd?:})ŸdUu`7h1-8g1dd<7zw#Dz US_'#!q| xTlGQ5lgC9ɹH}>0p& uh~A\r%:귌zr7K10)(,i]*]+xݯ󚗗wOnf#-U9,ddtT)+ebn'8[L|ntH+6`CZC0to7={bz$hĥ`׮])A@}(X 6o(:x]q^ \#YX~}LQ _9.\l2& :Z^-Vnrhf|*3AAmY-jSFB8! Wwm׋<ӿ=obnIHzgljy ՞^  u/yW^~YB#. d 8*Boo)MsNꅛs"W3oI+/;hĥbKMMirQ_F$NDrb2uZ+ F?7H>OŕRsbC.|d[!djrJ,YX-n ")*,PTWh`AQ DùڥXb@F- U "3(5tgf\ 5}N \Ǜ7mSE㖛q_9VAjji.ߌeϨFGǸF-zg.!4\Tw-]Vńr@n D<^IZB XGdb( ^#^by1;>/7O"V`:<* iVVR8T*1Jgg qU@02\CR\TdxtWr =xA)++S666h[Rs=rqV?1"I|'+YAŲv RPP!Qذ۴m߾AF\.*n/7O) %0u>'YLa?c2EF%AR"aqLL;`g]r.Kv%RXXe4NJddn XQ*B >5F *j@;\M+$%%HGGS+W\JbLF["a[:BzRsXZW=4qF rg ocwgf6\Wu LOz$aFn/He~GٗE׈KE~ïgQ$'V1lIIISTN< [Ud22G)7p-P8@-Uxc\="tOUn!\tHZ-f^K6Tɸ:f&{{[J-==;$9岀F\|Xxوk#J%>)5%n]A+3+SH2'ř:(c+VBDZr,jRN{AYhBe(ҋN,XOJՐLfHxLheKs"yבst}~8rHXillwɒp;ss$jG +Arxs4IT$4^5dHx#?\WzmzF!tNdSS21$gukeyP* b,_\{2utS6Ĝ\ʴc1М`$頬XQb9ObmPC~ORFAƱc<Ղ1Jxcʱ\Dݷv/ϩȓsf AVw4J+Y./M9FU-S#̈Oθzx)EP$a>~'ɘg\Ca$AİtxB r*.)ِ4@a1bAlhhJ6  3]fqaIQAWvV/fwuu)אn+SfSsg1vABpE'c-^^k>{ǎ.4p())cڙtf1^4JOX =55b~RLw 2, E '%F8d],/+Uv*ZeCΏiNs,oa mieC LrA!9TqaԀg0n%j >WJJx0d&){$)"I&h4-.Ͳ?bb׮?+,*kN9$vw>YVU%q 2,Rk74rU ={ X"CB(*d+F𨄨N^TsT|ؚF}=0bSktLQ1[-:5i`s qixW(r433A1vEEIHDC2&[mmp"Q8(:uJ>q:9Z_/ .C1s`B1qETGQm8Kh4$E$(qZjE2,`5۟MygϞN>E14Z {}xvy$4QZX\VNg++Lrʈe=%KT$*ȨRd9RW$-[4ýd)L2 O&s売cqsttސ{P]K"&4ǚ,6[l~15=g}عqAE`w < 7 _A#. )+.wpddFʚ`|ӟ|1wXE ~eareR5%#=Q<&zz}1`qy>4VHT AjYغukpa"JG[p|=Pķ`\s5+GQ%] {0N|'Yqʇ=+bwd$)8 aZի DZЈK{B"]R Դ4qDXǬeTĄ_*#U۽UUCOT`Q=-.N&qXn/ 1OBfkZNsͯP~{ln9|%9bkؿH,y0bӵ63'l5:H>` J>#r\-Xiؽql/)4QWXoߖ[Lcv:mʭ\y\pg-d&8 3qքVS#ݣ HBoЇL&ӄbQr9fD'$Q3OIZkN+Sb6(s)}= #FIv[a_اR;{m1hwSqu.)|n}F\. >njϸyQ6g\*AΙ HL=Ր{HFX^ᇻwbk!A`0P+a`ѕ] q-MMد>ɆDEEw,FbӰQAqJ }鷹{? qih(r~p$Գ'$ q25NI'-fعsˑ?t0DCW~js0쩊މHvr{aa0^IPt;g50Ja`z4\T<7KeU` bAt8< t4OcZ߉!x7h?Ձp.p~.M؂㷤)hg0oF\.:ʊkG"*c4N[-\ŀF\feEEcyv 2z&ci=x{p`ƬO/TAK; ;:GgŰ7v<Ķ4ZXQm ؍UuO03@[).4Eq54 sޝEPqif\雹S LZH;smsY:VY"t )h߉?tٹe.GI`mz"FS,Fb"H#s#3u(QgaҠan5'û*ϊD@< 3^~1o`clc7`kqq~cXl v+H[ ,HG&2wd;0~hkSgS.4h i@̡WaLt[#0!%wQdQmg!6&6 IENDB`nut-2.8.3/docs/images/asciidoc.png0000644000200500020050000000341714553676503013743 00000000000000PNG  IHDRXTsRGB4PLTE     !#! &!'#)).-4*0073;### +/)))#.1).0$16'59(7;(8>666678:::7@8A"H+am>erCCCKKK@W_TTT[[[D]eIdmFgq@huEn{KirGp~HrQoxSq{bbbzzzJtNyOzVvS}Z|\V\WY]_aecfjlnpr}|w}{݆~{vytr•ƛʞ̡Χҧҫ԰׳ٵڸܿƊŒˊ̒ȓ͞ևӈڊ銁gbKGDH pHYs  tIMEר3TIDATHǭU]OGېZ1UX& %;bE )$ld- OԒCTZ;4smPg̙3w?'6oy_G 8 ~‡?'+痦`ݝJ\TOgʠ.oo~[Ba?/ (ϵ5|N} ȱ0/ :!ʙ nS\Bk烘o$>aDSÅi'ui.kapjS4?D-ثPǖֲ:mnĬi-䎹0Oq8nʈcvLuqv|uhMY܌ƇK53vX4[_0tY*"9NH8sR\fc뚆pHŚcŅ.r F˲073<: 1jօVm.- ˱)ٓ諡MЩB܌TfYRgycCXeq.е&wc-uT̿ੰxGh V y( z[Qʋc`7nC"]qWmޒJgYU씷)UQ~h@QT7,74ʨ m7O;FҠɊ(OEBP*eWyNTB]:6X[wEX< >~AyGf!X+T&yĊ%Ng,WC"?63%E8i9C8~^7 3ƈ b&L1C7v 'u:.SYY \pyqLv+\X01&REV4qxoQ7NzPPg]GǞgx\6M~"6 ~*iւ?r,lO܊YhgIV']W93G8Z_7'n]R mng [nmlio\^b_.u}f^Dvt ȳ@+P(cl?ҍ+VTO Oo?. |"b?6澳%]^@)g-J/*'4twʌLN B1 0wt9>ycF9rZ9;=J*2VT侼<\ |U]in in U>PQBF-ISczGݬZ5tFF[9\0)ϊq`ν[GF_S#%M]A;ӛGY(paVq22.s._<iDQ(2A#*EQC88H%Mi44Fw^Xz&yyn Ζ-dR Z-Ϣ8=^\E9sS]1=$Pj( $C#Q>d?_|`6s*lX*r+'3 3h:U3oS&W8OVhDFiDPf %Q0$@(5+uȫ4uSUڵxHF_aƘ51jdeK\w:&\*`͌,'m] p"#4))߄W)H4d atP!oޥ YeƁ87Ì(#V_x?|rЄtL KŁ+ ߣ\SC(DLT V"bB VQ[/^{S*| *BXyFFFpJJ"JJ{ VV!LAZ^*[cWf755J}^!ԊKh~8陶w#wM%S,a6CanիP"H3Q6]GCC;S>n& 1Xqmdz=fFnD0C¿"۟"(q@ZQ҆MxԆ4MCh6Hʫ&"F#<&0LV2{Ca"y<^g,ATMJ6Ó4bva!@B@_/^ވaD_/`gH#2,@ilw7ױkw^!pV]O dҫs" աL KJ &,xf 3r#0ģV$4I~CͶg^ی<,ka14QFil3pO+ =#n U6t")#FE ]R[r2%TMc(JiMבK@@2 F3Loٲb*+|Hc*;l&@ !:n.&–=+R1RHJ`VS4ơ3KZ@:tFmqWI4hdf?n16lEnw^27*>^[͌#H#̏mfxxes+HC քJ %eUsn>1V>tAKHieEawua=ȷo2 Rw9< %WERaZ^6u2(M!5tif3 )*J5 !ȘAXc6w hk6LJ\Gkl9<~~}KY{x?ȳrRU^DuyMr:@C)qn;Q<%77)P( eEE%%aIZJ"<rW_=;|IE9pdwy'q+Kb Y2=liw/QqeϾ^vfW1vKޣ( +mT4]Gh5g o\Ľ !rPM nm%7t:\|^k~+v7v̟M]TWfKHJViBjMR/-Fh:B9~`ρ>aƣltu/R],K)ʖjNӮDŸifAQ0M@?nP0睗]HQ04:n{{ٲhއ''TfR35 fTfR`m9i(%JOV2;X HiIO<NfFdHzڡ Ĝt.&()Ys 9C$cP|49OAdŅ5^N^A96±^}#y0ͯŬ,eM&-ГV5կfRm%#Ldm}:i ,P {1{VeHMЏ0O;'﹋Qf} |:5=H#,&WNZZk6pb0bJ\fw4Rj:BfU0g~{Y.b:; Ę^Zhkq\lۋ50L}c{H) (e^$$*?m_{)_n"ͩ0"?ڜR4q;TXMlb,CYz0Mͩ }|)%<[2)kBWHjWw0Λ“01c#Piu46}:ј0eGa5 i椢{(gmlܾTWN??} Vw#4;A`rಅ3yFW1a刔v5(}Zuʘ8mmCTW&cN⭖.-Ȥ7ya4]1L`{ ;v5.=CO5pe yVTw)Y /]nii9^,--Z.NB3mM@AhޱI)Tc5ٲ?pG][0Po_R.[PMdm˨)ɲfj64%rAY^{w8a|I+dY(P28s iiH:˖s0~RĢQڼ4`rorDfqCGym5-8(^'R(D)a<67lm;?z*Y^' 賀wrcN <89x?#2ɬvYn rBi`2/i(k(ҭHTq}Gywn5SٰeUUL+/fb JF_?ý32Wjϳ RHb/ttt+H3PZR۾Ɂ89Y{4u3^ >/@qi^ey\>`L_?jDJM$;j;XْDZG)L~=RG څNg}/wnVgW]5kWVtD>j'aIu1ʈD?^nq6>SpRm|h14j* ~וD,3ut[?h$ZJkŔD┣@_2(dOҼ̝?/Tۥ{ۉD ;M#~v;;{Y9,X4mێ*]6˨H VJ~֯1 @^nI.%bi-$`Z ƇNt5} fq`ҐomEg3|=1~i捺nt]+< B[ u 6M,T2Ƒ)InzFL9m.~K8jYq\Mhd Ssg+s*~ny MBP[ĢI\:=q#L RY╗w*Gۺ|Zmmue>{pܹPV+Z;M H'ˤwpT--;gAJ+4 08eiUoj3 e NbG?$+w,&;7:w'cߺX &fBZSeӤ*S%c ON,+k0cFjL)> ;Zt~M݃r- ;PfȄL+'5Y ?d;/Ã<7>wtE!M!>:u,\z aWf Db&M݃|ֹ,^<Ij攱|E5!39o6.pCCC<^;U7L#X;g`e'q皙3 ?.5Bcc?==a[o`eJlQf$ݫC jjCY3>Q^\ .D&wHSǜELL a.Tf]s{y~</.4S+4%Rde'%l1/Z[[çc:PڗlmꌩƌfJgNdoT؄Smyw;Zc<,,cDŽ bTU@}}'+{V#(~Ӈw22bpֆLi'{lc뉿:Yqi {8O<aKZZZzsV`Sw6tWOY3pL%R`p&={8W bF">nmm>'nnnхy |Ai~Ԩ1 FT mc,?ig-݇> ,%iC}ׯ\O&IjlSJѳ5BjRK1f] ^ڹ9m;vL->.b;rx$~ScJ}|.9?M[\\PơܜnII'uzS`SK1Q=K/~ć6m_{›?KMUU>3{v%2T]B˧*8z70]-'ByN̗<^‹?WÌlzu[ߨSZlnNjz>UULVH(dO{ٶ o14OzNBQ l]w?=Y^Es: 2%@y>nБpsG Gu֫ 0aB$~R|>[^+BP3qFp)L`Hm0;}Nܧ<9i̔iNw\|o:W_EguIENDB`nut-2.8.3/docs/images/warning.png0000644000200500020050000000621614553676503013632 00000000000000PNG  IHDR00W UIDAThՙypU?۲AH!DY[Ǒn A0#a0caSeBX"B5:"28IJqPmцaz-3K{ŷ&/L3TR߽{}bdDBĶEQPUEQP ʈ H)eww7۶mò,,ˊt*l6UUU̞=VW\9bp+=== ;v,u]'ىa߸\.RUAGc<?7Vlv;KXÑD bhUiĉ;`@` (v* w+cl(  B moK#`)BGI^Ea~,zqr:/9aṕ:PUͅbbm|}\ϴ4O"0x]Kh? )_bW9e_#+;ghB;Qm 6U1ń; z0Ao'y)  oZ)8 Ψq,\;MͣkLWnRXD8QUI186@}}@(TNcAMבHvL-0cʥymq._p(8pH'򀥠(TEEP];k%mJ4Ӂ7q`CH@&άCľD1ƾSnɓڴ_:X TdXnj(,BuP-ࣳMo7|FruIفǏS^^D@JIQQ3RkpG,1Nx;}tAǍO}^G?Fi-i766h",X@AA.+.eSS;wɓ)snKK ~/L@;R B cb"8L3(;})e~Xd ӦMc֬YF!粒^u I_ύJYzK)c躞GiӦ1sLJJJe.Duu5NJZLJIkk+6n&I*g,YO>@ӴF֯_fSYUU%//x-D;wx`?TH4Uٺu++VI2aAe='sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxw%U{W7uTId 6,Ks' <`<03<=i޼  xB8l '%[%Yb7\U{Ǯ:۷qS}N]Ω;ko)@~cKLXX\\|+_[ͥVhs#G~iaa6࡛oў>(TA|OO2y1k1/5TLn_w!p/Vj5uڝ7?~Kվxn,m&d:csM`0&㗌wpA1sNp Yh4MjwKK _t߼{/𽅂񲗼lƘ%%5lJ[k}ͯmv{ _Hn<|?q2{1&0'6Op :td\ 6k-nnO~vk7t <8xWƘ3{ ̥ۦ')*qFv-#"DQ0 KV99* ^w׺qH8In{n֙ L> P\vsƘc^gl^2n-ΦV}>sssT@ čBjRqKs8~9K/R+M{~}Ik}7;^`P Z-g94!1=#=w J7KJjjZUjF}j˖T*V<(c(t= ˝s{KZ"M-g~vYW}:eKwol}>(o2a80$&iUVcHKF)R$RFv^jL\4lټjorh=* I眼mo[@xL["%WGA|64M3W1Z#"J "(~8fi~Gy mRlQ-mDVÌn=Ήrf8'h폿m+ ܓ-|ӍEA|69 ]Ԧ*ߦAyK1B5umJiVzD(+J%JRXQzTF^ R ~~7t[FA|$F)N]݅cNAj[6԰#P)+(^KcI>x鐖ֺE LjxY#rbsΡ&"9KW ƨ'{kgJFi58οWk\)?fЖQQJ$!Zsmf&J\XJ)¨e](^'2W׎m߹锳d0sb 5$GQ17Thfhwy$uݶBīRuT:%܆:Vi&OubB"۾;ߧh[ JdiUW"3"N=yA>T*#_)+˥0ڔ_#sm\XXH[&05cr\ W`#Pֺ̢Bx5W1=7g*Ɩ^b9߸NP+fv%4dLUkf I\uuLC'||Z gPjE3Zg~^]rɥ۲ WwP_ #M1W عkZ$Imo9Gv7s~8F0,[8F/U"T -j= ҢQ?̚} W'1`4ZKh2(iJj-a6ٟ]aM L<%Iڑe"(֘W_zVmqOuݩfB& KMFѮFf(FJ>'-dZO(o @ZnV W`ð֎66$IHҔ@D4JwD)iHZ6K ǚ-Z-4C3_ MVr4Ԍ1*,Ƙ Wx ڑ>  A6Ɨxnʞ)%Vw1&C07ٙi.̭$闬ۻ.vVfnj|%0zd*Q(EQ (RH#˻XX| lCuL:$<'$B#IbjEѨMufRؑq4co6ZcQTL\Ea0@Â& M&ζ[6Ug/y_Ρ*?1==EbjjBVgǎLnʺ$ck%Ib $ C(*Z#·(;#b{VhTJt#\ł&0Fqu$7?dd(>B27v{0jf7o&I,"^vI>tve$@+P}Ja0M9$^N|(oP_ ævLTiųvogYfjUt1t 9PB*QHZ2j QT ֠@l (g{!:iN3՝ W`#XΒV3*[fu"uW]2')^< ~r3xE/NK56L׫LjԪe*Q!i k֊wVh_v1fLu `uN( L<5!#c|wd+Q`ke̍v 08)8nw_':,,o駖jlLtJV^R"!!ڄ53fΣG#ҏK9DUA| lΎKY[ i$ "kS " `l4!$ qviv:_}oYlSV0]2Өtjq(SӘnY%n^'\V6Ix xcE( /<$I\:(x^ #27mAKpt掽 ˆ\y矿K+p@yi{?Vg`hqU~U+6;A(!b:̍X|< {\H:|!>tq( `]^mvvcGILj<]+\ EA|6\n~SWD᳟|?7. ج)oSDiVȗdEt&0b̈,~dVZnẹi,8.&0`D1רufgT%}޳27zq-)MYZZ4-Z=R)ܨҨUhT**e*2RDƄi{Z,p!2̢* Ʌp Gfys0ƷQ|/ scEϦ1A}:.nCGvi;,۴{1J*S jzJZZ.S-)J{]Dk۱ŅygXZ\Rl6lc*G_ Su?Dcr9!MRSX:ӦԪU B8I~z;]?Nӥ[ǃK)TcDZQ h&@ pu'2oT`FOu 'AJ#T5u>-p;n2TH]B~ dA*pF@D FjSD.8K'w0<}]~7ΖR m؉ΓvElok֛̈xz Mq2b[ɈT!YHJ$y7(KLMMm6x";KT ʼn|4h#/+`{8տZ~ W`keb9ͭ#A! _9튫&cZx$i,AfUyMOUTVl.\DA|yO1w?DqQy8H"!4fQr01.ifj)d 5dHY!RED z,-(TB8't}_}O')q_'J)XWUJrDYP*Qh zB "d9kDRc3|]!Qѥܠ8:XM +dc|㦔RmsSKMڽ.nvO%NSҔKJFLRZ*Q-(KRR 0(0.hcؾNsi?%UƘcSKZpu'M.κbQg r(Hgn\pt;~Rژ p·X눓$c~Zt=ݘvGۣr)V)S/oYyM;EB5 pL B&<;(R&0rc$7]Uz~}m9q8$>#Wp8 PJ&^B$EeYx`ӄ$q#NS=J:¢X^h::de6ڔ6FC WwP_ ex?_^aP:P^ZKY&PJAo.̛鹹,dxSOg78z9ru]ΝÔ0J%($Jڵ͛&MrU|^n)VZ uU7(Fa$o-z[OʚEu2Y@'Rk۷ 7oZy֬R0(^Zi\vjWqqo%iѼ,}S+sp+&{2>ӖVCro9`iic˖ͤiJT* rp:C>q 4JyQ(*2;=>߸jEE <#Q_`h :wOro=/k6HGܦM%ȥ2" u EA|-wu{r ]3'-rZ{ A`︈O87u)Z>`Y87P1KdC tXQ oPNV lkJiHCG$ϘZ74){4}0rE(" l (j!JEY@i\[|N-ޡ;: I!ijgǃU>[M +aIxJq9vn̮[7H{UAs8$iJZ;w"IJ?_Zʽ8t4k0TJ(R }[R.y-<0dqI)vMl-13=Cdjjfsz}},՝P78,"^$(u7$igȒelĄa) uM|uY9Gj}p$IBN^nqVKpbĉDZdFӫHA| l Xu֡%MS@ AbqBjC֔JU\6xR[Z<Ν~yEXca] 1 BA|6,ՊوeX H2b)\6 uxT[Y;`( +קh:(, BA|ꪑ5- "rٳB8رE(\qsKVi#OydE?H...}(& P0<'J_i277?>$Y~D[.vW=~-#>mpu'V嶕T?;nfѤiz F-, BA|6,oz2kn^L}9AĐ$}d-m򗸵89\A|&g]e<ϔ>ql֠T&Asp~ MVhJdE!i6ӉBBCrN #8읬0Ե^nk1!l1՝LW`C_l̢ӏYt.59eظFk?d&a~= %_L>+0!,ک0i.s LMOpjNDHk5=t0?pu'd4sÓVKvleuFxmz!"XHSKj}ݻ.ȶ֒ iHӄ8M|r,')qd;'m_(#O,f̱ZKF6J}VGjq>yZ\r|߹> ZpiB*B?#K'al-Ox% "0Bk0ATjujLzLtxUAl1ΦHl뷰3xvA|&O;1k6xn Άyň$-A_Qh !m4h՚}!{4Yh)/̳;w`DHEjE!N)HGN$ +AdņF\Y5Ͼ`;vd4h?rXFCϿEmgNp6O}8'Xpb6%I=gq?Ǧ^>uNGoo,&kmkB Y)] u։B+10*v:hmR$I&bmIʧYyf=89CMsq;VHϫ1"ֲt|-XVJN +a(=21{TPaX0޶P*H# IDAT =nl谰& xdv*ņ֦<_6Fk?c vWiYP2Z͔/{x>oޔ*fu'M..e,z`2Uj6hp]w4 /6䃛Պ纺hee"emP_ ûÔ)n;n oz|!>`NY5x]DNO[W`#PQ=A1׿ߏRqW^]glpҁ݈DU& '%>y@MD/b>pHDgh*.'*lZl캺p]nkwgn>kZH$|j|rJth`wz~Rw࿅e௲~x5{zg'_ gJ_73JoSPbNfK[l' E# 0 |͍giD8f8#dm1-g:>PB>1U{vs.vIcjk$MU37$q ns>|%rCCgKKoaލp,.,p=q /*pӛ^=UXU'{RJ fȽJ ߀?4s%0Rޟ /ȿw z:S,fAɷxމMq8M)};w4u䏣ec}0ڠu BP Vij|ֈF Kty Wb g1v~5ew=X]av; QJE1"|E)u 5E䗔R-^`rpSLBP sb=lkQC{3(­!,/WQߤȗ]_ W)ەR =1\ Zv&N4z/j{L):XDRJ}C)0~ۡdn619S-T;H]MT*$Is$I28/{ yxʞN =W_>eĻG1ALr|OOe?_NJ|"Rxs2."G)aUyK\y(LgunL7W !W etXw;p=|6KUɂ: .&D VqUE'W.ϖSƺ&7O-&y<& cw][ׯmLM]ff~~ayʉ{q> ;s=u\M7{oI_@Nw~aa}7pC| 6qWqOzIYlw2yXe1}vM5tǏM3e-8H\cIF^Y80ϡN>r~s1jKjܑE`nzLH΀i~w˟33+ '<ã$ O5x$˿w0n v{ד{\t8I6[ͯOWY{ >~|Ϟ=΢>vzogOޫخ9Ǟ=7s K>oZLs%HʚsNJjnVhH rWdOu붛ܱphDz>/~|[I?H>+ ۴F"abnntm߷E6ͥ%&ͥUیF)3{\ezjlJm^k>O4w͉4˴ܵݻw__~n5Yj("f" Asv@vήuv~y7pC>7wR4MIڔ0 6AA͍4Mp"c,z`]s`SZtPJh!&Bu;oCkV WwCx߭ZYbz+xJ EiniZ$qLcjٙiժ?V{{2QJ1==GTwFQi7V.Vlݺ-s?F7 \z`yv2W׎Nj,8Yݜ@pepV6A'6`zj@3|Pt|OBqឋ^_oLmFk!KFQ*T@o|JQivڵ `fzzMSJm~L R/Ϟ9oFD֕d}Α':/R'<ׅ[** vÇyLMϡT҂b8flj8a՛UJ^}ȩ(fySD=aڒ%'E ۗ׏Y4u\z饔7(l"lk-v;wf]\tň-*~|~n6ږe> gk "W(~,]) _ȷRJ}.\>WRׁ3ܟFDX)@GDޛOA)#5JkvzJx=^v XQJZv[Dl=C<vjY|qT.B֊mޘ‰ʴd`)pȜ]|npKz$=\ڡˠP8>x17ȇRoSJM>'b?y-ԭ,e>_[?xߕ5f>*"RP/ly;`Ro?Ivň]}G).5UDFtGؾ}\+J)6oģK.pթEʊmg>ȟgbŧYT/?4?0'?TJm? ē _y+ZKdd |/=azfRf5;ǀOr_Rj4?Ӄly%mCK^K^rz_ǵ^ m!*{I`')htduǎ jVKY{v^]Do[O&Oe l~ē˿нCo 6F'5_/]|^s:͞m/'J+R] |~sgG#ݟF˭ZetRD)"u6;?\K?mk6V|Fqǚ|pjuS!|D-'Ar~ 'ѴFM! Jr Ð(T*~ (S30 T :NԍiuzTjա+?vkRd^ '?&㯁[ExYlm%F׬|o[5l뀛D"ly/~ Pw/OD;r%}jJ|tnv{;;o׏ru;o;?("J8ٿo?/| N~ *^uA'2;/VdM>_|dI /M[@#%_/Vh ͎pm&bɮC@uj<[X'bEhwa%M,6 9V΢ank'~7v;Ԓfiؔ:#Zbs}yh$ׁV&Dʁf{ 0J'\ǀR\;IR;NDlgdYߌwkGwWJUܕ]#e(1`R*<,MOC૖cj>uǽ^hRұYFkn'4z3c 1Fc_ D mjgv1rT*1P4]w:1;ژN+1;;4/suEz+>|?}?N+zOB pwEegJF2~lx]"r ]Ve۸/>v'>tzf<͎lL+N5y]-y~$emiiizrȑϽ5zٚ^FD:˶_3V2V"rjq\XH7dhxA S^qS EX.1f1L 0{cV}#gm߽T*~?pO̷x6vwa}ᬵ271\|t:m $wr$&CālM@Z1>pYcFR<;L!v;n7,֢1;QjՏ1 ȗ]㻞NqtO~"G˟;T]DZT>O~vvnKsiL5MYy'9gV `}ڔ')qY;f,k=L"r>",[nu-e W UXBm E) CuN:֗$ qx C4˱C '5"1 %6\s==?*ꗨk,~7(z]&V#leWخFz\g4WC)%jp1 qq|{N?F&Xk`vзGf5x­Ϧz΄2cao]1AxZ_L-w6/?x&CicN~@Zvjq|Fu$=ʛzs֭PʗD2[)L,SOvw$hs;d Z|̆I-sue1 Bwm_=JKgpNp@Pz= ;۸~ pߦpm=0pu׿;˿%#A 'E<-3Y S7X<Dy=Xh۹@+v)D d5s5;K뎿Ei5u| YԈJ:O3<-$~+h}=hByGh@X0`<\fAAzJ#Ab o{sp]3A5t*,dmel6,/4ZgyRg5Fkn,Gn\w.f&e(W} s_DR Uz}ߓ(K`f@Sw0>8 `3%@{~R]w=R Je1a';2JP%G̬aJ/_8L^g{46mۭQOяǘd-\Gp-ER("?"أ쏣q ^#IR1m۶aL) g(m#3tz}ډcVtڴ}\ЉRw^P .ܼ~;x_ _G7"؎~ Tm:PrK8|Y8ۮʫ,8d SQ6S|R=ҏnO{tz ~8NH%%`Phi% DiJc(TXMRݏtB }~NOף݋z4MJZLQ-"ʥRQeǦi0"B:y\Uk%TWij<,̃IͿ߳v]OW/[x?3 *xg<-wuAͱɃ|0Z(JaR{JQkرi( À01Z\'a䯜ejȺ%4,(^]YELe]EWgIyћ|YH_\{nvKNMrV]3ʤ֊-uvnO IDAT[(3k,1>d̍ /v6&iBqwAv\u~scdY6 L`]l^n-0L6JqlaM-2qоOjyWVyuF:%봳x{_|1om22G@OeE0>fA2̖]jZ#fɠ$~z_g׮:tGZtK9B_z'+Ws&''i6$i6l/~m;ޱ`g½M6ލ~ '(]iExɍ'o98F_8uT*q?}?[~A޽ں lV>4FLitm:M-mv/^aʓ:D[+Z`o^=,/kmW[?qlb7I@\x=Rx&3@qɊ9|RteqԤ^uN,RKյ\w\T`x9@K~=8X$Bɨg7M&&&qTHb9ۭZ{lڴ'z=]<>8v?x(?ǃhZ͛7sE V!9/b _ݳg.:w1W(E(U,iY*C#jG1Qzhg0u+y}̈́Zb1Z`:KgE0GB]VI\jkͺO5Zq͈pW;f˖cM8Iڤt2"_'֭[ǭֶmIܐcONLNcIa-b*Іe!ԥ 5]܃zn)Rϻ Dk(IhV\F7FMb$zL)"6 GJhcI i&zÀzE.zܺޯZ~zbi{bV f[`Eqb݀=ވ sYPL֖xmvјj`&N6>1`v칽'߿,t/QԊ[#۷wm3V%zd7,3Qf8u#Gn@xƉ{\aql^M3DljI$$bULXISj *:eX JƐhHAIA)PX Y S KAII0T 0X i&j1lsɑX', +JD}?73|OмhDشy1s4⛋B1jk{OI\;fš"SNo$)8WN$7=9q xTMBWkCuop$Ke+ e^}}ݰiSJQ,*)º%ι`Se$`pAQ kC %åHkbmA A!`cN)Pnj+Cѫ{X\|kZ i0N'l61GnLB l;eg M~si-?;VEe1'QaoWe ֘DFA@9J"3C%5qJ@=6L7RВЦ -4CdB% XTl^ϗthlj 9z# dAV)%@#xI|.#ȉ~.F}"rcsD[kRQ(mAw*IlJq((AA ԛ)O# f-"bc- J'==Ytb:F DAXE!%RkaǍy_-s"6pmti_kW\a@_bczܨ[vCő:*J4(XL -Ϳ#*=.\)k)țoD-[vY##s8ް)87suJ T%5~4m`ŅUfAZ! 0dhpAz;IU]kaz-@J'c@.qXnEw3O7=n+9n\ H?s"J"r9{D*׈4B^Xh,]؉/gLy=x:rKoK{v+fϹu W1BKҞtY /  HPZ+p_4yta1RypZ'͕CDr%P$D~ 5nskL#ߍ(#IDƷP簳j3H|?zdeLX(ЖnzH,靄1!r'AtLT~N *![ d]N ^&e NjO*񥼫% d*%=i+h#DFJ?MQ)P %.- pJIc3]J7K%'m4j)%d kn+Ci44Mf(h6l3lZ.6/U;o&NrVvk,iZJrP7vcșw^%?qЂ T謤SES4Qݺ\%rJ6B $TB0HFZk0Wz>#5<+<`skپ};C,#4S"(b~]ѺOc[׽( 0`ttkopu?###>MgqsFXrJ@̸ȮSN5QB%lf%^mҫET% kjF A1Xbc *bTCSiJ,@R qB5rCƺ徵)`K|)΀y湥RbԛM6c.jwg/8scp 37Ns㜂P^,  } '${LT#B _5 H@G4QN=q!a\RH-rd9$`%D; v'APɲ"(AA)걦LP9@ 1tbgHM]abF'ɬXRrn*E*_Kg7%x#H zZ&v#!$i))pԬpΉ81&^B)T4bM9TL&($Zy9=%%ƸUR0\ i Dwlb,nxYr]6Izυ\' cgU[8jM ]{*j* R ['!1jUE,pUY5+R.( M:7'Wdv+"ZW}XSk&>:_J%UV"R,v\KЗN"f.>9I|=N1ė:72f=>{}B)î~&f8`0D@iK-֮ONM$1H7~$5/  FL5z4HK;#PG֦|y波/ԓc97N΍^AҽX{LXSᑆy(!>/SaD'G'ַh4yW[x191}}D&1j*wyRHvc=u?>V4@E(֓@VSQ[{Hpup;1>XLh$.^Α, K-fnpZ"9_v|X4Y.sO'Ա>?noqj*~y{oZͯkmsoR?cϞ3W )zf"p/ ;2Je;a޽\yՕ0<<#>ʡP,{06+Z_'/>"4/8Yˑa}e;^|l G-icvwn f 7Z^V7D1][OJw mʕRr6t A&!ot_6w32!*(J%^X!x;x5oŗ^'P,vbVHdwjOnmV0Oq+ٶud͚5z\A~yZ^c~IBR^dDYd:.n⥭tj,+2ɬes'rd+qaP58rH!PbDFJS%y׵0F>z6G/ccK%L":uwbA @|;"/R_~u]wT}]g[VNk*PA@X(6,~/ gUmѶm e\~'rN/Ym{oB9Ǧ6Q2ϲBrB8"c1<:2ܨTSO|Z:>CЀ\8K//IFGFٵky糼e'ؼy^{-oqaZ֯;,d:,[vؼi3Jm[{nV;ﺓ;{O{5VJ[kT}-g&fUϬD;_W`6 U:t5U4w;բΖ#FۦζSUeB ]6ծR>hJDId) IFOOq+'$Z gUysݷ~oMQ\駟nZ3Ϭ`rb֬%7tzru w=驩 `?'SJ}ehhX΍(XzuW?zm?k-WOp: 8 , !BHX\( DkM`4FzzN*iF~m֗N/{#7΍Kvnlڴ9‹/vڱc'۶mϴRchdqd ;{9rg~O}  TґImxy]gFސb:sNkn2+0P\Y9DI!bAr2>t> ZSULAǘDcUvLd&dSeQH+ӟ~9F)E3h>/"a!dݻGΏ})j>{kT\U*R)4׾nz]y5Z6bzzj0I޵k#_CgCWEV]I)uR @dPAR]~z<=XeɮYPmI#XkY6Td# E)PQ PH{mh$(Bk2lۮU-o=|e zB?HOEVJѪB6KurIvjBZFިG -^ V]R#gYr' .`@ZҲ(BP $ة, h&@*B!kLhDMDsJtپnVkoX8WqȲ< h=΅|] >9P:/l @P!6$Zŵͦ wσ謵ı8ݭ_җn;/3}c^V Zn]GuiW7Rh( >#cQ$Sڮu[믻l| )\{O7Ǚ>B _;[% Ek , bY'yŢYͧz7:b_Ʃںi @1R(nVJ06Iʕ/>ؼ7?~|tiX>Qg,͈%RJ:Eĺ3 CbŦ$fL{Ns,i {΍,} / ^={e87~keRbBıHItWUnbUoܰD>=%sO?V\dj /d(^xK9bZT՛c;4617bՓ+7nKf}w喁A /pr``(zill8U7 zIDATuc}g%j ӳGA_=p_u}ȇxR PT*]]Zd yrDWg룏O|}t;**ܡWJofk佬^J>zO|}̊{Jw+UJ]#3$-[ }y+Oc􉯏93axⲧV?V^o5Ƙ ԛr/o|Ggh}W[#ÃGw5~: M:+.䢫XcѣO|}|g.]Mx饗֜9DZWu/_8~@G\sub}1K_ yIENDB`nut-2.8.3/docs/images/ci/0000755000200500020050000000000015001555413012106 500000000000000nut-2.8.3/docs/images/ci/jenkins-nut.css0000644000200500020050000000427714777767434015052 00000000000000/* CSS originally based on ideas from * https://medium.com/@elhayefrat/replace-jenkins-logo-and-text-to-your-choice-in-jenkinsui-f7d35daed25b * * Customized Jenkins+NUT logo derived from NUT resources and * https://www.jenkins.io/images/logos/hyderabad/hyderabad256.png * as published at https://www.jenkins.io/artwork/ collection * under https://creativecommons.org/licenses/by-sa/3.0/ license * * DigitalOcean logo derived (resized to readable height in banner line) * from https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/PoweredByDO/DO_Powered_by_Badge_blue.png */ /* Custom style for Jenkins */ .logo img { content:url("/userContent/layout/jenkins-nut-transparent-bg.png"); /* height: 40px; width: auto; */ object-fit: contain; } #jenkins-head-icon { display: none; width: 0px; } #jenkins-name-icon { display: none; width: 0px; } #jenkins-home-link { padding: 1px; background: url("/userContent/layout/jenkins-nut-transparent-bg-40px.png") no-repeat; height: 40px; width: 54px; object-fit: contain; } .logo:after { content: "NUT CI farm"; font-weight: bold; font-size: 24px; /* font-family: "Brush Script MT", cursive; */ margin-left: 20px; margin-right: 200px; color: Gold; line-height: 24px; } /* For Customizable Theme plugin: */ .logo { background: url("/userContent/layout/DO_Powered_by_Badge_blue_140pxW.png"); background-repeat: no-repeat; /* background-attachment: fixed; */ background-position: right; background-origin: content-box; padding-right: 14px; /* Glue to the search box, to hide DO logo plank color gap with background on the right side */ } /* For Customizable Header plugin: */ .custom-header__title { background: url("/userContent/layout/DO_Powered_by_Badge_blue_140pxW.png"); background-repeat: no-repeat; /* background-attachment: fixed; */ background-position: right; background-origin: content-box; /* padding-right: 14px; */ /* Glue to the search box, to hide FH logo plank color gap with background on the right side */ } /* Match/contrast color of DigitalOcean logo */ .page-header { background-color: #2a2a2a; } /* .page-footer__footer-id-placeholder { background: url("/userContent/layout/fosshost_org_Host_Dark_56px.png") no-repeat; } */ nut-2.8.3/docs/images/ci/ci-root.css0000644000200500020050000000123514777767434014150 00000000000000/* CSS files sourced below originated in different Git repositories. * * Place this file and those included below into $JENKINS_HOME/userContent * and refer to this one as "/userContent/ci-root.css" from your Jenkins * controller theme configuration - see $JENKINS_URL/manage/appearance/ * section "Customizable theme" (or "Customizable Header", not both). */ /* https://raw.githubusercontent.com/networkupstools/nut/refs/heads/master/docs/images/ci/jenkins-nut.css */ @import "jenkins-nut.css"; /* https://raw.githubusercontent.com/networkupstools/jenkins-dynamatrix/refs/heads/master/jenkins-dynamatrix-badges.css */ @import "jenkins-dynamatrix-badges.css"; nut-2.8.3/docs/images/ci/GitHub-Mark-140pxW.png0000644000200500020050000001406314777534445015640 00000000000000PNG  IHDR!igAMA a cHRMz&u0`:pQ<bKGDtIME +-@r/7IDATx]yXSWڿ$H pEEȸ[::ZO>mugmkVZq-"("Ȓ!L0l}r9,vpùA:nn\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\Gw hZRP( EBҢRt:h$(OOOP(|}}$>O] IzO**[Zmmzaa ( I$I'D"QPpp>}FEE ppAYYA~~A~~III}}Zf 91G$ ׷aÆ ַ_?s(8)IZAiiNN JJJAA5E2 CH$۷ѣǤEEE|G8Ir<ҥ'Nd2a("#E@ci H :uQG;b9 Ig9r~aF!Iٌ֑nyxzFGGϜ9s)!!!NBS$O= q4IZ333o\n0HO{ 8N\\ŋǎ+!|PZ_>uJJR3\&N\{юcHh4ǎ˝D{^DUD.]E(ڿ ӧ;w#GL" <==Nb=zعv% Bw n޼igf[nȑ4/ُ$pѭ[TWu)8$dժUdzOv"IdΝJN] w.}g,Q IR}'t:+;a.;oUWD"[7gsJ߷no $I9{kڴ-~*7! |w͛JM۲!IZv?7 M w۷mSնkV$4}{33F!O=w b+};t:!`Go^ieKw[w6:-Mӡ_ٓzOפښM7($14M;uNFn)BkOOQU[[iJֻIJ&t}oK>鯼Z..**,,B)ۍ 4Mx  *ߗeVv,G >u?#_aPPЂ(P_WWPPp̙+/rSP|}}4iRᡡ&OLL] GM2ob$qyg;wT*s ? ioQrݤnRɓݻCgϜill4*h;nܬY;*Ahhh\|G^:(Zǖ`׳"}۶_Ν3x?9eԨp8aaa&h*++.Ѵ6 ɢ@;lxxx|P( 'EZ0 1 3I?A cǍ۰iӂ zr;$Œ@.tWRS9vt5Mʽtѣ/$t.;tИs}wܡi$I@ HBCCIR488? @$ |htjF"ꪫjkjd2ZF LYd)^^^]_TP(lkk{Фwq&L0HR*{mjj2ہz{{wSNMHHz߾ꪪqqGt.Hua4B.|֭[~ ӜCCCbJ2(ʬDVzsv˗-Axy{=׬bO $IP>rH2nۼbqUU(*??ӳ:_ Z3P(XMQ[S0xMrṟV$UTTܻwoiw˖-p.]$Iݿ_n܎O7dj!ZncP(ׯcIMyyys=O6m)5jԜs>4![0IR(E㩑T*]p@dzzz񔩸X؈4cO}`TddIA=nݺu5zAW\..I}D".Ljz͖g)!D5IRxxxxx8+W?v 9?={_,M F"5IX,8hv6N/ݽ+1{vTxeAX$$@bb"V͛7={)6;B&mٲ!x]qqؾ%$xqr575mٴlظ8>$JChǏkjjaSխ]СC:K&$=?tɒ7n8fd{@oݺw>lM5f4!AawƪII](u +'d2ٞݻ3z뷋 DDD0UzRijjG: %BK+J^~m3TٴqOgϦϙ3&-1B\~DVT+@H3jkk]6'=9#7~;nk{z\"l8` 'قee999?TTT>&ab=֒jɓ's"d L7n|g/\xR :lXlll^iZ۷o+rT-%6W{XB5㟳^ABb9sOo?yѦ u="B6&--((ϟzZYZ.kZ7,αB@'3sV!w}aF^z"22@AbbRs΋ty96--O>-,,rOѡee***VT;@Aj쮂4Mt9 ,񼽽9wNw!Lty}1x<^llliiiG]` I{b|~ttիWe21tK!Yvm j[v䔔1Zﴸ胕+oݼiD"Y|yHHa9;=ʔ^z͟?X0رcSRXy;$yzz.Z($4S8NYY L_af=2$O4ގ?>22v Ä,Z`ֲNOGR?(ڵk_gIϟ6}z܎#O2lΐII4>b#BNFHqqfZbٺTo0?vLT{0(j{1k;Fo}!IrAFO:P[[ٳ99NBBB\\Bmnjb  |>a==kR&-`=/e~Q'?|trС 'v I߿$Eqpx:0111~B}YaChhhI$Io߶ /_`Q1i [qc>}l[[%'|}};n"![6oV`,nXk׮MNNQomE`V n/,,tH&+<{W^=} 9XݵI1xѬ!,++"yV# % | #N:w~I[[[G {  $E 6J&=yDgddxTq{zC+V\xk؜$ zMMM tn%I|HiNjZmtt_cckӧDӴի̝kjI6TRx<ś6mx~j0 KY_v؆;1]vl1Q̙v튉AVN{`lzb(f]v6s}"FA䔔̬)S+-˓lsRGBgAMA a pHYs@@uIDATx^]`TE.\zOtAņX *"6T HS "M#@BzO.w ]˻W7ewvׄ1[PPPggg8Lpquǿdbߞ8rEG!%%ɓ(*.#L&xz ???DʕQV-TQr.[ VĮ;\P+89:IUWE! X@R\T`< W77VZh٪:|׾(c^$u0w\[ɉpsE#'˄ ßp{N  9gBVaah4i|n}cۻ:s7Xx1y$#Xr-+;G5EdD(ԬU+y̞p#G>%5O$ =dX,YpPH^'QABVE%}{n M#8&jMV$K,͐#1زc֬*ǽHLJS-eoeef@tÆ!8$8kd븱c1mTF2M#J<5O=mQ-4E39x X,ƭW II\*Ff͛]ƿ6+30/p냚5jݍpÜ95j(T]o1Nt7Q+GC=g6?U D9HqnLv!J#Z#K@Qwy Wf͜ 5%ի3϶]hE ZG~ 6oܤLvwt rga|-XWy"J۟δG@ًaUH=MJA qE3^pl~’GL*vhp<#׀qde[[zс}]'M$d86vzoۥ+Jioxwd -݂jB8֭ Uh۪{/ /Lrd+}!2ɢ,̗"[9 $43&FM9 {ջ5`va:X)VJ$9Hy98]$n6D!%ffꋯ0e I Vmպz)4n܈rزu X~^ ~B{2 &1H֢BXP\ρv~0"8|t;? o`zFNj^`qY xY`p_ozv8lAv}QEz%6dZZǣa5:Vzu ԻjeW`ô|R _x m5GvjDS;H@\4|dƒՑp2hi3u6)` BУRh^Zy$34y8?El;1sh0 Ĉw}q"4Тr0^M!M0d+^Wzu׼y3 ygW`%rUjHNǬ>FFu%;ja yW 0_!?B z` {muwv4쏶UP.j+*+v7?~.^\lFbA1n6Vlۏ~OWbXƸ._Ebz"ð 4ΚqF_xxx"*:s~w1ھ_-#S=I4! @K-oL۸~uAt{nGz`n^0SˣiTmZwOp PmNFwv+3\+r<36mA8+({,m"նllz>QjU|6f"qΔWߝjd}Xo%eOW:&VZ8tLXJ5ע^Jnp1IrŇ"u!SYXx˽ɻmU >wx|EsGcX7rFJ^ \fJhz3]=G!r$Gg\+G_II"dХK=oomq^8@H9C_ID;X~*s .:vRG[n1˔,wYes#и~-X-FPAP~?-!2;<}ĎuS r5? Yp_Rq?a//i8ڎdo}Jؚԯ[8顦pEHTG~e\s;uƹqv]QrE)B!F =q}@xknJ<vAa^8VON:W{wuQ0:qLɨnI?):0wHTR^| /dV~,+\}%+}~pCZxs v9`Ø]&Ԑ:4fž1^^$@T=PE;xl3QH7u/zqdš bʝK]G^)0!T~<#eJ|9?v~Z?)9OnnҤ1*Uraw^C'@vz]Ӳ)D '1rT|5}3nA8÷w>k{S Gh: Iȱ!vr1f~JsPh\XH60s0$%34I$KIQ u`s$d"2zQPPZGߴ>O4x%;"],VoʊH?M7jNgB xg/nEDD0qq ؿvڃ tS 87CƪWk>c޻;b,PSK,%i  Ý7 Lc -nn8x~z/MAٌP|ZzuhO|< w゚)Ӧc GrPRhŅZkG*?_WnlQs& {>:@Ƶѡu#Ԑ*8' rΩRO%JjO=k[b^R?5-9F3]4}Db۳xgB 0=X6m4W ͱm*͙sRrU(`%Ƞp)L0uGF2^x‍a˵Fr?J &k4 ZO3PFT " -[ހ'|9suOqHYyST u8H% Xظ$4kXC@hȜtɨL.ݫAJV~F^~!veKG}v_U.ts`q=ćri aFC48V)  M_6ŧ-j#k;DiwJe{EhơZ^ƻ@  6-a ﴨYvl>eRr}wjJ=>O !;;[d%DRX9VyƦ9Lؼm[o< <|*,8ǹRt⻙?b1;]ٽ+HL^-bz)&hL aVhMri¬_6ٿJZF\an;(,NOBו*SF*m6y2@£;ZVÛzP**SP;G&;0lXr/n#Ww{(`: 2۹];؏z. F`U2EttDR3ev4}D*,bsۥni=_zL2CA.1'lgF ?t:t]CA> Dzz i4ndLhK& Mb2Zݡ-@4(ǒvݠa 83]QF˦ D+,Dpg+UKڼ-Il{ 0L(C{۶jʂ q`7%=LHH uf" uRP,c _/w wA9Rc-@tLp "J=/{ىqww`΢U0=ݶ~s'QMV 0+2L8`R)8WDC^>sOw+&ju  L6ma?nV:(_;[WMR %0Vq%gZ(zૉKe t^^b:ī8>( _Z*@H༡|5n>p CN~1~e08F<̗{~1PZ5阞u gic燆z\9#4)Qk2%DtB[0iȬ/eb}=1x~Y~&|E[Ԩ*`6aSq)oJ iߴ&=T밾կ;%f*] 3v_.(6̺jJ`!%YydjT]=7\ptqpCzZde9@>it[c@ut̎pS_W bSpxP04MPW:|PpHg%AK\l3~DOZ}B6H}?ͻDӻ mB<[P\-# ;,KѬ[vՁ@v D$dRMe"9)rYT&xŗ#ca]FN,|n^.+JmQ/Nnf=,z$dbj:4Ժr?2lb2R4&&L_{-=#ߏfN%HM11cR)额lN3`{<`LI?Qض܉ ֯08ӒjD7(i;}13SCQ+1xc|r'g  <3M@Og|y2A\߾I'"(P "ζӦ,MhNF=8AjEbmIPpȊйckt$f(Ӟ"C1k @g6SLa8߷Œ rq`xzxSPEU鍄LU)ܟo!C Uaa`)(#oޣ6ߏk4gϤ ƵL wn[*#$ [?vyΗf] e@y:}t)L0,E]:f!"q=&RiFNK0E'Q'*XVqI)xՑڋe|T~eHcZ7ŴITz|šnvgs&V>4V\h_^_O߃La\3W@!~E]bv0otYE'1lXk*hzo0p4\]Ѽ6na hF_wͭC31}س{ƶ6baPvsAIN=z|ɕˢKMS!L*vawwaDfvsӔ[`ͪX7^~1ǵpɔ<W\=sS!Mp@رiIqYP,Zt۷l e  sQ=,q;X)3᳉)j6SbڋHדOaݚ;`{cYK(\Zu1cmر<;paV;f1V/@zgns5^F/mte, 4!gkƹڵǝVFTۚVEZZO J7,Kzgr$ o&x'=h6lڴ_Ǐ!!>HLH(lXk)g4ateHl(J|=G/kpX2d*V3q(c}2cuH:!aC(W79oKFr:XHW$ M_z>}{"|f zƉ08WBatu(c'rӲx7= u:bda?Qv0$qwG;fht:Z֩Ypgi sz\2]4(D;XG|<\dGE Dq09M(v2:͜C U/ R=II =232 k]`UQK3Cŏ8/3N5FF~YvL+EjNuhPrvYR5qNjcо}s)~U>R(&#%9=|o {=/|x&0&<wWgxv|5dvwuUEV=f(EB̶6+CNuk!'J@ySj Q ńz%Q\EgdBdz ry\wuN"bO? )+VRM(6$MA?_}-AՊ"H5*~a 7%/슚Uˋ|#.Mw{}N4@v,H>TOyV/ E ˍhwإIe; kLSPi3/I%fSkZР@تB2 B]еi$#j:P3ϬP@_ ߽ ݳY._4I/^{U>|X 74M<[*#_ Ӓ Y9_.w=w`ؐp,Z)iZ=vr/==M>!倂T3GQ`71{[N Oݣ&}3$^'z݁=)ωd0x,4L HI˔c( "ϓQRwt(t2;)p$E0a4ݱQi3/!9  =^Mo?;g׮ui}'P9a|N ةbIXqkft3zJU{θnTYˉE4&{]r&tZK`ċ+V*W;бk|ט8u7}Gp{V(/UTıhݳK l!Qd)7NG%s:Wh2Va'HnVF my/;^K3ދf%Hhy=,\{9r9W_c|&_D'Ndk})0x?&8젨샘4L[Oÿ-`]1wR,[v#]ʗ'hs:vkK|9)ui"ǹ~?Sj5Db E JtK/Cd8OQ:h٬N 34 un#_6kz8xhz]5ibg'%% "5#K㥗z͛0$V'#_nC]뵅#i(GɬA14?[dm>-~KK< {t{kl9 ]8˾e+M)9e}y^P7]S'i~b6ySяㄢp>ѿυ\Hhx,JCE6_/Z7B멄IY>zu#4t1d40% Lιo(4'G.C ˿|lȐmovm_E3jYXhQ r O`;E!b,@lq/:u*c»TϺ1z^wxHGw@)`FA~!zޏi?aOQLtk6eZ,+H@pk#*۫@f&ƇoU9Ku |y/M̋}DV j.apNˮ$fC8GIciX/zpv_fXNn>=^Z{1R} INٷ*zcFX+Fj-أdfxcJqR%h>S- m)ģc4OjӤ.~Y[EuCQ)؛݀ x>:/o7z(RrѨI2a";;:rɸ ,6u)9ն+*$ KA r-b[aݪ'E: d"37JpkI:  ~"8/^J`~ސ`g(j:  LQr,^v mWAA{hjʼn-AZ\CN~n3Wdpsc -=ț6+)_?<ӽ]aVh4D%1L]Z:#K$ݏDR{=1I.y34úv#Z3n>R$v숃M崧=Cۄ Gѭ[c{IܲN<Ĥq]V :#(WnҌB'ZBm|%0BA`OP*%4O{~h21W5|n:dJ;}Bs5$ܙu ZU*Eh;okTq$ܥe ('O::xa_3&g/'Lr ՓC)ki~J3\A ~--H=DCA J%90p$5mѣ;+(vsӪp Y?ޜMТU{:PM-ϭ=cqCve㌠QGE$¹Z;%lL,we''8 :z wP"77#BPrά;Rیbj" EB[ -Ugg'JI=G>C h\GnZcDff#T5Mg*2رVw;<=dubK&8hO_ȴَxq3 K!< Š7"$,J6j{ָƎ zؘ7ǢIPx#|ᡇU.lVU`žaCV-LY]׀(QGZN??)bKKQI\`f7l޾>ޒQ:4J;d|y'P|'Bݮ -6 O; lwA,67h#R@8PwO-9*Ӕf~9SM{$~QY1Y;"ۼ?>+z3C^'E^\Yu bJVm)nY`a Eq9% p9덻<λ5iB4^*Go0$v0(@I&d%\Wx pWצM1p 8G0~2i4 ?Kw4oFddNYW^{{=>pt U+WZnjmoP FWWQҀ`kxɸ<;&1D75W;=5#\ UHHDՊ:E1MeFtmPt,Vm؅?.we# zaa!j>!!) :5*pT,!R4rwQJs+J@(w+HE>^槥i-n])ERjfmi/шPf/ 7H U K{)ڈDy^WSѰiE<ޣ%*WwLw빾wme@hIFTvsECOO OP-,/K#|cUo3iz2q𓿹 @ntQxjz2{JW 9g_nQtvj35]4t7%z1uLEtjX5jche'"0"+@hJ-ERT[ hqηlތm[IWmt;DB؂xGyӹsLzt&Ϝ =dnax^SbZ<#tmwcpc{v>2(i/nީC$' W@< 1Us7/I5'㗬\H_s2pERDaн"5eBjai,[UCkTԱj 27'?O$t0Ir5D)0crlq@}]vsAxOGΑ~q)Hg⥁/Iw;d=;mUImno}^('F)Фqj0@")i0ډ~-A31*вn$=R f!xy?4ٲSfTK->#n%'+h :Ѧlɉѻr.7%g`R~=LٹF(kAA! dg0'ը2 5贴@~n6<]0xyxlRW>Tp1hGPq 6 ^tBMu& N nhZk~߉G}r?\'ڂ]:Q)A9/ŒK]Wnlݲg-"l0q:MuI&D1~IV+c%O}{t->̔1 L+ WO/@PvG4 feX0;#œ 1wuʱ vkv&1 ,#،~$arr9@%]qAKu̅%J.&05gѴ}8U?phPpq4/ðo?oic)Q'#}K󑴳gl덄4+jy?G .B.Mv'3).> ?]PV!kݸqnEص0\ XP bQ9׌QaxP0KŞ Z8td\ ; #OZ@Xڍ~^䊯[!hwC}LNPXlsWh@+߁ⵛ!)M@pCN~~?tvrϿm :G\XM0b8۫WfZ,GX '&)ɤ%vT!{q6.V\I@Ç ibhF"w3eJMG}"N8)&ݏ0g VN^?Q2.&CϾ;q`Ou}?FGt8L;;8/ C_``ot o㶛#-=K}Y4N38RsZBbLmy39oujF*}ɨf_w#ٯ $RW%{i@@ܞ6c^r/|)3CLؤA_Av8~A ğpS}(M,=>j%o'Y-,<?}3ZYȒo,!n;nnH5͹r>WsHͰvFv.k349G.d.x.:畛IS"K `/MzjfwdePނP?ebxJ&܊_ Koˠz5#Ǝ1(O. il+a\g?'SˑL^r4bf@ib2 }cc&->g9}:}|ZLED7Hk'Dʯ1c /ħT 5kp}4ܜ)zi9Ͻ֩'߆dU9vRSLc\S|sWR^{Jl2>mL-Df1٘,-]5h6˔[k|1nO׺\fo<*=_:bQRGBv~6w^=ҿfO>D k%K: JdšCɈ>]FzqL]й"qvQ|Q~3&:jΨI4GcN+Gku26u܍ߴ~y-٦Q!1&{q݉ Jo\y͆] 7Dsdԑ Iȹed̋qc{Xf2)3&ax=JG K-IΓ͌x3Mʈ5dmrkGũ?"UL,RV3A*\xWu5dZaNڟiBiztf/U4M=Wg|(5 WLJL -9h޲%C4%PX@d1jBfиq"hòmR~ ;xc)Ģ{} jcU&Ƕm y8)"v58CIc,@DXt7DAn^N5WȬ֨4jV G5Ĭ焑Edt-횪Mm@ jΆ1B?` hͭ㓷j0ۜ ]uznS.NFB\'*IZ ޻aÆ2dw]Wz{X{`OمJkPO4 \ԤRbQmS}b=з$ n <:NQGi?ot"HK6~#V̶R50PEfͮ*(HE[4>*6B,y&t뎱r?I*i oo7"99:*/ץ/ׯuU/twZl܈1GPv$&] _.RR.sicGӖMϒۿ^z;f gcX<'t֗LV窕Is\A{MШ~C1"&6So!.cjӢ5&:9b>HI#w,TbkҦtM@~01{<ŏI Qd܅Q;CԄ6቗>(OyZ5t˂-NV*/' /6HdsbbkSP;221`w|'dòG m0ӑ`D_|0}|^].MUAxAt-pAHHUKWykmw_]2կSך)f1 < "eDdmNG 1YZT73G#2<yℋsa:3sYڷ=OvUhUX{(/4PQIDs_v4\aIC^4 ). X*dXJF׾]'aIMC_>.愕$*|8"gW_Xhyg^ ?ͯ?0k֯mu&A!ļ$$$oxnؼy38_33j'% (>hQFb۫/^xE Uѻg/Y֖?b/mSFHlsǩP3df](_sv.#)(YXXg/] +M$;~-`ȋ:le%Ő #tbmMc ز‚tAdNl n29x7ٽ_Vn9bޣ=Kf6mrUt7'W&[W qj9wWI.LH YD0|qӰQT |u 8OO'[9v+?VPI%iAO?^lB K~1|9|b]| ;q/} /IbPғkyonA>Ocp֭M&bx3d:v꨹wu֭Pv{gqz)D涝M&iFpwFV~JK!>92;U%'x$Vutc+~@n 8{ CѬq] x1м! ӓĤʕJ6pH왊KLŘ|V]p;\ueV 8|{S3kQ,_]cW-=<d9:(:{x!ŭp I'1`8 08Ɛ)AA(CtHb:@̧Ejg}233dL˦Ĺ&Xor&*V~|&yyR4(,(I_ {{vo߾pO>g> *{ShLIÅ -3Tb>pݻ.]ė0g&XZn"=ww3VN (CPssDvAEY47##(E폀 S0"IRoA/#++[ иAmzsk4Bkvp v4En $%Y&DYcSP|\F\T3p4&Ṇx;/yvn AlɳUQti)yOܶ ]traSCD{vs>/0~*)Ą)^>7wHY4Ө&)}}}ug%.3w!QPܵ cǎE9y>Vmo(_K^eZλE|ܑ!w&P0LvV掩V!'w>V횢0ע`쩠@G֒C8pݺ=:1l GCӐ`,Kİhs nw8cbp }FGX6 u*/O42i=Ep"r; S,f>0 )&N)bC  P'J2͖ (ybkO1n rPnVn\e?ɠ[7o~vQ"55_MƎp]wY2/ UC9<>1.k2?቎f`,Ob܅vGֈ)vC7§bmn4yT2X2 i(Ͳ5ˡI=Ȏ9sl٪bT[l6b8^&x%xxMiK'.>UW,)ا&MC|5i^Ǻt9(dULߘ7M۶xs4 C9DP¦#`FdmQg~U rն{od U#M4@~XߨaHܯ{N~!}="IGg,]ݺk:1dU;X , $ws3QäCCPE|0?oy!C~fweZ'G  p5hNDDΐc}38bBf Cg,K{V_KS%`;- C ^*mټ: Z7tƎBA? Hs&@lv00{9s0|'xM$@""i3X{N"&5cJ&0͞Fm^ N-+9)"SB.gG]Ҥ/L$ϲ90Z #W$0Y50A-Xn;+=, 6jvL 1^ ^ɉIxhHHlc̦t6d,tjs~gg"9zN8%"Z`A3~B%B~a;ѷ"b.|wh 3ϫ@wǣ߳b/3MjזZCʕ*0V"M{3HYNJLΒs i.I#+ke0vFB RRP#ŁS9T?]ũsQ}HLx/FEy@NUD F n ~[V  sLw9V(H@L|vs5Q{o#~ )7/'N^= ӉZ>'pwEDVU`b>iyפ(QCr$n[G͢t1h&d$ ߉zsDuD£|u}+"ta]\^iP2AK6< 'Is䞢d\&쓆X HM)p<,"$h< rgݔk5kL͚e}urWWW#ݦ<AnMs) ,7Ν1qx0ySժUR[U f#эC]EMiv"/-YCXi i)$dq)Ǎ޲s#Ӥe8_c(8&cؙ*љYs *&U, !`.Uk̏8I#q4j,GM] E Z_|EM8>Մq T幀AoGߧƳ}K׮XRSvJA  aaΊWKMi׀@[*(7Y<ӇЊ\^Zh^)BO|P߄ҲͅYvƖ-w^&>R|*K{" #30Bj bnHe4|/<>s7$9 dʱԿE^PT!f/K~sF)2)Nn٢e?yXq53gf}~~~ץׁN ڜtJHr{5\"Y+ڕ”t4J1#d:w{H-|Ɩ}"n*$LmR*07~&LG :c><fYҤ^a/61;3t)$ϰwHL'04;W5!~sQbfd X-y N: 8/^G$8\o[ @ȕ?0Ex^-֬[7{* .3&ܳCMM@n tÀ8C\zc8aQbU&vp&63}bxĮ\2hN+_3Yl|K:GïG}f7ݦ47( bſ0(4bWWc:jڤ=:B-]y2F6o~m֮^c}(yx"paP1|k5M“=zOA-~JAòص 8)ϸcx_?KĔTy m)+Lc XjdBd;(-x3RWJjnÖLîݘHsvX1BC_n6͝'^ {×/W_oXR6OG=!'0aTeBjRw/IUԮAwӗHr^|ѺMk)I"k'TmIYa jXޞؼi3z<R7~zS|"WpgUqN/R??-^=J@qS*عxX'&2P_TK*-xH"@08ө5Hl:K$H /9 7M1><np,_YcǎCbb=3jtС.<(HJb]"1,KV)aζdKX@R,+sAF12wcuQTDyvBZ %v֨QÇge۶Yya sP4+ NJ~-i0W0nq }dzFTCȿ9 _|9nx/]=)@J@Ѵy3qU$"WZrE a. >;Q2LzjKY鰔2y|$.>A8ykzo\%v4 JLǪdԩ ZxW&$uTT Wg25 &;(dvƨQ7g= BFz:\԰-^E=.LUy6W @'v؁w{}b&~=g߽ЯT M: GQ@إ)#;_!*BFRF]2YLgbhCrBvI1L(-os@Df sV[,(>裸Զ&%؉`/QL7\tD*0]9I"3!&\t#:n~AQ&ٖr0N[}=0RShB@X^#Sd%c̤7 hL޺}t1[c,%Ӭysqla?q^R (Hd78KERҷ`&T'pGAڒ*dF2P1gg賒{҅ $N#Tv{ݫF#x7܃!GnAl{D$ a괿e˗cΝℾzkhw-vj Ò-?~sdUe>fQb3_$p~FզXp{_cԩ ERro;opx?v-/fSUHMY(ZN$PD* %d7/'KM)&wd5i&4WS=P8꿔ks-g F$h³@/RySs)ew"AE:܌9ks-@G\K7-xrdkZ_MkcqLg~HݡufqQR͇QΎ(b"v/_O2a˗M} 1 ,D#3ſ Q_q|6PHo3HL QilfnXwJ?H:'Yʗ|Kohqp@&0|.ƨÒ|q(EewN`"WL:t߾(yw茵gջmbCn>VDsPp[CT87-ACP}KfFaόOB 2){zB+(9JI>ż_ʈr( ű* 4۷odž  /*x$N`a._] ;*˅a;Lߌ7βI.Vi|S8ʷ)nS\ 4ܿEiڦYk‹^Ot 9kľ<1A q#X*39bY$"9W[ı2f>C.A*HT lnfQg uZiʉC]98y-ڢLВ-AH?q {k:w -[/G!Xk7S\f9~@J% 'FԦ\4?鄘YqR`xOR;ČT WqEC@aJ YD@@A;拱=wG謵:lذ!l,R7^}"L9\]~>k5xQ>(E0fw1 50LSѱu޶AL%); h۶bbѪeKx2=._;c<1_dZ{-LE^1ͣ\UG1´xXsTU(in\N S0a$GƓr-SL-@Ȼʬ[G)DV""ihwo^ĥ9kvC~lٌy+43“sDPpL6b44d)\E\4((e@rd- m3rTqx*;`pAp?'1Wc\ġ|YUDF)6ѧ􈬦g91P!~]EJ/ 8ОHMK,8dE{\b{hƹ*cͦhsё$iy|Α:)-=͚6Ŵ0 Jy͜ q8//Ё;N:GѤSG ,f sv8cT=jҜ!q)$CTg6iD'Sco"'E‘E*J̸8v8ҳ`IIDNF: }aP5H")88Iܬ:.\le%?#"yL c5h} ,) O2㩛 y'ڟn0m۶CQB}5 npVs l&{hf0O7gLI-+9si}1B̧#y)_Ӄ:#6{0N)D&#I*l& D-^'{EPpox!8GdQ&)">m~nĤdԼIj1B-0Y:uÐoOkoK}0H]:{= P\Mem־/nkVbL:կu^ƭFϿԯ?ċm% ]9 󳇈=OldJK9=U0phjwDE[F#q[Z:]aǓOƛn!JY& dƤ0sMJ@6܎Xֲhˁ+xbjM#jk5$іZ+WM~G q|1yX8*:RwDV# $5@\<](H-1Ai7R E֕٣#I aoӉ 9!D%_;1&D4y=ٯ1pz*bA^~$ɽ8kL@UjJq2nEӷ/BE=ݳ'7n7MOu\?J%}uhZܤad @0Zu7P^%%G3KL$ea!m(|FIwQGf !sX*1z/fz2pِ7 ߭ N ˌ5NOV ftDh }DӪEVxCџ37n쨽THvj*i/g~;?bԸ_|5!* fpakD,P>#S_ZNI%UIJ$PB pf..`kqqƭWmyS&䗛rCH?:чr4R gedH_$=5(}pwѾCNEuE FjCnKӰP9']*Q!^t7,y(YNMʕrAAzk` fi ETswEqgqڏ6~1ٕ&~]4g DR+ɄX.^f4]욭X23n_B23g|Ek/$bA?o/DFF[Jf Sf;E]s )_s5@\& (H͛7&)2ZGyviLIzUHj[C54b9IR "<"k֮Ç> }W6O1䭷_G"(hN=N][O?mUL'yzz˯~~JSq%%9و' ϛ46_ť9=Cee7 6zו)D[}°Ǣ(;iiW>¥/i/Y+׬51e44lHM(v [dl '#Z?:)Ǒ&QFQFTf`SPٯt0:ϑp2f5FЯ8f3Z%:;3ǎAh:wI✧sPUN*N;5Gď"P.K>dޡ)fdZQtĴ1jI @A3 PU=g^jbR6W& Vy J^~#3.܄_0}AA23'N"#-MT ''&4W%:(I:GEgp4 :wcM}ʎ d(m9ry1yn+ XCOJL={c͞zOh __O(̉F5\TCE+ yJg-eY ^Bע]Y߷(Oʷ=t _0 ~ͨ5Kka+u,{h46(֬Y=Zݢ$NI1b4(WuިӦc:ΎByPNv62iaxNڸu ~wÆx %Gz!,<YY8rt ? Y?v%.=: Dj&:^v(Wv=A;wO^RnU/fܦc+xx $Ü_P=>V.4WrepS@_b%>C]&޿6/2Xn.@SJ-0΁a:WZzZ5Eƌ+D\㊠`g=cY'5ĝv21㙼D3Xa=/mk{tirĄD9z۷mǖ-[|}<+WktN*ӊo۲}P*R^5t2); Xl0TJKܳ^:uP>2RG~9FM/xǶ 1UckAYX5NiQSۻ5_Q.]Lc6Ͽ.5|FRAzq J2%cABi ?Ί#ܾCG Pm -n0U;::QG= ";`<͞D a58~Qb58Dl앱_J[P& qd<]]; ]~ɑl @\y6EP0ACFķ+Edv;2ǐpÐ&ry+#@Ѵy3]uV]邦NYj "5?pfvrd g,p]Exxnzʔ8tXEAAfW0f :ns.#Cmq}R*`[Q: pssŖ͛bD'>-Ǯ5hΝj*[=xB`$cYR֨Ç?/ZhZ\h54 b-aX.ghܚp_HM!擉s-n݆dcpc${8чfLSYu q4fPFW5W?mڈ{ ]_vÆZWW;.1k~u)>t)|k? m۶U2o˗ۮB%;4ml"3#I . ԥA}p SPp50Z4qvr{蹽׈}dc({ԑÈ纵r12TRJ:6'p߇kߠ{0눏Bboذ!'5F v." r-9dg%.D݈ރe˖!&&V7k G۶nujސAf7NAr-%ջiT 7Pu>Pun8]Xs(eA;l@d#w~+{ sj(aJsEdb14hѬQ=t(9!M08~>lz߽dC'%&Z֭U3Dl20@"3Vg&j'u cku-s_|cZc@8ǏU<3] Xd|]>u1ukA32>IENDB`nut-2.8.3/docs/images/ci/jenkins-nut-small-256px.png0000644000200500020050000013220114553676503017007 00000000000000PNG  IHDRATsRGBgAMA a pHYs@@uIDATx^]`W?Fww`?Q,[Q% c=ݽ6@@{{O{zTrjYTT/??JJHO_HOOLLL2J= ޴RԡhkvܜG}H=}% irvq~2>.~hh(QFzY~AeFF:( 铵 ?YXZ[ۻOrtrdllQǛ4Y_tI3[[[Аz͒ =ue9`a]Og'YOuMO,*.*b7 500 }f6%CǎYnZn}FK+Z?77@rr2X-̍NN?N;tt nlL:\tр5E' ?ߐ7c.{iSF6k~1c>>hU w !4kޜ337{$708/Fr Dʁ̘͛Ξ9m\3O[qygϒʺarR~qq}~~]nnYAaAqa!3c}Il"%'3#214 #= JȢ‚͛{+Gw{ cgϜqc^.^k"D YbG~Q}`§Νk-Z 5Σ/ob9ʙHKK۽s-͸<;`א%vKpǜ,3&l.9C=_fR![1s46$ &ts!vCٚ'{Aa1rGoG"neFdY{ oxܹgׯ]ɓ]iucr>Tߋ\ܔ,-,ͥĤTGQ@1q_PHAV|4dpV`ƣ;w# Ow n䒜51>_DxXF))Ny9鑥!yؘ990q6ain )Ky*-Wvp={drm<{rMhXZٹk~{zY;n1۶nܜ\2ʻ3M.}iԳk[ts&C##*Iެ%< 7'܅tY:v<3h*,,"C34FG{|K#U?yˡEFD<ҕM>;V!E=wdBofEMݬDŊPKyG׭"nKGC=(.=n BٿΧ'?;|O T BCBN:<۶[+#ik͛6}:oAL ( sAO5 ck1ڱLE6Sރ#F=0f̓t^^m{ B"#@ g+w4ΖhAF"7 =*.*lnbס`JU]8Zغ}1{Gc6lÍݳ{۫VD- "6fUӓ<=ѣjS??`oaf^/KWBis1*c0͚7ۿ{SF#~m~q`vV{k/jb%RؘLNIdjH&ddfIzFL J;*))œ,LH|dRqA0ppBZrd!(Z%[B&ԣ0pDI:ӿO>"_>Yc^?|ЈA{T|j׮uԑE՞ʫ,VBN4v@}_?Vx@@Jj˫S8A5 ҚM(*&^ mڵW_C5ػg+:tJT+C.r_3jƪ}%fdnnNNdCfvd Į|:S:Գ_\DETMyIOىQL?m9N;/Ɛ)k={֣={ə;bmÄs1>$+}(O@ 8vhcǎqA/\qFFԨQ ؟ڴiCvvvB֭wUfƆԻ[;zb(Ҹy uPw9'5R`RK#Keӊ;(5-Fyz[ 4z.QZb~M\o~&,n}ͨkK{K27#+ $kdjDJ]Sdlt8BΥitztJ }>ʛ&t'3<6C=z9Y'=mv1/۷n31dnذ=ڴm#]!~bb"]X[Lnh`dĿBܝ҅WRPz^'z݋@z%Y=}=vNv-~I~C&-9sWhAVn~ddZZwE"+;_z{4fmRf.]K VMM eKg<<:v8ҷ>5r-%~681~?UӠ}>=奩*Ic6kQ[Xqۛyaڽ+胨K(&68@׭' }zt/N"wG狋 W|d|u4 ffgkߡCO'',[>t._y/Gdfd9[@gjmNƧ鳴8~xP<]SΗ*}Lj6]Nb0؄CY'xj\Iyq|?kc\}6Dfvexn6Mzi>IaW-];AiԨQsCt : ~FSѣ*xCPQ~ oEоi9-][‚2y ##$޵G9zs Ț% 96lEZ+<@kj/ܧF,hA=z#kJM͡OSNV>s g #ʌ )?+]!O s|w opϝ=ba4i҄zMѳFK:O;FylݗhʈҾ0' J+nyCGT E8w9LB-K/uua=aZk޶zN~dnlHvaY{6`є%)Wϗ%8oU%%|^/t5&U\\,/nn:~<815Ζd7aKpⶖ!# Fx{XyxϮ={)p0_mLqÆ ^~lkQuv ?~(~K '3_}μ *惻G@2Lx%´0$=5[oψ^f)9+W,7^z۶l8#-յnNvdhdH ɥY2)Y/ Η]Gn5~ӲpPƧK??ozsp˧kQff9[~'3&s{W6K e&܅R|6:Rr3ʗ>`ifμ.uP{Qzd#23gi_|bbe/eP~9!nN*|ce+ebOˢ}cZRoÆԿ} 8Lg^#cm|Ȍ)JyU`ʖ L̄ Jp*<4;;ܴࡻ#w}tɒ)+W|ɓ_p|222(,$}=igCΗWhanB0iƑ#Z9j_fj[_}-_dm[gڌhF(FdМ$%yf P0!v@ql$E&QAA>jJ5 [[(hK0idec$Mln&̸Le6a{_;5ea6033stdD]Żoeڵ._${I4x ;v /1sΜ&}?|}^tГkG'gKwo̔b[6q6ׯc.N?tJJI n|ƫh~ b:j^>Ku!hZ걜ӶjۂɅkɴ|d䰉m Z2ꄄ?p [=6A5[e2`$BG8r^0p>*ن]nN-۶zc 9',Urٲ:Dٻ_6WϖGANwBF,,ɌD;u^e K+Wx|;,.-ѾmNܕۓJлg}!AhDJQd]P hHdPO7"##)ltIO'G #jm#D1'1x09`hDyiIdonH'#0&::jSx:]&@hh}˖.m)C},qt1VXbˆ ]iP.t^~Vo\hBj x#s[قc 7ɓRnԻ$Ǜ>ujhb'[0 Љ:?\xP>/$m_ITz!زkPW@\gB)=3Y91 P~ϗ/dD_fdτI+yžr\HfNd&1ufFgkjj,İBj-5k5oemE>;y-Z-YJW)",Ll(gLV?. sdF30khjj9qe@x'LKA~^Zi7;xl-jpL-AW 2DfV._f=~!HpN@n<%E+,3Aɾrs0ʐ̀ KN3}5 rUDFF6Z꿯/կ_.BT*(-g^VϕAzs32._{76}wߠ W D|-,,w}}}0ؐF %+ˀjUD z,60TE_7ҷ?/e+Ў}('7]XB MX0-KI,SR}̢$!CfPo:ͽMVOnܰsgL|G;xCr0#+o^E+TRG+#tz9|{)">4yrG lJ~,Skjh3k: ַ, [iԹsg3v =81>0pŰfj0K۫X``Uodn#ĶhfُsQJHL"LJNC'.PvNujX&g`,I>gXYZJ"N955G#n۶R=C:5TkČSX4AC ڍ"Jxy0An=FQ b_Ϟ<׉lgLx'[abڻ7/?HTbE}yܯ 3PpNe[,aaJf͛:rּ?o:dEڹtJ/AGg}| 4ٳ755^DN?~Ff,X]t7S|BF7XǤ'#s+22*`BQ:Ѵ}(TV"0VΈvLOQLyԬ#Mґ=-ޫ\[ [׉L+P\'ߜH:㧀<ٲ k ZBj66݋5/L+""N>MOPXX8DGIu7mVŪfl00 VsYʿgm!i +5mGdfb̒ʊ(f@p#6+~ZSN-cԄ,9/ԫsKۭ gdQPXYHyhEEHKK3رmk(R}{jJ9;.dhl*$?KKPTzJy`[}=&F<=hHQԫ7KPJY_P :.C.fpX{aJg@ګeڀξ` p.ɈшT ?Z~?/_V": HJJ2mҸP"1ѻ̠>}#@'itytt_hڐ:oA\?ULL%ƭ@x󏍠מKOz4jH7ܫ=3"YL}ҝ!T]s3ɋ4\58fУc rqç.wCeԤIk)7Kн[V,1yߞ0dZ;1OWm~&hB׶(7s xur5{iҞ-=5%Z\REL̟~._4bޱʷA+?1\IL3֎/͟?jbwYf T.qƢ8y._%XOezF G0Ѫ b&Ш]Fށ^[$T8|@g6y g[)4cG*3%Xry@^^qƎj!eL@`/ G\|?OS+#m?!5[9Nܮ чѤdeo<~؜,y# }d& -I~ed[qi_'a hK;$cǜ?D+f jJpهN<TZE+v>zl޲ ̂1J$eouw_{pCv= B9&''8wlBCB9Vl!UOTgqQE$?$;5&2- ۈ$tzڸeeIWLO=֘ƍ `SRZ!}u~wM,ϕ|\wkU(_7Yݯ ʷ)s C Vj@RbיSh|:&N(}R6lB!aʸi5$j&1|UWlR^8~ӆ=@4Ptz_s30iQ ,ey (ԗ6G<4/Ĥmq*i` D &r-> omO/NnNcG1BeI;֘kؿp!hL2@"V_ɇJZcE!z-l{lL%^ nF3=w[]TolR:vCQQ7^7 & tセ8 \GO܃l\8'W mK#Lzwp>@CR BT_9У!QwhɋBΎF4cj+o'5B!zj looK 44:yM?29srQTܠdxddoIb`ZfEB:{%ĝK4JNJramkkkJfFlNƔ_XLpQcZ bHP }-~>YRrJN+9r>;4w.T^ML\}b?;+0'NEPGdAi[v>㯖4hغ1t^s*j\tIz;YYYѥW0X [T79P~7{/M" [q3L2p9;$(6T^g `Z_`heeuZ)Y[yX9GuY4N2Lmg")MxI_Aўi )Z8t@_ۚɧH|IlZ2PaB.'Ў=҆0SyoYXL]'ҹXJLgy ([5i1(ٕ?hZsaBܢ=wg9A8`5FSřDaaD+oƆT矎PlB2hz\{Xn]:dcmAVGGdҵz鞅C=&J=KK#Q\ PĶsņst5&,wZodDY mi'9({=wP=o \kPϕ}ڹS@zHvrz 0sOtp ]L\jj1HeS sW69{LOq+`@[Aa7 V鰐g>2W.ndJnaJNP<, e#ZY7:7F#e&BW\Qݻ$lrP>0Q@Ħtƍ|{?6-:r NmG}xK]PzD&4v}4:bF7Jx[,EE?YG~>XeNIbZE%ʏiҗ鹹hsʦj#Q}iYhebْ5e_tFݻ{&0RA1 `Xk5}>6dDYٹoZ̈DY+߇G*פG ._(4[x)1>q9J{fwLx!!C, A<3~\IA<%b;u\MB::èEb_Osŕ؄U/Z10-}u_zcjq'og&1=[" }\|2r &2,]/Q`l/S Xq]c/XhQ/9qK)iқ+/bކn|ๆfJ.nCNEk|xʕkxf,b[’Y`gf{2W[ o5)1ItQLDŧ P4ܤ|Jc"6O#)81M驧[ou$_k/(”A:K '(*&3r)Uxt sjj+[-5V`WLbFZ:ҨKhgヴtHl[2gXqT4-k?ڍ%kGdV5[E0_EؾùFD[:u4ܝ@Y%Կw':s1N X.vV"ϳx#h(ў6>F,Q_K׮=0}fVXި\P S@M:wGnLF0)9Ii7\^+A\ ɠb4e)5 {=)eQ0c j^"/ACL>ߠΫ}|̰M hm3M  q]KPOmȴQ`oVVuIq_;Nɞ:oA )h. uPc}ڵrŹsg)%%Um1J>W7K ^"SsC01}YkZvof4ANe5("Iȥ3ihzӋ~n7a?=LUTAyFW5!zP~ib/[g7Щ>Nľh̚OHU8%h58w|ɧ7mܰ=$8آҏG VDb@2Wv}άtfINAIF[V{PܸdjlDkDiԦ(24|Roj{UQC3cRmh.ZLl9f3X $>a0-9zԥe#r`KW>P˜Q@dвM1 /T*Z9ɯ&0+)-NN僱.mEhhC5;>=֭[0> L dHPi~xkLx*Oã }` ;_G{jЗ+m픐EL2(' Sy?{P;a'j*?.~O2d\ ʤ:Fh ?nԹ %ͱ&<8El'c^4hoߢf0=|_j߲1yȔk\Oz`37)vP:z :נ 6W,DSG̠4,$Wo?'m )fRML9ڹk ꙚCt&; >ࠫ,###XRPff,l='6&ڶh@֫nng40t:u>HD/ US`s2+ *ExT ]BX[;=O+6 Wejh4unDL}Gr?S'OYX[[}?8"}}L232b&p}\$ ~}\!v>$epߗ)44\-idf;8t蒳5nیuDԇ MuƍYaHע'JC{8(NR%QvN!-\L~zsі<'PɠmU!Biy1G~|`M]۷3 5ck%] àgN A1CZII|*9xΞ>%*  d.D<@,*˖c"RG BN ឬA^.3Q6i_oG#nھ A02BJP>P~;ˈO{1*zPȾ>3[ qY,;FHV[K23:uɆÆFYXS}?oڡ59f:~E`L;tzU \9_Ss諟/Ь/NR:o^4aqʤAyȥrK(M~F~zfp[ 22mۗ߷WWr- spqqʗ )mZ:|0B¢$SM|R(='KΥ9UhK!PW }u\ۿK1PUSޣ0-npu^Bf )r̨ KNJ|CwDc"W,|7.[ğ/mKKN) 8XT\juę)~炂~/gG[zzP2a&J۰#C9S綍vƬG3ݰaI+g>4hH֊ݞI< SŎLM='[hJ ; Qݕb(QfmٯhgަϾIo~8l)BBimRN64-bER^Kǚ^D!\?\zԥeݑ5 ΕZAKvt6s$$'׸?fszoqgu7&*bV뱯`G8{Gh/iǯ;Rp(UWEJi`BI Fa"W:bHA Z[?Č SC0USci}|UN܃H+~y~U'Qߒ#C}j*|z0cڢ٨kQۯtqꩻv;I֘@8V-<٪_DcȔb+N_?o~Ko~'-޸W&!sdt߾-Z)XGJenZhpyqTy&6KB^E& HmpK6F1ũ'gϞmk8~XvlL~짳 ]!T|r&s:&uA3Z}vz% YJI eF Et58XVXӀd"fK^NOuK R\R}=o3!$I!;H&YXZCq `M\R={;dyL.K5`fLz^r,p?Kx҉,M?ed p鬫(9|$ϟL|:TN/d^k2!V12߆)Ɵ|܄+ &Y9PHQ47&XK _#x%Ac ~|:=;".}YȐWi͞Ӵe9+=x˄L++xnxR6-=K1yI\)hWAz]C%p'O?szJҒcYqx'yv9L^x&O}=7Sll֠]lۤDJKg!མvGyqf-ڭʂz =b蓹)1k ('/O*Ϝ5!%ofU^Hc?zm켢2:Xy;~P[mLCYFiY}ǔΝaOkM2VjڙL]W &ŠOLk~I!\ԃ1sRY9y$:%p* ʊE+B_LhSP}@C-dПͅm-17sf4t܂dlejjZC99PՋAc*s§듗%]';׀շ%#!g Ii+„ h1Wt5\F ] [SdlgYd7;j,R$?'~ Qi0 G>bXk$zyd^'5fos箙a_2ѰvYBy'*:Voԍo]/IqeggP `]&RѻK+4v44-{Ӝy,t}`z d_´}ٽVX-ꝓ_TA&*b𐡈@j||6EGmqF%VQ/p}ÖV܈wwwf?OguVA4*K$:i^#~ުI#~E靹QP 5k.K)ybdQ#'z԰V\eui֫t-%\]m8dnl@mm/KoDGJɁ/8ndgg={vѡ({jf^q6*_ϦߴQ=.bQKҧo=ENeУ 5o/L`StEf%u/NIb⸁4gJh]5,mf8? 6WCXPkzWܛoߠU<7$G ɼ~ԾQb}7 ⠠4򲤉iҁOi̘se^ՒZ K~_#~n*#ќ 48JLfhOV2X҄ -i=i3Wdy)oߦggShp}2g3p=3=SzvJ?&fk Bug(hՏZ2@#~ ̌V=rˈ0 GܧHW"3փ>x }Fӻ5 M_?FK~A{{m@Y M8k**=釅EU 'UZtZrY#6V pL}U[v`gg첋vIP3&n}m?vL}TU|8|*p\vB|J=ϐ@ |ފ_ҽ>ZD?L#c#Srbէ0kq@zԯnIqq6ӡؘ/Fכ.Q*MQ-8ӫ2,,p Ϣnּ^v*k厚 C=ׯ[;34qơcO9"޺a;JEҀoq)7W{f&4~HfhD0!}:fCE/Ҍ?74ol2_WP^`0=`ŅZm0Ԉjt̄TO*=v9 ]-%j<#+7i7H}e \@S@ $53`aS˖쬙yhʍz݌M+Qۑ X3!Pυ#מ Kҫ߼;=0t~%PkOkrC845{s^A S3׭Y~۶-km2XFpCqGO:ֆꛖwԗ | 78X;K_+(hO7'?l84k .( >|@ 8$ bv.el[x9[o{BΚZ@Gݺoqrrʄ p4}[e#"Q&PWLL@4pS  -/3dce]J FiKXp$C03p#/GKy.ܱ\y9_}UnNZp-ڰ/Ua϶(!? į~ 苦%)|K(dndb L4#{ɂoYK?tV Trߤi#GMs;–5*),%%߲K:i3/cc-Kf†?P߹( S|kC~CߐGb-}"f܆$^)(F1-ʉ̍JEiE.NB ]>t"LOcOe)UGCw'$ѯ6ѤW> B%dG  4WÅ:F^gyÈڹc0_L`WStxWSd9sä;94\`5%#e# F5I}!DkcԄ-'iՑP*;uoAVVeOftk(->Kl"vڀ&NN;_D[6e2GP)`r|C@ֆXc4r(d[vEưW*~^b)X/,'[\qStjDm%%s sXo__z-)|q6PΗ~ Ƨe˚ԭ?Y9vL%eqO[yӣuܜڶ)ؤI ^֩V8~OcfߺR{z!9\[SRio(_z ` N;r4tJxEaL89QcY6 JjX,1sq`bXFˋ_evvvr` -K8t(BBJ:"ݪIv*6/~`Mڞ^~=5iDF|NhVU6r. jv{3.5-ePxX2S>8رmmAV8?x02o8+0(yP-:#G<> 7P7k+Q'͠i 54M;hrjWj޽ taDX|+muL;19ƃP_=3+sQQ=~}4G!#|a0 Jn(A5p \ίOOrU 3JܺDplA:1&LhJ3gv>}|q?nBȻߔnc5?9Y ϒߏƎi6YB ޜБZ.cӧ"ĂZʉk݊> sHG}\>Q&ҳ,n9(3RDY3*m|gmx\=2 Kx ͕ʖeT=w9F\NZ̠K·_/ϛgFX>p@EqȦy*ƆnXOnn/ʅZ¢K>Ԥ O(r7tle=c^&X=i̘@UFTPeBYri~{ &N顇[I' {Ï lF6A\sj 2^ym>4$>STGboAVTOD\FZH)ibC8 W{W5&>ZypU \c-0q)^*;|IC_8n7idce)AADkvҸgޗ!;,QuKe^OU@}cL@I$Wˈ>13o9ȗ@q |v^RcNď!-{WF$ѶkqY$mwzdZ3h]#;;֯?Gn7k| ~\;gK?ΝE,aDmAMuf`h&]D37|;.2PKx׊C8xUMڰOɎ qFL|sFd|h!5Dte,|#iPf'<.!Q{w_/*{ogm,$?rc2+3T#ҥ =2a|֪ǂyi 1m_{ЀP=OePe|+f#+uG*=3);P1YMM^9xLsᡒ l?p6cF;_ڳbnh1}%cxl*ͧo.N!`˪L[rS~f2JVz硬 ⊦)H@|[5VM닣TwⲬT2`gVKX dͶ}px4>tF@#p+,,5_88ϚՍ||lbӊO-êkq[]B/;.?.A\ $3s|2"-~[~ަвK]v <={7iڔǻ~ gΜBtGA9 . A!kޛQ^ L0Q[ة ̮07t<`O"!m,dr,Vq{ P*ۍlh2X񉩢h@`)+K@bbP`K( noǥP kehyp 9{6Ǚ9S=<_ws~:ߣ}z%+uAPЎ*O?Je:ߎԵ__Jv]i9qù mwףGψ)K(-oo3bI!9HY, E oɬȦ=,*mѯ,{o rRef[( UW^`X'RDTG2DTz {|h=>f {mY#m% QXN_ywWo6/~[{Jmd3@y?`},,-[Y׮Y >~E4hJcS'JG_²J]n_vLG ֣͌ׄ秼ח]vr}Y F/_5wokI:heȬD,w+[NA&)(fE'^ U )%?gҀt\"jQ~X&4dA𽚙[J?{ɩ7ÎXLoɌF{7}YPTTF=]x:vfdd_(((M!4"Y%IR$[xaU &("<;e3?] #""nB^y&d6RP=@X.v3xhL,jg,y3PskRXBш*] o5@R+HP{jhٿe,GxДI#i/ަ/};Pd'4Q =AD9Y*N,mƌ,Z)hcfJj.N ކwcH3aF?jӧShɒTPHnG).#P&q,$/N%\<(Iyv ne}ȥsmzfZ5=.約cq:į^/tD)oJ8EK4x>J? F#Fhh*@7PWhF`P5PI}WJ·,^?6"0@wGΉHwOHm"XN n.l"8R>TC3Ј1@`⽷_} O AC~;t{3ϰ-Z&UMM&]̥R@45&CNYՍ7 o4dpB=5#22sfFV1Qэ+@9|{6jccJ&& V:QK*#0eڱ.xS||&mtvZbfnն]sٟUk3 􂃃MxObհߐoz[ WߩY6(*[S}9ឤ 0#HxأT?3W~bG^M ;AЈ*!#oVGVU}&k) %}{R?|ٖ`ʕte3ssqbԵkM 0|:un|LB[m~WNUYt?A[6_d?~7n2ycjݺv6`Юm.۶n3ㆋfEׇIб|wCj%T<ø!Uohz;zNtVȑہ1^,AgBD MÀ4@L +)M>G)HϋV%kwK> 2n;0XV4pCBo~ݚw휹mYnM;xCɹtL2dƑ9GwڤIC]5B/YfA #,2ޕ^K8QF񜌡kȿMcOf q$ԖOS@`ld; bo@JHиlۼx8xb[50WøL>x@}J(**28lG_?X???,,z 2=+>9/|\^zСCܜOW$+++e).AK0& Ke!hhO. WϞ4x`G Č棯>G^| o\P_{σ5[Ww;7BF&{r|.LQ?}IbVg*}6mk u)w"&j9tjа!)ӯ5(5%7-bpazZb%m۶\i¤GY7NP/]/Wiwi!dUY@^+!Æ!::vMv4yFIVU#<ۯ4:uW߻131qT|5.>6J*xyO_M.VT)Ց7ϙJ0~4~]@;B19 |x"e[(%W{ /Sft(ŞAEPGZRKS.%~Nr:qأiΚ% 1=ْ Q~vުt{y[Uj;v>_LٯᆪIO͟O#F .::}Qz(Tz N31 *G:t0X0 GEESP7J+0.V{[%9'Zc#Pss>NI'G L۰t@cSf PABrcf6)E.ctlۜ>XcU |WQ%VH;W. yNFCM2xYǐ#lw#{O@vNܲ;3S֬= sgPK3Ƣ4?]D脴g+tU떕BA~tLig%M lP_۶n))k+kiI.''Wڱc7oϞ=؄Gח).>lmmuVG?0YVU}nA>O!3 _i\dھm+œ6X; ef8ͭ\E ULAsAb~:8/FVdGQVuڮUSzw3jXu0'+Y2"cg|KAXDF:j$:ἵ{ohtO`1HƦdKNdJƖ莲b)dSO#2\O S|Q#Ӿa/((x?;;۝˼ޭ͍A_tۻ`{M#J.c,uEl*p~(ZoIȰNS}?ԓ <&?5W_QiBDd͝;nNSXwM#󝒒"y?c޽{byվC.035]hieU*5Tjh$vnpGseJSLlڧYygR-0pu(4`0%DrL. {hEzN^H2O10OPs 'bހr[@cS̒\Zv#K&:Ȋ&u?I{krނ1#Koc`‡ YԘA[ .VXAN秼@kUD~VV&ߏB{-oI ]K݌nݻ=NKߔWX@aarJڴi3]a!jI|{;{z'YfZl}=,C#p#CE&&itkWN'Xf++>0q$z-Y2=V"`7^߻ ۼ)C>4"P0"x>go𽕼 GXRZ;qmӋL|&ѵ} \Ϝ=f8[@NG,흙3oT LX;oCZU ~'oik 亀D,ul7nHVlWޥS Ft\JgQ`Jy>9&|) Lwǟ 7]rEb&XV- &ѕ Wih߬8~&r-@q%z_swFۜ2ES b~ajƦNPod94lÄsQ}dK!28uĉ"!|آpppmN_e@ŗvkx+mˍ nԀ>zAt̔rS@Y4HVdnc_1dS̑ ^]a-f:`0](B~~`N={D.G)=Fn`3կ__R ȃ8)T*{m|1r:Fۀ^KXh /Q^nw!L.Vnfu?B7dRbV/d58:~7Œ!6%%YƉSSS{ փm#/V!R2K+40M[6 %011?}=d3@zf wv,J.1Y3]4r~%BFdbaMV. H8RC.Գ7Q$16є_L{aʔ;tǎC}{Ïoo;ZKO#0]9ʊMO>vr7: [JS3BtYGϞ(Cq[i ` ,/p~?<9\X$3.Tn(R4 ܈LˢDąndeKmҳW{rL\sQnL(k{>饗^zȀ= wgҎۅRn0ab B@ʦ$|MmzSց:o-7xݶC+%`ΕFܬ-fuJ -dn =@.JjBl*iNr.-e'&͸Y @YiOXc @3d=wُ>5izlDa.@ȿ;6l;F=UPBW._~RҨO>ԳW/);;5趉]3&[Av1ۈaLc.?DVe#;:sdqAmȡYУccvdR+˥܌dpa!ωl8-73Z*ZBN}JOKƍWɓ 5u9A8E3)#uұgF4{[*t_, ؟+;Jrby#$ 9 p~=&I.Y;e@3)7#Nd&AiCfFzkqrS6/^b&PT ܏W<e5ώ7rǴݧ~s.,;f-ai-]![0 c@wЎqq*jڴYc\Yտerf&0< A2؎W|kzMVlR9@ 6fb,TQeГ|Y$PcdXx* 7r󳳸@}y єxMTc<LJK:v OOq&O+-kkX:2#(e $? Ļ*?ϒf_.O09JK J ͇2#KgioՠuQM,ɒM$KO1G4NF+m'ԘdJTa3if5ЁgϜmg}KjJNTFmݭEDtY,\bu.Cʮ/2f$Pҵ`JO5l@ցmɘ99teZt?[4s6~);8΃9eQqn&artDw36N<<x#t7Wmc!+iʦ,np l6{Xj~{T|J2K"VUSCI9S-mk lvlvS+W,O\_] HOM|˄ oPG{hOߙϾwg͚>`/?]2YR~j'"FC)ׁ NƱ+|{Hܬ4g 9A2klksÌn,KdƣTtX+MQZYHSYd'i/)R~ƢM90Cjia& Y{ EiY4= Y337>hI J> lҒȔFBf7IJ,K;:9.~׀͛6m:zH=aJ O8aܥkW͖-11\p!u=yz{-٫3hْmزTJU2Xy'#$~H5tAĄ/N?S4dհ-1u.q>ױ6%U: `z t##zՅ^b3cxZ6V;7YyhX:Tlu#ڃnnlmln므]v?qD=h] no>Ç3kL)32h1k~{E/2ucF{ 2hQ+oٲeUia@G@ b 886HnH_E`܌TJHf 0 L՗T܋JA7IeL͞ ˒oB f b2k5̔l@MYЇYQt'\1#qa+`Ne9GF_={ [6oۼqӆC6DK{bOT~IӡSSM{t̘#{sѩ }7w%PpH2`0:N cpf4}zBk5pC``0"↷mLo^L]H7 FcTlP\/C,3կ5|wZnU"VnJH \6~w/FiLq#2@{`uq!%OHe ^ii&#K<п[QZ8_;Wb"՗[1w ~މ,y9VӀ'Gp9h#ȯ Oʉ[N8yōtc`Z/GћߠwH?򜛛KV_reI/<0zCvv[PRNfL|)SĪ}z뤖ߧ-E[I^f!cAIϖ2 r~aCEsJoŧ$DQ|!bgV.ɧ BTQ: Y./;.^r@WSNd:txIN$^v?坜JGѹg^̖Ü Tz)c[b-ґÇ顱h3Q摿噳g?ܠAcu2?;vܟڽ fdPcy4h u )3/Z |mt:g}#M'+kPR5?HA,i{`Tˠ`ƆYF;-:e3}¤BYhfbLj|L@P}0`M !!!`(G~?Y{7Pf+3̙o/:tJ/\00?LW|5}'Ծ}zfn20[i ~m rB֚]UdnEӋy.ޥ`K4jt@YZE,Z+<v5}Y&P'z-]:w&O)5+GlNʚ 0AJɐ:tYs!``lBKg a$%;q8&f%r`k97-_\Y%HNJ_Fp̜Ƚ#t"~Mz%+ gy%vn! U‡FufKOK+ē+ 4C<<<+C(-駞zz0THAW{[UtSNZP.߻8 t}gK 2y7A3~My i с!7bl~ԳW}{# :Zw$&-ɧenֆO)QLET&v|@Li R֩mbBvM%"RNb bD oXwAZ~~_\jsꑓnڏ wH&3W2(?݈BCcFiGQhHLńG''k_ `:O?jպ?Gg.:JKaү^ z rb! `{|pdIoȶA^|Y2eV&&ΣSOþ $b?۶2Ű#+n=^l:PLlDw.7.&VްQԅX&u*"ܬߔ. uԁ#eD\F` CC1_!`,3'=/qXRSR<7mܴO>m;֡?m5o3SxhBLs.2*|51ȑ#lef tߣ[fO~#l^5(e_|e}:?ێz޼qA27ye~m΍BˋL{nTčRF,}UY'Ƿ!lAȵ^#Ҡ"C}"u]R88?DA8,իWh3vn^о0]Y^~)D$;I0c}{̣>ZH,1_Cc\ Qr ߄%46|nݻ)))^{v3!"/绵'.! 7ot58wmNs sѫk>4`#kQW^oEaaa#G_3gu(mՋֽ["12~=p-{Q!L[e0pOed(AA.scKCN³X)rKHՊη6<=P![DŒ:wwZ2`(&c3YK/}FzW:Uk0 |tf$Ɩg?FmD%PO04wh?6hpĿ7 a[l]d C?O wkV鯾JIIyFY+[1l8aJNJz)/XKQNmn7"QyqC9*~e{4${M2'd`itY ~stK'pz橧eϗl7׺Mnnwُ#ZPFH=Ype% ocN-c{(8oi2 WB7BT\ G5?ףqKjs߃l\6ցu' x)ҘLMJ\&(Gk綯d*zfrgZ^@1:c]? =1V:4@plҾ\-vɢ lc>>PG(j`7u(4,SC!i76Y$ߏȹӨFNd ڊUSkޚ1 ,ǑCSUZ.}I;(s?Y};33KaV̨t AqQd+re_aFr1qY@fB k:5(۶9,]d;>ys[>`bMdHHEΤ|9bU_ocI>Ƌ/`Đ:\ի]D4 +vWv%мNJHܔg;Li/+'wޖW$!7H=Ccʍ FsьtancG:t[A,@ ~DE!FDmltQ&GG}ŗu IxWC.3a9 !Ⱊ-/;mwsV\? CXͩEWf`ӻ ҭ[t < _:c@AACJU8:h?k+kaG]LtLF5t~wz Yp#gFC5 Ķ1^9`<~b{?צF&}`dg*M(7;LelJ0-Xjd$@)qh܎L+۱}u/u[Ft' r(--*X}ܱgRR=2C ~{Dw%"Z]9T Pzj^jLFpG9@ΫCU4Z .ʰM,375ɓ'S%3#RM?u."Sgj - ٬RG0W؜9PFBL `_,272cʵmr6;Pbψ_=+y5Qj +k뒦͚}0hr3efR3hL|ˤ|б0d r0W}cƘ/KҦoާvP-L`B_.B7mfsoUf*-5̬lɐ+wg&=#SW52ta]鐁Yia.m{U瀹nr~i,oI'Fe*ޓ_3C:Qn UR[Z=Fh p UҖ (WT#o X]0`r# 7->,OBTf#vv#&`!OPP33 \C;u+VчQ` @ٰ+@ 7FtbyrhWqS_gtvQZ"܅u/Lr_7jq^=mӦyݦxW+BfԨ ƚy0}C)D@ ԊB)E>*a̫Z!5kֲ9JaaB[aZxYW@jaF*Cae@kI:Fg=6Lb:b/s҅Wr^ʞ1666vrRn2mptv.x8)*;͆dڜmA$'$MH…e@3%jo.u>pfݜKONԩLiF~۸zFqdY G_%شKVW۱QEjAB1k&f_0N͍c''=D~>\l2Ȉ}_ t 9W:Q߰ACyGSp{(yU` 'N||乳gS_TLN,t}$h8P*"w}nʽh@yYʔ;"e F# ǭfdBVlS7&xO0k/ SR HGgi(vڊCЅKWYatN 9O:0ݷ:@5>O#4XnlDSn\P*̠('SHZ0$a _q )ŷ fL9]9н{'?C?бMۯ-G$BϟX8%{h K@Rd9`˶kBH)QƤoX 8?1{RV$ `1xQhg@#J]\W]Ž "p[dL~M_UjrNUyz-r}<Bl0 /3Ve?_"cfm'x2=b.2-w8GMzÁwѣ|Dj7~ۊ ,":Zf5 fG HW"TW?~+(A0D5/㆛$5{0}`ˡ&qѱW<Z%)mI1\r!>xvf_3t!|a\-hȰԵ[·:qY7,moV [i$eSvUfeZ~{{@4u]ܔ L055<|PKm@k0mEaDE9tJc[&J/2YEb:9М 8LL,gΧ\~~'{`zm;*'<'7.\<^cXᔌ'5 ,1vXzy+Kʻ419:9Ү;%H0[E׮r1 fkcƎ}ʪL%CZcǖ޵kzJ0FהLڐ-/ o2nY,d,V 3L=8Q3B^=F&pN /RM!jNX'O:ńYyl{> J+#jJ1g?635hؠ49bHS{Y Ík2q2N,51J[Νƌ/TO.5ÈJn?x G0g앹2smO|RH=BoƙA3 J"rC>oNYz- ؎E]17Kl!laP+|BQڝny>NN/`&~+V}9BpI2~KW'Ȃ'cSgfG^L:GIO>&M.QO.FmJ]_>&:WA em!&Ii| ,3=˩n M C@8@8+WJPP] -i3]/A*+G/!DQYAsf*&&&=HGthߞޚ5jx< 9ycfRn]e$"v9JrUCML6+1کss3.5NN>ԡP ֬^_6XzOZ!͎OA4wx9?%s_[خG/\&Ðvpt {;{ ̔,C&*C>?=b1FH[dD8biLQ uĖ*r:"}שgϞ"i/,!ƐI&ÏYM7ү?B/_8OD-ߣ1@_z[-@m hYYa ~t+u2ջ6?^{nR=b6- Gat2͙J|Ư1#D_T/ 9yqJ'7xǖ2ghi jgV=Dvqu!+K+a" !*eϽ1t~rR"3h_GČ<:43Kԡ$C;r ,]~Ma";㏉E})ZBʷ[nq&L?p|,>A>_nv E &>ڶo G%=b+v˶-[FksP7,9!W}Jt8TWA8s\XSa^,}h̸aRllX:l.f )1̟OY1ǧĵwS{#}LN.H\|h7<ٳi]hDs03WF<ɓ4`rUK?6/A٠%;D,i}72aekm}#FLiҸĎ:mtXUGW Tv+W@h bN.mzKج#ٳjTۉVa`lj MxQ4x05iڄ=5PޥjAT.β-Cw0Blᾨk=;v>DIINf`co$vFfL<Ნ2-.l P]~E) C9j>#{xg<<б :zɐn&n4DT@߁қ !!,KHwx-ήbQ=_6bkdddw t,‚Bq).` vufMeC'Ut LC ?N8QɩDZ^wAѕ[{/)?⡇ե[1̘$:fAN]:o.wE€$*9AɑqRBě03)^f«.+;K::@.:A0їnt޸8YW7& ++**V@|,* i{AK4>>f785b3A@o} Nd!7 0P1KSOЩӠQ1>(ԽG\HӺohxGW s~#cw"i9? ss 3G HbFA`4 j~];8<kcmAbb£7ޠ^B}= 27,*[l-cOXu3Ηѡ:qҤ=۴ӷ_[s]e3mێao5:4@v1-#L@HO]VJޕ]=Ϗ)t0 **ˌTڀZ9|E:)sws#+R|/BcUuD͟Zfڃ M۶zs0Pk xaʔݻ?֣GhlfvdD4{ >33S1L]\p5 V<>ʂf,GE)Ǫ:XN{~G\8(Kkk㼼\roȉ 2Fuss8njc|05 ^Y # ~V <窤/͏Kl+W=0`LXF?9̡ O+S_MLS_|~;0S1OJXϕe̕gkO-U.1ZWV[onٲGƏȮ_Y/J `WZ.-i@'^VftxkkYS iUzZZb9-Zd_~7g̠~%K2ˈJ *NT#GҋM~[U{5Iӯv5} 2xOm1%!ь11!kYٔ{|' kyy{Jz'$~Uzqbb-o|I2>c-gE^~ycR2>ٱcrJ(i<407RS蓮!\생UCe\BV1ɂ /%5E?*2ESdxP ` m$=")&ű ~O&ũ88߹ Qz;ȉPƥJ05R۶m=79Y-j J@2,&yhC:28@ { 5˚Sp  ɫ_MNV\RfχT@B'}08Ie.\ J!}\/`Vs_@c&+.)^ÿ5ʁD=Pm?׼<eF>-P W_t]tJ~dr>~UIVU3us9b![lY߆e[Cdl:!BCJ U1fdUONA~z&PY-[,U;?,7:'=e j|]WXJX֘!x0)%+ mںEMM 5% wӊ+d l3|<@f*LO)  [X KsO68J2;t@ Wy/<#iQQtJ]8X R0i?DRȦ 0w޳gΪgtQBfV"mo VzbJjxW:~ҥ~&cG7n$p${zrRY-Bi xI]|||~ag譟}iOC2@;q/Чo_L$adl[jBogm[8f^n杛F?$ZθrroАC+t)w^%⎹O g|U;D_&M&YXXTAuk׬YazhY5@BLe~(wh&&@S֭4x35}W?~#?/ ̌A@Ӛ:{ɚu`Kg^=%{y }748IJ .\@^yڐMN Q7}@GyOoӶ*q%Wز///_DD8<{{ϝ:qbqc8Ge] ٶu[ }WiiU53kKVzSƞzN|ֻAlS(?/>oj.q24sz u$Fpܳ[zk QÅWc))g'n~PZjEЇ|$<83_>~j w[ѮCSMy^xq^n40cpOpBKPœ cLLv} tFF2N?WhګP^=XKQfi0c:ԡ6q__ߵǎ7_zn۰ĵ&Iou)qE%fv8Ƅ^]8w^u4]10)K0ԡ5OO-Zlc#_yuN۰=lxFN1lեg&>:}J4\ W<̬,YޫuM @sf]<2a}OM~S^xAalHdծl\xI:*^MČ[!ȗwi^$&&APKKKlfG'?[}AIO>1d٫F2*q!vll|s5`\wq d.ffOPZA+W>u董tH^۴q'[aD-y'3Cqā/+SѥKާ-y/hÆR v.ruܓ@uߠƌg>bH&HzFHOk+ͯAqb2--zuq@u8skp32nm;ڶG,~])xyz:,%$ěݽԡ$jӶmADD(k. XYZό Eګ@]+333v:ԡbnnNNa}w9j-  h؍ɽ~]c?{2GAP O1kkN:*%Gj"|+}ȯP֡Ξ;-ˆ4Eӧe`0Aw& #cЀc uyP{1Ft9f* h\^AQ@)3 cY/u%WWpaǏWkx`ai"$Q||] M6oML~CU(ɶu 0dذ}nnb׍40ďdGϿ@fπ.]uC-?uU a^[WI>މZ@1c¸ ѣ633ru'`iiu Ο,2qF4FO/O8hPʫӧѯ#F}ϥ:E.7o{`hkB8~^5&s[2KIRVOkB/cYfK"QX>Ho CӅM#lv\Am}{7sϹsp,p9P \*ۮgZm7lvNu$2Y.~BτL=Cl tC OO}oJ$EhY)k$`me~rmPJд0Êpy(x^mf~a>g p( ^KT ODR Mܼ1 ZٟcF75be;W0cko\Z*EHC3sY{w-EuEI8wmҎ9t5lٳ2 CeEQ"֬tN6M̞;WnL~ܷm(iIVuUUNnom# u˶B2NKvv6hԩSƎLEŘ-ii6 򑎪mcë7h핗_tttŰ, ˶q( ۉCU1LDB#OOh&++/X;ggZ⇲$f͞q|`m]vQPPP_v=MK IBL$;+S1u BfzC0L"8]=46Ruu44 G\.+*̱~D"|O|pdjsnyWlٲeұcFu~/̟e\E9^ $N^:t:TԱan6oˉ4M''' .u³?{ޒ%߿ &|JellOG[v[-[vŕ+y}ˎ;gz*QTTĜs7n,;w_`qx2fMӡ`I؀m`ضmIdYưWU8zE3o^ً~ꕗ^zgf#P`b__ߘ5n{?c55~I/9?pؾ P7?Zu0e˗3ctO<U%\z"20Ml0H߲HjuȊdӯܪ[,<<{nLa*ei+Vd$9Y8^ lSK`&bC=0es9ȣ[kh04\y^s4xd}??,_>lmٴI[0;Uujի4hJ/׾p3iL6uDГfN۶$,'͛6 ).^Ӿm۶7?Y>Cy0qt} Vc3*V>To:Bq B- 4 #%lgڶ WQ*e9~DZnޝ+Gw.;i(n?f"DrD~7gkU+!l^PQ?C -JDmOv&>D}M}U?=;ֺ?|߷aÇ{Zv`OY|eu 7nHu-H bc 8<4ßϮ}pTk`ӎJ&){O8%zFBwO #^w)uww[P r顾;`t !l"c%@H%YHBHɟ<0kc%.l#F1l=#!Mc%L,Ʋm JG߲y՟ӻc3X6ō7={q5װ%aZ5h4lkN`SZEq8ij_\|l.IQ~euӿ6!445Em3&fOOQSۄR__ߛ?2vEfٸx J+q IB!{ TۏqqݕS(+K4ص(KPLI 0|G4g8쩁M:X9~xGnlkk^[oe˛;aH%!*Zd\*pMsåzm'ӕ@00Iy3ǓuٷoDGGG}ܾ ޜtL?TS ގ$m!!#IJ.E}ằmښYC а,23)Ik˯L{^ kWMd޼̛?uoHQ,Bt4l3&l;;Yp\Na`&ibZ|}Dҭxn0g8OͱjZZ`ڗՏ, ~_[_8/? ۈ' CDBRjɑ$elVnpmKBQj`CzI``jXz+ # Qy~"m#'O}e=ݻގa9:\E}}CJ/,"Sӡ H8DV/=])I*[l1};d۩2}hⱨ}ֶ33D=+v8m0ͥx2ӅLD4h%Y`k_gh}b4#чm㽬]L$l¶а(LD1(Y^# ߵkǬ?\TVJ¡~I3 ]1E>y*!m\Gyi!yjF61IcV0%"Q]D7$I`555Nj I*Xz[e &IwY% ͰxzvUfs-#01XZ/G}m#O=qC)'$Xl[ak,--zHnkIHI-e`XZ +"z\î2?x!` 8piȒD0;8,B8>¼o$ՅNßM0b{v-{֠  Ȋ /77qTi=CTVXP>O_@7dVQާ6X ,&cKq>}PF3Lbk6wb&=!t,I+,,,2(Dr_|%e]}/ mټ;>7o@CCC"i$ N.- #Gz;O#;<YƣȌ;Woc Ʀ한5K.L FaC*tuuTWw/>ã-~yL|~,|Z o^~Ls064"044O^UwlrCccn׺{ 9VSEI&==¢"223e%T:/hGzQTt{?dgXd6 YŴ #/ӯ/\*ޠP8jo17}Vr 7tcÉX,YY.|Ojxd:i̚U /C iҖDb ^]d;92#*3,á`Z2ɰ~dJ,!xU9{F?k6CIGN?:Ob6]} -Yrs>{]]]n@U9'!k{{Ub& Ӵhkm1ziol%؛A U'Ws}5UYE50eQE3xL8&xn&mڃ,ˤ,]8#K^ۊ*KD"{qyy\s5775U}AUeQXOԏ, P%qËKv T5SCu]׵pBzKI m ۲D5\-?f.勗_GtARZ潰@,vJ޵k\,s]V3}>0m#qs=DB6r:XɤS6u'Z).=f)ʲ, r37c<$a۶ͥKa~{2~0˘:~$1n0&T%~h᱿mBc?+sb[6n'nKz 'BE x xY: g6!ͦ;q=";woc4He[QQo:̬r}Br<p@^)u%$QR3+Vp*gkfyf&K9H-ư,Ξ=~3}ڻ(^ʔM+Ӆ88TSܙOqr&-9i4Ɩ%9I$Tͧo0i73vT)Fɸ  eQ[W˹>HX{'?U \J.C}Hrn(]1&&s[I_ocAz:#GpL{e2{SKde! >?=OԱdDub݂xi HF޴N-oKBKP{/<CefFaPoX< M -O^m&3uT^x`LT $$lf*VO0M58?u%kpޓ$InBPP6>Ӣ:w_/^y9o%)$eAwwi%cgu mufQ̟3t<KSWU,?N4M4$J7-FK@L7,ġB> Uz}եx6; $a6=F\75}"cF c(IT{யȲ">өqR$[ ؖn['/_LcK+_{ ?w|b9.UA<%lfx\Oì]&pGˊ D{tۣ躅) Q[yer<|YdM=QmgB!n hS`K.w],?&۷^U 8d$0M /+FeϝLwW=!nf)=,v3uHJ1}(NOM >N'ϭTq! d)|<={L6m= =#MSWWM̼!a4H,_L$I}]m\y dզM㧏tv{|-U2X }<}M}"IV^ {s`9ĭ7Ʀ_:xXIKgg']]]g=̳?NEi8Tf2e ;ьiؖIzKz,8kΟaa`T6`J2' ;%H'0MF +tBd&h b%42e90`ljf}݈oqꐇYخHB[ƢECc=D.+p-+}^|8]7?"II%al ۫c:kdfqQ| gqc9k5 `\Ff"0j ks?쩮W!"A2%֭Y{]JmfO˅i[`Nz Dpp Ȓ`dY1~ӲH 1itj]L7@6ф̯Z'-~(ntCx=.&1^}SN$]|*. *Gn͚Xp*gd0kª>0,,$ ,@0?(&3FZ<~8Ե9/|a~r 34Q@O_?z_q:&brôlhk!C>*T:C=^[䛆6Pcpue g˜ɢT7:s6k;1?,8?㼴vgN`d 0M6%I%餖J*s<.,dmC7F'_ [ZcR.k, ݴ1-{ BSGOygz6ulΚU˩`Y6=qmQ.^$$e ''?F[EҺP(r5W\RsZ?׾U&L۰~۲mf|9Vqw 4O=(.Lee)i)IH􅣼i'sfR ä/zVɆ7' ۫Yd,`c͌p88"LHB0bC4Nmm-Ǐ}0_ X̛󮶋/Xжm-w'6Iҩ4R Zzd rJaLjYl8ZI(g݁ ‹:^{(`zaq&yWӋ/WםXÓ<=]W_d9uX4Qnw\M~nFji`we -NfzJ2XEfôO̤1eDb NMzKΟòsg1bXTFqa&mu!e$$UA[2ugt۶{ws`˲\t³K |}*/eL+0dLF2n\46mtGX`8˖uۛIfvPY[PXqM|׭3]|i߇2w|N8d}ƌ JNLK@I!K\Ьٴ`o͢dHZx )=BHi8M>YJeY\.m-W-a嚭4u5u cG2qLEbU;q n؅OP?FzorQUhjjJomm1x_Hscm};˗{$%<3 Y߉i%m˶m ZC451p_<׉a$5̳QXa>q [PuyyK(%x1)LxqH]))R\nHXo7Uq.XiGTPȲmkwQycS2$cF0fT)BPe Ӂ頦m=B4ίDnf[w@UWwNi$ ܡR*TEx-k=#hmc̹nnn9/e O܎ds93ٸUYv◒[ϢGgݳӦc۶q&?jG|ݹns-c44 |E~L~gң&Ӱ:ڦ]{e/?{ |V(Z($GU,@0ܡpB7XIlB $9i  A} a=p_7oZkv1ڻzIhC̟J,5.YȂY 6FƘWԙBQN,sAmۧOX}wPS}R|;8gAE^8:*=5*H} ``9[k;ڔ_?z|=|ϿYEx = tl|7Y x|I @,Z[̉1gMqjo?( XEOx68uq1fi3&ʴ,ʆ+O{!ٜ}Dtd˰bYgM/r]Ya,qFƌ,%;3 {f (uvԙlE)K$ p1ŲѪʰC:FI[o=Ӵ,]xrqm8͙^\$xt$i8jjvkk/=}ȋVmn0{ PZ[@@ 7sӯ}`Ζ.^\O@YMİ,_8~3O҄7E,.&W%%km0d9,I<^xMIeZkRZ݉X6&Ixeh,F}}}0-ڹ}|W<'еn̙7(BƏ6bxiK+׬^ti%m7g+ʰe.OPUF A"۔n$!eS nJݸu7{fִX+ mP.=`1~U̝1n !~McZv2*G?~&qsj,kC<ۥ!dD`t&G ǰ 'V2fdаlP]|O^s>ΛxhN^I dq/M²@f+bC%Ð]x/!GuM{Aq\IhB TZYͶXWBQj4lYQA[cs-W nms|K p,.YRuB;^*tu{na W׮A9xKFp8A3t$i8Ӳ3#KOnVL3qJ( ;#`c0-(+_ʫwQTMQ~6iT-4uk8 $KKMgoA֘ #D۞h^օL2d+2;L^`Ha!DM,{ж4Mm !Y{#g(k^}#F0ut,$ kΎN-ONN6`@8xAҒ/gfRv#c#6 1Oa e)%zpK *q1OHMulHpFfƻ.n6bƍ;s>z4u/Xx6c a޵ _ ysqS4Im(J__۷mc퇧͘71v#IR~tbvmGCi\$9$IQ۶@NKFf&M mal%XqBQd 2GOřy2(iE}(e <'oG6ôӱ- =gG,[&# #is8gMo{yMT0աrƚ\40REഭZf =7#1ӈwK0.I,Y61BUrrru0S+ۀͯ}mQWw~R%t(..yJ~F"6mHѣ4yҍW^uUo<R~घ2?r l~߹-%??Ç1S) k,S}dI sTJ+Tu`2MDxCrydSIu),com{~k2>N'p /+OLwȌfϺ^:FKU\.B8iI^&L3B#x@3dIJtahUE P F:Ձ1>"jZ}n @>lhk;q}0!Ez{^{urii驶BtذSD"J֮YJKJԦ>0gUEIܲpԙ,' Ga !g,YɁS>y) e/U`„:j@%y`%ldɄƸ]HzLӸ4eKof}s: t,H& aģ:[1F8A @i3M<vg[k;XY˛4ܺg60Ugmۦksr$+:g:,CKJBUw!#%2-"%dc&z"F<܋ cJ~b'iC)3=D!KЯ-j`W$BnЫk`@^ Sp m@IHף!,Cǝ]4|( }JT#B,ҢW?xmOݻ8y^򅕿>7~<퓆H'OBQiudkkطoohț-Y^L3qo%ؿafiG$|6Z,Jo b}=I 'dp]2 `;\DLsz2jkMf8 a{(S=5 bZLdD! nY[g3_PJ'CQAm$lpYN+zo0i߯{uvڕ5jh~߿O~=w_wMwp(U/~ٳ{QF]}'oٳW!zeGD3&XS]nt.V$ ΘNr$Gr08/mbO%Eq*X^xv:<]IW1HI\* b]m{ EVHÌ zB ҨjxS JY |[:%%^*+_zQ>2r 0bzנ%0USٴqSzI4n W? 4(:%gʕؾiĉGWTl5q/9$XQe흝tdۉoFLP\ny5?*oe$;I۩P%dÙ$Hkw,ݽT6^e/cرx~ZZZ8q"sf޽(]I3ffUW 2ZkvTiƠ8]8hm4` NdO4NEE˖/ȑûƏm۬|yBO=׾ZFZhrƓ]e4UCL< /Yyg8z(&N$33裄ÑÇ_|w%mBCˊg|Ĉ 1©R*$k~YHBQ75ؠ ,(I1h%; zh1wh2 Vy*:ѳΦfn:ZZ k ƨѣxUd@FPdU%D$L{m5|mD XGV>/ۋtDh0,t`HQO~궟| ExoWJpy#am\SŁ=v /]JVVϯXV|.{!C i95{־Ғјa38m).G|(H-ML Z%%w}Ydw\g[,Hwqw[7c/YW93\v֒÷mfuV2)@VX,KWc=Μ!E!ԴlhhoeJfDϴ|,8_꿛Fd]<xi 9"&Gq{LpW;z"+(R*++׿-[kg?%o1sǍ^mUNUP\0Sjc]2e0u4cVnyl]#Z :iض3=/ۻFv>4#ZH#眃/;/@Wg',^L^^a r' \DݞmtHN"biq_:;;M"҇c&Bʒϗ|+x߮|tGz.zؖIx8z6$%xR{8 +Yhv]tQ퟽N^]i@iix֖{ Eaˁ=` tZ]G2$E%Uw[$ 3Bko$t+Ob#_IQ>LEEN\̬naX-l/IڿuJJbeNr+& ƮB ɨeonjGqxɺj.7ˋK#H4K%`~]w=ӿyil՗NE83rSQNb]%IF񦁡̎;ioocU ~l?x(ʘcؾ};mHzG孱8 .ptm8p=ҋ+3Euǣuml=9Z}O{f?%g0ddIټկBZz==lIvc&G7!fXx|}}x=DQ|'B`6E=}߿ή.{7e4HHjY9p.ؠce-Mn7ymٸ21s>*esNFz:xi9Lݡ8 gۅkH$1Z,B4I/ P2IŶ-[%&w<;a)t%@9y'ta&yNQ_XU{/{11o#OtH]N@Z6ۣq$ՁD/I#|Xm'a&h(9oqebi> r#qx|ک޳)SpqBVWÕ;tв uhoDÙU01p==`p[PH9`'`?O"$x؉jb-[/]z)Su`d9>`p}{jkkϪ)lM Im5 fG N[4hLD _A)`dIBpe#;=Zޖ+wVs=q²hnm3nv|dk`llm)ö!Zw: :It;z1ALBP]ntiYNh_@?z6TdƌM%K|^p=g5kKt^N &x"N ՗F"܋O<~`[&v -A^~>/sionČNdIVc]m$"}ƷI"zڈ6ŌE8%gn/Xh41b=KNIe !  TWW#r$OE5Ç[C(zwnSpYZ=ԃ#=bڦP3hwn{j 35- 6[8s$'aW mlqlSDzM͵Xc̞;.bEK.;dol&t4t,Dx6H13p̝{2,i<= -Vo0z$F*sC*m&do{!u;=~hc[frjCOM#yԱ б 4LLdmIc 0lc@[zHTo\;ٲ²[ i : 0w<&MLNNe%Yf츱|9tgNQ$ ;~ۖIhK=:eO475ռ-,]t.˲{vZ}dB,Y׿ GrT(TrGzD27(BtFi>NOm;n4 (pj׿`Ə[Z[0!Rd00T"T YQP{#,8y|yqɌeaˋ `YILÙ7U\\LFfm](b` cIO}jەW]yS}}N-`—Ĩ>gݳMM.00j6KmDR2(&,Ɏdz~nNHNhMK $&0@1cƲkN K/rvq]dgg_@ss V<m1kM-=۶_pх7?(p;/`)??Ι;EkI K, ]mm혩 { '8TE!F5d$9+|wWC 0 zzzp8aVUqX DQ 4MBq.G@`bm dggqM7Kov &^s7ɦ %K:0`yǨ]L@v84S;X_Ũ2W$HLww7ɽt3A,ƦF?#Gصs'ׯgۛo 1 ]LR1T鉎&buqWopE7Y|~ xwcB̀m }|;i2^xLu$,nIHto.U)E!ׇiD"l!0caM`ZDg+.%,ݹp[[^{ݬ}LM2̬TۯӪAv8jKI*֠R$#$D"ΉtwvF^06}Vdmo0 ڐ굗d;͛<[MXEAQ VOko`Iq'hmn}od9ijɏHB1M 'Fhmq!bD#Qz5ErFb-9R ¡0x\.>|Ǩѣ>iƪ{~, I..X Ͳijl:c ,']g3kG)$>|G+onFwwo`Ӧ$ TU#GQUh4 y/#s=q҉FzzzĬ9sdI:o~{~PjU;,rE_a"82QrYԞɼ(mSmHmI=)EQzɔ@aI‘$w^ڙ0q"99hZN瑪 --T/,(,MӴ/^,͟d5f~}={ر㒆ϿnID+jZ?A Bwm?3eȶmZHb< yLBaQ!k^[C(+_j5 cq>_/ﻏäɓm{IW~l9]fͅw.%@ ;H.ˋ`:}}!>c]|hp0|p/p88Zuj v|QO;|0rFM?RFGSMoϮݷڵ۶TWcQ$aYUUGu}"mPEQ:t(4|o%HTC 8hW̛?x"Mkk4N!S4GccHX OQN{TU(2ʆaZJ>vBB ؼwnMiߞ=h$b^|٥G_9v ޳2r5U:Q(R\\-U{*ʇ{jҔ)}歟M PVXXzj*I(,,\xؿo?XfEd%Ir:Xm8Ti" X<Ή ?>r|`)**ⷿM{yhqGcرKȲ,ɸ\.tCg lݲ={PSSCNN-[G/sy\_~Ν%fر{5(\nLu$Dž]Զ +Ϙd| `4y2r7۶]g.M > ReۅAe͛gM6-rE2d>X:N>̪ 7;o[[Z(6+m`6F"shllo8 "NN)(JJ0L@8HUZww7qdYFUZGd&Pn==P__;imma *ƎY]mm8#3+X4eW\ަ{?3Eˣ|2IKKacF C{{;--ۛK?oǢ=hȐ w]"zr#Im6hmLmo8;otnwG-ۂpWVV۱}{iNnޏj &B躎i.yiidegKIЄߝU$5z==$h#%tEXtdate:create2023-11-20T18:55:10+00:00υ%tEXtdate:modify2023-11-20T18:54:55+00:00hG7IENDB`nut-2.8.3/docs/images/ci/OC_logo-watercolor-256.png0000644000200500020050000000455014777534445016577 00000000000000PNG  IHDR szzsRGB "IDATXGWkU~ssãX  *6Tk ĊEZUmE_^jcJ7Lx<ܹ瞳?1 <'{ZkセE8U==Dp=;泓Nno˟%!$4~d9iٶW*?ʸ\g(d/*Y?Vgiwνngŗ`&p0)`իqz)-ZbWԟ "A&=ųxu8f$iȒ+ 13!D?ĵ#O}wż>9}S`?6IH2^O8\wYL@. ?{GD@\\? t |ZKbm2tٰR/JM8] &Osb1e*"&0wn돥b> 9Ϟ;R\^٭PVV$ۘ$ٔ4M'&a,S>zEϬ87ph1J/Q {8IHWόVPTx[NŰL"Jdi2/l7 6?}LqP;q"Pvs5fR v T=5n`wq9)㗜}503XVkis?oi\g[Pj&FpXg/>{,@Oz{{Rp[_lv /E^T [6X--w%/h卒4Ώo&KOl1 aXq#Dg?#Ŷ`$ib/ U<7 Ka3 &Kkwc[|TF_M}D@;bx|\(ђ, ^ZQJKM>㚪TPشip|>J1rgth;F%M`P-KEhZ3XA>Oub= 'L]jBPkU2w,Ca5k GXH2$ÉS-nJ'9Gs\463[u Oj$Gv$HI$)=g\:h-\<'+Ѯ TRq׮Z7iڔοh;Q2 f` shx8Ů0$,{?n>uGuk2 NxPFI8RZ) _'vRJ,`dI+SQC|k.yXIz{!rH[~guiғdq gY7(6y`RzˎAʳZ94lfi;:p^01#?B\.ZU_po5 @Zᝒ֐r.Ƥ2i"I0&SiV( 208h6Vxm?kzjy<Α`%aĤ:;0w K]Oa1X2㒯Q$Ѕ.r`ӂM "{4$6X}͗}y;^޶ CVU6N#OBZD!ZYώ?roνȓ텻#A٥0IENDB`nut-2.8.3/docs/images/ci/gandi-ar21.svg0000644000200500020050000001027614777534445014427 00000000000000nut-2.8.3/docs/images/ci/jenkins-nut.png0000644000200500020050000010235514553676503015026 00000000000000PNG  IHDR>sRGBgAMA a pHYs@@uIDATx^]`V~ݽ1AZAATPTlE EJnƺmc9F@99}]LjY>}4`ooo;z&"''GZprr\WWW$]sog@q>MKKo^9r'CRRȐ{ _P{>>CHTXk@jX}|׹tYtpp0q,[ X];w"66z\(Z[{, yBH ,|QZjު ! Lp oӿdDӱb7o֮Yxaz9,摣\e'fUͦo# >As`ZXyyyI|иItoƸ5Cmg3[ۇ3ŋqT##ȢXFfZ+Zr/Ox Pr%Lq8~"GOBL\",l,p\(yE2:z_@.]I*nݠk@l M~Wc ?pvr3ESiiQIFxNI=Î%+"";af͐#ǣe>^U{ZSߕ!*{!CaNw_ 2@&LJJ¸ƴ)SY2M#J5O>mAq@.('GG8fQXv ~^BnUL)/#PreK4iMxEq櫱8pHbG8nn.]:㧹s1jQvT!{wwE gX2Č*[dn `h ٴB3wplƴb)}Dkd11r74uf}09)ϴ4H.?捛IѮ6F_~~7_ =vaF 椉d^BuiT̢ \4[ofaɟk#&x|:b8~B\fբL?I*+pmA̻tA1>C,YD{~BCNxQF dv:L ڶj @f +h&9ە- {:ߊyӋmKr/1t02j`^7aCѧo8޹ǩSX=c4VJ:&Hrtvruu1$gIrS~3m8qN_cDiݷⓏ`j֭OQHMMŖ۰XHm0#ړ``0?V s=vq4bYE~>Xj { d|:|8 `ĉh}S%v(l)?=<\P3U<oazaz,$L.4iX"HIKGtLj;oE@/Ҹ^F>7 BjoZrq&&"7َˏݧRX2\н{Cz#D4(ONEgS 2T5EGƌOOO`p_8dT:'11IDJet[y} ;]ag7y{uJl߽_Ԡ.j] 0X;gF 35$M(~^wݙyTL2 F pRehgt69eq wLI1KʥKHڏE֟&9^*0!T疓>-Er$d/2SQQ:W&O//e cSz+sx4qXv=W&Mc퐋 \p0a{#8v’?7XtjLy9Pv)Þ#xn0Rp#$=׊, v9oQzuqk'JWkIεBo,Z!Z# wG#wQc[;-l_7b*yo"頟i'@&hx:b[|~UvF"t}Gʕseʔ[oom۶YrH#G?p1ZD1I'?,<)ȑ "1o1H0I@%%)}ߎyǏc0uP'Va {o̊WK ZVwN+f3 /G rqjX21U;3;WyvCٲ^xfYQcŊb1f" Ξ|76+za9ҤR5Ag $4T`W׮]s ,, GÎ;q1 `bcbԡ&!28Wk]`ǟy VnP3KBzWJZ&ڷj7WgW_LJ}O7v" m1pxEiD:SOl#|hP yU*Dp ؾuǺ)N'Pw/۷ey3#*RɦtȦp1~nMpǎ?dhQ>\x@ !ϒ|^DE%N'N;}6 6M只erlyHQ¤f!(jg}}鐀a6mڢĩRCH%I"pN[U$2=櫹tm-1tg!S5=ӂTR">~mrR⥦gHM6u%w|p^}mSNx$`Ps'h$%!Hv0;ظF\{tO6)TR@P38MUy\ e۞f)E`10uk  ( fA8yxx~Z O~tYydpaP ^*\C8c:I@1^"[=X m{ +NĞL5nnQ_ݻv989@o/F\;uw ;Z-؞a̝+\<|lZBPjNf 0؆V(n:q/FL=Gהg$ϔTx:˗*r1NxD|6-a ^vl>cR~DGH&#OHuuuC ~x7M@ ݜ=נAY1Ĝ233\.LmYg+>_Y{tU<.E#K>7 fKԪVA~CLLLuFߧl*"(ESz1'n ** 2ev,ğ -  8Z[Ugs(`:֙mV$|wܱ2sST*0ce kĖUjK@烊 %R(++o>0{1Q "DE'.8~1"ӑߺRu | "4iPy6_ܨa'f љ&Hh1@-q QIb6K;i'#0xF kM @V81c+UKެ-Ily| 0L(C{VT Ǝm[5GA KR#%K8)Xyy:Ql(B}a7V(I<9 ^n+"y'TSK}=mGʼn gr!2CO o?vղ68O{ߢN]7KBCԬE%(:)̊;=6Tʬ5Nխ$lOeV Z~-Oy&0ŠJ[qWzj)C0Fca8L:v3-O@wL8qoZjPg8yKLXc\^GZsQ ;).g;Y0d _،Smd|y!ϷTlijFќ T.IǍex R8ñ&\@K2L2L'k"ߏmj]  l`*(OFԐM][y=Qd 0I A2aU Į];0lPU-( Y8%#N6ZK c3/{'W8{MnM #>ȹO{5 sy>5{p*6 o Il@ޯ#>|(8$S-8- )/%rt}18L\B6HN}UwwŜmB.HLWMW ѹ}W'pvJJXl8 34Zm'e%[q[OJǂ4u./iuvHًY "Рnu@,wcԴԢ{L͜>-(,Kځ H^O穦E; fdR3-xp(l{ `ބVW^iI<"э}يvN}˙u %?܅GvLt֡&~\BYl_W{xJfsѹCcTP'EHPFв-+=շ/[f[0Bva\3W@!~E]y0 z1dHkNsDE O$ |..hVSN#0%!Nu(^}{==}`:nn[1Fl<,4qSTKR/ d &|+bi@$]X d* GSoقĪbش~=NE‘IU™WyQ2{?-o$J%SXv-?6(<>-WU\]qPLO CuirahRWᣟڱ V?B -:`ɒPySó)n.xcD|;sjQ{<^"~1ݧΫCxMywa/ ݺbmı8'AJh}CFf1j9;\]ħIBoSW(?8MO*z+eYRfjCc!.΂[oZBn \,?cࠏT 2z&c,QV{썞%š !;9lwvMѶ8tq˥j 2 Au%7RpTĊpT7nBgCfQ,V,;U'Og/_{@lBJK9 ISG?krpTTY$\jր1B?{xb}CeE @ő1p&h{ޅ&bȢ U˿~^IbBQC44_1Uer`1 өB֗z3)8DhP nnbθ_ _B5b2yfU*qh_xwV il"_1u>|X ?4Md?S*#W Ӓ wY٨W.w=w`#;ñhrd&rjUʁ?tx[W rZͰSF oÏ_ŏ^|^5.&8 bD%A_ljL$6]{B?9sdoquF]?Fefr?Cœ SZvjH|q)hҥ7ymL=_c-(0>M':oj *K qݨҠ gC7[ L.~Qu0P4i΃xo4# jR $> %װ,r@u ^ pgSF~&8LP AT| -ـރ'ˀO0yزnݵ-Ųmy9m| 3 D;0pȗ=ZGnoo=u#%"o8}6o3Bqv6%g#鼠 O 2Db صjAd8GaZhٴ>N 3}9qF~Ug5=w 6h<Ѥn)bg'$$ f#9-CWz͛0$V IB(DNxk{=|>g5=[=G ='{>6 u.>puځf+èGڧZwsr@#tm`\48%e]Ύ !R>lrA VXOms!3gOw$jy_b @D6WsЦy0\7)T4Kw7#SqICCFS/䜋K=ѦY vA! N/[9(<Ҥa{/R5k,,Y.8M`7\OPE/c#m, p*ɸqR;ńx=xOmGv=/]vx67@1`57Ǵ_'MLT x27[r$™KH@pk#(^EI׿|tNΣD9Ӝ,RYrށ3H(۵j={s܏^^yLm67a0ӄA>*{-sDF~FcS+I3(|, +E/N׌#^+yCkN0F j+~xX}5 Z`qΤXcJnq嗥K|Z<ӒoƂ):Ԧqmz;=5q5CQ!؛( @_ _wg6))+ 5:: 4h61wqgXlfӃXSrmg"1 O l"mP2ĉnѸ.; e& ׊t@?3,t.RB&{e7WzPsӑ%CSځs!Nf3I9~QBuK !HhB?)3$#`h}"?N5GBIkh~3 Kv lMTK`|t>Hj$ctFƕzc;wѹIe ,܀GнGchU Cǚ5Gw,|Dh#j` SKǎH06Z7%(svTKؘwGaCGO`SdglDVԙu阌bi" rEBZ*?`3gӻ`Ǟ#bLXZ4%7fx$g"T5(I?`Ք=\Up"Nu3{εkO17MbM@5m@d2 l4 Aw"$SnJ6Qׂ7I!h)h_-Pa^gajH`q9*l3fݑ![#`-M1"`9c)vw~Z{a37ē}ϜO[C2('[^#}07wXrmW&މT%"C4AxmJ;G{6F gc?mǫspVwt%KvGWKE4 cv2؀l5]4tO%z囘Kض51~B*bv ]4cyhFn&hiؾm;O]cbC,8SQE~9GsJ6NtZMMHϝ =D~vxME=nRbZmz_C߆;ܻ_(Uj' QH3ءb-xOjhgLYue98T )"M9նy]ÜTlH| <|H=6~F~g5Voj"S! iCQYuNFl XJ$czRe1o968>/.\xzR@sԴb$HN˯*&욽n#C>xߞTq[5-ɤf7[ߨWʎ 1y.4nj q0ŝv6jMfO?LDhD!&\zZ`G\Ivd~yGu(?/_D[Љ͔+"%41 K3'ڣP)3ۈ%yZx'd&K8֠ٙps!ߠe:bpeA-o]('%ֈřx'P2r njR T⇺-z1jΜrrPNmhE6pl"%hM"6U_Eq[횸,w  4j׬ڞɴqFuxFb׺IpcYB՗@;J>'F0`9a(=hrr+ |i$I +9iXqm݋lm&v7Fp&&t)lsWh@+Mː& AN~tvron8u\#B.Xg "fSԇ%3Z׭k=oYI,bDJh2iQ/?' d_ێ1NkL+*Z}8z0\\,MTOqHR\\jtp1{alxp=,Gi1L?ƓX!:ybDV䣳3~v~\o/;49GI}yEa  z;=qK3fϱj^yi*GjNR@ )s&#gqNUt[SBbgDꪸd/rNİxѵ-`)=ML؄Mv L?o$ 2J W (EqbU\ 'a` d%wELMC4 \<uEj3J6F 8)w}X.Qy0^C@ xmfu}[Vί2P4u3xaDNb/-&ԯׂ|eϯT l[l_įO il+b\3Բ%+m Lљ8+&STTr<`pAk1-Κ%š+Iʯ1 /&T 5k'h޸3š'cܻ_A$rͱbB\牃kto>-Ɠ`|u,&%g&vrz|~;?evGOzJ=wG/I =>kl4&v͎ #U}z?SI"xL跤S!J#nj*皯ljb+k"s%jARaj6FI uI'־e =Tc8_Ilt\OVi std Ygya=h7EA& Rg'B8 \st۹^;}R89':˖ԕB}U9yKKcǟ~j\QU{uت)=; sk`{ߖwbB&ӿ7xu$?//hO]{.b"d.࿫!)i  .z#xHKzRO>i8c%L11%S-pdY˖\Ѿᩉ"j BӦeШQ"hòmܺoC0lے~%:E7myՁ32ɡm6~[b T5ڨ3icrbm,;ftYsXJ ]Z%K+Ijb}H"2 S&dVP0Fa;u#|^T.f3af{ys>@#xEgG튾RPNT5Rocwuirt^t5;ukZ/'sKmq+-:Xߎ8:b̓QF* /d V89t,qM-Z&sBv~AW^-<8d(mPl{?2?r1,~fTILM皑>=cA5A3/xgb:qNX(} :~>[U."XbБm%F._cO#朋츈@xȳ)q)pr bRY⒩|DتpVmGHO>w ʮ B* Dp'HJHyUM*a)bxwG4;À=*^7Q;GԄ?7቗?(<j~t:ΥA|']Q+pW0 ɖN6W]W ]n zQ򌜴tb ލTKwCrm0rHD3>9lGؽDϠj_e;mtER+3该+=5/5bWVt1c+a4¸TXO.ppĚIU⠺&^O̟9!'\ [OԹ.Q~ڷo<.,TX{(/4PD/Ĺ>eSRGC逸]1ҴߧQF2m6;!>z@7q`˟lxݷ"f0{U'5ZRS@q[k(ןxMiCEr ~L"?ÒvET(E[KF҅qLI/DՇi,JQC'%0j7}m-SN [HWf16*.z8r~JXGc4W{,4'`]a)]f\2v坆%9 ?=|q/?ï$*V0yWQM)d0 b) x7g8Y+@t͚7O?ukyfF!ļšnؼy32/Ъ]f^{N1F^y Nj/cQ!!X*׮eﲘE7Xm{F/öf3?П];Mm bXş(!eo 3(3&/K8JEstFrG%صcp--.LUP ZĚ#fjV*~hѨ&v;1Rטr! W犅v3/QSsptwIxt]s*cL慐Ʒ+.r *8ubJ1x0<4wwfW(K"\;%-F-ТeKmDY4lhl媶%HXNMLL"d$hFBvܞFn~.Cx",}5P2+Z0'{TZI#G9?E۶mE嫤g7;v{ヒsgc xCMT&}[cc\ǎѣD' o1nߊO>Cj%7[#X>d+{^d-ȓZ|;|Gd.nNR t%DS>۷*Җl+\OpfcpoZXK?sbON;҄!6W} 75''&cf SJ%(SK#FOƗ~[u4!]:4Ws,Y |{8jkQ,_]ǮZ Sd989+8ܽvkणOq[Ecl__C䷂ _mfhCTPY|z^omR8x2J^˦5sM?턉P|y}Kg BP'~/0f gptOϠ\)4&$Lȅr -3TbT|#&&şkW&0{nb+FO+MG ϳ@x2ٗ fwTbߌL.@^.9Bma*1E+ ׂcBnZH@7dddjկomFu!n^}Jog. V !pн=;dt1K,S M]S0 vJdoJ VQbkWm  *Y9>NRQ /r#Lg66WȰ IS.GRA;gK[r,RWBߤ #6M4>w:.&иUb%A%"nKiwb7/gsl9rjeBST}ŧpQP'דd:|50+0 2gjW0nb|h<[ ,ɞ"ŗ_DFz Z>${F gpT0XF=b<6n؀2TK֨MqƺO ?_αɩdrG\OFBq_NaO/*°k ;, a~bUQԆ\d+ CyvIb\aϢ+gpwP6HHkz Nr,ZWoLs5k-0/C]=(T+J)T{ӯ2"]ٵF S V_zAa]'KS Ͷ0 ݃1#G#]ՔwMsS9C_&`3}j w]YTU4isfrsj.ځe7*o@8 ekjlq \ݳZ2}Ң4\nVڢE […chetVu~/Lw8bbp }놪FX673ZU^h剧DHTus[aE:v"x1&Q$o!|j4aRF-h:%ŊY8Kc/|@i <5S?/Ht䈭=et@rqn#ݻc%d8>|?$ŷ 1y&7 ;oÝwߍ]T!'t>#HfVdt~ =p;K)XlV0ێ<"jqb98! eeB 5_6`Eڪd R`ΰ544$7Ȍ:Ԙ(s l٪;e*zVĖ(&GȽL0:vX1=!,.v"G1i տNE;hk $y|.Sl_MIW^zYG}=WטB*V adDJC iHQr\9GG|2XbȯvZ\NRP@SJ2o.6ۆw sg5>h()x96$Sq0:#0Bʞ'h0o9NYFIh5Gw/32A0)5:c?@aHh(V3Qwnf# ػ8,G?x}큢<#,+Oҹڌ9sjxBSܜ !V*Y;o̯iQܒ  AF)_hBdRU5#yi\)Sr(ұ8)75lx<\ *U[nb!Qp`'x [ ٗ7#Go8.\O܄Sz598r%! H*W ֚]rnnzIDʷhuVx%UЧb e?GHb puzノ:Ecvš sK!݌Qz{$&&˱_!,"f &iT/ȓvew65&G*MNCvbJA:aa@!u!(7k=}Է+v; I}Ij\2gZ%\~}X*:([<EL9vεdsWsHxn̙75j,+ҹwDպ~l?0-K&j.ɵLgwDǚ]V \k " >"mcZxzNBi2~tCc"ShH8DرS;T W72dس{N  Mey%Ԙnش4QFp n;30T1khy(2u@jgK~ 6V+΀T z>L8#Eg.`28CO,cu`ni(ƺ5k9b( sWl28w\I/"ν}{hv.瓉td./d|Q q+I")jرtj-ܮ.4E4K~e96l+kz{8Vq {f1|WEL]Q}.9^T]"S4lK. ,(z9x -`&_;Hr pE;>%C#{}ZZ5!7Q˜4}} smVx:-óBM82֮CnzV41514{Ed~;ҹHiI:*_Lli5;(" sUKV!,L(Gƨ3{ɻFEr^^hb2wVZ&^M+!5Žo}*:D=Guf~? bWX &M—A@ 1|K4 Y&SF: N܌C]D̏ԑ5-IEZ}t6^^R.[g7I1`O!ç1FrI)I&sݳW0RShmWi<#]|-}̳gڰ`x`x{~}> fs݋^O$N+xpz.wD w1QI dF -*̡)%>[̛,X,%H'*1tBn1!Cj\v~= :.<u%2Khv8I{dw}֤\M#L3:N7\tD*(/5QS,WAy"/}vYGw#aq5nuA]؟e`;C7'nO{f8†f[P=80G#5S'Łu gӷ8 ߪ$4gzO{kic4wԇO H)8 d>PbΝbty˜[B @e&"K@l-O\_wW8Q/Vnn fᛊ eNE,NdOUç)P:] &ZuK& W +A6(WoX9AVF:wl9rcz`=9{EeZls4jc:y9kr- bm]u9L2Gر簡l+ 0) &LU!fDSU(KNb)_ GĒKpV\g$d[!K6̞$bQъ/)YLa`%J\$uC?y`2hhJr,1Pv.Tr8dnGKIp ór=7ymmAL tFMڢ#;t2n,.JPyU!U/Y6U%#B&g?qQkh,;%b p%eS/{uV#z:)1_h\ׁ5m*RV& )35HNoND0K⣐kz%-{HUr{1eu5F%D1(9b#Ok?8ij Ӿ"Ӧ-6dbeQ4q-e ?q[G!R8ebBeV,E=3j>] ;Ȥq{L$6#)+?+\.6\Qc3A@h8o߮#8?<q8{2_bRo +sFyh1 (a]2ȏ=;\飏LkV'>o:;U.gpa. yUr)lu˱d}l]t!:/(HfeqYG4hՊ[=V,xֲ *VP:j'8fظI1p +/n*6Hf:yb'P<+lnjsF&s0hMVeLI@  x7ZʳB-84^XczN3L*)'j`> 8nn`poǽ݋*Icp:yNyT 0iQ -zqAK1Z'3רA$\I^xNrA][r9` sQQp:3E$}c!dnEAӬԔ]СCh.Wx'W)o%N۷bmDLeuאIE;$<]uS'nb12t|"A[$n2;%44! V@3 c )lx=Sc<ռ#c*<9}\,zrpN[q"3ǫ#q{۷nՕ8<ńbWQ/9]-Pdš/.;o"tQPL3}U{S( Щ+)~@]vCu 6 %w~VnT&4<8Y"j Nפ姬 Ff{,21KL)y%xQr+^Qy$8&S;X+js f'@_}Ezw0L_~{> m۶CQ\9}YF|t 2t썙{Di+{rRfDhF%%d6ܼ~Jq: ^/Ft$;^"wr:F(2lطϔ6Jg&I¹U"yɹ/aa .d :axMerd0ٷO|'ޓjwE`09G woyWmƾ/M?kV|9L:E<ͶAv`R xyI+0rT8?w$"<)-evw1"# U艊ArҨ-r-m zͷܢF7yI1a}M_ %vh.m#7kY4dk<\r 5 5SaR; .j+Ѧ][}~Jra"q˼pz.~+&GE'BbK4Qr˧lw lj=*Bן9avёƤ0$3S&>GnEW`(:"䐨3='Af21y(4+ccMz\GGL@NZD2&s ԪMk52~ tMT>h֨1Z?qw;s]j֢i}; C'ӟL@PC7FjU]|"P0)?cWLe9 e'ctud*V 1ȿ~Ò2eԤ++dxV>GG/O`kƀby208Nⴟ^4>+1Lbċ~t`v$((L֎:bP3jfͤP?-},?SS^ru>54b9IR ""쵵k㏆ѣ՗_`uacj\RTHh 5 nmX+180o'O.Z L`PR+@mJIC_!&Y\3d6'lŸA8י8qDŜB\L49OIN҈cJVpuu;izQdn>r|2Дq`3vytsĴ1j\P)'& φR Ik8|^Mә=Z|Vy ^Α%2;%%YVc'NN"-%Ed'4W8!cz% 5%8'(`JKMgnt@AR-W@&.x?Mudv^P IɨXCOO={ʘzMh __jQ29إkwч-VP+YHe- I鋯tqKq.gؿ_ kA vعO J^XI@`bm:b48q%HH9jzJG ]TXe#uְ0+1lǺd)M!>yfAWO VQ Kp ӹbKoH^q9֨_/2f]#W<8m4l?!끇7nZ t@AǒT>(ًBX)/\c: mk %mεyɲPALBrLB8Ľ{nP@aO4 o u(fS5Fe1;;q|><^#ws5* 0]5(H!O?p>^JZ.l"${qՉUp hx2+YGv!Q~}ekaB1rHm2!fwd%qGn6 r2uKp@ojY3gV@Dbз(S&R?X(~ @3T* 1lD7mVc jAe$ECnUFqyFF΍=vuv͜mǏf.PiSOc玝p3Z@!²ĝwݥRߌ5ɬ^sz9s/j,?Ν3D2 W` {f%2g)@(m]ܴ t}ƹkDC77 Phj~\e( xT2#pLMJ4'Jacq[ιXw;gÉȉ97ۄ裺M"q9Z'{WOa8gݻGq-L'i,F r_>13L6EPuK3uBYyL'תl7[xaE{ok 3vu~z ,"}D@qh,QuIj.HvQf>CdJ>&AibԹL5= \닧k&LG"8tc!X~ݓt'x}!~&dg#LpK50 o7' q`G:U}t588խ.^ND.\_8G5ւbˋSo1p@k׮]k gd`;AQI̼>y҈VyA]7#$8 }ſ}gu5Zbԑ_zyvlۮ_+bp2:#^ ʼ< tuJb޽ngWq ]܃>xSE-˗Ua1*lfMӿ1>i3J#(qViߢEMpv<}3JǏDZ7 "&.Om0nr˩9Ywr пB̙aI 582*~Ǯ.MF4m}xs Q&5굥 ӿV4dD@9׊8 } 1 9io!PssnUWĦޤYS cnݺUWV)mfJ)\ݱ\8>GB-bbEnՠ06ԮSG9Vq谱Fi4l>XsLn jߣ5(He)iPqkG9ed lތ~cF|-n0}֭[DewH$YQCv3g.|ML:s11>'L37_ߚ&q/9 n݆Dcs8ч9tT qR? fyZs?!Ȥ7"r} R-,g2K) .\6c,R5RqMxm۶U2˗1ADf"a{~zZ*Y<  ,SO?m1=7ߤ)P4lXo~w7{M K5R2L1ؑÈ庵rbdxtl"GwH1ͺߣRzL6t(F|6\#} P_R?" XlK,yrG kD{veuJ;ko (Lfr0ww 0 231Hk;\JC9{A!&6F =yyyM?\0y&y1ݠmd>{ sj(aJsLl.C"7]3Y׏ilj^fƌwCK?IP$&$`Kv5sOR&HdzJK2Y\nf2^6kif "P:pQ>y⤮RNQJ`bQivQ hH ֏K\{MqUo+IENDB`nut-2.8.3/docs/images/ci/jenkins-nut-transparent-bg-40px.png0000644000200500020050000001075114553676503020542 00000000000000PNG  IHDR6( 6sRGBgAMA a pHYs@@u~IDAThCXXTg~03A[ MQL[bzfMv&jBc ndckCHQT?2Dl'>e}==_K.n޴i|Sc˗}Gv`Z:b9iĻ2,xn77/Y\^^.}!;(A|/^;&M\s'Mg7{v (/Y:MhDX6  v@7Y(j:6 .NP`VZi';{B0sVx:.19ukgzb=#<}Y5( %*\cGp!A~ީ[gR kŶGjlG(Ԕ@M̼Tg/\lbvn'°{yXw8o 딇B`hw075wQUΛEEN;ɸC͎gH +2_L᫐ة7!:"tx44qX,lB%zZY@౬Y]Jԗ$' =9ݺAzz$^<ա||㦌.Qn^:Do: 8}b#(̜pp!JPp Ͼٍ34Wb@aI%r)y[ |D |ƾf+ssw-4$Fi|>5,4ԗ^ j&yF$L{opv;hޛC9&3F$MjBlW)c Sx؛>26c0}p$Ū51x $ ΁'(*.{u/N.sıHz:#WZ̖e]3l/-.0OɊ[>Ɔަ}9i&l&/e0t$,(+l}̘rKt()[pv݄ER)慝&OVCrdOo4`8z`2M?!L$q]& ]sGP0y!$s.rVzʿH~n3 `& qPfOV]Ht!ϴx~A{HZz "nb\IS~"Wbٺu~k @!#RǷfNvSbO/ځXI=urk?EoOF]?yרK;#yv,`mTͰJv!}Bp8Lz*,f Yzʏ?{R9saax7ޝ=;_޻Zn&*{xXE YP8Q%P'/xrPq8ڌF*;@ @ZÇMײ CJ=/&3lF$2TVV̑ -&%'GY$1ZfpR;~0:.gFsu9mh'zW =E:vl8ihmّ/SҞ6bޡ lݳuU' X ht  j<4 mFv I P|!*Vj1,y0)r " q=֎8Zo@n̝; =p[mS?Q,+2$b+ip :HI|-:sQ)s`s:'(*3ZsH?<~+f.gtM$S &9 7 OX kyT",}ox2FF=;P\\^11IJޖ9 -U[ U8iҭ[_=4![ L.9~'>}o^RQhI TB!vʛJ$%'}an73 qqpY05"_^F1d_|$5ׯ{u Ŝjj%Ay.1/6LF8H͘ʋ .^4zxJ7i[t1/ p]PAx<.DD<77mt _ް~=۝~e`\Լ~f] h+=׋mfGJ+KHNWq􈌜/i ygz掬5[336}ߌ(Nq'==#6iZ]Gu&6,;vlyN45jq3g2?[ Ћ#GV~aF{j@t7 M&R11&L;2cGQ4vE^YyJ@ߵs>>Ϲ3*2\s͵N4ZJ,L `(;\rƽ;vG _ ]VB?뮻NkUWݵڥ8iEWa(#gZu hw gyƮAzЃhym~p}?Y~O - d|5XtM۶胴yc6ڨ>h 6ؠy0GIOz fNuYQ&Ї}Mj}\^̨̕[%q14J:'0,,yB@׼5͛V@7|擟.#Sfvh]vA}P/mCm y{OAZkA}Јo7.h#APn;Jp{Ggyo|cw-3fjX`Ak7{뚿/-oE^?Ko}7rK;^!4@~ʥugsɬ׿nCflM׃g~ lvmi[#̆۶B|9C~x宺#H[}C>SZMG=m8뮻F_|[j?fo0{6}q0}͙g|3i6ꫛ_WO6< o[o~*(Ocg~[l>'pBS_^]몏M_} }k/38E^îaB F5o:>q{\):&E0 vb4(+cf7p9Al?ꆾ+kmk ͝wٖԞ4]@Z|:vV1jN_sWkd[/l7*.YguZ% gAW>uye>OfsloB A ɦy=foBԠYuJxM?yj6nvgbHƫa ՙb n1ī{%- 1@{V^#|hR#A_kWi/bၰQHA=ųyپf(uM}öOKs@駟>Tf,ڈljmL9WmYHx ]P0S4at!>5Ͼr +#@F^;#,{;}".Hr'!fHvċ=> q3H~L9.ڨ9O϶J*h4L!A<>*5 9ak}i0*r}4x>g\Wāq G[D=."|YGY#\A;A4%s0]'u]aqrXjt}8r5#]Q~σ!Ts&-*_pKOG-}]kQӍ9}:y|!t QkP<ǵ/,/}Fu}s/IkLu=:+Mtjw>?VGXM69S_xP,lLu^ŕ9W63Vd! ="_fa*>)ݽS2Wl L?xccwD|lme Q< X\޳:uy SqOn}Y#C<ǠWP)˓K|m܄%Ҷ^g-Xss_qDž^\ym@|]%3B@3y!_G?xBo~󛃐 >Dat8hAQ.g?;&@]N]Ogb`_׃@u};>Yv#˩.V6E06)( zlQ /|sg~P~Ly"]tQ{* zuv'?<sSi \rI; ^Oj5 PN_-l2 hRЁ"">k6.฀7Ρ([:kGG /ON:餖Q/~^oZVk5Ά|;cBlfp&r0+kΚeSJ-p}iˋ _ǧ^,V)i6(Z" >G vOlwT)'쑺e&ߴ9d8/(͐ŕϞ&wxVm݆SIԅؾvXLtPkFEկn[>$]YGJ w=On~,9;vqv;<󡩤14c΋W!Α8Cs9c֞}ɱqh?εi[xj>W'BMw>JС*It&u&S;n |i2xꊧUo9Ǒe-e8կ~MC;A'] -X4e$wvپfqӂe1)UEXl]G/Y0)M)])2ga`6 }. ^d@ @X@_FxPa.HP=Jơ Bo;Hkl6n(n!﷚;LKalEnj n[%v+k BeY6X,]k.Hr8p6~;w~DxPǻrW!L}Nb{kØ ]}<9c[!C|Ƈ}|h5,n60,{L㊔<Eq]ߡscJL +Ch#8,8z[ w]ߌ5CG3fFwa<>]s踀g^#Uʑ a[|akbBNcCfyEz=\#<(Քa;u\6rڗ`0]uف:R^Ds%vyY~]viͥ>WD;9Ո8ꃯ掸̣J(ONTڱ,48N`Z|Sjϱ[{HK!?:W?OɅB6:j^&]C=.Gg-VT QKm7.K^mͣ.hpp!ZrҎ}&0: u-K+-|SA|N][ WWw}ۉCfoo+պރifLvx.ٚʚWI^tú&*Op/Ģ+rTs%o7k MD)Wp0xm712{ͭ3k'>mgRCy+0_!$ub֬fRKCJz u؝Eض*"'reb$LN93½kܾ^|s^Wwu9| |킏[y+h+YE7("vWQ.?fO9sPnv'8_=콴Dx̺ xa'jAEWCeg4O*5-;%C8MLXi{R6BS[BxP Q8bv-)r&~{ # Ww" l" 2Dh"Eϥ}r\0 ^?AY)J$fx?SFD&*mtפQP @ {F F|VqiTQжNf@6kym))kS!}_;=tA1A׽_&AhKWc65#룾t9<ߣiB瘢HV|?QxF6 & D|g@EaAt(>hV_ Ľk}O[܆^%,9\{Ps.B4j\aӄa[G;žC5a֒!IAʄ2|]|F>9qa& nY४nX2k\{條4\+U2evx \A4!;cB3Q>O_җ*-eqsxy@ &d[g- 5tt=X1ea!!@%o|ꫛ>OOSkYygVikh9=8llD|5IT=Ԡxv 5ua>BN(4ơqتKM7Nu"q]U脀35R7ݖ}BQo(z_t΅wv\,w]s2w(ޅ/wv* YɼTelqm6mYCeV]q(y\]|x7xIn$]M.+ړgq򋆭Cie\lpS+s)>}?lyO|ZLr6>u՝ 1̮z(͚y L./A=劼@Sj.lsji܎r{-3B~Cqc`~ Q{%bwrfhS^.ԧ(ai ;Ҹ49_:G 36M; ũ+#6ksSi#ҵ늏-n3nGrH#?;%ʞ7|4f056x!e ܣ -U YBm"hq[.+}iۋy) tz;ϘQ*>pxv#t t+KS 2uHktOVW"hViQC: éStB-\u0||/6#~^/ YAe'/\ u˺`c- KO)z<2>f ;ov脙q톚 Gu$X/3>"c(aMZA#O@&Qp#2Q1Y>{~<;N_n/]@^x.D(c1BԄ|^ %H}Uaq0sd% _?!]-/<#?9N7]qA :tם>羰Q(u/Ͱ)yW,x=hoAd+sK G-^b1UbΦ4s`<82X)ŖEPxQ9taO 5}[h+-f"S8bfÝc A%/lv9'+䋏pu|k_nػEY#<66UR]£_FvF. hS3uComI?!xԨϞ&hQcc*c#~T'Bί _kإ4O㝂3(Ω!_~kBX(?0'ȷO?|LjhBtQ'eB:#\h˯ 0VBe4AㄢI a BQG7/Rx}o #\Ί{Wȯ#pe{roo wA6uҦ?N#w?(+<$lM2@5|).>p5V?6a!b8"B0@|`km%R>F?v9@;+ `S*jh;զgvF1\BzD>pC]p\nGl4A6t8 .Z[ć-`(+I3#"=m]nՑRuY&ʙaS4!˿WTh`/ѣJl}Fd$d4W]8ʹQ(P7NSO ؉@(v^cڦpK} `Bχ ftڍ6{5k}pT/OдYveN iwO hDW\ p!ŕ lk苋) 9AA@-`&4gas#4 -`Jװ<4 ro3`)g= YL.m>7̊A98Ck_´ $`tX; 0!M: nG3#ID| T/1wh8,hwԾjv^ʋ?ˤiwwH=\/̆]=@DK~!mI;;r衇q54PPF)~ h87~bM:1}Sm{=9'B] n5Q 0`:>mguMnBEkt2~([ b!Y&d4+8胓xOH/-MNԋELK4mBј3ɄţL2Aؔ6jvQO% rs-:ϫ 3H4S  {v5w?aį?hpA Y9uxcXxfxifgڗ,m+{>gi|m YL,N]iܦ$Is`ZX٢IРaCtnưk>@Pz;̖cl2H.$99G*PBi<=(YHOHƩ8q,<8X,Y)׹ PEu/;yT|5`6Ȅ O?a)4GHMoy[}<`{ְ6BC@`y03QwfHLJu~YMZ[ߕ**;>@HhnNw_ 2@&Ǥ/iY2M#JL5<6-Iq@/(ggfpSbպiJlڶYV1|$ΈE 0~4l9MxN=GAQo 7k|":(~~"o[cX0>Ǝ/ ˖ċ}t1 [C={6'O ۦm{0%X @?"Wl<:{]cs*$'NlGn>c0M%Ҳ%K1Oefeŋuk½m '|P <aF 椉d̞3gΈζ]e?&}-7v-_D@o|r C{GFժU&u1/?Ѫy# ?5,9G3ɉݮlas9VΒm{Ik)/c |sBRb21zg.?|gb`ͬq8剨H5=]|ܝbl݌!ULO$"\csۓo.RPPӴao#Tb[yxgP~=$%%aX&`e2$6ߧ$)CEɒk 7'/cWf#Uڊ k !!'{ю@)';/7[4 Z>DSvN.|f|m!_H ´)"^5@PojAS>l9b#p_of8gsA-_A@ УXfUT o55kTb*ٻO&8cѪuc%$N48*L} 6f 6c&e hj͘5S]Wxs̟=A^.Ύ gH\<|$yY'r27# 1H>$k9e)BM˅u;š,L0mF]jJ kܸ}] 8-e{F*8EGaη#Q^ ݟ€ɢ2o R/g.ƐEP?,b&`ŸQT|_/'M‡Æ]6*D?KWOD/gw/^,fl澰{n1aXoqVNQds:9uB/7n:(Ly0~CM4ƈ>MN᧟! N-ooi2 $lU٬0dCX$[h,rxvUČ|. {`IۙR2sݫ6>9xM 1saaaWZ*9ig3@_ZԬZ?L%&IOahKBkytZ9$,#ŋ1I鉥%Kj QVNܜ*s75nhtoT5#|S," '7O} YJ&%Gmuc}tĊqFN5.бv @-?S_ۖA^顇EM7 & Ew]ԑܥ3v,y2ɕƵFUaIBtt 3Nw񀗯رjbAJEZj:bk#T",/D Ebr Fƨc9@8/-, 9(X&v1/<ް$|=V)V+07]ƾqv\~9-.]!8KlzI`xjF|wAvf8yXIS3UtS@Q#c[#k2* ___/ A򥐑9Xy}!;]W?x#X|5v9 @n[uh w7W5n,+Ca{cB_&LL?!t/W^iRL2*EJ sae+7(#&=Xr7~.~5 BړD[ t,lq+O"f U*q)_'`C5G@r3+HH599_߾=sujN: ϣXb8v8v܅ǏkB1#3u z~0VިfXڷn+#(Wͯ4i^nԂ^"md7m?|C]Q;.7\` #W/yjڨ>ϥopV jMa0jik<-v~H~T|*b!@4筘^t+^m_E;Lx+r$#[KYعK|`}FQQ+2 +?_`{ڽü6c&֮ߨ~+*G )@dhGxO>>WmPp{*kmzxS H4ҤQi6at gn> T,l9۶}T4)zkF"z7+prqoDyCJ3ٴٴN &ϭ 88|:ODٴi Dx@ l\Oǡfqo8;-awlJ=m'J ~̘6EQtTd0924!}ztX0 7oUfOsJ! $8u 9 \zfWOHLArJ:҄QSLM-"h_3,'%p5Lj͛oŧ#G޽hwײ,]8'-Q^2&a0R`, F2Y/qĦ'1CױCE~\O"f"G1kzb>7lsL4 9\ mc?8 d?͚݆{>au/Yydpa Q*bC}zEU0l@d!ZIGymN-"D%v{:lٽ[1?a~:RhS1Xø;g7wyٴ0#!\Mdj B564BAM0]-x <ѥ]dLKn9S>˗.7L7 =ZR,k:cU+Qv"4C7l'1k\ YX:a˛q,X(;by\Ŋ+1)#ꆳ94#M ].۷/[p/(᫿cS PH ǚLGsIq":?0iȬ2: ݆|7*q0)@>ZC~4@_O:okF&`'5ʤiW){aondj&2ˆuVT,dA&VD8dJڎ^+ށprq[׵HMr =^MG'`q "&ϧfUP붰`s03#eKGn*jb#<1WD4{ +%HtʱlYt>[ 1S8E~qrs+L/δ$s|CMƾlE3c>4a2zf*tOջq*.M`ց:drŸ~(](  v=>mJ͂dc)؃䯦Q!֖$y % ב-Y:؄deLzlpYJd8ЅEɥpZa}Xj3T. //rں8K%D``U, )ةt`/VAǎ eXsۓkU&54gϤ o9qOn;ck q_r uǶ'1}F 6L×2fHIA`~38Pt͠(/ fΘ) E;9vzzy`CD {LϢNC07D琝)*_~\c A7ǡc1ogaO+Z+˕BjihZV޽Qj $W31 P51I$wpC zBD)vպ@NQAt~q35-;/4L0'qwB{g؉$4^?":ƂJW̶6+BOabucڠ>Zt)Ttw!18TM}rj:J,]@ӆ~9{aĘo)䋐pѶ-/J`75<zA#7&`WK*~Z>7ޔ|;gMhV)ڭ(f&?=UEԭ^^MԸc8.fTuWg|)q4hݘ:}7MgNe*[RfjCc!:ڂ; ⁘t8v5[LUYv*9=KFDFf.T,Cՙ wvM猝8|qk+j 2 Aru%7RnpDqᗤ$DThfE~OF:(W ʕƽߩD˔)N"*6Q%U`Ć)6OYP8K F2q@/X2rPB)xYopd$< G:}Ce|/!@UgDP԰GGaΑ%~& cLSpi3/IfSplj`޼2 ƒ]PB$#j+dQt{~yaxowA hKf"_ 9 l&%eɀH Ԯ^I +[vw`[tJ'BUʁD^?tY1n\䜚a>q/_x s'$̃j7]Lq2y/^bC@;#!) )MQ0L!5],uqcbYƒeYs LR6PHk"mE%b?OаcOt73.Tixcy?'OӉ@`b!I,<ݬYx=ҥ=g\7(負 ~ ~GHc/R@wx.JX >V*W –M;qCqS1y|<(>EǻWR龽8, }#c8d`NG5}G$})@D)Ejbh]_*piFԤ&H|.ABGaY\~Xɳ):{6MKoM6p(1|#zQ{`߰b_ؾk/|. `2jQ绛ᛡ`#HL9E P]H TƤK7$>1~>>HT', Fcb5LazuY:8'49xCK]Km%0`Xy;a*Ύ@Br4Ko 7aH62G@Px6zl0l ȟ5h##xslp/₾ȔzÇ<`Iyh ӧe_fb~|5o }&3lx_ԫ S,OIͧ>ޏS>]7ÓoCwb3 еqqX.ݺ~]VS{ Ugib6yJeҏ+VΧ6'bEv-~)1$v kWkanlRS% M ҷrHp\iеlk'29bJwl\y]e}SaV di6GDhF͙=˗-/ [BʗWP\@/c#mӧXLq-ڵ+_%^51c twwy h0Y3fl?]b%GSqq,Œ_ר c(4^a$A|F颜GJ)`| 0 IRGP[lt9D@ WM$ss]޽G9+K{=)vqo۰lƇ,< rz⒚y1G?}9TPZgWt s*Xv%6{FOaeӿ!"I|1qctkUpfS q1R}?W[1˖ŀןaؖhڔ=J9NGV;,E_8iltrW'xR5غU }Wk GP_2(\D6F.ُ?:mR|z֯guct(h lbHѣ%㮰̦GԱTjQMb$ JA-EZF$ݴAu]vfL *_$ { _ԅب#'Ŕ燂PSTc/$0ٜ!ϔƎpuk߭Fƾ} f\8fA!dtP3f܉_~@ Jjʗn,1cTPP#Zb> wбfY*vFJ.fmnH&ɕ J"7oRS?ܚ*bԨhX@u"tj`!X+y3 c]Q<4X {u:&%aHKݴQB{Ch:w@O8K7ډ?Tn%{Md3QK FP8 s"\fKhM&&4[?#K 9WC]( f>E+r| wejV4.D(>1U@фRfQan`h"j2\$Y",niv}懩 Kv lKTKbǡts~Hjذ8Ə+(vC p Y?ޚ[ţKhڼ<6l8vՂGw}k%G׮na` SKǏH06Zg%(svTKؘw. gaNbǞSdddTD*+3L1#BD@d3TNf$  νG>Db!hZܘޗSgbp"ԠdOc-Xy|/wnx 9pmfKUժZa iiZLd̃ʓ)TX4޻cQfE!bslhT. =tQ ,zA={22&|'[c/deoպ4&}/}xRM?Tǀ)L"-Z ΪqG ^Gstc,_30僂Z(tPjbc1;vbs6Do)R*-{&k;?N)>KM2ԭ&Ii՘,{mكANƃqtE{6 C0Dׇ;!!)eD[y XuGqQ掣Gb7-_xQM'R /I zu@|QreIoo6Cp26mߛ6hġdt7aɓIHKLèߎcx}oҝ(Y2ӧ1&IScvֽ%֭]۶Sl 5v6EװRhn wa& %JQ2h會r.]5\G,o"ij R0?tW*~|,Iߡߐxwp0HC&zkzk+5 >qbvY" bJe;/1Xo8̪#u.u*>ɼ n!b hɦ%to!)Bޮׯ>&Njp~V~6mp2ծ\a;f_4j`А)\iڷ]*t)CFAq@$(0hI`nr:9b*cּ2XR`3#W+\TZ3.]g/ѯ QbR SsVM+סN .sAk1g@f>FΎߢz?FE>D:Y̮щZW`?-ZZk"ZۯDW E 6 [5כֿy$mDGct1P0EFE0Y$G"K$ӦM]! be mW_(r[,]K CTDK]Q_=#NZ@XLM~>do-.Zf0fcg}alq@MbްNFi7-CR8Ga88ڭ 7 N0tsh #:cp`E17I=J}XןBhr[{LvW>#RBIxTE!v) #߇x[Y1o jؑ#pqs4Qm1o4IK#MKqq īR&+r #`<)EׯDl5K>:)?~ GX3?{_  RGt8L;38/ C_``oUbW;#1)U}ſoP[4N#8RsZWCbL539s zkX ֯,$N @"uUP9'fb،yS`9D Kx N:[Igm);By{'Ϩa:qeZނPR30*>9 +~( CH>e;(.q'S˖L5b3PD'xLaxg7/g΄Zvti-]?(HR~yZrTJEPsMpsCXDs,^x3ԭ^=܃8U9v RSLa;# { JkӬ.>7 Rc_Il\iƘtd Ygya=h7EA& Rg'8y1sm@KBWYśg\ӽzFmʠr6.aj63S>XlNyؾ$'Ouh^&xd 4bxV LDݎ'sÝU*M)ns9)8BD@?w`MoL'ݲKS"$O Qڄ$.!EëW*B{Ęnޙ~c/xlK]0IxC{ދI_NN“=G|b\QU=FMc.n l/Lc&%X޷%Dr /ʕy=讋SQ}"MLT8w#$eU;;9yEg ԯ4ղ/xԋ~[.};cOhza2C?@ūaоuCu (l# ưf٢>>}/*)f3f{s>@%x9Wg튾^PNTRocwu.]Pn!5xy-:VDh:/+\bW`Cb' 99Sǁdԣd "!Ub}V:zrx>7œ==0T)df[ 0$CQԅ:݃cQiga74 Pdj:׌d}a8p6& vY$>Ӊ;|OEGSg:A~[U:"TbБm%F._`sMZvRD0ٔ Oy.yD8s¥KP\9[DtO#8y7kϿl O<_>n\5+#<[L.oxFo0dFHHgei?/?OCgz-'yzDD 5"߳늒צg}-I)xw%&w@{X{va B'jA98%ͥĢ^ 5{z0:!‹|#ut}6#NuVKqF̶W"403;+ ~ 6kn%=٭~S=0x9ڲy3̛[6}Z&IO럃kmMÝPJM<9sMü>l qM>qb>.AHLOHyCM.4aibxwG4[HMH([ءσ0~>Xf<';Ѷy=]͏Nǹ(+j2t#?ߕ˕*] ɖN6W|SW ]k zjӗ)x<֥?{n-ThQ%ƌy!>~4,0BPovUj<9;i[KŋWkġvyi)b׊CG??$[uEBdmzr"9]4t0|b(Y< ℋsa뉺8sY%O}s`P.n`:ڣDDFiƆ$D|&Թ`h;s{Kz*0҅yq v.\+fj\ g7cdW,4'`]a)]ftvg%!o;/b>q/?ï$*P0yW~Md0 b)<Ë73 .]q&X`>֬_-۷藨7 !%::}닮uj 034o% (>yhc`kзw_+:5>zcͺ]smϫ!%lskr-|QVv-afediGZ\lzΞHȶhyG3x SfJq JƭS֯]kҕ4tD"ƒ¹b!]5K\"]8 >W X)Sz (˸˵·dEy99 G1aOw_V6xG~VU}?EӝffIӦhڬ6"I@*6[GT$,&m<&2r5 #:p!;n!+' aAX|)̊ο+W#ax~hժf箝x1w\lشu}LIʕ"s<pAjVJ!J߾]t1fX&~+K_ V #,\<<, ٨~ Iָ\\+!L)L-I14oK[02&ki.B%:;m IOX<0qzcXv~]{6*srqUpx pIg1~هc )߲!!(#۴\W Aϻ1IX#H7 1@)Txdb<%/eWRĹ&AAXf(S>O%3܄ !'ʊ_~ Ŋo}f G4/"kn$_|,~\9v$fA6eʷoչ;׊ؽg{q߽[n * =M-ciY_L`}B" (֧`X44 S-/#@.TU |UrGk)}\D{d2tܥ"H  ?R>}ޯR@GdK!)e$y8|Ku!2)uQ+M0oS D8pjYP\}BLX2շr=j&~:mFԖl.!}@NQ _n*sO2z2L_j&}1>!R4ƍ.UG"4$KE'6՗֣>IϞ=Q^=}y9sZU,KCCtMnOtæQDIP^%SpVEFРAݧJNNV_\T29Ip@+ 9ԩQ3/U^ާWEvtFJU#eD&W - )/wf[2Bk7W3 C.HR^H>VH{A//6kRDh Dk\޳vrhդt9}.}`x8(-eK{iu  π`FvtqG٣8nK*urrՔ$#"Ъu+ qRJh O1IMGPjyfYخ<ǔ[k%V͚<~yQS]$@A00cR gĹ,]s @hݖ+]U/J *nF~{8ڒkѧ`9L*V/'H 6CcvdȱAA@6aصb0d1 ;QV(jC.JrtsW,Gf}bBu{qْ5_uٳ_»j#i{7$BA$5%'X1 7? /"MbZg~)D}jE)7=btQF 2>2}4D}+/5K$qiJVľ}{1~8HY?$Z~2yiQ`*g13,~fyOP*<<,w1P0Lr];D;SSE3qP ag$btD :;K^JgG18צE= "Buz,YKt*W/4Ƴ"$*ysrsp"r;N S'7~U0 +4,1>+`i <5M(Htd=mLi@rqn~.]wd2Gҏ9}T` [[DjfۙwX#N,bAxWk4yH[ C"x$ƲPi#)4Źkbs6k3DrM6˖Kb˦v#^&CSj;- INr4y_ ' |zBTâH5<>M)/E%H\vS;'8~A[ub\xc`xxMA5JHsD2f䥘RTzJc2֔oAobݦj\&M\x|μ~ެZ/sL0]nTK^-9=ةЍIL?)^ػ#4Q4qpA#XEĜ}hC4C Q %JΫ!2:ˉogI̗1Q &])y?ψB~+C*UWȱlp" He! Ir *Is"舴4rBh @~N>9PRAFClr]>|+ց8MRf*WĠg|S}Y{9tz!,^L{ ^s|:uaΊ7ŤExLs2Ґ*3}XAG5/q4aZJyOuYbNpqļYS)GaxL"^J r&ŘdOve 7,S^Q^ 8ʱԿEʑ+0,<*8_8,G{]큢hQ5X v˹)8.y)ߴy3<ֹs>&k z>#&pܽ}PͣpqVLY.Nᄃ|Ю}{5 Pv؁h!an01JݺtE\\,&Lqe1`0IKTR%}aOE+C 70R!nBFB42ΪR&yO}?ShӀDhG'`G>(hN^<ʔgYttno~CF(SfDUA`(H)FW,&>0[ڇ7h<'xKq Ԓܝf#|7nb_$v֬OU酈/AÿjC p>=z(G|~_L[W`Y}Ĥ/@gz1QZ|b*]z뭡TF nov\kI$xFMtk͖ p#6R!&7i](L7<2;GH՝;wi'CŊP1W>>٧{BCi&lݾ-f 55j>=T#‰A b9= rg܄qIuPj5g8J~J N0-OأHOK+7LgIzB,\:vyםԪuk Xv>R %sNJVXCۚ;Ie0Ϲwi#|2qE⅌/*vyI>M$e_;VN u"#&hЏ070Fߜa[|t:z}CF!T9WIհgF6 FslYEڜUB) KJjU("9EcζdK"ג\᠝N fr伳$*^9Y{JL^vV\Y;@HM0&M'Avn  RZ$x0]&tڹKD?NCȿ=y?KC/[jL淽h*]FA6n3rĄʐ\+A|`8XZdRrfo:W`+;b$兆M/z/>x$a@T"$8TՉLM87n2Ć/WHNJ#BB@Z:^h1ek7X];wā?ߩCw/I~sw;?hll!3]Cbnp^edgC+<|bG%v4TlQaHA4]+bs(D:Q- ףuBB*s Ҭ#h u,j"hbdu_mkRH^Y&nAtD*(;)NS*WAy(7( J#SSPu{4Hgc=%zpX{#KExoAI KR"KVX5|̢lŖgHnb㜍}JeԔk5C@//&N%e>٭El8§t]fGi 1 Wn[tlW<׻w>|֬9%q P=dŋW洘]QJ46+3Hlbs a+JD;"Qp!ʌb{5$.AH;y@d}vCf.|/M .6P$݆ǎ D ʣP7lSO?C* V1- Lɽ;X߀ЇʖcϜKcxθD 7@9Cٽc{#гסxR;RQ}AuhKR_ysH_D" H8?h^Hj ]P>ךt܂KC?qj\h~ųʮD@$~C*l`2bDzh_O1DL?Ggռ.7.aJ?TmNs',^T=eTL> `q.[D9ݿ-c;њu"A2A{ٮLOUSe#@~TpFO3.AAAJ@0!O  F$kK>4X/ `7-+4CYg_dc nΙXVx-Hoa92Ŏe< o^D~Od0YNZ2/1#bDi\tҏ@X8z/[ķ:C\$!Ò!S_LqվpڀV~Hb/Q%&0#FCSc rpRI's;^= LpcjK{mvl;bRXj]=Ms(AUrV%]-~yvϲq///Cla29 +_#|GSf BYD/q۟dÖ/)AиޫqqH/$LlG@%j6eI!8Gra7Oub&YʗsYT7^x*Mn5~{zTNƨÒwm(@ewW`"Gtپ}u':6MmAuڻOoٴƌ,Ώ4,'nk 0D^s̡BL(پƊ%gFͧ!y==bo\D¦GcշӇo2e8wo_\lz^0f7jرcbb%}NN  |*.j`H7Idz3Ax5Io.LrQ2mEXX^:QU'9~5uBjh[m#FS@ JnVF1֭cSQ\(5ܤQm?hBgůzCxI2+RH'1i@YDf=|bB 㗮BdeX^l +%#%+=&aA)*Ϋ`XQrćȊ9%~>م;~d72ESp^Jr5\gjr]]t5BG"L!3r7eFr9RtzhT(&> epGu\#EFAvo&~*W a+RԚ 7o?GfHITfĩe[p1ѱۺ'o,vz@On_Ϡyf}R$;yCOP׼ bId惌F&%QƬ6'Hs,ʌ>S|v'#UMlNfY`in\NAAm& VINbo"V|ʳ.omd#5݂:c.NƱ v @AbЦT:-[";ERVqsՕl/43“sDP0HaWKh&e&~5:Lx8v 2T8{+l'*9BUB=8{䠘 *BLw j0=}yg9y#;Ysd8b I89!K=.1ohsUa;h6%E1F)ݥШaC`359h;)uIt9abΎԶca1I90m0GgOQ"_^BP%سi>dwϴv_xGMw77y'|4|C"\ (H^U\ :[r$3>/>>=Fa.Gɬ,.B߾MZq' 9>OMN)ŚuD@ 3l}L7+>H%/f g"-1/ ZENjb*2&a E UC-]:\pQB1='`i& 50DhO]0wDe$xs>u .yנb([x:|[kB>q.[C瘏N負 ݬY F0sxK{.Vgxci} fMҎ?$ы (x–(޸3Ǵ?`ٖD0 HgTCIVێ3Xl.Ɂ2ǩ 䕠ua|f =NZ*TZE,J͹ &19|2,)橓߷r}ͷfZ@R2)\Z.8Id{={Rv=OI銠iV\Rbsa]4Q_Ip/W;*2|bD]5dRY"k]|ԉaxḐ4ğ8`0HnF0 N/ q(̿BeFm9^~5Șʤ1r?y ಞ\%9VȌ111H+fmt%o1%yji :yi房 5w^; @W4؇w=%rbA:ճxd zP#rPK Hɝ} (!F/NFV3F%5)e)+:L/S s^@a"^fT(e@I5ɔ&cƊ& }z_^ ĞGVѦm*]Zmџa.݊G :̽"{˕=LٙQ|F)|hڬ*@A2 4O4Ib>ȄH2.6{0 L$3夥ҙfp~Hdr珐A]ȌWu,f1`o{6?? BXV̰h!Kѳ'nW &6cLj No4m(EpiYˢ)3n\kYH4ڴiKz24IpQs5V^[[s,1y8*:ٗ[wD <# N ـo<{]4?sڣ#I a6|a"#%!Y|LnQ+t=E!QdzO"2dc2P8iVpKZ~$7ɵN8{Ƙρ0R-Ԕgi,2s}"\4ݳzqhq[S!K/WSc$wV4 LI2A qUw2e쀸.P0)?#[LXe9 e'ctudlq #ᔤGtlq洱dzh|6Swv/r.)NK DGGp$gψHI46oW|&M|ږTHY|yx7 i&O/+5BM&j2Yjv@\]3(H&CRbW^̚_"c2 K`BHV\%:\\ OEEF,zM_򞓼$EB#1guh%{eR+HRBR~qO>:=*5nk"i 0RrIX<d<@%* tߋ# K&J,&5O |_,15d^a+ q]i?uqd7vҜV ESi+\bh5[LY$'%#)90ee3fK,^&D5|}PdISÔ*@XGnn ABB1eT툰AA*Ȩ7C̖u2K LiLIzKHkhװf6E@&I5PXX(22U֭]>ƍ>a)}wոtͩ0Ikh_!Vb:q`L7F7i&0() ٶZ,.Ko2wH,kseWmIO0zL9HLHԼ_oXf V Kf+u)K"&#$`w8 |R|a9i>Ts.k"P퀸q*2]])WFArF4%$s$L-h>'mŸA8i))8y(EE9ȳ<1!^#9(&ZUWHG,ˉH;SS-H޽Nnر \P)'& φ^ Ie8|^Mә=Z|Vy ^Α%2;11AbVc'NN"91Q$ 4Wc8)ԉz% 5dNjh$,`JNJĻÆg(Z*2P}d bck!OӁkݲ7AR8*8.ccbq`^E2^*ZO?pZLNfD#vrĚ~nb]!xҥTJZZ:bK);UDkCQtMa#|64ʓ_M C{#+5IC>&gN߻q&ZNk:Qf-+4=rTCAjOx*_H~nI.NpXD+FSkʼn5CWtL ]OP;v]xWo/ڮc+Vk6z>C-[tVѬdq`ErPTI]Xb իVcĈtRP=[.uN7NE NQ Kp .s>9Wߐ4jJԪZ?/[jhI5 yp&O>^*k:_M"'-ICy&3G$= W#Qs<Ѓir=v;֭|#=ndݚݵ$<^#?M*.O7 {i_^5|~\MswI@.d1WҏFꙣ)N:L7ÄbIdB2jϧz 2ߒ͹YL-aN.zH1/wX'S#̙=ȳH%Jԏ03`?CE FZ_eeJI#ܵ &NB.oM_ıc̹*͟{9ڹ nF(>CQX6Tꛑ&U[kyA 'x}{tkHdČa|h!^x΄7*\ Y+3왽S\Ȝmau.niYWܠ< `;Uq_W=RaF6L15)Ӕ2{acqUιXۯx ! y\oLٿg鲒–b6|h1ݽ\o^}0HƧk>{a葘1cv "L$oVtmTP0 梽ys}a<sѮII>HR!]n ?zLg.j#ϦD@Pwt~(S@Mi52N>iɔ~$#(8HGa9}ʕ/_d5;I0^ǩ Q;: :0\ƒtS@! jIB0#1z摀N|I7]_ \zɲeꛯ{ ?9Αa͆5a ڽ{>f}&9:=DP 3tO2"doV^-3b I7X/~/^dI``z"F +35V B]4)gN5]apǥxD{޻,,e9~]'ƌRAzf)٤=S3lc4y`gővة[5ay\ng*8qǏ߀ 8L `㻼4#]K)gqV svпB̙aI 582$~].JF4m}xs Q&5E P; p"s|Cu Cs([ԬL__Al 72mt j6[h$E˅S}+/2XTN-W”ڜsPfMX#*E ӄ#e8Fc2%x-ߣ5(He)iPq 뱢G9ednقǍ='scvѿoѢE ùN}3MǛN5w)=0g:n8#\߈e7nܠ犤;p__ 0p٬9sa1 ; ? Zjd?Vc$|]$D8xg{-Zc{o(5h7WطwF&M%`)Lfw~DqZ912Tl:6)$f{TdQo6#董t!1K׭[u$URKaI%-M4O<(q!2~hXbN>]d5mɌ\ռaAf7?q ~火w R]~>#SCy/C!ȨhDFEC'o+QLw^ pvߦPLc2:4'p1.r!>u(>!&{x=h6?vx ckƍc44wOSw茀8#򩓧tr:όtW&JZ@\|uORHH~t%0(H̯%7Ak_? ;٩.dBdT젰 vS!Nv*DvPN ;٩Aa';";(dBdT젰 vS!Nv*DvPN ;٩Aa';";(dBdT젰#{gIENDB`nut-2.8.3/docs/images/ci/fosshost_org_Host_Light_38px.png0000644000200500020050000001107714777767434020322 00000000000000PNG  IHDRp&7sRGBgAMA a pHYsodIDATx^EI@{ҋi"mP:(J*m H# JBIȷl$F?9<])ߞks\eRc<g>0㪾 9ҿ{r94kyYs嵹̥ulЎfݸj\0A _SUc&A1 IԌ)FZW]i C\>:ZO8szm7YÇ]N>h=u/z_zt뭷GzD[[>K~{zWZ A<@|I;VM7/_}UzСC˸ov+~}@O?]~eOZnBC@#F|0y/ltnQәg.ojzҍ7X9hgy /cB6w}wyg?3(ra\[|0z1Ǥ_}tG>UaVw5פ+Ւ_OW_}uY >n+V <2(`bvAkv3}CzW3auQi&JG}t1J UW]U;|zEq\rI҄u9䐢 u]{ B#k@/"niZioVkwjVXaz(-첥o_Կ"w޴ꫧ*M>䭖8p`ntuץ^2*bi&Zi 7L/u0iM6)n?e~D0xf--iꩧ.uci-ۍF{g 6(uA A|Ꙋq1ENM7]Ϙ@30\\~j+I&?L6d7L0/YUN8aq-~c ,FM*RvfyRWk"S(;u[lE{ O1C{.t3c;oSO=9묳NeYJ87>j! RfitYg~dCI'Tv3A?~8餓k?J]Wa:(^ebu]?!jCg~2~_W>nfE6zujh3_SN}n|Dp jGf]?mail qϼdQW6W`jSЁc.zuCG4ۛ5? QD~t&Fݾ0W[`t،m@Kz&7V)5p9]n!5ӧYgΉqϵtAkVΝ-[vywAS`7;WU\kfT8{r?yiP lZH+p(dKs9gB|X(C-~ExMW%-^_ n@ 'ӟR&&$}ߥo9O;M9唥͋5cq!yWL#A>>̞6Kf!ȊtiLD9#ѯ֨n [WGdᒀB\sͲ.cc=8ǟh^ʻ@ȠIg/֐SF:~x/2%ws[ J>#x{キ({/azAԧ~t 7F@?lqIK{:!4Ԩ)~n役6_: 10ۮ:-ߤAn>t$ŷ]vmWv\ .´kLx.oUSX7 /Ш`P@Hmf‚I"d .3X?ڽAʲ;g;c:U(@ԷkWA]Sgi6&4g<_C-#V/p!3Xq'~ߖ@6BX#J 6BrpaeM@gWh13dW%7w :L%cMLwBc+H];o-b 6He8^>Ff 82cx矿Ȥ.}*m[(O>dADvY:!_pnF) t̋ t.S~[neO&sgDP(?&Dvgs;2$_9jo]'48>i760]<M\z=cMtkryW.H":?Zh ݆5p. Z@dC M̼|` hM`uƙM{egt}=Y^Ts+ PT}QmJ&w(Ks,bEar;^[BP3v/ ӟW)Sj\jwx]nVnԡuۄ `/cDMbW~V,loLTh.&BvAKV,p,*vf387}٧?1G G.׬Cͬ0@%RZQx9׮ G&5hv\.%]p_Xls(ЩF l ro:A*5_3 o.Ee\ hlrB-9ϲ5Ի0#idFlyA9HlSxi|Wx8ކᷯ؝Pӯo nhLZ{DB:kr"Da~9_wBK-X}4 cxdv121@\W@Qg 3Jڠ@ z[B(2./Bj~:/ 0w|p:'g(lGHhĐ=V?2xڍ t,rNC3|ssSWVJW_k`*W9~'{ k:s;Ehsفv/y`L"o M% bLy !N{0A} a .bܒq[j7;fi@_K`/Ѯ^RCY/pB3ٮ2Ma뼒S+M߄ީ:y 6sZvgloe]RXKn2 IE\ u&h<ݸvʕ;R+WqȓwryW2{x>׺2Ӹ\p677WGl7+\~4߬^k'=+Jn1L{U;:݌E"fǁ1xwY~FA"hNu]Jd=.6%gkrx 9Ӛ\j3;+o|3u7%4VdEY0hrl4[B#aB\sU{;.%_bQcm$#,3*s~`R*ѠB\2rQ2Ϻ4igR xD dClɘ\D"okzV5k(Aq _n < Yۢ.Zuw)ۍP^_KPn;&ֆX#6#|]Zџ[7=;b,~sP<] ^Akڭvv;Gc >A Xḭ1}b6 ,D56۬Q7 g=Kj% A`q'L5"{%Sk.W \͎f`GR :|jS4_A;%ٍhocpXx re6 ev׃qWTB07.1 q;}YyS'ܔ5yd]wBv*,^/h3 4u-'>FL `Lh7'zAE;a8!#Nf 43\ι|9_7wy|C]0vƚIENDB`nut-2.8.3/docs/images/ci/OC_logo_merged_171x32.png0000644000200500020050000001253614777534445016361 00000000000000PNG  IHDR msRGBgAMA a pHYs+tEXtSoftwarewww.inkscape.org<IDATx^\U=gzr JZD$aU`@]u\IԅtUP%FXQDi&0{:z~k«W{}5d \E>d[Yd8  \^fY/}|Q/%+?siYy^d A f*%[`mnBzk$nYBz(8IH5<#:HլjE)?~Y7!fJx!j(o |hsy jWK ,(."k@V 5]53| !!F5! Z}!~UGJb Fq~(AV9^D+0 YP(~77U{Eq(r{q<bP1-Q")@JR~~kx}~9T MPKnG$U.Հyxд} 5O7IT 2IjhS.UG*I~Tx(?Mn~Z/o]zL oAlvŨzDZ7jAi!ae5~$} B͈[Yp"#at?.o0%ʐ̞^5Z$:6K*3gζk*vXA8 1x&w'rXT/G[.>̇NrZMB( bjŢj$H-U)EU<~]^HͪAnV^Z\|OLTM% DR) 65ycHx׺16IAIBsm_,Â$@˳z^|l+vr,4'Y|rn,Y^c XgpRlŢc]8 o=?>=nqH^c?'hލ9x4K+Ku}hP]wÒFbcUkD`+?DaHƗhEkҋJQ^':Ѵv$ "#۟.qxﳥx~b֮Oݍz<0TJ܋# TF0S=NH +~ܼdhrYukq($xvlz Ih]@+YH2乏4bV:<3fFKh N/<~;cuwK61~ޜ^zߠk`0rL%uОzl$85ޞAZ4qҷ ֣o9 ?sD[g1oVy1HåDUӗ趟6"?]O tnpB(IxHO Rvl;?Ӌ<yFKck_)Q!mO߭ o^DV h߲53;}~|Cx Qb:8eat*K$mه??հB$ٍ)k6E*Q^V*VLQUg"򈐘u5FHԭY **|:{@!Jy=_`wˠ?eRzֽDdrj$1)w.MJMvC ]=:r$*\$ 'S؀(]wG^^" "NnVH0|`G }K^gXsk+#?*l)/o_wÎc7c?ׇD̘ Zj0nĽ8xY\nLIDGi34//oȇX^Ɉa=iӢ>H] _ժ\~HѸ~5Us0!\!II3j,? {s1~w] P?Q V#t3GGW`}t0o~?Qmz3TV`֩s 9fϛ[bWI,_=zZ;L!ʚOlǧ.a1BfTJ!9΢5Ǖ)u9 x.:~~e0TQ7^^ QC%?rn@ F=v*Ti j$hc' >vuq؎y4S45Qx GQ#nh {&kػ#Y-Aϙ@b85RG#zp00UKA-FzJ\Y_ZN苗٩уWuxݏ|>/x*y]ldsPF3tD'/;>ƂdI^GCCu;Gsiw!ީKݭmx$^$m]"x@ԯiJYÚC4 I6Fk -%^б!I  *CBPm;rЭOXf.%~9xsiykDImlĕ6yW$6/#7?lVQUe~Ы>m'v󹱟 *Qjjb ) .`=O<"&)A%Xk U9O }rQd>@jr*^Y0Ԍ';|ծQQmz?z`Z?]{Ze׬@ZJ TJ m#1*0q2}Z"C#'kD*kuɿS5]WDJYׇJ~hEQư_( sj Y%+lC.1 KܝSúnѩ\\C )q|k 1$ΦZC>3' g.R$sX*Lzmb`MJneeEҨ IqL$aoްLz&h'h:7V)|%}$8LG*Qp&N[L`}6p`1>Ơ >!au/ UgPPH ;@+aC* "L\P!$ uYo}hፏNn ;K' %L`>Pzm߽G֊g 3@⯉C+/߭-SYIXyU΄kv{;h6:իQdb[smt u `(W.TA5{MzjJK_+կW1"z|0eEuC ːI[n7~r^σ}'=8Q.Eb`ηx%_#X3y BXay#Ov^n%#,Upo1ּ$]'4N.=tb(iJԞ'LL<1Y'gk$o>\_08'6'lo o9?Ĭyˎ$>U +/W߯E?y{VtD$\)GL1Z$v%l'njYRB'rS  u?,3.`A 5HضZ>fqmE03e~QHO=.|=CF\1- [vi K,Y0mQ 5x@qcΊLV&II<#M.De)e}9ӂ;C k$*S -ǐT6N̞bPn^Ok$*Cݬ3f΂tF*1Ce' Q#t:2C*AIVJ@pf!n̒@n[n@2bR*dVva1@t_-/Bh# Ҥ=_&k3 [bQc#AlͰaѺ<$*9zD%b U5݁X7ZaY6!W,O{-ǩurVYi҇(PPh HB${a'/#9CR2sCqvlf?" ^|gMm/_ŅZW]=@QJ)v$KNHfxѠC|A{Op%ˇX6I̶҇a.hS8 uYe(~(D$8zG E2tzVϙ.//mY9^kQ?H IENDB`nut-2.8.3/docs/images/ci/CircleCI_vertical_black_logo.png0000644000200500020050000000373014777534445020246 00000000000000PNG  IHDRkHZ pHYs  sRGBgAMA amIDATxMV9 =lxlunMfNs9I+Ǯmٖ]V?\8S3r b~ѩXY1R?J&b Eh, 1"tTbHEX@Ǩc8x~~1"HWˈ0"H *ee+ee(E2Ue&cYk{ H_ \-\Ä,vss QjqA +<@}x35XyAH&5Qu娒ZKےf"f 5`a~^Q\Dh$5RBw}10G9gK\3_Neh4SڥYzؑ"p j Zʕ0hkHMtU:9^ (O Ѵ{#?H#d]_F/cJ{0喷eXkS>՜Pܹ9~ W|so*>{^JM.6¨\Dנ죊||2"@>遁^JiR#"\/!a.B2&q.r:Q}tjLg~\z+N9Z_,??@g#)cHCW UFvspɓⵔ n x-u[".{׫+ڀL9jn-^L%-p^NuMn"Tg/b$R(ײi/}Hլɴ: 1řWs ;FIǟ"} H&n&.@CSqCw}}p09g럑.QW!3 7{z9#$?!zzX` *VCç9%2"X*|HL>v[n]8۠ٞ|EQEQEQEQEQ|p(|KTFQK(,;%T$ۥz`}=_).]"xyͬp,:\a `2^V6UTJdS-D؍!ٱ!RzJCHq\Uv ʑ  ,I7}MQn!rbooEL`e$2.7ˉJ-'GR~'-`Mb0|:x4rºɄR܌)t'WN[4BݾxtԮ*{O!S5Ԕm]=){B^,SbzdR4ʙ^ke| spdT%M i\9ȵ G= 2oLc>u MLSN.=G>۸s)zUi5WR/֛Mjo }ߡgOLJ]QarE13 4"yU|YGhtCm&%y{帿@%D~[r# he @%"VBQkJ?-\Kvl`H] ]ѿ9c_n[eXi!?>X;ZyX`B)5+X ,?RP *n(y SPp ‹QdeSq'-Vl-ZlcҌ+9BiJ9mR('ldlYvC0"H!SΎw?B Y@:Lˉrb'Хx 윶ƺn]Í?J)섲-r-XCb sIENDB`nut-2.8.3/docs/images/ci/gandi-ar21.png0000644000200500020050000000633414777534445014414 00000000000000PNG  IHDRx<~ pHYsodtEXtSoftwarewww.inkscape.org< iIDATxu}_ٻ䷁dwgI`Ah! TX` 8Rt tj;F˨b:$uȨPE>% 1 ~].+;k&O>~?{~WTŚB.,MN(p 79MN(p 79MN(p D&`2\,Aq.[Dvd}`ȹ!MJw׀1vv9|Dr4ET̿sOOk 9_4,R£΅s[!D,᪑K"CemZD5$c)}3]8Udf 1I&lRV7-yg]-+E~TĕH$xT78v8[{eDG2~NϏ1_JY3mO|*qA/kH$a&x۹nK.}z(ҋ]SNid2C<"$0T)3ކ%drLԞ~YuȨe}a"[Fqv;U5HKU?: W`p 3cEy"w^IN⟓NK)0U>Qhtev`1c,5= Nl8Y!"G*}1o f0X_*c*S?R]D& Q=n]=enEਢ',k8U 08ƻ7auYE3(wh/PTDTh[+2y~t:oTev@>?Ǘw쯼EE)]םY.jc'{1-X ຮcÇSTj>zbBrKURn]5 k=?v݊|UVɌ$S(h>?Q5Ir nz޿) A]79lSݽefVk V#-U'UlXp.Vw̓@ [fM)8h*ۢgRuUd|Vg+Neݾ`Dd F/bH ˚x:PGG*Kw#6P ~ SUxyhhd8=at.' :gH;wuݙn.mCmEDՅdbo O&1U%kѝl]ug\םf g]{=\.7)q-udT̽ 5[qUES~Ǖ{i**za҄My\oKw۪!r A?՝?~>5+y WY%G,iVXr;A ؅BqU\*Bm(fM B؊ y?Z\ DvёN;)Ϗą- Weoook)*3ӵNځU9-"kLDt *d_RE^c#&=0l;n#zt&]%{y`(5Tuz6jKbˊ}qx(vqg9l5ɳVp]wI8"|@U`Y@.|FPs .Pej)7.\8nB?s>Mzzj]< 2|リlSeȟL`(nˆdKփ3ڟ3h_T_OP2}QQ2Xz(8t^~ԽvzJS:#&wj[׻NM$6vتl$raԯ S2GK%F!#&%p[MN(p 79MN(p 79MN(p 79MN(psIENDB`nut-2.8.3/docs/images/ci/jenkins-nut-large.pdn0000644000200500020050000054000614553676503016112 00000000000000PDN3 PPaintDotNet.Data, Version=4.215.7694.37221, Culture=neutral, PublicKeyToken=nullPaintDotNet.Document isDisposedlayerswidthheight savedWithuserMetadataItemsPaintDotNet.LayerListSystem.VersionSystem.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][]   PaintDotNet.LayerListparentArrayList+_itemsArrayList+_sizeArrayList+_versionPaintDotNet.Document  System.Version_Major_Minor_Build _RevisioneSystem.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]keyvalue $exif.tag0[0] D $exif.tag1[0] / $exif.tag2[0]7 $exif.tag3[0]7    PPaintDotNet.Core, Version=4.215.7694.37221, Culture=neutral, PublicKeyToken=nullPaintDotNet.BitmapLayer propertiessurfaceLayer+isDisposed Layer+width Layer+heightLayer+properties-PaintDotNet.BitmapLayer+BitmapLayerPropertiesPaintDotNet.Surface!PaintDotNet.Layer+LayerProperties      -PaintDotNet.BitmapLayer+BitmapLayerPropertiesblendOp&PaintDotNet.UserBlendOps+NormalBlendOp PaintDotNet.Surfacewidthheightstridescan0PaintDotNet.MemoryBlockh !PaintDotNet.Layer+LayerPropertiesnameuserMetadataItemsvisible isBackgroundopacity blendModeSystem.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][]PaintDotNet.LayerBlendMode Background PaintDotNet.LayerBlendModevalue__ "h #$Layer 2 &PaintDotNet.UserBlendOps+NormalBlendOpPaintDotNet.MemoryBlocklength64 hasParentdeferred *  System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"#*  >wTUg?{t+b{ػXXh%1vcQQh0\=>1[^׾fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0t  _" 3 BZry —A[GeEA$$>, 9h  d/ 3   y  B + 9h  3 B +   %d —ϳgϐGo\}Q&mohA˗H˗.8n݆KcҤ6t$:vvm;zZpq)7 UdYt.:M u۶mڣCN>F/Ŗ-[K.zTaA዁4ΝQZt2t3jժe`mUOoְQ񲵱Ce_m`eiǏUV=CcUǭ[A1'AAx_{L>[E.(\l?%,,Y h'+Z"͢2ZE mݟC~L6H)޸E֘:u:vރWtWjA>op%̟]|$?IzFzZȱ(S,]ǧ9sq@~\9W\;u d CHH~Y mڴCbάQ9u}Tz1ګk?{^l ¹Diqb5DoA{ؼy z7D~5H&ac,)}cqgYo)CpU,1cA܇PWP=ń 9u5+ڦy_:^܂vTd;l`ceˋ~֯S> H94F ȻLHƅ^A7ҭk&$\S͇b醽2g 1m;BM1-YIwr,f*MzKU68ph !ϟ?ѣuJC8F\o5\TfmaJqv<{3 G{\7.~.ne\|ZtK^W>Z'>SMOcmoR]G/][{C^궨v_9rbccEoA#^4+,`1bkQ':<#M-mVMN?cgf5 i#B=Fq`y=j 9\=/bߔT v-Z+ OPp0J2 `}Umea2.1jL??jV"džٵګ]wVwD!cJ:y;%5KޟjxD F1aD8/ɹ׌Z[G~oiot8g m}/Ur<.~ύbgb+ɨ\6lǵc?>WSϋV-""|WBJmJ}'(Jݽ2J8-i,]Z[ٲ?;.#J^575=/SSvϽlB]7WW?osEue 9GrJ mێ&"L }jhvzs炰k>ԬQǨ5=^۶sOuL1nsSK߱LC @!cP;{\{39oKWjÆ _ ԩ@X[ڥ6z:<~f=w 7x%\;wuX:bĵ5U[x ^1ì7߬4,XqKO~y V*}ӉK틆x4@}r{# nVy&i}Ǧ(M)[ DZcȋt,]&0g|/_b\duoO f?ǹϏqhVU%s!tZګs@K ^ۡc}_Ywᄁ 1wnqQرq,P5SRtr!8QJb?,[ -[^Lbn^=,y`m=̹УUM㽟~Ry8 p !sZ) zA ٵkV1]O9X}m߮3vlZF_#eLuD(}=|(_~}|9wmnt6Jt쁽¹op^a%$5Ϛ:M@C\߸XܠHkw)3A>߿ϽV>M +WǂKuƇcbС3{.FBQd4ɏQ>vYO⽰tIT{8M3u1'ŒIo}bףQnrZKs,1xYA\skz4=w*R8x,+Ņ^e_{,ZÇ жM;cE~)NL{Do܋04CäQo5uyې8"PVCڌji'L/_A6oފҥrT_:CUf:9W򯤵W1fx1FC(j9]Kk;/s۳rޭg4z0ߥoiml*6ZF˰6w:6u 'fBoi,ʼnf{^Þ1*+-s#ޘ4aCb^=zɐkIc;v?'Ça)KM=/i_K1k ךQ Ti`i>NLKi~=Vp]#1C A97wkha##(1{osJcOŧhMyf8~q/|IVb#Ln&Z+<#GWOTcݺFKE>9Y_G JcFISu.^V!Yt9SK5ãN>>QWcYg7m܌Æq-1+ŌE^q:Oi n y? dwAZut)lZCHX[K!Xp1ljujo3vs-bcH\iwk,b~*qpC{X3*-\('Z+EFsL5hQ'yjȃc1q ibŚF`yg'}z4nK=(4oQp+>5ŴgI-ꫡbӬ3yۏS)3.' |$~51R o??&Ŋ/]q=qFۭk7}Gy6!y?U>ǢJ#4מM轞,>âpfZ x*:+SǮ|,5K1Ŝev$&2ƊE5O}lz}EuP {&݈xODc?TcQ[`³4uuA?KA#$gݢ ȁ96Ꞿ:ݨz -a^^JOG55Wt/W2{=(޷+ڨskzz2$\GPfM3տ 7ƣGDkAޓ/^G^_G?rNڞ"Na\SLc@}=BnѥsWtU~\y١.ps)o1 \{;'~>*#/oxXzi]FӢ1{ǧ;Pt99d9TS[AB`` J:LzSv9}([w;`iQ6[)L{0ip*R%ˠtɲQhױy~\f.][|_fr_ƌPMT:q]ZA`3أe9^J[ﰗ=|&LFfPر(q)W~khϤKp:d}\1c҇ f޻;M1 jSLLm^\ˏ}/ܫuRːcS7t,ר>BoZVi>WsvŊ hۦ= +>.킙?5ER.Zt*bމ3H.#^LpFݡ{I8Fum)'Is#fEd|*N:BkL#'@b%aUc Ѱ.:K߃Ǣ >Vdz< OR>FV]p:Yh& y }vP`qtk*رs c8:G͚uPZʹ{pm fF8UfZbL𕻯pKKV\SU*&]ʺcwr2>19P܀zFO[ hzg>4ixh  4Г}'a0tl%-dus0̚=7lƁGx>'N(T A=BNVKϤ7NsbŜչ5G l8|=]j[mPZ=,Z9@G߭Tg3~az'1 :O2"$-\@f.8ʕYA}|QjM|u|% bxR 3t^!m.O9I )z#s=oWy&˺#}ѵ&cuԤj5s 8v5%OZD={czչ-;+Hw **?l,lyq&- ,AP>|K5zwGI *}Qb-vǴׇ~7b#޼uWjA_}E> tQs~#Ŕ=BxSODEA^!v~@| &[3󂧥qI\5oO>~%KmfϘr;n>VĹkwdTE|Hi1εs+EV 9q$J)x<,^y>nnnT:uqqWIW\DE8q4-[ajze q\3՘%Isd/>dž}#A<鵵oy28l^sD<&^- V{WOu4:{oa>h,ʔ-[wR]UI28sh ZnݺZ5뾗SmiY}+Ut]dT /a#hY4a~y?-fG\^㾋|*:?Vc_i#o9Eu-[a "Eϳ☶ }Q?$;uS0j{y{r,16٫N[BڥZwGw`t;o .X$:+¿ڴ|-kȋUCJ\l߾ sfLCg"8*W6΋Kaeߣ(fa^;sj'h>r"jPPה֣$ZZwcauj1aj=mGyMqcކk3ݏ]}?sl?0& Vȿm*TͱzwS.xh :h67Ŋ3IjSDyѽ7N dWWNa4o<`C9|8jTe{Fg/Ѧe~o#GsqOЦSOXL>WJ/ˢjsS1ʿXo_'U kZ7E£|nř~󒯍_ÇќkU2#Qi)Ա211w};5bERZ:DYen&HgkT*m̊u:ew`,``,=6ň{Ns>/%8j}^w#cy~υbow.9lO維DgAW~u[H`Y&_p?/_tDŽ)ΆN&eCڝ>[M{[&P|ݑSp ٳ4`Ѣe\Gϖ%%oAL?.-Y;hNhФ%-~tz7|ʺW?E;/lB*u}mFHM Ν ^G.\Fcuw׈y,lroT- '#1_fX?uP>ou@ޡſœus6]ʖCpEYAL8cyߍ9gKyX5l2VR>հWgꍩap4(',ylS4o6{Me҂+o }K;Gy1zs]?ϗb'7n዇W4ll[WzWV=\56:r(j 3miԴ |hTR%է{1M"~7^} gcfwTAr 7r /-T xlټ54v0m/-oe~K ]E}Jg/~=sJt;Z_K_ڢmzo=丁>hbb YAhƎު3ӧd/KXڻC'FˆQSA^v(;y1^JBTԩaYgZbY| Y]Civ~*"p!HtV/twT_Z>#)gdKN6vI=VL=JcfodCBG;oS(U%*:uݻ |̜9l IKqܸy'U_߮5ÏգASvq'/7f J5ǙxUzMڠnNƖWjHglyphh _$GZjUksYc>7uׯs_)7[P 'f_SmB~ZӵWZmR=VíYV6AFtÑO9_z=Z/||EgA"Uܗ@|3f,Ͻ RVA̳n…)ro?JUjkѠyΊ55+o=/%NMwM9Dt0{zI} zu M4$$5k _2ꬺU˶n}eUM]BemCa8,5My$7K{\ DMHuAi.]L>`.p0!g繄^׻@ JrA-;d-'ՙG'2y}9D`ӡ(]:g"G{M_^w=dO<g & pQVgp/]vXn D.\kL}*T!5/,y9o{$>y>O3l4iގ-=֝on|bψI835z1!hյ ڵ|e?{k?-PM~Kv:k>}e^[^Zpn`1^:vu^ Ih+ft6ihlܰ),ln=\k k| | Yңw^{5r Cͼ?>N~J+rw>ޙf^MR:<Ӹ8ŎGO+WiA'ϒ;~'}4ˢCθyh yyN X~P*VE+شi :뤎іX>(ƍMsjY<>^OH٬i-Š<凟*->SGBp-W #>LtV߻t.>QvT>ͽ uGe4:(O[^CDEE 'X02O?[6zz=:|{ ? ΒFfV/aY}Q i/푠XWD3s.Z3V`w(,k*:VE ?=(kH9me>T?!r'Ac8R2{(-w, XI3ܸ!Vϛŋr,.cծ+XH]}KgSgqa 5>5cMtݚkצ[}rl~@NJƧ]zi~P3.M_~jڔmmlmx/y%|_~W/ |"*>v:/"p19L\{L#QI.{o&{Ot m 9+ Gx͝>i*5(muC|zQ?,F8_Z2׾YN![ײVχ={jj™jl¤ѤI46=qюog~YɓL)%fi1SZ.eˡYZkS1NKS>oUZoht2ٶBۃ 3ks`ߕ{hҪ l|g ~ >.J/1`\MObqOcg,}詨Ө%W0=Gԗ¸uv8JX3?5k߃nD "ZZ؀f7xBV\3(Sƍ=h[Xj?+d/ۤIʕњ}C7ze6˅]a&[-;s(,XԧHSavWxq[V۽?"=>u A묿w\i#Yy ˥>ʥʔ3iyߖmgʷ7?n= {[GZrݲ1o}0.rōI˸cվsw&Lx;ùŻ<3g k\AJո^9Zp c*mRǚY.{i4WnFyQF?uUGV:ԿQS,@P^S=|13a֚=Xw2hTk.7isalgGڪkWav䅿gC\)kiEwtٿ9-?|gׅR>45εx%s Τt3ctIU+W ɡ̦͹S. R+&E.loō{|X;6بASp.zY 0틠F9p$&\`ea|=Zus.Pq zvioKz^"ǎX=d,'Y:/z 4.)n٩.ȹ#0#`ϒ:õ"-VI}?;Cqu֭ۢ (7n;E3ȝRh25dÙj:LQ1/m ;ҺbXJp2>؀ hko2F :;v4߈5r?yvt5 G\6oUbXs?by=Wϒ"\01ioM0WZkK골&|3})xZ3ŠHׯ9c->b(WizN%8aj}lЯ>O!G2]9QmCAuh0Py+xEC85j3{!dju\{]ן߿@c`pԮۄ̜KtPݶǏ)_۵KW;µ\zRf~Ok_n; ]`ciqSc]Ywǧ54|4ڥ+{^t9$!>qH|agtc8q-Ѻ+J:cx~†>|-XgBRk8fqQM1?&_L}xUWLg?"qwww#;Ŋ[B[0@ HK$! ABp"Z\}}y@{o/yrߵwY[^qxmU~\]pڿ=,X;998{UU+JՄeՇnв}W껖G.lɝ۷E賂²,KBVK89:؋#ɍץ[uC03>;Ts"SlקPjlј 998lŃTJ}eIǃ׉z F^L>s%,&!lxNV8{[Gyt}u 0*IOܧ3,_{CO?{nnWh[.vU|UӴ=YVd|`_K-e`rq< n8~Zll{C>E&ig=@! ؝,ZSZjuoDУwXPGYYՓ熘kz7HJNZMGMcl%p[YyJ\苙?SՌ7(-ʽpLu?'M<<Α1Z;{ ^׿9:8> ::pp&kKz/9h? ^d9|m?J5Vg}5ܗ1v&˞kҧ|_chI~c(*(EĚYk|: lmi%NUXш# p{WP:t۷U<_k[+##Q, |gqpZ9.>dhMJMR!0аӌ94z cŜ`D>|Zw~_&+q|U_^엋X;xSj4r<׊_gWޣof_0 }n&\sNoE'⵸ݡ_ щ'u`>-(_]5^ ;7:ԡ8qEG 7uŮN>4a1-8 `\R:eAWe>{6NKN EQjF\Yv31dlD uie-ZYXoI ?c\?luyW'yEd:gg3N\g{' gÚ'9{oNsQHB?YŬR`9s$N{P:x ~>,2rҫ0eS1VqϒZ<@A4u=gΓ7I2ήC~gx)G\VgK7yN4waǬ\K\gÚK}\#4m'Z7Y\!gidSZlq3OSXd8Q__rK^^(jC5ע߯\Ҫ8u5k֒\je|foGz|#,=QXru tqV`Ϯ^r vs%#臍)42s01gyqn/BIsZSJqNߦ-Ě(t:i2FyU1X;WM3h-Y)b-% W_rlߠh)4kErxC/:R@ȤlDO!紣F9kաqM[ǑqYh+xէLe)IQ /pN|`vN%iuǏ?ZzcŊ]||JO7]ǓV #Fb+qcmQ a96Vge6lՙ5p%5gU+)u1Ҝuy:S[lK_,iUH_h v;ʵ5Z ܟ֣~Wt/ϒjx#N/va}Qw:\kiEEVtU:^q]c{k'cb>)'a2[8и)kDNY +vo\DZ铦Z ͍'ӈ/~t|7ʓ8li]؞G EmF+ɝkzO5IiK}giYDx])ט[_ْvNPNj<ڵ{ʢ{TE{("vyx3!zg͊5W EN#.{9r{zzsoޑLB" uc]管fo"77/Y +\= qةⳗm_gA8NS^9+9PN19P֑Ne7eK{UqVxAGfFT=I%b!}~ m?a^K1X/ Ƿi}k\\> _٠-b.R94kMޢ}9RPHNzl9hIbqZ 5FUz!XxAǀM>MLtVsdCC je'PoKΙT+βc3|pqs\{ "}k4hV\w{1r_wVڨj77*껕cI8t=<\0p%֑!LX[sCGUqVxg($8l]qYFGm^xXoO#c×A>_5Ag1Uy2c Ӈ}|]ӵeA~MdMN^US^_Whbưr͵n!JU}w@(NKa1[=$ZViӾRqVxƔSɢ .kG^)-- 8-lr6G!|(yҚզg8>XV7?fg7 tc'rSj4 $sUS8'ru5 wrԗ-FU߼ߕٜ/29WԵw=|[+/kZZs\W؇Mlal/`89iՉ߶TFm}[ՆR:^quW!M?h˦ .P\VYg>w{Sl߃V&s`rYP`&R$wwJv\!m;ʵ\57Zq~ru' l;GD'g3V)Vz-:7rymdx]j_ŵ]*- 'P2)4jE)@k]''{ 9;ҪU8:񂌵kױ?ְO[MgIFʖp}~5 nӢCoZ~*&O}B>nV:p j]LjXuey_E^0/ L`n捈&fg'b,ư+?8A7g֧ S؇NG2Uj|R..0pq{Yk؈V |ʕ,2>zQ:ѿ;f󟂂6ۓ'Ը-|s6GK17XDp%(Er"?^\V^#gFjtU=Cga>pao:<OeÀň:8.{dhk OJlV+?+;0/~zuVINҚJ`_wY'({Ю׮ ǏVxǙ3g)<,u qV_(ReJ-.klͿ5fܒhXp'Ԛh,,/k\7brB+YKwNJL䁵ԛݡSJUϨZIъF0tAGq]dnX&wE'战jѱ#yF$}q F˅~{}0ȅ/j,f/Doֽ=98uf+6DGJE+(sA9Sڽ+1=~O=fR|Jm-%e;x?Om⽊}t0ޒnylE?BYu9~O}ƶFp|O%~z {zYƱVMI7U!w"]g9VZv]ӷ)=Yuz-{iw62Ę+iqC]("&*VB#y4Y4k^)ZWUCZ./b0pEw^yuK̛?_x6㻰X.u4n|f:QщB`1h@Kr.0s=\4~ [0U}{ Vٲ1f80t\jg-E7-VxG&ޘUQ_YJEɱ}qZ5o0Zsqnk8頻5ne=NS.0jeba(u R5v`?}G~.臃<).&˴܏MGI'~GΧI?cyR}-kYo1SCheQ{1eXYaNBsQ.:Ǡ},e,2_ιH='q._zX:j?\7$kӏsCcnʜGhJGH SȃuP4p4/תNⲚcr1zgQϣil|-NbӲśt=kաhZe#yRTT$Qe]&ORrxVWG/Ya6 }wGz(CcloY^^8 > U+0Qrfq /lĴZK>V_a7c.A;qYgQ1ܬOɃ-͇F|11VX歗&ɝ}Iгk& F~{'a\gաdڕy}6LXglo/9,zO oNܯۑ-rG5hFS+kgxY<.eQLq>尉S>CQݺ}# keZ.>OBQIe>yLh%5iד}٦EଂgcCϥ86*C00/p3ѵLV,/y^sBzǏTU:*8 j3,lge/x+I!< .#/ tgaCui[e9wW j{JϷ[ˈ"IӷiAI m;Z^.|H:Px?jzڂNj8>:`|"qJUN%!lO|a>`Z뤦w1v\ [_zQHrkݻy^])GVC7F[fxiա`4j*}<(1a1p61,5Ko\'( d'ˉPwJ?mȥ;NOXbێ=TS~L +sHs ˻D\ʵ?A;r1[M`0g!p^쯆V&>=ed|m;tЫ@@ӻH[Cyz62;V{`*ΪC|>}B# G*4Ͻler.g`t1#;˽R|.+KR/ONIPFX #jjyvЭMLgB"fXbƵe P# ?OgV7)<:=hß \r87J EQYnvg6ѫoZp]/ (j5>+Y{y"k \B.νG϶bR*r^k3gcu%KʘE=O``OJ#D_ŚsKqv2Kwtjg %':Dw\K FZVX8 5wb_sA}GMd.hZ/(k# >.8I正QR!RP9 ]OuG%/~hVvg%w?M*Gc4NEf }F5%..!R#yT\V>Чw M.2{.Q:a||4cz7U?{;Hի̧\ I.rI!Suha<=.s>\!cJYZ`uuu垻cg%ͥ{4裯\Vg}4iVz犎bR#8e{/Ӣs?f Xb/YKǸg<5+-ޥͧ3o] eMIzC~G2Y?yy}FyyQXfru6OKw8uTqFްЫżD^h-qglWK֊׏{!'0(68O{e,J%Yݫӻ-r|}(7wPGNT#Yz"6k6]G<8_n^]~lw̺P*AOgKI?ebWsOhH :M9IЪs۳A>z@Ί/ZSke-rm=PDl!}MJ_iL:sSqVꨠ#+kO>z t,p6367wwLS3QŊz3򯙮u>a5yxr~ϛ]oSZ$c2qSxt" ?qx>vo cAknm΅.\SJ=2C漣eh¾5 n#FRqVꨠcbޱ5R_!υy_g$Vuwiz XSrڴ)7=owU7^ۋ .L~u$C$y- EN%?wg5] L}nxp>?n_[֨oc--M#kB~ZNuJw8uT1)!aΦ=>cK_A\3 EofNk1Z+!BnO$m%^G~,ʟ-uVA Zvf.Ŭʱd*.^)?o_sw% x-ض1^y >kXIJXBɏB"@qY5!z璻GMqbܹ*ΪCp4n̄>`JIޠi?\pO-[:Z)Pق]zdR u%тA+bnmeC51nw4ߧ4tߤyۏQT|'[MސS-o=}($<5\KhM rqa!ަ~wɮЂ'{ hQج{^uH5Fps[(clEW˧&ԍ**{SqV`\>URw |ݣO\7j&RoT~ԇD}OI{ Hu8!W̓ǂC+}ºQy\D b`Qyq/ٰjFXBkԚ{i,V|.8,_䉱]M>A@a1Ia\qVF ,lhU*ΪCl۷D_w@YS@@7<)ZIMʇ fhof cP9g%,48N>d ]ZcעcMy}3Xq%MEw?f+0l64 w>PRJl_.*N \Sු_@9 qVҫp!~S ~*ΪClR@'hAa#F#~J'fgPGۮk_ʿjO|_~"WgYވgnn^? gjH5BCӟ}'TO<:7Bc[<C#%;_lh2b {=ڒGt+R)GaѫGUzWogա 6r *f%-iT Rc̲hZq.>4^K{t|xr:Ig\ʎ|-z;ksIzRwēpX\ȃQchD!_85ʚ˅^Jrtӽ\ū1Dbwr,Ԯ:Qƈ᣸P :?_n]cz| 0iLA7;ݮeTXۜ3]@;iҎcKWyQ;v~3nXՓVr:K[3ÀxN1` r^8E%R-MwiiはSJ/6Bcre}׏{{h('OYu?o:6Nse^?ߔ)9Q_f,ZOMxђCU1)VK) ZEgu?1&~1=}0G3|<6IZw>ŧ֦z԰egj*oѩuC4nޙf1140WMezϕ2{3*XbUnYVYu .PLt< sm׷U~PG8.)c{)kem (;.xZzо=5>%d݆2W_1_yIˊѣLV$}3F:zP]bF<<\`hO zRŭgR/Nوu׏8kKa3C-o]?7 98uTq1pu.bmlGlV-p./1(lC K1YE<=SXSU\c{3{eH_\W+фUU䁉n Kck39936Wspab6sԴlz!c&f,oœu?ч]YJYsِO1E7&_O ݯec@ӀY,~jXc/bA/Z쫯A#F2Kiy1)yPvfF,S0+uЎAB9Ή,},5eWBY͓ŨX ſ>Q GF~ZLN}Xl&}{ -krMh΃l8\m[*רLe;qmE;u'Hvy[̅ k>X}Ca1Ճf׫Rh9k &W_z_%dR6-( 6d/,4ۿ߿B kUUi|7}j<8:QLt} 6۞Gu&6YZXClJno}h⼵TQ| c],hCM11V;qn@D9XMᬤ^M YiݎnܸΡxJ.M³|}(%9"??ͫvmBzgjo ћIh5Mr_S]J>0G1z6lkYXgi\sͳ2(*=F>۟7rxSXHi[.v=mBKk?u\yc`YJ|QK ͛ur%Ku/3i +uUQ&tZXD(z5Ư^}C6o ][7)++Zjyo z _k/tecK`_r?w/YgIJZ;|Vg!9X'N֒jEm8doR=Z0uPox-"gٸ^`tyF9ƊZy:wStB:zˮ"x-zS9::/@ 'OF4B989)N:m79Rt-Y01nU^rrrtpM{۸QS }i'Qr:JO8B0YSap 2y}֒rz%Mkq[o$IIZ` sm{w|_K:k^C& P>0V{vwޅq4Bю};Sx,rcoH?'tQc>۫V?10o۷5x  U |굫M_^4s#x1c)0}2jKҥoߋ`]zujQJ&My 1/puSsa6wR?Y#]WBcsvC}FN$;eYP` 0ת55lՙm=:gQZ&ŝ%;ws5kߋ9~>} 84#+kX*`wgАp*(8dwj 55'rK+חGxp_V}wW_SjKF6%9Ex Φ MH~)9k?<WX1ZsiYSֆ>=jsnqhiZ<^gk1B"26&7JwCb>A0x ^oY'& MޫKoN"/w3RXJ!+~>8eeeI*82m ik7.^Psi ؽ2sʶrQx.{Nڰu ܗuhI/9Ivoo,73o+ ޏ޾}j9]vgLnkhSZں{ؾi4泑ԪcS #ooy2 ̼Xbk!J8h{͎:+%%S|:q:tSS'O tU,ӏ?.QA!:r([A"Бba5vcŽˏߥcǎGOczvctfsL1ӈҤٸg%|'#K#I猒Anϧ nk\b˱.);jk0[T7V#mU}}w>b)X'pō: :Zq{uh@d q.kl9~эu?% mg%?8?ve߿N?WzveIMosCNAU*[_0-]NL)GRFN=z;wN8EG|TbUZ5uW\Pp6;;??r(tt9?pvE_LLi5š^z%~oÆ~?\_.o;Jǚ{<68!0v y{u/S!K˧_<YbqXC7mC'=xYYa#cOUz`EĴł fxO\VΓ^=0v/ԏua7}~^1W8S7oL߭ME~ҿ&M;[5 2Jk׎Rp|㌌"5ݻGgϞt#%;,Yy'1e=J-"k.)uѼysTVJNN%[[{翤ܪU-hڴoNJ߁jq}:{١C--,w5eT:y$ -Y%'q欭lY/Û9_tT,y5C v-6'lP~I55k֦=%ޑ_H66\4_=C|eׯ!CHcwdw%ܔVq͏/ob- =CO-;^L5 wEBv7x_ߎ| BwjR#&W T}25k s}|{I"xG`T6_kk{ڴi^tN n̛K=s{Ƒj ^7o/:ucYĴr2Mr M:Mpȯh4nԩcg `<|ƋD\CXJ~NWp󦔿,9=YV>z(}/C|38@.ÔL9%8.0|7Lk[ҥ+tĤZx#lbe_d~~ݸ_"GPMO_-J?l߳VzYke~:)yEj s%)W\`$zJQ=3~qX;H!.ݎb9t:?J٠\nl_~{.k\ws'e;QLHi}-!!֮]>/ڐovg2)#3V^1LILL?P,b/2]]ZT ;!q czG$|=7wbn8 xX3g4.]d4}rwg)0 3gcyecp>KIS'W{Sh&j"coXSFqԯ]2[ KCT@_`i^˹GץY7ދiɾd.rUZctK^fn<0z2OlB|slx]IzOSmG#fJmPU&Ug%muGr<@/jQ;4Ckv׺Q¢r,ba5gWy7nys/b'OFrlZg;8SpӞ}cGm޼oL6ncv^?`gŋ}zbl=9ȁ|x؝.5+4$'K ]Ҙ _飾R͐i֚WEm+{;4m]!s၄nfe,Vk" /8){xm@ݺ}\o ծrsm,m[K 6-\pO`ǎyds5<f, 1W6}x piҖe$9Z6ΔHc{0xnC-Y/O!{vQE㬵kٖgq}~:7:0 C.ճ6W>}]&XM}Voyy}.ڲu;mٲnA۶mviUEݺvgΫfBwvv+ⱞ^b}=Y9}R|ı-[Н;wK6m$tޏ{=(1!<=oȞ}Ws/^V&5o]k׮suĿllBEݚ<60t-kWWo/j^+FtOg3y4*a2\^C k琏Y"f#J!YbԠEGj]#kjᙳ??0}48FK.q/gֳļ09WOrhQ))yqXVg/8'1?DYcZY@_yuv ఙ:[g2чGk{5k!ԭ[cl՚9]~OcGsb\ݾcm߹vG_6kwݏsv`[\6UpO>a܋ɓpWopFl7+·~(kԦM[M RJԼys F'_ ƍQ||XzqYYYSժUrʔN}:ϛ){Y*io88 {OGLmHuf񙚃a '5I#{T+shXy/$Fa ,'աԹKiuIʻ2=`m'C.X-x^Rϯq?S&uiz梶1EᙒsmY[X1ȫ߼Qة4j᷋hA}CLD: ޤD/;p3qp)cQ ڻ6/ޯ+0fr8<)0dC~68&Q>+5ⓥ9W+++S{8lՆx=emGw쎝csO?@^>)y1@Kڳg/e:wppQl?{&}׮I?ҫפR?_9r$v] >}w~>''19|b\_ɑZh>c`筨s=ފ~#٨7a<3v 'jK.]z&a'4 LA7M /̮z%"1oT*Uy kQڊ51ay&֘iSQZYB|hhbZEkk][ԃ^ffA@>I-b9?sm*i#Wy? qǻUKE){x}^\|}rX@^MJTbtY9pVb;RËXw17x y\=%1pǪ,x"|zoX/Hc|NZEcR5!<((4bmmboCoQDX^BCWgu</j z1oW{jդ(}l|b0XpaNn!&v %lTx۷?\\ 1c[,YsiwO{QoSHpY7^saf^$bLqZ K;ĺ$ԧ'7rVZ*Ц,.UAc3i-"\ 0W+|TY6J`Κz]hYJԢC=30g5}+8zǾ#ı2gEOcJ۹ocģKac p4[ a8vMacSx lOs9i8P@l{QXH͞i~.c/=11QֶXLJrq>?ǹv)$8<7GpNp,U36hl/^ٍWY. >}>ܫ9NtGFhT\aJXQxെs1p:{^ϧE?B#wt,|}sUdIZ*aru3co XSpp'(r`g)acsLqȘ ,(c^m*TU,ymXUwM&~G,ˠyێҪ7h:Mq8{I(I_đ%&J[`k<9ܷ0w@S;o5 o][<!yrZo$i!>=C_ /RC)ZbeC7m^o siQvy=7hٲTf]>o8>Ϗ?}[QR08>b$;G \ jiթObAoA.>|UiYuű,΀>ﮮ }r5IX!Y>$##&ԏOf>"k=xkҰԿmJ>FIs$+AT{@s.ںu-戵O~TD6B#2륧凜͂}%wدʺuzJrhG_S}(VcJJZiڞ2z@cYD]C[q=-jkQ4~J fIK]{+rwCZZ8JciiYS|<>NiMkPeéXXS#s="a\ɘn+#AV?xYk7?|,00^}  ̷XOqu0&Z]~Ml>U&%\Gw]~M3?a?^8+yW82"|6oޢhq5Jv i88t7}VPBgJ6W֖Np +|T'Y7k]CJ7pbЭ%zf^Ԧ^(uwZ!Xs.ڲUe G?xRq A 18)+CCR}'ܺb=`)]ͮc YI[n?m9}8M?gΰ)bp=WE/w?J\_` -~o' Hkz W>Ne1x7pZV:דUFa|`මvG$򣔜ZI!Zu}F-cLam{z)tk&\\lkR~icߠb؛:U€Ř1OkbR>ɹ@ԠA#ڲe+E]~:SSԶ)¾Ch@AbנAӎ;XeWJgKۊQ}5ڤC 7.b><#>Ccv_o8zN1^TCSO#_Wh HݚE;svG1Ja>3Z0sl:7-Gn-56W(.E=I5y2cP6?Uy[Hr.n=75[rx) _m"Ҽr r_EgQr8 8EGMp4]|MRR%KNɡ,JvCFoFo&BN`-bh5#s%}Pd>*=q*{ee}ըQSR.֠Ac\ɒ߸N}^oLFWl* O* mj[7oJC(%ǗlKz.LYS \c3Yڸؙg אy~>~%:/wGbٗ;D?5|ЫoOD}9Z߀GuӃxɮ.̅ڶ@˖NӅ.s{_+5xH;sxkpP?ٟj ccY l6U5V6Ͼ_Isb,n:Pc~>Jӌ58=b'JI(SW'PLԳ1R1!Wp\*WjT-cװG"Ƽn>d!ނ~@wKl%Z| rsOӊH߉{j+jM{~)۵kwhfy EcbDcǎ˯I^€У~*k}S̙sNK `n۷%\g1{VVS֭/ ?}ҁ>ț0abHIeJ VQpzĦ8E,>ܟʵD4|fD4&*`:61җr(J|N]:wst:s<;'C%~cXnV go)q9ENL-3ǍC~~mHr4wXjՠe'g(6OO>F|1JQr>'mDvVD 5=}uClqOfk4v3l;B ~Z|VpqwN浛~$ߺ& ^Ju>h+ִW>}=ل X Η:*B_h+wc>>+qe%c /z„]};_\_/!2EݻRlM*T1%V\PEɀZc׆ q4%5}ד1oD}ם t-sq&]8,D)^eɡ]SGw)6jyNo潢}ʒ_^4^@!:y,# ܇$??$̸8ySr*u6f1\:>n.1_ǝ5'eYՒ >;ޣ@;>'}Y\h?9vrL_xq?\_+ݻ:7ifDΒkpVnBC/n>lz|μ]|%cѣR#z(Z'JJHW:җ_NW<5D·/ib}_ԁ\q0?D[zШOkkqX7([aB|i[)ZE.䖎s?SuLnͣ$Z_1' k; ̭HH`NQjiVm>Zµ_K^7r)95OʡKַd齩ixx9(6Q}{L&${ =!Ti"EPQǂ."֣XyY~'{f$3ۿ0g=ֳY5Z/nz_("쫘wcS֧s̯ Bc$pĤ٬lAE !ٴ܍zMrIoߴ̅wx{yc5v?y}>\l,xQ[ǖPp_|#g|n lgk/=bAw5lxu M 駟QvV=q6Ϛ8 [ʯU=ěr?:Ff8_NgW֩ZbـͨL!4Wq[|8..Lf]rאkJԩC\=Cѣƹuk+f~TZ6IX5݃|N t׵Fc0ʛhC]XͿùbŖJN<"w?eG}p6+މ5ӊ9`:;qZԝO#6s5O>wu/#<[7^˛'Ç x%T]Us>ׅ_~aˋPAYGZcƩBI6ý[XJNPmlqR%˧i2w6mQ0@z%Tjn[/#p+J/u6Es'Cl'^Un:Vs`_cѯpLDDjU1y"Gڝߒ{4yyΨ<{>\92FP %m<ڼy@ 3|=sϷwO2O9r.#kO>͸t!fk-=Ol`ߋF_6<_&Me?..\ٻ)YZZ/EhAF-8I˦ӆB簪9U\{^[sHT*$͒zX}FAn-xTn#]e'Մqtxf&{h*Jd-bű+'E}tzRb#[@ɜPA{GdW>+vg{Oz27g r|4Ovkz-yQ3P .ez"#u\1e>ymU̙#7smkKLg?ƪmyzKcFk]B%eS[ nϬw =r)Yf'6+U$NA&bۉuA\޻uVo>YMBJKUhⷵگ^|D=%d6L:MAqM}kN=췬ύ聙jlJH(522ֲ6+pwJyLYp5Uf?4kwziZӓw6#'<*z~r\@@P ûS/.+5XY={};w>?\~W#{oLv|y.jBЕraȿ!O\+lnakMJCqlߊ]SLv 3oxȞU:'x ]4QijHA{ͯKxB-H 5ǬߘbMIS3|cl.O03%)E-oZss60;ǎwAs1N]Lb=k˖ǩ{#=UW/x8heM)!GfxM1YĦd׹1F;Wy>/)>e&q7}y\ԯIq1&]_=b86.3+)#Ŧ7 E2YAPAk!ji /GI87nsK<:faocozf͜w؇Zi1«eEK_GBKٴ4zR=fglE?bu/>FU%;9b5O?K z_ZGyG((XxOU'9[T WE &Ss87wC-ٓ\ֆ/#0bd϶V{zo߸뀼By`v)sF\]_9D8=&3ӣ03|oseYHuN; W'V'{ca?f < -ȑ}o5̟ C"sUH8+u(Z\΂[$Y-܇ S \vΨ|.k< lpu b1G}B|[gq-_ RQA;2.+?NPnnL`hم3ý#G(ɱT/4ܱYk>~]9DL/2ۯ{Pg)7-Q{KxЀGq>Y{eE'M+sCԏy12vk x%蚥ns=<Ǜ;\ޙq˻7([ y[> #1b%qυ 3lo36.mgcuxDZV\e-;5G4fqJܡKEoEm:Sn$Wr qT]}N9kuGUH="{jl8 gS~,P*==={jXclJ Q⽠XXdKǢ+V|;t>=A+}6cGGq^[^=^%2h[o> p}ᇔ['U >Gz kGQ k &#ۧު_71|Yc-mtN9t1~!7`=z(M<_1we kx0?p :-T$IO8L߬}31hB]{6@c8 ӯr'<<єy3k{[8c?ƴ紼^G@VTߎ\\Iє\pSy! h7YޯcdMiGX"g<6Kn:&D?ƽ"w;V{XxPz+֪!q^h{,'<9C%%~1V.~b#=^*NЯ 2^Be5kn0_6rVc FGz$e,z!(~vMJ36;ӥpn |8B6BXsKwCvB*Ot~"#: c'kɩ7u??FYϲgrF[=]VO ?x^3XEv>7[i3YqHgOZ%p7|깲G=1i0êq/ ,Q'0k?xmR.:vN:݇1/7kZQ^E%ǜGy癷 _zfdz?w6{Yɚ`8gIɪϷ1Ŭ;nJ5{T^Ձ112Rz l^Ku-bHM#c+'g-|֮]O;{g?V8Qd"AU1+2܃߫ +ak|B %0R-0yYsĹ~ᵡՁUcpe.͋[ޫഘQ[f0VS cU/Ԗs'414qJcθ15ap_GzqTھ\˔Ci$e(^ Çe%yg={#ܯ胅W"<5j?N;}k&sa'uA^ݑ#h;-bTc=M1`T_J厳w1f(/)*9=c1c"ΔHHRJseRFz63n:r;)}pc:9H|쇴y#DsnHUnEbm'qGN #F{=S)>O zt}wVidZ/35]?F~0׸ YئMw*|b/W)yl\gs(Y*{<%7B.+r˗]+g<ʗGKbâ֊W-Y3>Pns^΅UUİ{Z8Hy]|>= i>=w/4765Syخۺt_c=$~Y }gGiyY8/WZ?k޳)qCy>Wh>5_<ƷoV}?jW_I}J}f%ٕVgPbŻ7lՍzm?UkqwG7_w?eK=D^gw9^#lD#oݹ:RgK9h1׷gv\FPwUI2~5ZUC{r zU-;.+?"uMKke$ǵԵD7'$]wG?y|pVaSg?<{յAC|}~sQ۩8/ 0'sP}mA)4a+@帴zf%mٺvoZ;J3V{`m]Ў{Qq)8{__P?Rwls\!􇪃?"c.\Үg*Ϊ_b`NI[p$yqjJg*pz\n*/S=c;#_VG>v]>u?w!pp=,8O-מ^{ZrzI;WѮ-a=Gh׊o#xJ{Vc||xaN\{kfUSfjig[4g.Bܒ1h+Qz7c}{5ώ5"Rl >=P#O1sk _@⥗F>^]谐{1̙=o^{ sbOmMz&FңmN'[ ¯-hۄ<('+"27PAI99!pX":׈}L>w%q]k9lw(oyD m~#GgZgC/7exWcnw!kP?zCs*uwh՜dajVs_S8j:.Jr\#1s(*-Ȣs^hr)ҭU}+w;cYc]#d=x ֶ;4!ǯ{2ɖD^.߰E991^߹^yr۾vn^Lz,xYt):wcw?\.hq].fbb}pgv* gQݻ:zV,W ?U^Z"a@Yz(^X!~_uhB)0aPٿγ7/Xe螆ʙs4Pf/ =ABZy}nݱkɓx}pE 3i۶a vE\p޹cY;d̀8}, ~9}5аViN)kskXjuh15)i8j Wx 陘9]ůqԥs$g + ?sw_aO?{xN>C?Ԡz-~KnjMqbL'W/<@q:q,!$'ujRٳѷ*)`jL9>Z5:1֓/K{Ijs!]ŔAY>y&P8XxnŧF?]bsXϜɨC[D\ jxKN̅BR^Z-:2Ϳ^ ;FX4M&8czsMntҙ3O/?yYzͷ|<{+9YnA >Gx$؁K_<J]]Fy%Nc\6ڰ#G6?V^7U[SƟ0v7;}v!&o^>8(|Uk^졇x+Z=F_ clxuu#n!mw,Ck8g$3ƳN3[ZF>s7צߠ;v4e=d}75zg1<0ĺteٵg|:2+pba v>xJK4+G=^'#-ꍷǕaG.klJgX{Jc6wE]VcLi 4`0jkZ>>:vxJO#~8zxOkڹ-+ӡ t.FzɜV5^ 㩃WZ4(ϧoȈbln_w3uÍK$c3fvU+j3*_[SgsK;Ҡ!ZeTVZb`,"0ΆW_gsJF Bg 䎡ȣ )u~rUWM(jyc`.5!\Czh~k$gE95T|5V̗5FwS])R3n|vq }]8cK87ᴲDI̻>3ڕ);|)kΨ< T9_$B\&'P{+=k)^[_ЌJu.iN%{d *SR\6QbN{6uQ_x2p/m`=$|0r o03CiI~5X>]Bopu 9OsPY]TY sH]"wU_}rYPjlA&3/=TUً=_O?yJ=nq=,~yᦸF z-ǽ.ʜgx` jWu3*)%QE?/~p#us)lZE=uj`|QPg=~u`Z_S}>VK^v͵Y|16.ښ>d &cph'WVzRaj uh⬖-ϓ*Mˣ+GGB"9埯VJ(ʦX4DGan}}ѧɧmU s=q8=qp9nԔɓlжe&=յcT{SlfΓWbʵeb-Sg(dM.hп>@>yZ0*ꍱ=uf@.䒚kWc{΍Ib.vI+0ΆEnZ3u_q|B-e'ԁ莏SZ69j1`aQ<uiC%EW*9lkqkMUb 'Go=:* }ylKb2wll< ?ΜGX .b{\ݏ_9a8+~M.a޾p*nȳX$O-Vu_3Rz63*ϬϚh+wl<SL,m:W<']=}JlibzG IiI9q6.$kB>>?#j6-C }e>3zBk~iWų1rxFiMo{(?Ҝ$J[.8JB٩ԯAvw|eڸxcz5=*kNGx̀G}g~ŗ#Ν3:,2d}gn ^0O.GFrTX˹:hxM۸~Of a͗\y`c_C#FRTOS4ƶOq}\d6kXb5KѡC>17Q| 'q6.~P(<4c;>Iɩ̰nƲ.~gU Ύ#J4KO\7j[WO)iq - =6w6w8.5C 8O*C';jX;{O=~?2v{ӪU pcGU{VPmE>7w} ډJ]s~Ƹ'N[ח{}ľedOh=<;y]|LWc|XPG5t?Ŗoqq"k)'_R ʖ-q6.(GܻF h 9 e%W>Vńy}8Zm>5p'v6u$c [E/܂ ٵk%՚epVagW Ni|IgΞ./"_vYG0a4p`ֵk'ӣzWIՋ2m>^U9/lVd܀&l*\PGyG4c/jܭSQ{D|nl`zIUoqyb[ `xAØiXG7c^;dMaʗfDl>1#o€cy.1z"k[ /K e]nsjpz'Ov[ܹ Yw_q pz]7wg ثg-u\ =ޯ9hW12CK"9c-ǵu5B Sb&{yY%/SIQ9c}?3s3E0vXxB>UrDLǞyp[ ^Gyk: 1 FiY;Xl~EQfaT3is lW}1Dq!p|+qZu U^ ZN=#i)K5Zic{R32򫿱SAA15knoqy+=GR/G_ާ7MS}[/#cOA\v* @x,?/Cקq(q8n/Ӱo] OǶ>z^0caD_5⹘3;a na ŕχFv'm6 O<)řƘaK;N0y:'ٻ$k!zӬ'5ΒCSX|ICf9gT1 xb^}t< ?G@xXgH y͟ g;R^ZO[ `x,ii(%V5.Jb4)n;F76,㛖B|&$){Y}˜^U1cخ7 ВX aʷ}+N:K>XJJL{Hr&fsώf2"gB4 k6&gQ1 P_V\c բvңG,5;c+.NgKm@<>W*911q~%ywlIq{#u v}T&Ziњ?T~wҲt\5Yqq-_2/J~\TΪ,̔$Z9Go+vZbkq]*4jW]]^MwNj1N N`iР5so5GMol7C p\T)u~gM)c]TWM{~הS{XΟo?14ח_֑Fým++~?3#2Z iׅ+%aT~6&hKnfq.?p(W3yB>P<_A hErf-m+h˘vӢqz:'tS~?V07JݻŲw/de]⬈y胼P8 ݵ9>F'$+A 3ov={]1u/};9!}xܞ)ѥtMՋGozz|sJ 8 0r|'>O?զ7WOip1~A?7kd6Z =½:j/|c"pU-ϸc1jZYz Z!j4`X1s,Blj^R'ZuZc-y 눃(qwHmiqx.쿘np|(^{ ~ g^ʣ]3z۔d-o!iVܼ1x82[?:)sZ; cpx-$Y\ogO+(A~"M ̀d";nq/x}81cu8{xtG"v^C xO(Ɗq+1ga2劑OC?vNi¹EC723:@sflDBF =GVju4"K4p(voH8)Kb=.x#(Oh;6"̃>Y@o8ËBzktYCO P_is-fO d﹩gƋQ-bq|S]ʯcORY`XW?3;}:4Nb䀖L*iy9k>2 ~]{PWm +ZkڵfG N 1harF&SX$ga鉠h8Y Xs.4Ϊt{>mOMOuмMsީ~km|uK?Xcͷl:-zjk|`8xkXkR* FTRu@) l8B} 63nsr?OO&h\cq_ f\;oaq56ґp=sŨYh^uyԱU4Q hA~2'w L`QE>=]h'ֵβl& 83EVX\x࢘_n>[)+ N:woEUe/:~$玿kQWtxMc{sOs&g @nt`eJ\Vil\3g9F U~v>GN~eN*,91XS=k2g/aoq7e<˦oWuhץ|VBصF Ì#16~ɓtq8Aqqyޭڦ ڒ6@sTlM;c~EsЃѿFx+0fpu ~'5@ϯ^*F֚; E6WNdEM׈㪙:7_;!a8<|n\=y,͜y%9V,A|#ݳ~9oT"f4G4NƔ,{yL4Jџ;=}J++dT~$ސh3(C7TٹN)*m+s߯Ԗ8wA-ASܑF3:Wx]u?s1g%qek7gOPJ+*zi3}C"cf{Y_uqC̷1 `O"ZӀ"&eh K<]R|3bwo ]ɝ|^,x9Lnɿ[Μ8 8g|{xb)aW<k9I|]Y7COO_~n]d$kskZ3ZM}hj6Ǝ9v>ZmvOaf__F=;Vpmd"fvzɞTzqq/3k1ǪشYԡC7*`񤑽cTSܬ9)cw.gO԰T[M᪾guzz=u+A+7CoȫE]xTUss|SNI=! H z&HG,4"E@Q:!{ݳ&{Z $L2{fLP(Ơ4[u$5 #|ON"GAný]4kl%nη߉<i|%EPE*SH>fyts'q]GROwOrv=Q'GG7*_ޙ ^\-^К7|~[3~Y1;~8B?̧V&4i4e:Q6u齉]1T?*ėSbtnAuޗ׭KHiՂ)ߋIw.*9XX\%ztyɍJ\*w0=Ғ'#ӣ&eYo'n|76)"ȇϩ'/.]$4|(*Jy~Xo`GDio{BNT#lњΙG+YI7OAM`{ ZXzy1p]kGv7]xS܇L=[\立`l:az1cmSOo*[%$TM~VUR2Tz2+v..:]شsiwRLQ dY|'+S4c=+6w[?3gk8qa>h!Ť19zز$oq,Y39 4,82F2=yYgí$GI19䬞SOf__&-?ޫP ?1\2xzܸ}pE녛o^9uwjݟ(>v}%W`PəhΜ+&>~X7{4|Hfw,lsnaC!~UiiY&=!m.̹(\+ elE#_}:Iq/‚|(byS =V;q+Vx@1VI)&6Z߶ "/qf$7z2TX82~3Ť4`?Gbc`ń 6Lm#8_,`ܩnRxp&/mc1Mz^J[1X>G TM^S jS .ĪT%ܟc05"ȗ㠤mNb?[ ޔV;v޽ke慯233zRUlWk<٭>;uWO_@Z+W%|w!bH}($r>3O=H~}=~c̛>/ܩ8+86s5fFa1qqɎļIH_2p{\DXɕ9ٝz[Soc8OlQ'squb*?Ņ0i wwEMbn8..fE{|]\3ޞ>lB'jڏ?j-?-.9੽Ĉ f:ȼXڶubScμWk¦WZpwdzkf ǓzD1r{j#ߡ.!_K7r7Zߥ-ɜ>?Xi-rfA 3uf{kW3<3W|:1"<@? ݻw/l6|L^,~%M+@>Ś~l˽ (F-:|b3ܹsCj`KU5fΆD| Xfhz+}v t.d^O5[ѽEQf̡i4ch=jPlLI)ö&N:Ӹ(XiST|>뀝I'M'O1DRn\}Zי0a.Uj5QxGڡ9uv^ik6iN.d**)~ifWkdK%ZPZ NocVۃ (f3ܞEԄj ;0Pcd02@B?xZ5"rcٱEM_W**)Ν69YّvsM bn 'ݚ8Y wW6.PqNX~<}IK5{k+Urpi'lgg~1/u"LĜ-=VW!kJH畯S<Ϻ&QXh$͛1ݾyb,C:x}4zԲe0G~L;w۷o٭{Sz 9Toⳁ]څ4kNq gOaW\ށqcE='))G ?0ǺBc{s y{94O*{MۣyL"gBv19Fm4KRy|X+/B/3<}y _a?lL|CDE^|m8؊`d$;u4&ϗkzyPBqT/-4hZNm32K9rPcǎќ9nz\7_\[Ѧ~GhڳiGzϡYS*L;q6rcaʔiJJ;b߼Y0Uf5(MN"6}zƞ`:)}\Y"5PWWs~Uάdl`ϲ}oGIѹsVk#I1ׯ ׵0qUۣ]kc9ۿ]B۴V(=R0/+ 6q V-5.hъztIo/쩹b7eV:t0}ݼy'O>Yܻ{ܹ#u|fΜEm6q, IaԦ~ ڪ*oDŵ߻lOJ筟kꙥyĈQf1FYa;v>4A9>͞5}̸6_Q̝9]ois}_Vl~?g5U؎_6WUR{n YcE Gj9_[E}gᜋ UoCm17}he^=ZT9ޡ6ѓsG7oBG\B>-}}]}IyΊsZމ♳kg L~Q1nokLȍnzԢncDǙe]CiSB(/S< :.d^pS6c5;֭[l㘱!f~7;ϒK+gIJ>.e%zxypsJ/[{zEi)vk`YLE}fԣE4x8`GaTF@LSeWOwC; Ip@[[1G jTd,7hLݺE  tuSἌ/]BÇWŷQHSi,odT3e9gkϞG'uACѡǸ^6N}$ 50Gzۭ\(bc0-bkcP~U{}ȝX7zuX>2vTϴ?zC:VASbn C([MRyhj0sbI4}uѥY<y<U A/[~e۬zbf'>̯\Jx :x(8u6mB1QUx^}Rvi:иvZc-5oCB@苣.F]6oNOfJ=/_G//5lX`W>/,RI[6jUkUB;'X;5ql~Aq㏊JJϑ&O1)ɯ{y!olu~qR $F.5y3$m*;XG_˨fE l bE%gq{Qjܸ9_=+味&IZpPO<_^MDhȐᜃ$_;#)1(v,⮰o>/^߼hgGk;FŒ2cs# q֭WURz5|(<shmAM{"hp[[5́~ͩ[ta{ɜz|/E X{yر+(yz䝳Sk ]Z׫Mؒ'uqX2x8k6ˑh}k?cӧ?5i܌$2k88EZ>Sޤ /lzyZ_3qdZ<zUK 3v:X%XÇdŮ 7,^,q14C" DZ&ׁ=+kQeu3hoiEK- Yrb-z坳9K{^Zi,ϳ/r6m%aedtコG{A=##WJjyXS~7DW)?0 KaClGW_/8v[ +mR؎ck+w BZn>@_Ο8Ikq ?_{h*O|נqirW#gr.- ,b_Ȣѣǚ۟?kuN\ʾLYg;کiZp{UӱeExy;oQ֬B5kQԸQSjӺ-uҝLSN^w}s3rˮa3qT{d Շd+^bҋ$~Da_|iXf5d-c  {>fgݭ)K=[Q6g۷h,)ʺtm#G8{E0a)mL3ƜG?}P&M]sk浵.={kmG/mZ n8"#Qj7k׵]'?{YB#G)++gahރԤIsPDTKzp5(876ߨjԨه,Vuzy$g`Yx CuZp~\#9TC=2/$q633/Y^9=S Dp6=9BجZ<٤~6[uյևqϼm}2lzз+׶.V6iuW ([5Az/\أFNeJm(0r-E+vYW+xb^p͜u{mV!x5}el3ws'Or횖Y98Sт_l^@@fE?:W`_iXUnY#͚5_;'nݺm3=G>d>\˕-g<F|qZ>JDOgc#f 1Okר'%ٳsemܩqzGpVOx)BJ$DslӁUYi~:T =:6lv $.M#)*Ě6z 4_;'?~gGB i8q:ǜARzc_ՠ̫P[SG{  .`Z(->}s=~]쟴|JV}lh\g_T 5c;>>|ݸ"瑳 AlqΣ,Xd@I-"fMygӓW>5x޺n#Gd/=ڵP,bz6$ln['lBk@_~POt\;znܸiswǠ@ZfPyzYm]/|hYX%+4>,j7a?qGʔ.5 YسkmZ}OYau'Șc'6h.,ڴnLJu\r{qdD `).GGrmI^?s![PC^w?gv "(\q[k9^wQJJJk,ݨkoYԄz88 G]pQ`k/βiϞ8M?mlQ,?w}րDֹ'ݧs&Ou%Y0^Z:>|<9'Lb_@wR%'rpp 92TR2{_/?8j5hѴb7޽az :ܽK-jg$P8gޞj?v40_mr.,9@IIp~weY87J{_>grbNԱ)[r0Gq? dykb lp\\}W!$ڶ} F/O>6)IٳO#h5 u1.ǢE_ ~L;.N:ez~qr|INXds#7sqO>[k^J\_II =BP2Jx M[k} g1Cŵ*`/5̆) Y0$"kªiAZrvĩl㰯]+>ma[u(d#?gJ>B>Y'c/I}ov<?`?3PI,YG#g}D^8` n[d N;KoV4Uux9U,Vla۷n19ۯ@Yp6.s_Ga9T ,-)sQcQ8oTR:wUxMZrEaFީ\y䬌׉ 5S\gâL gh2gc,j/rDgoa#a[rf3%vi 6?xܽ{ `zḍ}7l:w.g,9YZqjNSBI:ՂN}eƺ٩@(+bR s6朏73ŬYUZE6l4닻lqQmԭSkgÞEh/~[O˚P((0Y0Cmf9c'3٬,>ٜ:I5㚂V Pl5gen| \`ޅ ho"G76%Sa{k% 8xHaܲnַ߮6wh.#I, ;([GJJJG-u1͘&ΚA{;g=;zKJe_<=g6l*lsV(;, U| tM:}V#N7n-k/ :Bإgkur=lKNA1k'a/6}QϕN6r#g'E]|,v` `87С [O -6A,mxˑc|xsSUR*ʍtE޵x-jʁx68Փk2 ^([QObgk捳r S5&gΥl۶>>W-[wqFRй Yܞ3lʁR<>锸x_let=%[>os}-cOI rwx &)*))퓲9;.\@9Aw`m۶3JB,=΂sۯ ̾\9kSJڲgkMou5> =kK{}Ӧ-yv\/]w5%ˊ[/!PS&O\~+))g5qvtg%kc|=QCK^ * c{7tH=X1zB^8 qΊe;|~+`-)*2㠤?a' /`}`g/Fqy<;sv\zV>-^5Q6,k8Uz{ ㏛hbVZMgϥFPxU 3f,޽[UIIL ugӣesvJ:\xpǪQlba3.FrV ֭̐y-|\LLa?32g^^*U|`ZW>|w^}h94k\I%֊ ֭Q(""|[abW,mi|;ŹF)*))b ύÑ=O$U"w_DNmQ۷޼y˚C%ɍơlt3_;1{Yzi hwرcy-)moCye>rX>#{=1ҟZ)YX%%ӎ;/Ьmux rbdbQѰX(G֛әCo}h2y5.qr]~U&N9pH6tm߾ݻTB9^\<~h\C<~V\ok &v3vY1VIIЅꥳ-aGoax{Z?oHl|?lGwabQqf-寘smI%bA "GOZ J絋8(-[ UϝS9[wOmo\]d4ʁ8-VU$7a Ԭv(!Ď5Jk> WfkvmhH-@03"}4hjִU̵.GtrJrTty+ea*UָDqT?-o/|G[PǫW͞5N؂uf?o>}۱ɲo&ZE1tfQI,b|2MZO5x j8ɁiOc= ^tиum:z&裏ĉi׹رo~\-Ϝ9hڵmOnb}EbIr'zm{~dcqٌ֘eP@] 70s,ԃб'm >9oTyj#vr[v®2d☒R>z5ӹlܼ 7͟ytjPF0S|rOeZ #ɦ]>wǎ{~P%23R.F@cEPe}Nz">Keh1̢b7M^ȢI>=T$\O}sq X%%%r 7oBM}cj< GC&Mj/g)2G72-hӎ޽<*{?'ح8oG>2F}ȷNNֵ1O[7TB7MX+mK8Ԅ a1kqa>N=88qyT|mڿ3V;T+?DWFi;sC}sc_!]5sQڷy᭾^KUZ)_eۃ(؀Pq9pOÜ@]=z&ҧΧ_~FNSWߢ]{Mq\|hւɓURRRRʻGll!F(K1>" xط:-rƚXrVKcWua-Zr:wM΢ڵ9 ZMv\ߍ0syĈqSo MIII qf 6NkW1O5Vqʮո}("؇`)j, }}]fquR,tp.g΢&8uGFtH`+b:tLشh݊VURRR*beffқoMUkmAq12ٸ!X>x^j1T5:@Yqb%y1g?qg+{M;_ٱS\^3i=gQ/?_JJJJJWчSRRM歖oWw]tu5ub(+kV7}ɬdqE={SttǑI΂ȕ-JJJJϙn޼I}66l½Q>i3ռ:/@u6'?p"£Ip37⾃RmrM2Xt2Y%%%Tc]f-ы ~[l%4vnnωYb=~X8qV=Lalw{Y%%%@&S:il'aN}scAh17.NcVn߾c1{V_C꣏?mXԯY%%%Hׯ_kј1SbB)G㮓iۻ :FwjidSq^ݻo;qn%g32ӡ#98u}zHh6iNW\ԟ%%%%ի~F0alњ⫱}[JQeGz'\,sqfRqڣ/g ޸8G͚d{ڦPblL<9sVqVIII4nxSXDS ՍJI-nØ͖//[L*NBNlzZbGWJV~}3c._ZfUJIII }}u\o/?ھ}⬒R Ϧ aSd&'Jҥ˦8b=g ֧?ǂ^_ںu]ʁiߡ3wO N4oJJJJ%T{m ]ێkӋ.>^n7fΞ8M{e^J?q'{=3hذf18^.C RURRR*B1b`wsRNNf.V.n޼E-$g{c,W_/ϑ3/^wޝE &M=Z%%%cߠҥZ)@OAŅRwܵIq{cK~׹r=?|)Yb62"88TBb7f|K=jLQ#Pq-'ܞgX3q3g/KW'oয়~VURRR*ʼI11f=rA=ez1?q&gMnٙ3˕w׮@aQf*p ߱ꑧT6U(`G,I`6'1 !>xȚ&O33Ǐjn]',~̝3OqVIIIO>5Ik̦֏*wޙŜMsү@g~ȜEKΎ}}⬒R ־}Wjr4l֏Xu,G%lK8&gGy _RddfV44Ύ1JqVIII͛ԨQfw {6%9\l*No9y.Z{,G=/.ˁ8*x4k< 2^̶ghҤɊJJJJ%\'OO} F0go߹cfgإK 7ݍ=wZhMWdgp_G|:DU/@˖H@qVIIIkkw{hwMʼn7]=}<}zۥxNOoB7nbΚ=FGmSB|5U^ ^JW֯ߠ8T1Q"1A-f6ܞ<0Ü*sЧyr,NNn|sR7_[P_ 綨Rѫ_6h"cşZO޼e;7d>1|z{a 9/_Z[S=WwWKM|*.x8Yط7[f-~{kkJiiJJJJJ&8qBC#bf94xPfSqg[r=ޮ5]#m[Q+/Xd=z+˛cO2ZM&qg-tXhOetז>apkؼVbխO3gK.]RURRRR)%Q\ٺu#cdz +zkWU?@1bo=mNnR|URRRRQG0z`.ߘ|jC6-NN P *Yjw]1VIIII4 *rL^z _+ۼ[k؋Q΁D@aT5:կאظQSޭ'uЙc[hM-[-3uԼY+)QI"XBNx=ib[ȭg\@[lUURRRR*0Y*븙Zrײw~ȼ0REgJ5-YlA-%Cѓ]F^{݁8STURRRR*PݻwO؊)?z9J0+-Y`zMpg]PU'7b&Muz())))?&j٢5GQa[.lGghه O^r6tdd -Z⫒R_С)Z ݂wp#[i}Ǖc 1Qx/_PURRRRu5:x }+Фq3Q=cS[2lj1N&1Q!{hn|N zG~oW*PR8ˡ3_T+Qڕ;eeeqeVМ7SQ&_{dےusie~G.OJr*l޽' 6 [O>K/?BGQyJJJJJ/P ٳgv:{3a$/;&SrZTN=aPhʔi4nx5kYV^C{3g̋tMwUE}>)*uhXUwޙw(b "tt b݅E *)HHNZ;gsgAl 2222*<'##4<^xiDNʹ{ҼN>;L=Ēe+^ɥkOFFi YtLFFNTL:3 ONO/_Xkj:!жCFykOFFi W_p1/m4F՝0= u*&Nn>ꆶ=<^YtXvv΁Two=N᣹6o%&0n$?h/wh֝Eв}/hձk:wk֚-T'##4:uiaQqZiN.iz͝x)0r. < ĵ]u|֦ ugcic"g90|\C`Y C.D5늵uV7}4 'O$8SCGwvY%g g6oZvC=ضphs4t? 0:&?a0v3; IwnSj}P5}4 rfyiO'M6m,MKgEԡLCk`mLĜ9zIĢCa$.&l8z C{pC?sHY:+wi 7ÜhyQ6su&CZkƮL%#źuvŭT'##4摞O'08$vvopj;ۦ04p*lM`iuűl ÿ*{Ls'`^;z2yD_Sj(1jkFhm_{222MyWKw4 kvza6!s\`I4;zgV ǿԷa}YױoKK4];x=}=}kMUھddd`ӧO{::Yk:ugzI(G F=K%ZD^ǿ׽s,:TWBD{kcIרsސ}Bohhړi4~9rx'kt^k_A(tV` J?yɼ{o}uaV>/5|W0rY&ESH9HzpLE0zy L8HmJ4{^/^Ʒzaq(gs,jNu̞L:m_{222M40޼7`А/TӾ. aK:~aAfmW*@pe0rs/vڜW^MW[=ONʼ?`|?uAfE'%,P m_{222M0n\x&>D5z5Uv}6 ) _~=x+åpr5̬KBVU/~7di^ ]_"ojtwLxYwa覻^ :ާХ{N0;}'_{ (޸k!=t0RKYU{MS駒uUeMZ]кs~x&;}4 GzFΕמϘ=С. 낞9ҠSo :LK.uTKn%qrd )xBTHUiher^^=tHX`~}a…fO>ߎ\bLכCaQkڛ%geddƵisA]kk<ƛɛJ3V01~B-UΗ29UOt!BSɪ΁)Ű; [׷ނinnd>x7E?yruAJ%]̢_{,4ٳ222 ӧ]<15kЭtߵ(0c{VX['!.rw(ʒ\TEETE~8 Q  y$ !xz l;=zw}W7a74[|W$H4vĢ`wEN!;捶=xqڦBϲjrl`0]BIeWrko!z9aTK7պ' _yE¡q 8~! @BBxzz̙3ᣏ>}O$5|=wDmyLpTu-ג_[w̙gT6掶=먮щ9Ms4׶]sG-fWmaw::].z(ZkPXcTE\㶔KBn y8S N={xy̭aѣ履׌g6i}J%iuGY琶=Hܱh2RѱF_#aq%1@ZF_6ҕԗ*|KBxK=sSyp& ݻwKٗ7<~L$[og4ζ$ Ozpm瑶=@9v >F}~mݙ1+w)9i),{/`TG^rS}TrVǯ ..NDll,eߡCPP=0rHxi.cV Ҙm }N+W+瓶=()-M[xٗm;tU}' ER_v݆+՘_ PCfݵYRK%w9 gU&GbnCz8p2c ""B%INAC>N ̲iiԯkQ>^JbOtNPe]py.,*~[ھdddxi yjJCH鈴HƮW wtv=ݟT/ ^JޗjyJ›'5p#K}J^ ' <":RK㏐B'Oܹ'88τ#k r'&=;U^KVmsϨ7`(/W/m_{222MWudee;XVMmm{ 5^ۨ[!IqFߗdK8K6‘Y9Lcה *2?Z_tO{&=GzF QXқoHг:6NA:'gV+Ri'X"S6•\QUR5G'TG'Rd\cd NNNWO?H8[ѣ$%T {w&<&!O0? ḿ<}l?ciړihs`;΃g׉g]ŢURK_SU$ˑ|lRGwY^4K%TE3#~?2?zD{("C7^v$84ģO pT*8]Ar{ o4ўj{EmtN|Z?ciړihk֭ZDV^`TޫƱ/C%(5jIQ+"I#곤FzY%e~MDR.n$x pE.U&?ڊpᎮDg[NWBSr1'ǞȬgɳZu/#FS&=6>qm@R:1qezItRJ_AɌ*ISq>7MRSfS2xn$7:.| \7A~ fe-[D؀{p"DKEBJ8N(D"%Ӻf{ӷJ6[죗9}4 1@Oq=a/{ıKܯA4f#YWՔj@",GD~]W##ȱԳ Z? a֭"~ MMϟS^k~wM6IHLȓ* jq!e r(OR!uHSkIV>B"ykOFFiWطoD ARѩB@`B\v [>kѵ~RמLw !_:&Q 9iR q*(ܹӂ+!p}Q%" CYe2emµg=}ѭUw8PRބd;Q ^"~j}@sYZu >m/ejړiYg 2WʱRN\cׁ0sYW1Xw .RJ.OLÀNG(R~uS>Wrϱ&}ZQm_{222M?c<}Cxo?m3L8֠c]APj.DHs;zT|uOz6=˸Sĵg𞍡UlgyS|J]"9tlJ.] &&&"-[cGJ; M`ll,a xC=ѫ<seBJ#P(G(7"0 `w]viij} 1=#jړiSХ{oQ/E\;g;gyǒsOIEZCws(u%K!b!*)XړUSyɴgYמ#Rƞ]`e/ɲ eE,-;i\dŋR]p0x/rXjY=F nIJ/W}%,wu/ \H,qF:&0$؄ YZLK8p#TמLei;e |Iɱț42pu!,TCYW!z>=/K>PY ǒ{: KyDa;}FwGa֬Y0sL #ہr޳įN#ఇP pʃne( XЭ;t],m V!7u6,٧]ھddd/c<}qvw9YP_#ɱZ򐳮+9CNRѵLg:6H%%x8Pl,];ֱgc,XƯ\UάDI)װTX`P'gϞct)^ s9Ė|cc>}RA=TYq,‎ݞH(9! E]B8BCl>e[ GCm۰5eg:ZҷE"vi}4 ʺvZzZdT̼a#tDn# jZ/f= yԀCH(Q[SBLX][ Y*&Ӟx6 : g58ֳ9VXέRKB*gI9mCss?~c;_pSNA>gz@8gwg{ֳvW;-P̰PG(XCȇ-y V[[t*4+}3ɸ eȼ4f ٷ?9j$XFGsVZl4y"HG)Հp5!wDг$EfZC=DcVCl % ٳ ƜG2]8+YޯW(9Sv`0s<#BLE%71s)p?saҤIf1Lݾ.ءgg[b#M,G!pMtlgcMDd' ʹ!}+H|[w}èkOFFiИ6hHhױdaЦ}gqgyJ}` IZ?Ik)(.6Ԇ5#VZOBKXE( r ,72 !`A9,Lh`'wa˞yihkaQmު# | .H:JDŽB,lMq]CjHHM $$ӺQ2RXϦ2c= dݘ,5c<ˬ<.?=;Cs.9CU4G_ ~~/ %]$p7)Y 0$$Xt1c$]jg]H=]ɳ6J`zkXF1[edX"Y"p,C Bn\؀~̰>0ʹa*C '4=+## xw̹β6';q/K7IZ!)O(5$nG }JL$LKP^V8ɮ,W ɡ%uѱ\ gKH|+e6eO {0fWO@& 0e\5j9R1c0{gɺ1Yt=ggg7g7g9ǚG! !!@C!vn3b k8raM !!&gdj,0tJж4ZCiړi44lި}a>jx{9. 6GRLF(m35!,[bcdZoo)`{Ҿʩg=ѳ^,Y?̲q 2yql2,˟yb{1:lr%Q.C g.@ؗA?Dsky~A#b 9~8.%bH@nNN؁€D 2 vԱngCV <[lw<l /5+e'!V[Ws܂An]@ȁU9K6C|`%VdRt""5yع[oٳ222ӧO;8USk/gt &5j;6Gb@nj'#D @a3q-ɴP1?D H2+Yw޳={=[%kuY&F&EM#,u7cC̙rXbjCQ$?6'@w?Ig!R(t.7 :7+}0h!׏ҷo_}=[VR:ge;p9t( 4fGU4oCȷ?)NA(KE~`AF oб,V)}ڻwoի–sbd<ͳ+ѳ`bI(YR,fY̳fuٵU!Աѭ ne &\2?XK|8awɱI !L=OXZKZOBϒLK%vϞ,_D&k+`%x ρpQ Ͼ 82?|-'(\3oCg^Cѹatn6@~FݻSu&b씹5*/ֳx@cr%'U0kijg1˲)]yLgϮGò۰ԟppWr YȤ{d;!i4|w=+##i'l%lK̹c˲ĉ/W?@k$ѵ J-X~YkS"=gI]^2g}Dyl0)Ƴıe#G2Y;G :pt'M>}"}xH~2x 8ߩ?o@Aз`N,$Y{/tEv:w,dN9^^GkyϺauN!b=[ v*`ͳFg0Fix-; `f%W/&_}8r؛,B.$d"B&,Br,D.tNvΩKB%Z+fVD!<'Zu!],9/̂slgv2p ?FB:KpǁUdla ѱ.L@t,]7>=;Z-γijl8]3Fϒ,{fL,xAMD:GCϞ=yz!?7p!8c|!_CE}ürQ-uw!{ maԬбcGJD0 cgk7sYrrjxd3gd!5:r f9kGe{݉{32_=+##*nٻٜyFׄͶ`qzNxz}8ۦњuA9 s)~r'E!uѳH ,-D޹ijKzۓ޻ij<˯WƳij'=[{6JYe9 ׋A׮]%H Yrfpx_ ~Ļ~tsСc'h׮m۶"ly֛xl 3z)EJle`wcJ,zvmX1E,`l`>c]5Dzs䂡! =x`pfpbɄ t:w&\9NWaE`} :"s/ȨʞyP7j6dh',o€ $2t}Yfsڀ<|$7nZҿdZGdH+3m[oJͶq-KzޓRI/Pxٓ:l=Y&Fq矨c4ֱWri{t:u$ˏѱY}Cp} \?gp\ n,`Wt P<9~[]'Ohݺ5OVxzΉgՁ'3˳ijI=uO%YkgEL :bX]zvI`z6г o| y9 7`!25 Ʉ. t0g+9W` 9sr\0x8̚@+Ѧ}f-ZKE0bij-;Ѹ/;`z܀UR3ɲ2 =Z;(+/0l٧Kyϒ^Ngޣb=ZlzBбaγH}{dYcw] gޣ]{m߾;vsC+pz#e~R>gpfفuy.BdL=%ko< UB˖-E>LRïI,[YWj&&sNU2&;W1<]ž,q-`7 yzIR7PJ`M0їG{m`=kEYwf:k$/*ӱWo0JH߂Q#Վtv3t1]@ytKZgdlhO>6~&a:Ng1kGгZ޳UL%ݣuٵաŰ"L`i`zvm̱Y`~n3!f_)WSc:@NGN ӷ_a4m[,Y;nپdX̫a0Ks2eѾhѾij纪]3&|K2YXa k'ks]?^%qI\қ< Ƃx6'ύ!ϏFBYgU1gkiUx<`=bhee#N&͛h׳;?%lX@ȏ mG ɏ :w;s[9a"|<|'f! i֣gгuZqTGgm+u]`K<{Eϖ0γ$/9Yeg_[ ;YH&;2(a=:r Tj{x;KUb=l%}aqa#"Կwm0\}]]x !LH=|O<{=[nGjP-8qy6' rgKѳ%;bXJ<X g}az Sг,@ȤL`@N#\Ik0iUH.#WKqsF֕=+##uT "~֦#SoБxC 0<V/Kz}2i}wV_ =a!z$6>m`Kdy]aQGgedd1oBg8.^.,y8TICR1%%".JȂl΁>d&CO<%ݡEzv}aZKkYdg=ѱG<['!},NԳ.W5WBDZz4U}c-STj`=|lV˰}u9bqs%:k1"x ʛoK!"sgO<|u!MYֳ{*麱%lGϮ-E٠"0(#g ܹ<Y ]]kmg6&棾 l.{VFFF(O0Y~бVEwaij:5{xvs ķnٰ3#ojnYNҿ}7>zvijմ/,ͳY< = .U^sx*X^֠CW#*RV?J kVj`mS0йfw/^{oOv] h)D]zYv|Cxw:ؑZ )5`EnG<{=[ tݸ=[tXZ ˂`1v<zH"uc̳`{9hUJx_A%k簢FaE%rʷR*`u5a^-aMh)y2||=]ї?L9v1yco6ӺL%kZ>Muh6ӆLgL;73m"Micg~Uɵ#Tkq6dhqLj: cYZ`U*=K{ 8^cz8aS:%H5A{ðϕWM;hz1Yٳ5:l=ݛ=6O[5WܐmnsXZT%KT@\5*Ęg Կ"|%=Z!5zaz`F?pۛ+v-fZrbH8L{3jKL[6{LkPA3YlL!ȴ;ٳPY(̴,ɴlbzVvV^ & ܾ5:V!t˶Z})~geddױKwAo`O /uXgIk`;Ϟss;vE011xȳ.j={̽7裷>ƄEP q/]5ao]o2x_'-YбH̵߯4l-fqMdռU{-UIeĪuZc%%x^ekA)^AN-u~sݼe{oNF|>P xc2I>T{٪;F%_HH B% ݻͻr.͸@/ű ]0h00 垧aMuY ,ɴ뢹Lx1JnTr醚}jƳy1lٳ222ZEy>rL|MGXıVxhCg0H~Nga"{VFFF[( gm;s %œKt-ԱÌQ`p '}E_?W̫λ.)`'h;>3yx_@`Y v̞b֎PZڗpJɳN̍yqgeddXRVZıVw¤Th١tnQ`յ> Z DgXkP%&{YY<~W&4Ǭ  y?(T0UDUr0j>.wVY#0^ sN]6C SOi}7_z+`혜;G*ji8+s=jh {˞c\CУn*:snҺvJexuIСDgL{ѭEݴM8v]3&Yr?TntV뇿Н 3sO0.RJ0s(b+Ww{ss[9-62̀ d-|6x8|ة+۬9[{Ce玙Zq?wƳ57Oٳ222ZCy &8h$Rʪ`Mf.=@Q Ye-;ӸNYkI)z|VWy0%='za~Ҷ7,#nz6\ɤgKxv/XjY!u=QdoTWֱ o!#%g>23?=tWBk}Œ`YuI0+\S1a{-&@4>~v0fqp8`4 n3pg2V^wrs|Koklm [S6ۮCךˇ?գ1N:;CcY~~?ng =ytVXߓ#t=#EHgeddp))MVG>[c)Ք*e۞aI޳#WaѸNG, >,=jK%Y;儿&']áe%ƥfPWNQ]sgJ|+|r|UU޻ ]˭#lkVu9Gk?OϟEXw kz[0i.G0Y;"{P/tXgǑ)'{VFFFkGzFijL~8 D= `¦?T|:bXT֊j]gftcs)qjtڃl$v+ c`{05s nQ-{Yo |kƷ\\2*Ȫry=[}^L3;|cCAol}TGӹo}J2?F?ӷeh8|ijc7nUy{%{elhުZv: = Vz_u*S2)sƖA>zi9Z۟CwkW[SrU_\wU|+ڿ*]hpm5\˸v('>mzƳ;i},eh{I m'ٳ222@8"c%2R0 gPrܛȻ9que MVmMTGn0עgsnuvxko9w+wJ7Rg0u<ٳP7{/TߣƳJ'{UgeddpyH<;34JX6ѳ*F=wKLs}r+ L K˨qRj*hթ<+ O]A)T]o)V9 |Kp3Zl|&D(M֬kl~ ]Ȼ*=[xݣ]Wͧ%gK<+p ъ=dɲPXT,{VFFF+FgKk}}^~%}șW3ջ: b_φ6=@JTt' B{$f:nI¹|͓Vo2I#ʵk>+5EGXr}~³䙴0`BMҔi߯etEK =#SV֪k]Y{v%yww/.g2*/)Ƨ/gIQu 3PP9"䥞 L&X[&8?[y)dVZ#]CVkWC#oO/r>q>z:^F<{ =;9W1{gedd%&.J=&ٓ[UOozU{; Qڃ\C~eja㣯(Aa*zʕZ$ p۟s8A^Cָ:V^l7qEVol[L:rcref^wfoݕ`KȻgg3ǜgY(ٳ22281kgIoEuŜgg ` UsR_UucKV;.:kYs`pK̆GA:uYK}| \K$eײgגZGVkQ]µij_!C'-xG*lJx6гgKڞb<Uu=+##pכ"3Ďe`]}=(w 3cu: UWfx5t?Yggvc<:R?; ³B>CwPQ]Al1 7b޻bG%Xw^;6ĆXkILb|{2s̠Frggs87Ͽ~kм{b5ݳIlhr9T[5sE+ƓEokM>L)1l赕"kY,zOø- lboO'afj^Ez{euPLLLy)M: >VC`Q7CN_g+cŦWiw^ -%\ ή:nl얳/; 'cٮC' }/(?dm  Z^j2wlMZn~_tY(_ۖǐ1~["gήqv󔜽C9zRqVQdd,nsh3IcMUַy%*{tNi}n #gJ8үs-]{7rp87;Ndg;0(k4k/spF:R-x9 4:\V[iVYbVx&6`Rfhr0u&&}s6g9[96YʾGgLLLy"sx,g#ecع++Ja_*cP59R&n}sw8R HpG.bsb2ڊhֲ-cu"%'!@Z oeVZiVڷ M_Ŋ(?p6KZO@ٚE&&07&憳sV>!kY&&<#XWk>IܸNUdjzX_~4-8zŷ"gwJ9Xy*A=r-Ξ5rvIGE9{p?9^iO#gSo<.xv#9S][A5[5y+bϭE^֒x<ؘ_@=TU*rTly>ò+pvmKl8pvyֳ/}^154[U?mNؓ̕sZO#;^nu|"N8;Qg犜=9>J:ͻ?*̙2 1m:.v,ں_)0oW&[Un ubo*[ZqG^bA{ g;gL8g%{(g]xK[ݮy gTnfUPsV\^VĊEA겮׸ )7SdYx#.v,rvOw0y]*O^U-Mi=T6mۥ~O}T=j(o9y3O[1w+W@-_Ku -M/26h3|yG_b,sj~5P\OOƞ1r"gGpq,=s=ׄx|3,S^JyxV񤢣*?Č-ҋ+sDdg-ĬL[w#g@9𩯽Sś㳙9hҲWP/c#xR#'0wߊV[YVZZ6<|aec~SE}ɯpv s<0x&Lv'<]19Pkl읥5Pb,m'5P=gzz(gU#QgR#e;y. 9FM{Ѱc4O@e=NE8!Kmن<,k0CSTV:R-)KLyKugѼHTqnlsD8;a#|cƴ"]_Q.9ۋ㬱w挊l0}cLLLy*1*z^E'+ћjyT&j6덦qSZw@дW3@1^#5! YpK|Id.oɼ-VVkgp[[36`M+N+ĴMyDTvp;5",56@9KseHjozg;θf 5PAAJfT|g]ﰐُK2211奔+Jh7weժ3֫zc_;/6BU!軙t"">A݇pc~ =zJ-Ӈjæyw/Z8WosRjZIvb?AU\CX ֞zY7вg(<-a;zSqܬ.3kJj==Bn v1pF=p.g/CC1qsIy$HQ[[N)V߬GXQQD{L7{O's1cj>ker>Ǒrs{AJkQ4u߰q)ϥ<֮\IQf8+籄9]+gs0("us$A炳ӖT]*;O@m*|=X%ZǶ(젿@*1+Xu4=GLG(_j91onjUY0׸͔sl۹OEEk[EΕ8ĔR} t)ߏݾGrVϣ#?J>{˦툢rĿH9ްYf9ۮ`}lˢ˰}ؿ`a:c'Byľ[=?Mm3)bźz5;4\j7\KVE{\k ~)z_%_58Zwt9_͸B_c(AGr*y+mVdm$[Q0d (["UrtC.=1h.D&ƀ[YlKJzf=x|:cc̘85u;j^t-l6WadX䗌LLLiTu 8_圭 SeGtF~фjZԜwV T6Qz=NexZJ6kMJ * -+Uզ-sJ>9ζ3^>F^ fDIGu QQ3=/>mb 7`{q_!#''g8,&AӣSI稨w.OR/B,g1YEٷƾUR(>+ %7er*T5VۊAZuQa;Z!(a[bLУ'r Y[V5S—_Reyƫ{Ih̸pRǺz`1)j+OaopY!Tr2Ή~\q cА{cuq`ka_9ktn;vcLj&̔UWU1+ͪ8AΗOƽ'%֤vc&l֊-'zFٯ:~| %c (ReQ|{aP|"(_O8;t8hϱռ7X?zyEi pD|sS!\K˰(9=IASQv^gc,,ޱA%݋#VGiM{$?Ah pQ)G\5eXe}gk g1^K8keemdM~75eFUJ!uȕM_mKʿVtpE5zوSOqT [JUeOp֮wKUQs C嫅1c7xcebbH8x(ףg|#_O+gj2g^9kS5MGw9ydkQ%ԭ_I>kƆkrsuݗ@G+A+YeXX#O[w_ c:csAXF.8[( O݃"kpj]'0W[-^ hq\ŇF#"0H2"^$`|m엕em7f~q3 |W"ٰP{g<Κ3KMdo3gS덊CSn`ebb;QKRp"G˽=X[d笘7+n5wx)y+[1,Ze.VR_ҿR58  _/ *"_sm3avӸ>QBذ/`%nmX_Pc5X8۸E&߃Gcƍ7O$hX7|D}89e4$dYW5UV$嫔ʹ럸k$ B3,P z ΐ0#o-&l1d!WGoφa.R8ƿVuy5BׅKu2K:Mq6IKu I!>3E{wM=8@,s)GsQ$"5KϓrΨ e|5X~`Y&&)SGf=giLL=/sY3Uz[-Jae>VzC-㬵G]\qWe g-RO[\ଭn㋎#`]K-fe+ڿ:TC9 024_6s*KU`炞dh}!.@պu8s7Zw3b5Z]_ gwL=j"Fyo[Qݫzm{VcbZ-9|^Nu-,x/f(1v-Jk׻4Fyu:׌='笪X0"H2k<ꖑKo٠Y\\Y:]y+l"o*5l.zf};N0zx۪~]Gg>_(.S RCέpV*jVoleՈ8{4gKUt@%W9*r?nsO%lM6FkGz ;H2^hvQdix4J>ֵf]]0.g;}+m,9g5 7~7?֪?VZG/`~Uz>V`,N vi?ŅE?KeEZtEWOoVr0h $7^SČH+yI 'Π^t@ŃBSOkGgrD=36Q]{'N l}@?^,lчQ,8T-)z 3Vh;a}=LLLUiiTq̰Ok&~ljlVGR2XJŜ&z4gK*嬘%hRuZȜk[E[ٲa4z5^'Za꯮3v #boHqͿX3gYQ>yc6/4. S`=KZ=u:/]esvB➽ ^pW=&! TUW竻׫Tj2 *"DPT289VcAqJBLCR0T뭮^Wz;asϽ kVp}NČLIi+[w4 {,oҼ? @}'{Zy7+?)Q~/}oz!\'޲) k7cOy}蟪?ZMz8J[?nݥwV>Ԋ>EUinjꇌT"GrkTyIf&p5dC*yHyRbrk0f7ަMTq-ƛTqM*?QK.d>E[ +o05*{6~|L=ށ/ITq g2~#w|}ToUUcv:<;t"=eckpJ]ߋ8;y$^T}K&euoooG`$֓ӍCG꩜9sNZk<+8MgmUzXggrIKWPG|ձ)l`kr󊨦׮Ƴs/,\{a҂%6]DkzОw>jyWVn*w{vmt "S<ʻ>VZ<ޚM{V6[.JT\۸(gUS~ɂc'{V6lƺ ,7A'X;|N_D>s(c=1cϖ;@1#R$IA<WS suU[6$I*jk&}ͱ*fm}s癵 zV{m6w u8v³wwȠ< :"O&$9Q8C"߶J})\{U W_[YgSĩ4{yՋ2(~V̱BϓV,8V@XޞYWg@9o7[&xoyYgelf,7.4m55]k ;8xMEjVU}duͷxo3ǥ2:kNg#c)|D M;y*>Ҋ[ylGՋ^SV^Bc+!pT_vC!h񲦦 ustVmL7Q {Q]5sU&Z6˯:xuǿ|ʫ kMǺcoU{_/(깂W^˾.Tt9RJN0zvȚ&=^g:y jCW=5bWmwaV:ҳey;Dg= :םh< ;XdyФdٙ3NN˽Eիb,{}+N6k8+eyOu(:9\>TSSK!'{+'g asrvwSG~бgxduԋ%}aYzq#d= ON7>nx4{Y+-W,Z」bv۞?LeUT;mU_U8N}oNgz,_Қ~ hǮ=&FOhnh:Vw!&U9_FMSKyߦr9Ge>:UUy]X[=ayubgkEae͍h3z峕ZK6tߌ3 ;xݳgXMc􊌥a#iŔSwJUU_+۳#ac={ՋskS܄)\|SNXl0zݫW\dxN-1yO SHSw3oR9UݫZݭk.jqcM|ͩOK& M,E N;0">؁\Ҕ Kn*mY5wP\k-1W'"3e[8njn։pyܱ6ϚO̯M"p^X;RRCڿ&CK'ste\GӫhO}C)a*a񫘼C[)&uOw?GO)VьC(,T]5:K=bzҴPɩ )ܞֽ<\p+]3o&kRK`}NG>DZ]:0 ;`_n޲wv!ׯ,M_^ICy?+z jO\;lj}ђesLc'PF'`}=]5"2Ʋ3;믡+-W%$͚S-/zov!/kk'LN{m.|LBX^]jgaݻW]\]LM0*Fܵ^,9{>h1y'*z #Lm>vFfz=,`6l/uHMB|CL/-*6[zvʫ  g5Q1&a5F=w,Q hm}-mN̜<:5L#_`G}QpX$K{Af12Rƌ)ɚ6y/^,0gG;@tn PPaintDotNet.Data, Version=4.215.7694.37221, Culture=neutral, PublicKeyToken=nullPaintDotNet.Document isDisposedlayerswidthheight savedWithuserMetadataItemsPaintDotNet.LayerListSystem.VersionSystem.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][] X  PaintDotNet.LayerListparentArrayList+_itemsArrayList+_sizeArrayList+_versionPaintDotNet.Document  System.Version_Major_Minor_Build _RevisioneSystem.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]keyvalue $exif.tag0[0] D $exif.tag1[0] / $exif.tag2[0]7 $exif.tag3[0]7    PPaintDotNet.Core, Version=4.215.7694.37221, Culture=neutral, PublicKeyToken=nullPaintDotNet.BitmapLayer propertiessurfaceLayer+isDisposed Layer+width Layer+heightLayer+properties-PaintDotNet.BitmapLayer+BitmapLayerPropertiesPaintDotNet.Surface!PaintDotNet.Layer+LayerProperties  X   X -PaintDotNet.BitmapLayer+BitmapLayerPropertiesblendOp&PaintDotNet.UserBlendOps+NormalBlendOp PaintDotNet.Surfacewidthheightstridescan0PaintDotNet.MemoryBlockXh !PaintDotNet.Layer+LayerPropertiesnameuserMetadataItemsvisible isBackgroundopacity blendModeSystem.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]][]PaintDotNet.LayerBlendMode Background PaintDotNet.LayerBlendModevalue__ "Xh #$Layer 2 &PaintDotNet.UserBlendOps+NormalBlendOpPaintDotNet.MemoryBlocklength64 hasParentdeferred   System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"#  b}gTTg}ku{oҥ(ҥ(EEE{DF1Ѩ1n(`ǂ )JWEVV߿wnEre$&&wCU/!!!!!Qx2fs<7`?~ ֭ڡEV/-77O7SE޼'"͟C<!!5YB0+e s3+q /k+[X,rOJ܆_ZH(OK7cQNodlݲ SLE&Q e%K̒ζ :LexcgoW_ӬrٲN5jI`m|ʿw.c0Ǐ#.,f͜:?5%I3S{GlSC,קجPR+s``mfJHHHH .\ZfZ+sYIKiN>*ϚW+puϋ">>^򭄄DXvu(DIjzla],3=m2̷gE~_'U,cE곡! dG16:^)ڗ⹮̗Z< 8ƪ4/kKXYX󢟵m.5R׏Q 49GzΥeԧFW6)E|HNlCl=t/ZFJH('`_[/7eVɵqهLņ{tޙ_g[YWE ? ;% XPxcO jA-נEx!5{q.6Gb\]3\\}7_4&C7"--cg'7νkjm5/%-6W_-o/%\֖0W,qŜ<#'Rj҆h\-NM7G¥keD޽{Xp1* Vz|'(J׷\ݹ%/[K kνcs9\ిtZܚRKԔ%}?B^?A؇ ߔ->(++^BBBB$+ 6lD: XgW挅j:~G5t[Z(_'Nc˖ZkrjXy.X=.G-J.=󆥯u5%}Qpێt0=}Y i[&_UVK6m AD[1}zʕkq)g\q:n޺+/KSc!u1s:_M+v|z:}]LuNJ\sjCǭjK ۏcةk!Z_)ϵ_ VBBBy7P+,8+[_VyVy8v$RӮj|% /Jj:_jk˔]ww8oqMz5'Q4SxY8ĊQbE&?!ćyƤ>'8"q'S=a",JYž>|}fbBQE}nHHHHH?]GTCD=~sktlG$\'s륄d\:vpm*s-=ZrU}_ Ʃq*R,1w'ܸOpKA+MJND$$^FTܽ"Q9*5-?а#?EVOoS<)q*ȘB_>f's'?ˀ{h[\_DXFV(У{/P]ZQ7oFtt 6mKGqOO <@Zz&/UҲt˂cO<3fb!噭\VCMf=ǹqS*i+O8KqNS~8.}gzw{sL+싿>&p]i{>Ztѭ[ɵ1nyc|2t}4CU?NIW>}`WҮJ:6E+Ŋ##`4nԄcZ]2-z=iXwӰgH΅#88b_L ?'2ƵZOڥZ [lCPP~jsܨeشqsiZF6&۔Hg>̞5={B JnҰVG.oictK5K)Y_R4kd]1L{y]1UE\۩c9GBBB#;wˉj,m |&V33KTٳ!1 LJSR2i}1 : mZvc9{Ħ?^X]+R=0,j^,EdȔX/Ujԅ5vZK|n~}H(b?~&ȣ)DکCGy,+Ņ/_Ie]{1̙3 мY 'х#^+ƪ&~Hעm/ŁX0ZS4c~W%VBBBvzx{rU_mes%J\K>w>#GD0rj VJ5BhXCl>ǵNg弙_g(5<ů6Vjdm}ZTc?sxqd@%JHHH0_r^5W=:{a|lT5bA\KLJ1cmѿ+WX!pSXgv<o#1R=񅋗0ǹ't>ҿǻ"Nji[Cq ^}3r.VpG2N>{IxQi/>*Q&)[۷\+!!!O >s3<ծ]c)ibcÌܳ3NeթKu8w/65ԳCd-;E4+:6t~89 >-c.]OOϐ\+!!!8x09YRo,ODDFA>6Y/zbS۱}G}EE < wy;:лX{p,ͯ=);мâL^Z3+7P򬄄{ ++ mZkX:sźuyC+J;`o[occJ}W+R|nO jƻ>b>5а:_MTu8`*WKs[ Xz7==.غmPP7n…l޼ &LF*8JqewpwAagQM9XPo/&Мğ4G8d&:eQ\pړO&Kّ,jshyFGObњ]v6}}5}MPMT5q-ɵo)LexnZvϞ; 4A{GR^NѢ+w}q8xƘ1CLJc5~g{WbYuJ)K_|Ŝ{U'X^7V<G!JM8ܒkirPN߫1MxOg%$$$ހy<'@W$~´f`ڵ݋󷴘sx1jLϡ9/;ur#9x1q1w$?lN׸~$͍O|^ vzcc3b踩(W ,8ե g x΃axZ /ħ*5b/Q(!V87þº)Ly^WyFOfO2͢s8KrѷO֝5aoJ\JuɤW5B~Xj-vڋؓgp1=?=rX.6>ס|d~-L|%y,WU ,9>@Xtn9XRP,\9ۏG̳Tg?\&ljqLI,BZGַ.Fsyt. g%$$$TsL>obZ7na}9։f%о[Ώӳ/|^' t[ws¯/%geaq3AR}\5s:}м}/S~ڈwK`cWG .ع3YiP6<+!!ǡC.8oҰ{H p e2^%^<iO'qQ,XXUƑw ]'͑Opjp5NY4Hͥ>|6֥mxֳťЕH5 CDex}5}Yv?N}GgEXӴ)=KuUnq1ɵZܸq!UkSmqc^ų)V˂WĤ>s;wGӾ1lً8n)84R쎽¾|*:ߗc/J<_׼En ˖ubgif1m{"?$qSK>yDx1гOxcU%v-i]ۻʭXw{ 29/{Ϡm!|dk[ ~=G򬄄Ŀ k!ʵ)6k+"-=q6Sظq fL1FLCgw<>?Jy4CqVt0){B->sVx/j]F$@U{ɘ0gX+1aJa)zf{fX$(qc^RfcϫŢ/j;7yLL6sɵ:ln畓TtѹS7=Vӯį4םäoiޗc,X6hW/\]=Nh+va^r,@%kտK }|׿aNDkځ&Z]CtmrrY ݻzr'N,HIQk3ܩ)2 fϞaK~4*lUMhYZGU-K޽wc¼s#nز3o;ȨWCqԋwWߞi%)Syǹ[hٹs5 7HWaUgcRj ~={kXҬZ}ňOâ0łַ;h}<tes$V}o+;tlc$k w*ZlA,oPyǹۨ׼#,ͬ 1Za#%JHHkmc8ݘ3gkekI_E}uFn}ϺkzH|9twj)?6f?ۏzyy>=+җU ͽ;"OmQ6}qmhbf5ɳ4F%,rky)S\,!0d{ˎ6ݻv34/f܌A{EzxcC< kskאg-Gx)Tveqiɳ,duQ}g޳MSHN6'϶iFRL6_ȱIyUKq?|EyBY'R.hiڍ7Id?#S֯׈563ن )ǡ 9ܟ\s\՜+Sk֞w?jBH+>^Ǧں (e@<+!!">>ިv $OrQsbA/VG%={Vd)?γYij6<+!!bٲBښ;)>>ӿ^`5ZvС/ךGyLJO*`Ip\H"?` Jgb®Rj 5ne*ZZXaoFF=8 k kYE<+!!I_<;Egٟu4gj g7mچ|*Ky><Ǵy2?JT/EsN]RU%|zIiE.p}=6c}e[Y7}RYXʜ$_j6l(yVBBD˖mPGӬiKp}:c7[j @L?Ο)\Hz#iO{)NfYQjh}zc8@ıQW9+ɏWG'*v; g/?EAt3 g? ?C򬄄'~՜5P:7iܜ݂WX~9veeO+M$7K{@LuJp.LzZ˞3\\{ wX{ƭ0#{'".fQxxT{6[Y*?UoZ)T-Ucǎ<+!!`}5:ϐgԖ-[ -7K^\kL>P~Bme-̢ϷyɏLkNw:w/WElk}0+v5 wpg7+-W΍oڙfX<;1q,w$^SKZy eTOiEmquɵ 3gΆoɱ~PA8wk֬Cg5?ً*qc\1{G߉Hq-Ši͢˔::=YwD:7:iZ#jiCCÐ,VBBX`9<T=`'<`x_/Oۏ -뜤.wGң9Y\P9h.j> 7>\ڂjhܨ bww-/xߤ=<TZfN&K8'j<۳{O[eݡe.+8lC{P7Ӧ}/yVBBȐr%*q/E'ο-"t|Ic-{bQFyVKrx+n}j1¦ ;\gjPTΜLE.i76 $>.ȩ mX?f_c\R:U2\m ?VsS/Xj3_ˊsx?~r:krMGߴrE8joagǐ%?-\+!!A55d&+n0cıʊ,<˷7y˩1sw8rNiJL8^GH>M5aNXN8̳a [~ƼbVǿ9JCQY{t;}F}ë]V:s~6gL1FTzxVӮ 5\]x1C?Ӵ]yI3.[ZV˳#ypiO 4۞y^^x^=nȱpp(I['c R8!!9jZz#cub-~o69cXx,*GL< ܩ([ufPG>8zאbě$nCB*Km٨yL%Ib8qrrߣy׃9]{=-\-16f*9^K"/Ƿ2,J8(AO~0[#M,xFu-3y{Uĉk%$$>Mfy>XkVgt[EԪu.`gkT)ho[UBХP6Wnҍ=nJ:!5p.Pk:M.mo}+s옮~>cgWE]geu:YWdry5rOmUuP[-VI;β8Fl,VKڟG-KntKUAp61ijUoz\8?tPܦFZqOɵի{;GSYۻ?C:gx~>/~כy8OA)J1Ɩz`툾twng\PNW?XWGkJ2h#V6s09,?z\YR7We'UĂ\{ .%}e\01~֯8aWZkK골&|9e>x[+3ŠIlgYW> +1pØU}гGoxBrD̙88b{1-Q;,Vhj8N_B*+TۓG'+UymřOyT%ۏ\Bu9y9H;[p۵W9||L V_n8zMܒ㦺Xxߎ&;M㓇Dut3_p_wtz vPN|ha 6_d~X"h.%(/AU{>1ds3kL~Y ǝ;wwiKj֌p6ƱWwOG?6o2!d%l7BJ׫qolc} *ڲt<$iJY:kyŋJ\[XUh\MAUø~Tʊs٥s-dj3 MWUǹP2fj*1v ^`cl^SNU_z6!ŊGy13,mT|A{۶k%$$  E4'Tv)%mZ3Uĵuϒт/=kٺ/x+qƹ3k]k~o'7tMWU?3j _{N?ENMzO,!frj-,tjp:z.sM}0X{OzsލkԌ_w<87ŭ7jՅ9kAM=ՏUp*CgĊ{Wq|F˾xZ _C:.^O&rb03f?Z-vcݤannyN_{}gRH빛TTնO9gXKjLӶn՚ijUbu~/<Ew$bUbJlxy(YkOs۠~!o@ֳTKR?5{H}=<>ڻЌ:\G΃1/Qӱxu[Txb0j=b\{[ޯs\~1y¥?ĻGg'_uSb:uΉuVχ";fQ}) 5VCZr/scI&]99ؼ_)r.Bep"<6.е0ls}=Z&Ǎ۴jXgg/?a{ށt7;tUUmcO_f\YXw2灕>(ú@@XgU=pmK]Fi3EL!ڿ^>\+!!N:[ؼ\kfFsPfxl:/QZQ8sAMӅ[9ܽLJju:O[VS` I±GqmP댳g4k 8(Sq>M[E[\1g8ؕ8_;yqfܙ9zxUཔI`_'1αq7Eo:\YN[OoB7MY6&=mt[\Ocr^Z}mԺe8XK4nݝy;G\K@y̵ƹyVK]>aanZu͛tm,!!qԩ 3/v=S BkxpZ65j1٥<6[Oh:~݌$j_b0p 5w=Kq?GfFT? Uœ7S?;f?|IImO\ܶlC^ꍋڥz5?*Eȵb|\_gi)bдw&m{c<훅"<_6 WWyI/*aiuk=MK|}G쏑k۸2lWT[&x6yYWܽ>qf-yVBB"PYp/.ybWoYVQ=a_'}3ן!CpOzjЂ~tݰnn){ݞñeҼKa@ Z53QroZQB#W%&yW"Z>g尥YMz>ZΙ6bnC玍;K<^|3*}[ ]zi_> Ǝx+ eIUDͳ6R- ' €giHeaWxTcW3yqAYZ[Zs@ڪp͇^k(8biJNj8O66*MMcYW7+W~rLx1 &Bmc^x+ɳqĉ7>Q}qk4Ҫg7·WQWB/{N(qcޘ,-KTfuSwEx0ҵw/~<{ MwaUhU\\͡OX\{O1trvttzV]9޼'wޛ!5GG7ur Uޒg++Rg]˚իTM+vt݄ub J~ժm>ؼlh͜߃Wg)y-]A][u}=4xF,sytU</:(s@s".^2ZPkC7O|X>꾨Q ٕy٥3~~8gAMjZ sԯ!<+!/d̳+V̺˃ckʼnk=(s? ÖsOtzHJSJ_`5뚨\<]W)oT|r) $%⮓3J{}ҩ\+..Wbvb/N!dogU/N>MevaQxma.7pxj_S.⅋dVB_'If&|^Y$Y3Z16]_l͹?cB?WsZNz5#"$?RggŊ?ֈz*`1tJ~<Q96v_K-u4-Bj>)2q-2vyUcݺǼ */1cN9pnD9{}<]pJ=A5}\%$$><6mܜb9ֲA\d[XCgT<=ziT 3t=gju;2!n5FƭR &k`4+wo+96ߋxjמ"ZK9=+UƦL"1R-k:\}g+U=iUR{jkɓ&Z иQ3#Ӳaa'y)-[/T$],J"\{UP-Yilͧ(?!j-gv_*uѾ':1ל~ {9tUVZ=$:5 э'qVkZi,XzV<[IaȄYʹ7/xE8oJq6=Wkkޟg՜Hpv-e[cRVҹ+1⟿Ŀ<@Ӧanfm_Q},V'ck1 G@ؠx:ǐg:".͋NfwR=G}+"(ߍ>rV|gW94QWj:D'}jx{G0ǼCl^6>4gx-esvִE_BBnz7>WV ـ:uL {xq.sf;jF`m+4Ϫ\I\ۼCoUx6o=+Wuh؂ki~hز3lj8sO9+ٓ$/ce LY=K+m͔Zc16$޾ ᐇ}ÇıkW8πU, ;/עxn릾VvyԬǮ?^`o!oNVkR~u<-f\y}4I;/t^vRnUk7w7ͳ(sb~;yVRKc}>\[_}ҷBBSF׮,inylj{-:JUNŵIնeسb}=)g' gzlIUӾoR}5H}ɾ?ݏ6ɍklyš4 qQ+}iԚqe2ިXiC>k#]D&9fl) `i-&lвڞ w3Nq`_eWp=jRJzp&?৺^\]uc֪=X${ksiٛ{k%1~rwT-͌|I_rVW+}}¼ rϠ WFWnw_NGS|zKpћL ]5P95煦" 7*['"""9O[TB^ųek+=?,7<֘7,iv= }M\zմLT@LuVresٞćz/ۥ"LOoX7RJzLslK۱]iG\JÔ'hޱ欋~" ߟI۞(KB3? =gO4ң+gz=gϦ[S2".j\9WUGD=Cgkt:5rG<~;߉{b+H73QTZWӗkk; x=?qW\q m,iw0z ?md M1ßwbӨ {2:/!]Ӯ,nܧuS_ꅈcojǘ`-z|תK:mX|:z"|F,rc35YK%6lV;6LyzwYit%ﳨvPġY_eiq9>ϣQj +F^HBK;yy%!Q\/ \NQ)~q=^Y{ǥjqm\4ꉴ+ JUѶ| AeS*C:rEZl?{ ;1fʍͺy.WZ8B~,~ tLO|(N`cY\9G Y[˪:''s/ϑWf>i8G<+cZģɏp$ Ndd,D mNf}_MZW mH^LQf}杳>c8{uk{4&iYb*ڟ>īG1~CC_">9W7(KutZ=7cߑ\{ 8*Gb߬s:0)~Fh/\ qqge=D1CFF*V7HКƌk Zk<ı]kۼ=[e83O]2S.8jGoűbKzS-nxߠPsm7+3lҏJAphW}PF}i{8Sc0e]|L׵1XW\85ku I] gH~-87g }:V qs env}s4{Fg hu˖-<+!Q̰zX3'+x{{NVC3 ^R|ꐝk)e|KX┊As*Ot<+։ zX,z{H=迗BVοek|R#ƵDn"ÊS/K۳rqŵ~7?ݒgF [_RS˿S}7hw9?g)yY{r1O)~*'3,^}xZ bGJ3Vj^d2/+VBxWUzTQ%k3~\w7zc5n:)ĂY^T1P盛'^(9Xc3>3$JHܺu 5CÌYgѩ\:X5Fs`U=S&sIlρgsjY}=\ WJ\99-*?gvSv]cNb||1J1'q=KZ s̃xMj-[NlUй=,lPNcI?^ޞn2^I;Sx=|N^4?3GEG.@M8?Jk[ހLsgiS Zua/ gYl(?LO=>oc; s/I׺7p[Ōݐ\#>@܇aAFuԴ-2³\0T=1lX,HjYVO,NPQߥ6< 1iϪOZʵBwI{8*.W:{☋rοQ<"q ϖ;3~TP 2Qy9gε YnҦǫ+Su͎2!)mSZԷ[fyϦ 8ƸEx=د1P@Yԙ:>ҕ:k]id:c\ƨ5*FI~ggq}YٴtbZp]|/Bkm;q/rsO2^3 pqw:ǔ]Ӵ# k  J]2И¬lYTK9EdӍ]N7Oe\9%&z$#=_.l|E&k~9I2.1#G- JXJ))ހD3犳d}A&ŢkL&9G:0w\/|6vv)`Ly>G{Ysi Z@} )ag6~.} _?y~/G ϊ;y_Nqe#nzyg<5-:O歏ѣyϚo}[OFZSOYBGyCQ1m(1^ٸt: 5ˆ">BVx⽳pڄ]I}n^ K=^DM ,>QwݙT_t]xT}3^IJ&*EQЕ"'!z)"*Y;po;wn9wv:m83=}#דu݉[穉d[ߖ\Q)o#7Xfd'_{N+ ՇoКw~3!} YUz<8^~+rqv''GW= "Sxl],yBë8jF ۟v. YeXFOĄn FGhѾyPjjKH> INɧjC_q7q6F Bo/\IIoP_doʃLŦ3ؤ,riZ%phE,\Ss8ϴ5nC6VB;}G{8};y=x]g9Q$?yo+뼱?+wO |½uaSm?Ow1G"_bZUUlh-8kQCGnn9;3{Ϸ ed |cUq6.)ª]UDw<9 Z#cg!BV b91Op2W?]E>Tv]zZ#IUoKw⚸Q¢h p Ǹl-.Px>;8rnZgMk*pż8H5˪#CQE9f9W]]Zuh-8kQC_cg5x),l2YHTgUvSXvhq'֯gCIihi۔{1=+?sqVǟn]FdgmG 7{$T/CڳD'd)sU{hћ f+ϭȾ\FbZ\G:ukMkBq\!+5BU#[>uܹ֓kY˰8F?;qV˪L p69~/|F =kؙ\=iފiw$n9 Z{wʞ0}O#Y+޿XuϱVۃ?Qk]4ڸMkE~a^}Mh:|}?h;ޔ">ǾM NGaw—u2MqY؏})85\Ƕ4Y&$,8kQGVmJp7},0IL%'87OI3-_ ЯN^B:a-U++3тpncmK)Y-;e D[Sd\8&;mt>Zթ]Ma1Ըu6h4s_B@sGm9Jn:\犖UZئo>τ|f/fYm6 yn 8ؑHckO\?H޽5þݻςa5l\~bc⬃=yy6Ԕ_ 8 IxpVJD\yxe}i5St\ m=zv_4m;=SmE9׫<ں50|?X6cy"W6/Z[ٰ8*/@ l{eH [uҩHZvƼMT|VbBc`ŵ*M>E^ށ.Џ}'7Mm8}c5Ϊv;4MpS86 uqYؾƯ E`1lbşiS+ukզԆhؾ\Vk/9K෌}r[K2ykg)qP.&qvڴ-8kQҥ55~o`E!)3(j8cc%s8rHd<]Κ y 3+cP͓r#>W{@҇Ï}\jʯo߁W`8kpv0z{v槥fX  : {c5+ШUhQϖbY˰6^ U4ͺ/*jed;ǔ sg'O=}qHH}tt.ʱUb1v ؎cTUy%~`{E86kyG1D՝7[IP]_)cY˰2~gj֬%Yup%OtJK߭[6ㄤa_^Qc23ցoZڎ7XbQ{̨g/p[(!U|&5䬖~Y; }>B)K{0j2 ZeԐqqrx:Xg6n@߬T! Z .-10C2M 09m>cha3~{qy.\^C?YՅQSuRo~Gl;YPlA>YE<} G'ONo@`-Scpk`~=j= ؟՚%!_iy^ӱ1ǨsDi=.%6աc# JH1X"zRӱYUq#f3R6cղEX?JVo4m{8/^)L3ϢbRʃglBbr>3HlXkJ˶b5gݑ2%Ge΢ʹlE<Ͼ'n |}l ;3V@ՋՃ gѐ,zF,cQJ>OۿFcZ&'pV!CBgYG~}Q??$7J{jq2x7 mj(:]9=U}6!ہ# odʼou ~H3?_H5ņ|0vBmhle[JUNIy?M\:Q7"gPqpU+י"ә׻JA.ע7#o PEAlgF㍓S3&ϓE*WVFF?({x6o \ʝգ?wfZ{*] ;kw:ÞWaO-RA1g[lzؖ(xR(%%}GgS5Tpl\31;rZ7?\^=6O{biM8[=z%k0 ^ ^4Bxf*oSuȯ+p̌?)U5]wc-j16 /=Tl2{8dx(:z~)ԭ[7TN c`ܽ'c)0m2)om0 +s8۴I m?}u [,%'oIJ~[y#F}G^rk+[jچvkDU(1kFC'̤rC5\z6Ԣco|Q_,*KYr mA XHV1ԧM,w_XXwVb>}UogCèso,RyjĉZ 573grUC4@Y`ܹ-[Pn.ys)1XĴ\~$&'t#%FXk?]r,3ה\3O1Q79gy-^/:lLgBߢEDL2l Aop o'Fs~0x >8flDiB;%4(kXBkX- >8-5zo %{\!O9 {5Ӡ!}OnT'D9R$Nޮi4j0ڣ=*8C;67QnkژL#˦2wذaZZ;{7i59oؿ[i͖4 Աg7 O _pVQ>{MNDOGq=9"?}4$lƛխO/O{.]LX (!ZQ#EǎrByU9~$8vN7co+(6̜q#*gcO.-7W'Q3jLT`P8-z^Sp[ӵ+6Ep 3=?k0[T7j7.}Q}];w}a#ƚ{ȏ~G\ܨయjL/hHӲgӈnI)q.kU~$L4Nn+ώ;}o߾MNb}@R_VTՕ^C9t0>sy}[dž|hٲtF~0%ZL9zZlK<8 0wE:y4;vNuAkoU]kƨ4yV\Pqv׮] 㟧˗ ;CΞm;Y)=5l衇m[h%is- \oPݺu؟5k~u8Bu0Ç?A_B#gυk Yp|8JN*p6ѓ^SKӻ/J[8؝fm:Γ?Qfsja?^^UX+uqL=sw]u'o7?'O?cnuܩg8=w5*x7ψŽ =읋͋ut<6%&HJEDq^[ܸqWiq6)Y#wIdf1**^cCMf8zi,qKaU:듣BW[E\ڏF:kL-bt~PH4 yn:}`@PULJw|_԰zuj;['?>65B\wI(zflgsu9\or  #gͯ~УnћFo57T|&Uwem}SPRFsӡ߻ҘڋphmޞԾQ?Miچ<-[ڱn<ݛPhE[Up6=|8x_XCB@jϜ9Gύq6\~ss|^N>˱N{Ѷm;i-vFZ~߰_w#F A_,.]1eeѣG3Y ^++Ё# -;Ŷw}p?B~0sm;?8M}`_m2^)+Z~~G3O+rZFNC[w!FHk;jNS))H=okL4yHY{rHl]5#9wbJY mEqVnݦׯobx uZnuw?9'^W{ںumڼ6mJl-[Ӗ-9y͊IgΫZUٙz{&tYvob}Rm}a|?bM~+W.3G۰~H۴$ϐ=ۘwWZ_DΉ3ڹ ?G٘yZ24`ǹ:fm:˓5ә@_okTc}ӏ:vOsMi|6X\'ֶtg}Z^t5 3SdL) iMyelG23g:pj,5-l'-v̽76#楨 QC|z.Ǵ`qze>{#$%7%/@KluڲKc. &gMj6dk|ȶ X@AhoU-n_UI}xqmXQ^9A:TH `;FhϞ=.])+vxquuڶ}'By4dH6B`_oժ8K/1Gop +WnpV{+λtdO?"R]>ڵkSv l>3ZjKqq bvv چիKN:N}J{9?p*) "6,8lë3^gvZ9_=MVMVËoDwss/6ϞژJo_Fv=w`!WX-xJ/tRq_Q'~y z"1%s}XY3j֮ۗ7ٟєwBF8FLM}:ΦORXd—8k8v$ugL*UlTAVlg{lϊ{ de suu; ǪJT};=Cʵj߳wvd9cw쥗_As|Mg^&ELa,h֧]ʕ+t:?ӯ7obǟPzF|}h„ u]2ğO"ۀ8|NNB9|f\]ɑڷo6c`O?׭k{oɥ woSM|^J?c\IB/Ը"]{G`\NNp"sl8jJ.^}/|5v+VyВ˹6CϞy}سT|U9YYjj_xO%F7~9.c}oذ=jժŶaC/w}Db~I< ʊ}Q[.yzz }J&Mk8ܷu鮱p>X ^<ٔTN),r~׶Yq>XGWvg2"4jQќY:n%sxND?;LYs|s=//OCa2t4wi[ 镏ӻsirܐUMbȍx?W )RX`h}f97 츎 k?(џiQOIQs3> ʫSq/t͛7X.s]QNwR:X2㠮]Q1QW\cOPNn>c(^!#ޙ/x\5ֶnӞRi߾3[x6X1R8Ǡ@Ӗ-cth_׮}yܾC&Nծ]|(6&(:*|}3&Tpuٖ\O`+oSS\[1#fy/ݛ&sD񼂽^0m\^-)-u%T؈Q)|!{.VC8Ml?O٘kg. yUiJ(cxIux!ElzNz[GD\%OX/H|1C>_Z%c[|ZLW_ {M e.EL[hܢ߯;M($dyy6VpVCnChPh48瀹5t/fgQ0j[g'oXuXpAzB`E{Æ g!U}ZحM :|( My%pvϞ` 0Bi5-C {~'"v?/+0^;Y/OoW`k'!ecc# SRRuԉ&OB59ߺtڤ\Qk.a0p^=1b'MXmՌ ?Daћ?(tYQm\׋zc8&5Ԙ@u_XNmbѓ1+^]7jaouVlqUz GP7Cu5=C\#/". Us{G՘e]QysGuIȤ=ҐqЌOV;6=|̜+sVz{7)%e+m8 ^dn l yܡa0cmV4o2)rlMۆl* v%pkDa1Vų_5mH!I|[sٷغM;܃؜38xH.OwsS^1,>p6nBp7Sӎ(L bRsK} sݓk\DDD_XgRff&уs̙ÿ`c]k R9r=pY&|m0GpMp.UK3Z4oUL_)!yY- >Z( }rӤ)1N0ٍ28w\͂b-|zGa>b0u޼OxmyqAE4 Խ[/JMI8͢5bXg6sSjS'U[=sfliOij7WS#Y`CU3+fGD'_@`G; `[ #jCh̏hc/*g[R]9:JqsKiy[ }1ϯؗ~t`mf?nF]voJ#ّM[b\Sup~wo+Yo&⡯bq[TPc("<6nĽ\oŦ CsTiIr=Pì&\,pp|ߟ>}:h;b,^q P89RjXhfP3bĆ|]|ذuJy^}ŹB{~f>ﮮᔒ $4zy PˮX>$##:ė%16,ڋn΢q}ShxX(M]sdѫbn x?q$m߾6oB |A~TÇ?DT.ƢGDK1w륧䔍%SlWuﺗj rhoSC)a+JLoƵ&Tiܦ=g ynM5m>w,oȭEyR`H㶾MZvIk]1 '<̍@!ނˆQ7BhbGb&m೅rS0NG^_6oyX@@0=hm(  -֮5ppcפ#??z b=K?nݾE?^Q+8Np.=0Yj׶⸧#7i)x]G*v)Ǹ~8ꞏeóGXOH ' g8aw+>6{J\)>։{O6\W` u+IunB=n0|Y@p; .[HwG`\i KGL|}'|M[ҦMY|}S~DžcG-'Slt<ul^F=K۶ms6꾙2&UVnj{IuϿc!aw D=zW sࡹ\ɲڅ Bz$PUcEgS Ӎ~x>GϹmtj?[t'x(DQpvz]@ܑឤBwlyHड़s$x*rQoci%ye{(9W']t7u|,GrSTZNVHr|JHʥCqL)4gLFWl* O\^݇>uE?~כTE'Ȟ(X) q3RR˴@Ҏ<}$Mn26d!B= CsK(FZ|ޝIĜWך:uZu뗊 ݾ}s| @cF-ǖg5m.֛4yT}u|F=Jj65ި8QwرQDD EDPv>Wo+)r ?-@BM0#""fRLbUꃕ}â ; ~X) ?+{PgOcB4KrpۄˡUwӻ?͟s_;b-aשS+P:S01Ei[>76Lj3Ruj=!5wE=!s>f~DϽ!m&E*t94%R`_\7$ l%.m]B7 V߂ݣacܻѽxf?; [q^aO+O`軕gcP[(gx }3fq]+rW/P8 9;-ѾW0fC|Vj|5@\3Qb l~CiKgRUT_quϡ2Г$!a ~Nʌx]_K~ވR;tqq&4\k| Eؾ)4C4.͂K=ޣeAּW>n_5mڂg A;q lcXş ]v5le}NzQls()>qb>dq[ίO}~X3"fIMp2~UlEՃǍ_8Ki{p2Q `dU1U ~IÏwtrC| .RA~7U/`E'DߒYwB"W_HגnQvF:EUcK+SfҨԯ]k :DmXS`n >@4xtKHOvB/0r ֟p/Y{8JGɛbSRJ> O1 (6$mJ.2ަs<+\TօSD<3Utwĵ l 1 ǖ!}q.Ƈ(ͽ>^Zݘyn'x"Eo_1۱5 >pEխ[;;-Zy1XUCU=tqW;tui!L>e/PTd,ێqVݖ*^{7z㈋驣a\a4eX&:U4~64B^w0Us[!w39.֐n'֌>3ؾݓԵKm Y/SuEԘ¯ {lOa3.wj SvSg%Țcv g/65(VZ7 Rɡ#Fyi-ӟ*Z%FsX/+iw>Do&ݷwg}A ?^b: y20!jQVf{2OԤq3Q.z< E{:ETƪ1NJdpu!oO1^[~|e= kKK;+]KmJJȈ#/"UZ\ V=]WG,)> XTD [՞tؼ ՉQV|\X'obmuFC;Uov ek[r-kIxx.l<48}*z|z|/!pnu]c3~Fl< umWP/~>|q^pͪf6Gij+ G>9FgQ?5BQxb%s\PR]ٿؤ@?^{V{ɾׁksײ h_txXv'8Vd[-^㿕~_ꮉG<Ϸ+}E);?c ($jJ"o`jJFQw23})J+b8"8kGV#ON~\Eg>1D~SZy},r[cڵ:b{P?>v19|P˟֮]dkMxۯy룏&z\xO OQ1תįg'4Ppz!4jXpM81R-V? aLD.RƸ47419.BUEɦY%D߰%q,n%` (_5O}c%-dU!>TlE nrhe"ߑ|[Gy;/EDAow2.4r2dM⬺6Ct6F1\GUC~^{׍wPE]970w61B=+GuUc}iZ߆w۶mԭkO7<\Ri׋k{7ޘ&ǻ٢ZSmV}7hmN$kx.2֩ vbml^1@ m˜sϵwqf1ު1Y~.,%E<f'$R|Jmk3yLub#5,f'(Cz˺ S85žzPxK  DnnɌ땅lHf}<=Xzh4]Fs|eZ4;kgRkTde6:wgX3C~|!a~_ვ~cǎӈ#_e.XW721շcl}AB\IBVFs ĩ  [vbma=kЇ%וIrlߊnO~̓zvv*Y~HN4#b7CII(:z. WpYYʆ#5%t/bcJNۅ>b}UG89Mem*Wg+8#m:s(ǓsC9~OⰬߪ\gf }1? \Mx C]60F1OžT9K/B!́Lb7C<1ѯ>%i3Xԩw6.:v⎂.mN+J0jL:FkJ/j oګOF>P\#ɝTmYqev3LHXF)(`06c5DzmƶlTY{V|'2ff*#1PJ}rƣcgolg^{թpVr/ȢVa:9?Ӻ!gs=S2^?(RgLZ9zލNZU1Ǝmm]t)ƩVpʹUujףƍʕju˨q &bOݽ )87B7{y:/N<]l$^'+o^M9"K齧UYg>aIP8gl#c|~d[9϶Y^YkjԨPs{99IX[тm3*ƅp:5 !7uapP?3) `Y6̾j6%KVN_B^bͮK*:eR]5}`֭m)4$V[F F>Z'ZWNbqz*1"H)a{M>#"ﵦ8m6ɫ8(B)[ ['pw%9V%XRgD s8~_ٮښmfޗ%6ilb/}˵5O(H $Wg7;g8Sz&4iHE\]#86l58 چuUnjW%E}\6#=!smk?Q Y8!Wia|1ѣ>0,rgSщ?+G̱1F]OrVjOD1"uyAW~o.mȍlL)ەܗQ%"Pj^9)3ys Ģ&Sw(-WBt!ˣ ak Ͷgދo\}]!-Df}q$=mYj(k}|gm ĚQcQsܹ\oݲT Ui7>͛(ԈT -uk*z`iXΝҎ;,jfg$::_rᬌCٮp˓T.%NZ^.+\GPx_bU,%|#klB%& ޙ<:5m/3CF%g#0\9jʽ">yߡkN1EZ Y3$ o~o.uCd]+s=imc6cA6nX`={ԪKύؤ&0e֜ãؾnÇ[uCG~54P+k,Zx)2]`1s ݃–fW'Av #MJ!bc{Tvos6x+,PS }ג6\ִ]e1-q:q9BQp2׭D~A/S@[țeCA,-)+딒̵<)*u*pX`N?[Eg|=xW)òĶ^ëՈ*sĹ #a]c?`̘qT/  a\gzm-^X{yj/Xk}Tlz!** ߫QG,^*^j=VBBgUKerhʯ 8ϋ&=Q㴈y'/a'6'iu,T}D֍H|. q\yQ|$3H[Vk,o%c=ܓ)!~1'l<X_p=E ^> Ⱥ1WMCoMŐJ.q g2!7SAX\xʺƟ3o7QFV]> 0j㫸i>hPZaeG1`/o{/mE>Xy{ PP}WFz9bW(@{5Չr7 zrBI Í3:WXmopOE.zخDrloe7.0o Vѩx C l'2ۉmݕ|'.:OTk! C 1l<MsK^}( 5sa{/lc3VpirvDܓPoX?X]âi4EmPjZyץVzq^ޮ{=Jif1V=.>g@#]TT907c{>+WҴi/1_G'įthߑ /e3㊴97sQ‹댡ƽ1{4ס8B L%kI/VdٌUw8橡J-n9WiIr>j}S ~vu 1ӻ_c#G 3"qkM/S⚾ } X/C嵨ټ{V&σlGȃED``-qbiuc=dp ;QF۱Xճ!7:Z?C0ti׌RmQwe1zPlgk9cc-N3'0 R($4âYV4`~:u<8u?EGy>No][^[ ^:5Z)bn|xXkLW7kmDEq'sQv$^KtU1r$/7#yOs5}86w;UOk c]֎0)X{49:Ԛ1JbT_aC0y>[u1?*ku9,|{o!c$Z_sYz\=$bi98̯,8zz-3 ]0FgpV=2mȷڋ1?xךP}~iGb3wZV֍Txc#,Ѿm{XbTy`fm$^;졃EyqgFuo8bV:C>bGC,2+\sԿ@a+3ڵk|*6l4SJqE?PQ|R&pa~5}UǸ>Ni_3>~!T>|ܼ|˚_Q.ثW?*gUEV_z:z@v;`yFÇOm2h =i[ihic7ыR&G/] PHpAN:PF TEv \>.y,~_sVLܗSr\۪X'sh{e[eKζkʾXYyk b/Ef5& M査{־ݓ\I7Iy}R8bwog Uj; u>Eh;իa9Ÿuއq\/he_;˰CL̗ﻌ; !S~7Y C=k>K Ύ\{W)Ϊz?=Pa2t7SL|Ag'|ՠsũk d\S]9z~7~D-wߢ[U;}oh2\D_"vhӦEB +^7igdžIXa (}o<5,%Oe/q@Ӳ3bT7uhE=【9Y-Uc8Gݺ亂zX%GÝꞬ={GKA>F9PNs֢&xU-k|:Â5uAGVu (9ϤX|(9eFFrOc(\Cn,UT7U Mr r)25O:d'8@5u]-uןc=zaL_VڵZw9iJMM~ҡCO?vtZts'eS4_9tWsϷ.(8dѯZ5vG嵩Ѿ{Ta;@ SlN3I'` ZE!~mZgVY7hذdUswuvO^5!OFS㩭{3!qf#^k֬!oo?_.>_i1@ސnNj.R._S^ZF#/vƹ.bܶcWG6ED%ǘr Ba>E}ؐo'MRk$FQ1!Kó[UӃȁmWt2Α^{M{9=һw_ՆG͛RA?^.]/^μ5,/ڻۆK"}/H]fp*+8~4> #\y,ԧ5ONZ #LpZuMk#meUA؜9oW^=}yJM߶qfy9Uk=_kc-ې9ה X39;s En'وW5l؄Mf']mJ˰F6M}kjg k&tPLֆҵH+wh>y:ϙcV#cUj<_]Kωjb]_ߑR#W]6wdzUYY9hc{U݉[xBtV9s<G/0Ɓ<)''G`,YL=:ҠJX݂qUԣeZgk *Ý4xu9qAUlm, ik]Iֱr2܍r+"r\ km%<4*U:R_(c-~OڀUEz*#{ڲe <)k)8(U<4^t2 ZF<3wlG^]ٿ\E 9s1z>2YbdczGoՎy%4D/ORAuOx^s# .qa +l}Z0^|36|5/DM1X[_q<ӾtY_(22}699V[MooGh*. gmDZ!324kxX,\|Dž{3#n`@(Wa>+{8؛càb8g^XX`e==D-__QջuvOjky}ڸc]U˗o&j{xE-j{֭cMУћ,YjX˨QHav,}G\;6T=H>rZ5qhjL~Վu-`/\}}}V޺_LIqupo͉58]ɺEл+cyU+{~Z{\h>JZ Y=p-1hw}8[ݘONy h@gbUkidgR/ɕ1BߠɌ3|_i ê6 Ş /| "2eXFet~ZӢ(s؎JRӹ7LuM]7uUqǰK-bWRTwK\/a1;L;5XlHv;v ߭)ݸ786Q'{U=oZ|رӨ怊˖.WJ7UlN)qlH o#q}MA'?n;I[T켊1&+yʺ}{{3?3:HHTss MNM9gĀ("*P"*DA@$I8w־Tߺu:э}T]u[gk6l߾ƏEw,ancKY cW}cz;k2߯QӤA(X+b6&OGoYD74O ߁ hP?W[$?~҆ rn^\=X5kxx\{ѵ,y9Ȱ ~qzgQ/t> 2"(|8hy+K9(,8aR?S.ƏwŽJqCb$k^q^bhx*~se1؟NYw@[-nm8[tf48 & (yo.:اem!/{V=NT掳+l$=^=>~~q) o8轢ڻ,0^>r,}z k4`0LfE%Yo+F8p{ư>EM8Z19uamԻXkeNjP\YҰi}CF|>O<^r׊{mkO.MOPՄ1VE4x߷观 #[ZRn=髯rڟ;w|b`,"Ggh1fX[NɈ+/).urǨqȣ,NTꎝf lyc<4( {vQHsk(k[ -N쁺Yk$c 5Qn͚GӢ؝ٵ8Ϲ,8.qgRVj7!:$] ceqhOɱwkl&O8<@+ʈesԊzؓR]?+ vZz.pˣkɕuddB1dg~ri {X3nx7]{QҺC糟P\{ 3clpZ#s.z0g5"tz0 ƛ 3|qNjkr/R`@0I^{5_Ï?͕Znxq5B8?akFw:ha k֢fGu9y_ԊclDo?fvެϋz~/ڶmPs)1T~=ur;mpfΧ zÜցkOvvںngu31֌&\J% 9XK{Dp*h`a 5_ݥBSQqV)r.-&UQGB"2,؆ R?_~rU06?3ڽeQyvO=o1?k/ҙ jyYy8>&qp9n)GF3ޣ531-)۳H# <ڍ >:%֢?ul\Nhп>Qw>y6u1V'hcƕB.k\yXEDD֭[mXh?) 6>K .8k wuliq`P)%~HFW\}*6D!= u|/ůuZ ?*RWg:G‚Qy5ovH=nNJZB"8JLx%džQ(*ʰW֫5GG[X{A>;X?zk…%uVdl{|Tegq ` ZczԷo_@3=vu}Wv؈`<ȋ`7w>}wZM_-9sY3n?z(vܫz2w|"cuޣ㺌;;.;4+ h\ey*gۚ3"kL羥Vϑp]Ck]wp}i_m:ѣ_0&8!rKoݫ/~i禅N_=B*O>ډJhq 8[20é.#u匡F×sbҭk?U!C}37ZO[wܯȹ8ZA8n 4܄{7q֌.h577Aq/%U/ON+)8ru}-?ehup9^Hvhzi9JHPz1۶a77Qg%}"imV+@xSts-"[omIC Vvm=kg==zQ/@p}ꙉs)V[z*!^^-Ai5jEId2|H`.r#x/x^)B95G{܍G#׈܄Zѓ̓]gM3̨MWޛ9>!;Hc qVlg1 M⎥!. O=e 0Vxhv2tjwd^ڜ[ Q@EѰ(qZ!F(`)`džXSϛfQظYޣQ(^1'kmmE>aY)Q.#'6>Zmޘuo|8[;}p#qZ8zI5'kL$l5EW*0|2bs !kl./]fͧ,cUUoevxzxS?>ys>2r9Ԧd bms<|| u`wqfz GHbM`~G>cĹCNQk~c/y9|4i ,ooO ND1 뀵J=%J(xc20,㛚DsG٭ g%֗F-WΧ!ǃzr._YPDXXySt6>0{vjJ q"j*vXte1ե֊k?u`jwG58X3#i6]T+_CN8M=gaFm+։ZVP;cMJ~~NJ/*IUJg j_s6t [+80qVI:y]dmQC㭒;^LW`c֭X0⤪9͊H EIq[S>UQլJ} `Oq*Htd-*UkYg5֋>XO*^QA:>i1V.i|]jZ+**30.h1{rqmi~GẂPW7&#)FE:5v=Fz7wCxsŗ8Ϝm|lE٣x\-r+/*Iuʻa&%Fb iqemxCe#= 򿨱sc=<(>:捬YOcCSm)5/7Uk g5m[Gϼ=Q`7סv=Z/๡ agbܘ8 N m~ <f MM]6U2~m'楗7 >{Xy ދ>yյƊﭪ>9uD;ۊ?u͏v[6[RkCoD.EUka@O{5i=5WU}c qOڒM=WaF}u;WjO.>nZFn3sH-rɣ{4>F녳ZR]ug1-oߢo ~m,p  ie,tMLV}^,v°rq0뉺nz+<"Oӎy=:"ئSTk(̹O![Na?YZ 㽀msȞ&u~;zfg!{ rȧu+Z^=̃wF{ g*+ݣE=GRlՈV͛Ð8 .]qzR'/-q iԔeC`#{r&ROV[<=>cwbDqjjÏtO(#<(bfd{4{cHuwK_ǚ v]b}CN>Wfe]~ϑ9$er+}?ӧEӀ.)5抑=,Q3:JNQ mzR`@_5\h۶mGF^ނ~XpKy2% f/lz"p4N}p Uw] z㬜1%=>5d+~^'Fєd?n6ລŴqD=?<wӢ{>C>G_۞K|5v>kOOr_?=Y C4Q؟Atx0nsj K}, `+mzc`ǹzHg犱gG۷mb4q ͈ʁOug/?68Cz3{9ڭy19,&xqV;\ B\><} cg>˲t+ 9w|UQZxKqOua  7ڵ \VؤŅy3Ίssb|+ιApȰ ֦?Wr=^ Cq|}f?p{Hz~_+U]fY] bQ=C}71֌">L1q3{%oWymMXh#U`yZ1Rs,ЃѥFx+0GQ e~I]?R핽VoEͪECcoڃkq= V?q&OO>pZ_:]~)~SA6RT^^xhϝ[s(Jh2J=^ph{) iާ)Juj^[:uz(E;`/%UM=aW>cNȵ!a(1K>{b ԫ(˵EkuCbfsYG<%o,0\qi>Y _sbnf-ܛ^y|:c)0U)gyB=ڭ  '!%95pkA|:Cen-G Q|\3'%+ x*ɅSÿh})#!̶VŇX |H^6gCb 5ߞbqc̞^={YSlM?SӚ(+STTcO^vxU{:$Fuh6qsYc୲[s}2mԞ;#0^w}\{o{M'<*֮}vC-tmCjWL-[z*'$+^9)cQ:;_SeXl^CU,GM[blU'ׄ}E=}Th[VrX-WcYTtIfU=ZÜj*(>a~z&qS0g+=d: ŧ`ߣBE(BuZY9nj̺qVҧتKS<]ʶzyɂa~z+}B1xӖw;Zv' [L/jI)9YյJMqVVqݠ3Z(q]?z=b -_[҂9|1a]16@.۝Z'wsxjOĩzeF[K_61 3D̚5{u~8$t?A"}?"6׫@̡9vPye>q4ؿMpc\9ͨ nFu>?e4J)$8)Q>k4k+yߴ!Q uƩqawh[Bmz+x:jКラu|XTy=\EK`9|ZbE;FJn6{BwxY9*c)==vxX3PC>vQoo-8+))(YpVGqϪ{PJu3j艸qV_"7EʙJ{k-[zऱQԯ[>= 8겹((0|=UN UX>.0 vxVWƊaS?"~6*XƏ5ڻU4ZT??=iѸ,8`57c;E+g}Ǣީ;nbfPWE O=S=.IbW}O`B=4%FB g8%uXna.?l^t/UΊ<1x.F%7gXyϊAXp)ί;$k {8˅+~y"ЦO73ҳh͚/ ?6k4kfgG!cϜ4_#{&!Yg QМbc(1V^{CիWM5 '1wμ=(0S+P*8k逳b:썹 =0eg8q7i0 﫲yIbLMcˀas6ޛ/|Tn T%Nj1.QÔsu{^oiIQT i3]|λ^c\9F>g{}wsWyNnϽy [@?f"=~*zQjM?Oz x J 7~E}'x:K'DŽ1GEI ?oǭ7azC>ۡ^L`COP~Z$EǨ(6+%Q1pGRm }ѣ7^O>:uG<A޲{`+П${#9_L5 7b?vPp`ǘy8};yȚOx@QE>&JثmGS~uV9{X__cooY2es̞ɷsd_MGD}@=i2Z)ЎwFL[}(r2? g暨;{yi8F[W;uM}V5j}vDRMZאxqzmkT 롚zHE1|oǸ8ݺ3gΚk ;GX5ȊZ^USۃm|<7igQx\S/mZ%9~msshH4QHɑ)*^Q+y'fSi⇖Ir4o|_ڴd|\⯭Ck/+O \~PJK<rRZF"ρBܠ6 "0JR7ə_ǧz_Yq~)CɉA%Tީ QXk^lt|s;:}Νi͚Tܱu#ܿŹhA={x~W7w?|A1y,mq?,[vfшXE]]#cVPbOP|b͌~i:b'Aqv0ZkA4ooYVrCᒟ3iP 7GBY/!C6u*+g.5a$Zh {Jzx#e˫Kh۶_?cS'O8W=p ޭo^ye3=sZEw,1Qn=)3#186"_悵'h̹d}T#~pӡ(q5+մ8lLDlgVb,|c{I ߎf\8}+֣S4,a-rkWRR6u-l8Qajͱ=NLo1j}İrWJoKj5q/ 6q|JzM#G;.|!+s.:t0}& `@}/ʕiҤi{1'WʼnTK}˒ht4i@z^22x[;kq,gϵ1yy?_T\s̸6_Qr*[n>W\mTۀq_Cud+ 8O71 3cݻ"#czGO1qSDwC52s4ȡ&'Sy >l$<Ӝ3tNjy؝є!y 3nCRK|MMTގi, ־}ׯj`C>C?gm_t.9ϝ:rMnމT߹QrŪN 0ַZ^71 30 }2zg 0W])M=skzerATmsK1̷&PT9{beє٬1{*M>@@ƂΜ1}9ڵk7?v<9gmKGhǎ2Kg@:/ǵZ\ߪC /6y{խVJOObb*}:v$ J;WuFyQץ뵒8$0 |[>JO`@ ׼s@cclg%W<>O3 E/SS1fa_~k^}c2zq-k/ oBo2 U3K>1x}3JwcHT2G}geoD,uZ_ r^~Q$ipEk9ާʖ-[_Wg\i카 ܿ/5ouRֵ׆(0>C< Ks͓X'86\Hھmc0ҥ˸&6r///-m\G/ jϋ!ɩλLQ$eE?u>u6 wgTQуۺR$jX |ui""O=H >8{B rҀǢ 8w;{\µhg~{j14ʎǺ uof c֬yy@CcKMA`j!-^) Z11\5!9a,rƈh݈YkO =Jru }ie=vX+sl|VS%pVfq}_տ}u4~$ZѝR3k"c8_p޽qiaޠ[+1K/uU+zY1k cok8f͚X8k s9`gY{=h 54Υ%ug]jMԩBN{G5J6~ly҇?/[(*+-3fg0<>~ /sQ-J++y,06czwac0`-jZ3W|h5*ú%61R3{"B'9pL-h\!{8 o\z3gQ ՙ4o6tg{\[y[%rBE%JZ<@;ddN1JExuڇ 1OyK]Q>i4e4ZN^O?3\U/$3E1<ҿGjPȇVwc0F `-Ob~ Cs4^I% *"njYMQ=S(*gTG,qa=f_ŋz]򕾞;՚3Z9 4{X8ɼQ{z{G_ r~X#>P{/]: y߯v9JϟY݆{rڷ uð ۴\jPpSh$m{kfqܹ 8,?8Ҥ,3,r!:kʯ߯y fP=/fٳgsK,Vߦ-ϋU'X5msgװnSg޿ "Av=mUڲy ^W##<<Ӟs*5Pe ?scϝZAG =<8pW`++>"<Ҭy2ÌDxg-ށ5Oon~˞8oEGWg5zd˖(YzZ(=s v+f1zk4ʚ%I q09 =|YK1jY G h 2v&4pӽpyϚ[z 3g>=5䲵 #\S'ǀ}PVf.k;bWqVd.ή_X3 ƽg}lЕ5g #qϣ6lxQ7C,gھ8/YٜޫwM_xD!3@΢o !,Nz㍿3%AH uںe;^6`f4n/T8 cpVr}@/Z9y𠡶X&5$P uW85 DmXa8jU)XFF~F3_sYY(>VZcl8u2Ίk Y gm n/38Ϟ@/_ F}5 `/G[7tY[Yhgy]bZP=30cf{d&EK(c=E**L5Ì(gu8+5Bi|;憳UIm۶0GQܱȯVTk/k/]2Ͽ&n<߁k^8 AY->y3g.Ћ/ypXb*2_bq4_6[fmٲUpCm4oT$ucۈѐgiϻfq|h gQ #l8kig81w6|v<,uPz_<-vMpQ2YԧҖͯ1@/|0jQ}SjX{Q/qUw0Y>&Ѐ\nqC YwyX3̸I95yqVO^jF=TS8gƨ6<͎SQmp{z+WzSEOrr:+s4bhYW늓x]4b-)x˂7 3h`[Y#.Sqvڵ}늳 `ˀw3A9Y)umv΋Vp֍>Zd$9Fӄٯq k8+ya6g\kС\OO=ڙ' c|xk֬51 3n ggjpuNj+urOk2řo1pVj/BOMk 溇r !1gYRlXX[ëٝ>YwgΫ=ʁR< x/~vŕm\Q*))7x؊)?}CTOI _xŋL5 3jqvj1-,j8;O03 Pp8~m_hYVkYճ'75i,r坻5XmꄙϪycgS;v{.7ޢ{%K^7v2h >r0*~>|?f굴yk7ك<4{^XKzKKeUWe?w\T׶=HDbW슈Pk1kԫ1Ѩcbɍk,H"&Q[;5PS9߳^{m?FI6ֶTYk_mS]T yy[ߧ믿R\ >g8]iTZ:+-x3=+ݎ !B14:uiN (q.="K:|.]NRy\BW3i8.NnOc(!cF[5"{{W7 Wo@Fo)W(I{ ʾF;IÚ]}Gg'WFa҄n><9;`y0>0p=wԥڵ6g+i±Pk۶CN.|lmÛӉ)#+/;7Ξ@58hފ[-igσKWOy;Z[iNԱ+xZd9%&3g8{'ڱ#Y{LS-2ڵG;_CK*BɼLu)l\pZ:-\5{<+?9h>p<[5M֮Ǐ؂Ϟ7~F=`b<9Ilp y6} Dzp x7[k1޷i69su҃}X;UR įVczQr͘1V\Cw;JAWfP+\ӯfڵe__ŗ T*ӦM/Y5<}[CGRXx$7<Ř7nF}xdz{QA^̳< yPb^q&eEGKwiY#$1 8?L'O}T0rԗS a5/Wsv<}z*b`ck޸q8VJgTfɞuΥv.NPLd a ꧝g{ԧS_4p63#PuyDv40D^;v)Ń8ވySP6vdc]}ZMmw>֜OSvNǧ_9vv.|IrbmuP݂>0fϜ9qi,\Oɍ?WWrЎMw7_}|}upbvP_;/NjqFr!Pu,C?FЀA^9%升}~j^sGj1+|ֽ[Ozc'(%%A5g[y^Ug76濃׃UuT5*)+S+³oG4"r~ۿٳa~zyt1FYk5Sbk[i%y[lT/\r#x5n#SFԲ_V ?{JqUvV6E&r//ߺԥ Vyh<-_{zӇӮt=q  Xwey Ӄ{!0ˇ{[Էs ԮP;ֳ]!~iORf%ƄhÆi)ԷOj۶ڵmxN-]dԩSjjpZE󻍨Y-o1/|%B\YW^ϝOpn 9>B|;< g WQXX8].E1jsJs׃;cxxj5"P>?''dYgn޼E/З_~s>bz4s濹sg}8!Nv^<(h:Z|PZ-Idg7ytC|9?V<[ֳ}v3v%B>^)qmsܫnE|ZB]yx|1?rʔ1A ;+Cʖ[^rOy˓7kH=C*>ٰ3v &7wcL|u"K(55DϢ9or|>2]ZFbXn&ZݧB A'<|RSRiŊU|>EAFm,oSQ|Am6]un8q2bf_ZOԧ֪aE3^.hųx6'[ŦܧűI特o_/XAJk zMV`@OE[o s,ė;Wc 1qfE=BaކFE ;w,uѣǔQju+GcPugcXj_</>B* ʦE SMy_U^ 9LԹvjHqٵ&s}{ZZZZrc?Jz{ܳ9~TjToҜeWrCS]G!} DNN.Ú Ď*-oNM|c -ĸ^gyڷkT 5og(TQg{x{g1З76ѣ'(==ҵ-&9ƤnPWMǎW:YA`ŋr\e+Rrʪz&Ь!cp"TUې/VUrͱym޼}dYY9%zǓ'Mj >ssgWuG|\]~R.\Hb,Zg/\(AbrssiۋUƾbկAq*rcќRɵOjސZ5iqnQ[ȽWg3ȑ/ygil`_ -N6a3zϢ_DU wߧ6mڳo kB+s񮓮cQ@5mAyy#K< o"'(8(]y2<Μ9OM4:2Y8k=&Ax(,, 6R^1w7z#Vү-3CÈlڃkkE:G[g']А&yi}ɗi@8]uM2\K<+u1cƒ/X7ƞ&}cvvUGU r ^`xxV;2e:_k1߾z  @$zԥK7pNW.}yDs<ycKr={{HVkpk״L @t!5ԲEZwx}aԱɒ0ӏ_qU xc K-"Zs|[KpW9QGg1Tv%*WR.^Qq;3[Zn>{6";t6R}GPFFxV@ǯ>J>Hsf>Eh֒ש4ҍ@} f7ؽk;ɒ<@)z6goCb{gjӺ=0EΥCG"eP  |}o߾m2nݺ)QVklXǏ-'oxiWX?<驵=*2Al۶ݤg,vӘg9Z#W-+%z2 PGDV P*.ɧ%K+ozK|E:rKdkkoأݛNҮ߳VdjžPp/W OY58 C@xVrb{"~wdjF6͝;߻eZ4"C;ﴪ'Cn/ TSrsr)<Դ=pb.[⩞E{gؤ_"w,{ Toz6vfh5oQRRɒrǸf@ q➝7q8sy>ͳG>B=k׬ Tc֯8'u M-zUݩ˗b"1?~"V,˳pßggg{xVsy+^&sj-6m:{ɰm˱wdmOv˖+N8D}xVSXXH1}ldNtuv%ĝ|ڴyϩ³8Fqy^=9DV#?FދOY;7oxV3^zY|3&K۷MYF\h۵hϝcF!{`s4IѼ>ܻ-}GYAjOIh9вM{.*^̦O5QQ1tةV3P|\hyՍMP/~gG|&A w w5;FMP~&KZ&gXsOֽ Go/C[P߿ݣǶ?_Aʄh5,Zr-ꆿ9v7zb`FI~UE^{q |=^AF?Y ׮SR"~w\Z^X?nk୅XAHZZ4yTv%ij-\/aϢ|E% (7i܌n&A1fXSI1$۴nO74/<ܼuؚX'<' Z1u}+Q=hw(??_+ %r ?,' ` -W'@ Sf-FlɒetIYxS* ˗) ؤ><`?zC1-)]j53gX|^MqiM7Ǩ@* T~}{ڵ;),wcXzXZxv[AIJe:Z}  ӧeGh=+ߧ|Saz>ؾ<=|Lzv<ۀo!A'x1-,WXŮ/?oPJz:(9~45kd;Wݱ3Q<+ %޽G} ZZt]bZ5<2ryy?qS^jsQY܏=-[1ׂm޼U<+ eV\sȣy]{Bz\[ޭJ>z~e\K^*qY{Ã6X xwYA/s%TAL|rh򤩴tR =x=,^|@nb\]={{TyV=ЋuŹy?WO;@KCÆfM[wkYSYARظ#^7kTDY10Yf?y?^u6T΄_¡M?C\0~=?9s6%$ v:&B 0r潋q,z?A'%%BC-ɹo5kXi#7o ={Kƍ>pApYB{ݸq_N7oÇ Y9y@N}O}>9 mڴ-_I3f̦FQ.=x!?~&@'V5#G ƄW'QVY/rjB|_#^T/;qǻ!RmG^}hh\ܿ, GSl w Qm:Pr`̏S1*}}g;.A*Λqwnnoh0\} KZ[|;{럳Q޽d cAJݻZI5كp:<\=ϩj+us,k޼TU _рҘ};:ōV{a_F N7o ϜTڲe+M/jӺ{ yZn^y=wC=Q5kUծe]v\ޜuIڳg.  +`hv' \MYc}e-B%NўTR*!"Bv"JҦg1f̾|sϽ{a;&4s~}kF,WDD#X/ZϞ=zWOs(U_""""|WȸPmŝXctȱ&[L-K,ZVvZU͡T}4߫Ggpe2Ca#ƸjO5]O?evJA);H=Qc5oPtצ#˶0{=U4R+""뿫H6힙5f_ urv3avfΞà#~ܭom;tu;߈3#ĥsUui|믿 jG{?Z|GFL>#T7v&s 1jؘ#GO{x̛8Gk'#Fҽ7ڴl߶j]QyMɵWUIWDD#V)EgZIrJ3s} =zG]Kl m;GP막ucl5}.E+1>-ueT}4jzч)iM='`oɦYc5ˇwvzޱswԕҗYוP6]ׁh}:nCg0i=c',إA|Q8&hh@kB,. ?sT3UUi)M[=wuݙs^?ItLlīI6&,Z0Ns"z-v˭$m:$kbf9`ĝ{7@cu$&hzpR h;ǡmr|c n{[~M:Cn?UUR~EDD?b{kI63Zm}NV1v_Rw>j43'ې> =Ge;aOZA6B]aa(ayB㘝fLTǟ8Wd1@zªH9&?VׯHG^i{yVwtvukRḓԫm DZ7a5r%*-XLX{dP'͉-7-9/[o}M;bZ|o X5߇ӥj~"UU_X_ ;q򴜁C?Us8iň^gtT,&Y  W\ZwG ҂$#D~-yd ݺ]'8pT}4z3KxMM)om'ԋxuA?5ѻ+>WC&R)?䯜y8v"AsM ԆC7Qp,vX_"^c)wF#d=f^пRV-ҪP X;]XxQ{9[$ Q^rN}wѢU+s-Z|.*)ֺ1b˴[jMOͦ+U_"""^{-9%uCK[JFz40p?}ٕf>q4kI,GbN=FYd(!RؐGHP %U|C\Uɕ؟PQyش7 :4&Z=RǶzM [ݵϾ>߇US=H;~U{DT}4o:Zod5Is^+D{z_q+@k +DeL-)'Z#\%ԟrd!pSeF.elJ1baaa89vVV55!I]yH;pol%v,'v:S!BT}WDDRi韞:p䬲 Yu7Llt՞:Y]i6T#z CnlE.K)%eduU 88x8 ExL q_q? |hѢ:Xy)D={FnY81|zsǪ~EDD? ux{^~k8_u^l6q~)8p{J]ɭ6L9o6p%7/I,YR IQs2Ѓaطo@HHcc _pqd܀@GW&1 Rkk.~c5pIUR+""ogϞuqlemsÝzpWab$8"!IF\jdQ|Cn"uYJ{+>/مD̕rϬ!^Uy4?J8̙ fJI8Iwv,cϞ=R?^G9 zqÇ /D\OWDDRoGE1^e1Bc49vu:R+q*JdjRaH,!N sTu ՌXYqCi |IٱcvF^oō? r㲲N عODg]WDDPGb͚:M9q݇aoL8ts:1] =vLjgq4JX<1 hjF5)%T!p]?gW8ʸ鉣H7-KO\~>m{{{Cħϗʤ} %p_3P2Q(K=[}ud<:Dr| -[~g2iped!JgN]-R(T"R rpRyg*R#OrB09p ;#7opA͛H$Ȍ l"_qF!'rB8WOK(8US%'K~svGqeS{1:g>ii/53 ړeJK{mz^*w "#}+ } )PRhXYYҒqa{"𤔀xJ D1Oa5p&y M]OQ  Zs韖_ϫX^vxmQ;ɳvFqK1aQ9ve8"='B<qrB q!ε\<,ZΙ~9D=ؼՑQI]pCdJ{8ɻVfff SSS8Dqj{{P/ Ϙy{0#s꟔_ϫR^>o.^bK>8טE$Xc'oSLKvNK{y$$ܓcoBAk%=_A\KPI\K =@zPeεxφ9R6, =&ؘ!q8|>Up?a?V\ CCC*czE“xԋqLB <[L#"쌑PhJ=27>*Iov݆a_'WDD*Գg^6->w8`o,7K"^gk%rrc.C %{ggqP#/Y yJiԳkkI%9y7*E ԍo=bbpqȿ,G'۩i鯫<;WDD*T f y]k,D3 9o C7ǟ0ޝx|,]Pמ*\K={r_pmyγ̵k*qjZlgUba˗e065W|<~ pps܉ JYAp#>u#~u#nePJSר"0 QpJSnc\,pJIOX<ۧ5T}R+""isEKV|߶wO>Z'+<gX|};q%9|6.va,s-lgU0φ(x!lgkJxZMXx a"rg~S[``kUR8SKD)Np pg8&w86ߔα j;cAoU}R+""iuv^Fk2v)`֋ek B:ZD#C1==^RxמckO󮽏g+gW2r" Zıˍ`?׬A@ZNǞ!Hh~m` ̙}}}ek6%sqc!"12S =c[X>ʓr6)(z 7˂2A{U}νli4JMM{{&CPtE_M#g~Gs"HwRR,\<{y6zB=\[}ıyra<[Kʣ_ C// .ܹsԉkCSS߼Ky8%?EVAOOO`9#\Nܺ-ĭ" xq( %puKh.În?%eZkXѵ#ʮdlbj{z_OsCSMuILI.BgeZ(C!FRx^ۻuv3ϖL[޳{yRYZLr*\8c\̚5K`̙죱- /9A a?fN6M`Fbٻ$˖b;Hbl9|[(E*8X `{ #G,a_.6Pc9Ϯ$&c7t#t=[}gLם)U_"""UV~A1]GFF$-Y2i6?]cT2m|ߓztx҆KX ǰ|k5#Hpq.%8zG\y֗8֏ γzZYe<ք<NN,[Θ1C`vwq8x[9'!/Zɓ' L6%dYYG޳̱Ű#|(! B)OɃ;)(yfXrɁ%q+ ,̰M$h Yk/hjMғ%KׯHGvYߓulCkA4^IE!ol>|zzvs;EoҺ=,\q%yvIg+xxZ޳4&KAK#aъ,[N4I]]؉COA/3b(ĵ#R%N=(qQrb Fl#m̳%#V ccr_GH>O,`|A\X0p܄?%f{8|G &oQK?>{ɴ~EDD?5kMըc[w36ϑUY)$Zdm<`HB>c}-ݟBDÕy;g݅'xZge=[]=[,{Uz ,\!d &L>f{~CO#g)pDD^_%WƎ1cL8V'vL޳{vƃw`MvSϞ$=[ ce=KzE:αįal6# #hhj:< Џq߆Qg)yA\I#x'?SÈ#Йzy1}]l /aeg7Z5%~]D؛uk[pkn„875201 $wgW8/Q~EDD?u,})YZ_L_'o czZrimlw?#4ҽ)~bgԅxU=$N2f°?C{'qg_8~L1xuСR }pWr`uvij%9yr`| {r `L&cl, +(t,sO+Y*=1_T}4TUϞ=`BqǮrmCW7_Lz`#2r9k7}/z YeZYgԙx!u#A=y֛d=[C,lgi>s0Ƅ>|ڳfcc|AaK H G!w^[L[4&Ep?^!2γg7K<{YH!ɲ0!5&~]E!]G#dda. LzeГNHrTcMKu>K8= %JׯHGUų feN?_iYVDRa7A9s͕f=h{=gPwggxփ8Գ%=[E<[M<[ }ı%*e%9R߂1c5X2d̀K}_HyN=Gɷ9BoR,`ɮC߾}] Xޔ,,rOJ&2ɲ;s0Am/XKe'K_揪kn'iv =Ars84*fY޳tqW:,>2>X`k14|CE~=b!ރr޳%˯S"ec86(z1h l27rOggR?O?~ $ $K ^zgϞFi.:vu-l=l! ' +b+zY|Mܚ>lW7&zeda'a ,adbG 3R5{QK>i;;#7vW/X~EDD?V3퓼 +m0maJ{ޖk0Ʉ,gzp f{s.Y ̳$ul]g}OWbq,l ͲjgY6TpX^s$נ,S~@{2l.W?Oe'"e<&= ?=ֽ;v*Э[7XbA2{ vy6NGϖ> [as].5%&[̳yX{Kg.ᙍEĭvx`,ܑt,t#bK !m1$K׎ b*9A_T}4TQ) `} _#*/K==Z?J6dq!:ZYl' ,sDљ x: ףϖyϳgUK=K׌cyRdž1>ĎDL˓=z@O1'6l?O~ŽxPrxzQQ~7q. w¥C'N:u$gPy*xWV…zdZig#=kAEޓl q]g l7Yy<; YNp9.tqaS*O2(1{5v;}7v1TrDiVYߺm%N[6=Z4 ټy!˒bd+guw&(np=F>X{k>:C6@Y`#fY;޳ۉg%%yvY/Yew'TVß8vZZ\#gYΦuRȒ.{@v;쫾?G#Gcʏ 'YHu&P3ߺ 0t.Zn/[BsxWB *0V`;˳尋*æ{x.2Ϛ+ZYBϮRX+9K },v.LvI,'c~3Q0l1+BЦS/ppr)R WDD:y@2vj]c* c\磡gul!+n` Yljbg-g^:l 3ٸrx0V2<{_2b<:t #)]d[XUaKȯ ~V{Y=ql'8:RooK#bѾ[7|>ѵW8gl-gwYg*gckg͉gד| >cb+/<{j3 2y6z&AEX<[XB<+d&#t1321!c{ǶTLOɄ똶ivԳHm=ͽX%' _OSWUUu)%}'OǪWaq^h? ҩ8[&Xzo[LPvd`1q"Zblo Ig'3g@:גxֺg|#gs:U Ug1qleC.Tbhס Ilߣ': 򧰮~ 53e K-qF MM86?ysGī~!>`u"]Ϲ:"y;NI<[yl9lg7ZϚyΩ=".ĵ gRY:7eڥn1N DQ31GKmG`RU|XK/Ey9K0%USk8,k-ꈃo-Y]o曌7xѺ}l8|Çz6xl J޳=H<y8VR)|,$5 oIı)įi[ʳMRj[_@^#s`μߜ {ri&bqg)Ɣk* ;!5YKXG2/8w=8Vڍ-[ ho&Ş3x6dZ?iڱ3ñJn$ /lh)+!yl>qyv-r ,Lޞ)uVkS9MSTg 8͉ظ&=Q_T}422oh6pp~]fò@Sf-\&?׶3N߈֗,K='A{Yg:גL;5Ixgat:@,Alf[frY?E}_[oŐdȷ~Fü0QV4 JoaT.eqjyֿ>Rw?V#r<֎I}L~sS4n"6V`A\$rvٞ,ޝy뙋;nAϕ˴SLMie]kkd<˹#F8pfL/Q~EDD?MY>-.0ٛ^0w!XAb>VYA$Cw%3B! ,>βKPcأQDz>X|u,ɳ Y|hw믿VZ N|AKzn`IS,-/g]3{̽e+k)Fy.ϫFтdxE0LmC XTX)\VD5I[-14Ӗs6ź%0˴XfۘA3-d8yV&I9{b/Q~EDD?MY3gk9ths{zc,,()nhݩM]=ϒcnOulMfL\Kj;g@dzfJc){Qgx)FL2oೖon VBR./"Ys˰yΕx:wɸeRD»_|=)z>AoTscj',;=Il&OK3mifbLgZٹ;Iuρ.ɴ:NL ӦܧM ucdaYW,774x ?8 NyvV@u--3uEZ<>3c -ĵR1m54pb}ʲCo5䞃5veg˸u 8Qtly71p4lJ]l{dUaASAHñG{UȹAK^ȱʠo/|ik|Z 5`ҲX5~i0->-ʹx92;~: d¢VuUȺZ|-gcY9c/Ûo۶#{Ǭ:}y_s+~>k7p/y Y:wse {X[naˬ/yFt4 |ZXonw>G\$,׎g+7lڟ{V&js$3 =+""JҔ>b}^?BƱ%Xw} '0@γ Er$>k+vpά>Ӗ*]+~m¬[OJ9SB_ K}+8WȹmoeJƕ>`MXuKRncN%⌮:x^ι-Z]_ xfÀ_;ɯO[;[*?jYA =6=+""JҔu:ᬾ/3( ɹPm6<(l}#akL:?q`IUSwQ-N:O0R|حXlð!z3.`Zz5ts`K@^af̽)\a]AL-+$joIsyì{דW31/gax[\:R r=Zv,;B6eRt6 Es pjk5y%iʺt9[lz8qZ[C4CfhۥcvBàe]U/؇WSZr==ۢ'׸Xy Qǟ὎]HMtL1lw$&c"LNXM)yW݆yW[{Vٽ[[y>*k |a^ \(uj0 G;άބF=`Գ=Z ǩ]ǮF{Y/R~EDD?MYrXA9U l/lLV̽u|1~ :c FG\:Lz ly+\޷zWַ\F&>qudYeV%8NSiT{t64lJFemgM"nSテ~`ckOr${ 3%uV\'V+YΩWkey k'>s2G>I6~ܿO>:e'0&6W0)S2ꉃ1Klޕ܆W6 $ɶtY2SJIk_NǗ*xaŠ0 ,d}0h=gr0tmcfC)Emo07nv/++i/U_"""͟, 6r5ɱg-zSt~5VYZqUag_/=Xγ#u ]+orΝ1h8EEoso3Jה{_ n^\Yl+LmWk%k몞arYoF[h- *&-zJz0wzVjL{6ߚ^}b{έ\ѳ"""MYVyvij,K|hE)FJK8dE'~jUcݝ2 Y\> w쎵^͒<Ywe_k҂8/ڠмX)7|+Yk]W岭>ߧ,,ܷ-_G폒]C6. [Oy1nraKb9;g9ϲ^({ +u̻vȬB/y>`=5-]+GSb8W6 ͕zʯ##s[\»oazw9󳎩g^9|1=+"""є5ug /%)uɩS=vI3l9^1q_+apX?ⳗ6H]γ}GLf=PY;جE܀9_=qBSw)Zw}~=ƛ9NnwB01!qC9d?b\+<϶ss2}*VkW<(/7z#,$`z.u:g+_"6%?ķo5kvJt-Yna΅lZVU#h6`s}l<_gwz6lTay{uuYW]v,kUQ0]$$V,NL_c3 )Q ͮB׹KוطT)J 7삗l_(,[f[yULkŲ_%~e!1r ԯBv5il+%{QOdr; f^o=P>5=Njn%񬩌g ³g7^B߉&1?hXm@`YW,덛<;},+ql%Ҟ'o5bYZMyݐC s.4Z`ӡl#uzևx֏y?@(lGL{tٯp4"˰xB|F.=ArwH'ͺrgoڟPT<λ*SE|C.q \K[˜;<-o%7o+͵YQWA`}ɗgpn'k$φW`_Ot_ij߳Zk >2))YIO,U_"""͟,rղN<$6ݓ9Z?}&r`u `^m1<(l l-.!xvՇ8+wŒ1tdt9zHiXll(śոQpZN9Fkh+{i PAĵvη#o$n-Y޵s-)U>Q~Yk,Hcgg]g`Qγ*`<[&3D:JƳ3xoAM8n3c6`zRUUMz`i4e:. ֌c륽O5=+ܓ)VpSNl.}a` {ց7&u?Qijj{l d &PטN䟭'w>g)b/LW#vOf,CeԷ/H}+mkɬOoXxmvul`]gI<~5p=k'lx9,g]$Y~.9mN9<(ÜϞ߼kK]l` vs+F@~ 2daciE{yD}'q]zYQ=AWQGK_C=hMyG~Pyla3c3=PYimgimS,sWpnho6ƟD$g5y'{^ѓב2|qޤ ׯ!C,_;a殭П΄̦Au?t/X`,ٟÐWaj Ϙ: / c}ٚsi\4jkfzCfe[H[5ֺPg%{PO5kEǞ%-ه~Ʃ\?ә6{Z@-b{,Cr~<~=!>C8X-β3;ݳwYC Ҫ̘9{nհNY;e}Y Ck3Qr)wj_7DhVpw>`bZ3o(kYJX+>ì-JsVq#26Kpl[iڗlms=P6q5B W)ظ)h 3v!拵f.=͛+&`~ 2d̘{t">6nnNSg1"gL9=o#'obv"]di^^KK,}mpPGXH8$O:+@to⚵ 8ju[VڗDaa;Ҝq9gL-29O1^ ld!l; (>8 0i=Y==c֫!{D~ 2d̸r9#Ǥn/7(c}YƐ)3oYLtl <|^sgU*#\v==b9DM-}kZ";vKkLyZ۰ʞKz=#7]4nڿ>aY;{#LcϘIY}Ø}7ov>sGwR(gT9cnq3G61g+}{2dUQRRĤ ^_H>z?VI8S [ndt_ wXLkQKWI9l^Vxw8ngy+v˲֜Cu~ %MFZh~shP~9O0*c-'y5{F8ggeenuvR߱mK/џo6E9c%gCq3ڻ?Z7Kא!CʎܵA!8~r9˱vؕp S  !id<_Dc/"Βx%SUr)ᬹfZV]Iw7F-56[3kVC}IGշ+[Zuԩ F*µ:e"n&@e99q*Fn˜ϓ>73k1QgoUelgG;$$=!# ;y?J5dȐ嫲ŋQz^'XFY¾g*z~r6rt/} #򓰕j?r"2sb]7x&gy{e_&w.J2_ E)΍רU-zex$ۄgy 2DhEݶV_3ffSp39/K85nݤ=h>:<5/d-z=PfΆ:n/ )?arxߠ ׯ!C,_zqZۙFG#gOezD*zm)`8vFǩ3x2)*_zY cŵ_$9c,*g^woo2exmŬMWBxM41ת]pS@0"@ʁ)'8&K8=k=v13˜wyh,9[:}nچf2|]O3vUc6yQ}!C^ykmh1PkxO%_%b/xlP.V7[DQ;,s k+䒉OQJo֮6fzJc,}b4G|2V5y6#6eg ?-Ko ,u9;H3:gDڶ0,Dqf/{8jq8)evXĪ7o=n,ڳo.7l)5dȐKxIv٣vwgerUկ\b/ϊq8K'j.87n5PuQo=Z>Lm!0Z0ob(_K>V#ܗ:KuA?W䌭?l헽Xd,akl#wS06<= 0*B-pmׁ{M1c1k1|qE3GN`ʴ%&~`3mԻOO7,~ 2d+/X7鵩&^;jrU6s*"SQm7 cdYKUof<-x4hj_f[x$%d_Z=r6P61gb!K~ئv;&Vg6lWB80eI;ֽ̟'qHǏXYyz_C Yp.H?, w*Ϣa|*X^)~O"*5X&wMX_*g;B*o`\}5ټKԛ Q39r1;"9Ⱥxٌ.#KcE=+)L}~1+;xEǶpvGD(]Q{3c6pڷ0.r63uِp똬ZYK9d?v7V宱}z_C Y Sfc@QǠP 9~F%%ωV\VE|-?/mP}eg%⋨;zBC{4*tFo:!{"*/ŜJ9{^,?},sۡ\Mel'{1H۱{9KkZ?qxD4W?h (XnE~-oHsc`޴{2dgi+_xr~'#k>^( o+?HĢbKXM>D-l@7 ^lP᫓7kgгۥAD g/lhݣkw0dU=V5'>6z4 ߵ{+8ul[yarΒ wӶ],{C>]3rf؁hLIIIM]oZY~ 2d;z0g[C$E=ZIVoKeUTk>gM^We i?U_^7fB.C :M;]!r1a5 g9{gf/rf%Sgմװ>vbƌVg6q 2/lΘi{M2&$p=+gtPxà_m⥣?~RMUz_C Y#FYacèZLFEYo_:j1XzR9>5sw]voN?zsn9+3+1fCsȾr~%_yYIy4gkB͹``$-0vмh1LڵMpL{Ĝ݋-݆ǭ#!{cy~ 0͉_FYH]+|V?Y4Z:z߫j5dȐxb6y:2C6!+Y+筊X,Hrl"/^CQBwWDXyJrؚ|~ Ma+raڸ [6#}F3-Z2urf_s箋eY5dȐRȽ_3AHpp;ydzÊ=pMrl"g)s; tD$=Izc,7bΊ%sVe9cٳ#~ G΄Gp_%c=}HYkLsOf.; m{C0u6-gΜ 'z%CdyBkȐ!˗%ŠCli.'KV%e񝜹Eܧ2*ò|}&.>9oa9یxl!#~5mXfSJUϋ gA湆Ma䡻7b~#,g9猉w¯g_?w<۵MTYMYnb9N` |Vְ#~{)Ν;X{2deI3bLV^~Q=B1A9YDb)W3^܊qJr;J/{U3grʳkeD+X{8&^Cx|2 7e;2M^n,Ǐ{,7o]CÊא!C/Kk%oʱ)7=V!޷kc%-#O\Mgl}u?&]P&gi 98 3!`oC΍{+vpⰒ3"5dȐҢho}<XU9Ί|Ћ,bOrH׿HWXw!r'FCSk/2)GogpV/T^u {yTf@Ů^YmbQg9ƪq=??§[O ;v!c.gK8s$.SƦpؒZz{/z_C Y,1{Wwyv>mJCXKeO̼)c+WjmNBf#(K)_yR/V/ˣ$3+( !U`lr8=#?g8S3f cΝ̘SDן$}{2de1o'8MY Zr">5Tu{J+cg1s1YH!2&c>V\οSes)̜M%t`_ ~&VLeUsY0:c򕞑WeKsl6_kh>sM׊GBkȐ!˗K{Lgܹ/J`Jrx]|yX]fg1AbjdUh̤P{yeϚt%[zI~#r134)L 2vg|xIՃjc/exJ1lS; X#q g{%%͘ V>hN>%?YbU3_5dȐU7eppvgZٻ b,%^r]-2`'V"jX'Dz^6qo؂ WVX$ {y9cӶlጻQO֬[>א!CW%h]o1}n@rYs#R0JX%O,(gQ0{Rj>QRQf;E{285cQ/VAù {ƝϘ9s_5dȐU ߱Sh98JeT[j9bLY5٬Tuk^c'ɞYa.yϬ) V?7i퇼uW*#^ |jA|m7rs~?1Q&jp,)C[kU2j;idUf+},X1gbYZXm..giӜ%m~_v^Jeא!CW1MI[0VvΈ^ ٔ{٨rIWyJJXv6*cK'`,2/6<=ƅ+tJ/|奵GkipyƢr/+mk&JNI߷reg}Qi5dȐUq&v{t*żndLqUQ*9bqXmߎ|crdKcl^Veew3y `0jǓ?Z_{CkȐ!׫%%%o/#F8>8sLVr_U_Gg)UkX* c5z$ޕu2{o݁?;sF)Ǐׯ!C,_z<~ƄI `4Sf #b$k7dr*c"?$⫤Xy.@>Z}OjObiP>}$غ{3mJ~3?s\۷NG~ Y:7 yLwnMI7Mݭr"x/<9AE<@(ںZj Ykovjvɪf]<0hk}fg~ͣ_Έ5c[2+>n=j}Vl>/i;ȸoiob:2 +|Fﵵ{}m5*>!震pt0c$ZQ- ,}{j}؆'Yg-/eӊKd'n8woK%\pyK :y`Ǯ/}z=R/lj~f=k\5 k Z=le}Bki^l!c^6DF勛&^U?߸I轼6Yz_3s-xqA΢iW?|A:{[`=u 12,/()KjnTSj UsI{ٜ֩!g2aV\r\qʶ2v54}؎;dY._{}m޿l_koGy˖ ,;K!kJYZs_:Rey8Y[W3&=l3əFB)dl9F=\{.~R-o޼Ŝ`Zc9[ #Tyy~_.}%qӫ2uZg$myCzǏת]4ճSv=Xz'Șk%LWYVh~=l4[X'+d-s+(<5\:4NTtܘ}voS K *.EywL3zA$fkj;&jN.X-&Γ};ga7\(sf׮o}Gwln^}%8qDyLQ-Ut%73PsՔsg'6_牵s=iƦ+J'^>M]=k-^Z-^9m׶kt'&L_1{Zmgӎ_XL'oS9pa)JS_m;"Ǎ_#!'٪ )dXr:I(%SܫV g,͈t/ow2Vה]E2ͷb-]ߓV>+^?_y w{M[kؾXoyaN. _kj{čH$qM:84H1$YY v뗖==/;珓SR{=.mĨSN_ed:WF1\zO"ً$F) eRsOu%yv~}Oy_g _eJ+)9y_{Tؾ\;w=UG.JքKHRL=إ+>UEm{(䒼gg:NHLKHptlљ*5{=h}A4!I"/qd%gwiՉn r%8&A+꯼9tV3n͙ +=zPz_5>v.spv1ή^?U}g/JF0w~.]{|?~O{a}?1 SH #~C"l~IɃġy>_KyA db>|^%j,/ګACMةn^K9A}7-a[RJ>y%Mj~W s]p퀰DQew;~…M޿l_[)%_Qib&sr$gan}[P{gK|gL ?=6~bqe},Κ'#ǮKϚdiϹRu`b]5E;.jݼyCyy%K \ٹj]տ{ӻ˧'&{pMHA(}iƲ}ewYuQ,~qgO:mXm9S #FEE`H74JáÆ~f{.}(K Q`(z{تL /}(X]U>nut-2.8.3/docs/images/ci/DO_Powered_by_Badge_blue.png0000644000200500020050000002177414777534445017346 00000000000000PNG  IHDRX}~ptEXtSoftwareAdobe ImageReadyqe<#IDATx]y8Vp . **H To`y+ȋ,b?4$p`[I3G̀]Vߣg?|[ "pGR8s>B=#IKq'[ }5c?nF+>ϝ#ꔡxt XWB7@.#I>0jcD4*?}"{v#E'U?H:j%L2>8|`C? Tq9kƟ7>$` 1-dcHnB"@9^.a"[EB+H6vlMG '&_{ “N[Cxν]K:%V[ޭ@]$^--${qWclŷyK-?4B+.`q/o_A|DgB3A=YwVVh@x?i7F9  " [OpDΣ4!s:5{&?9ſӵ>_(ġMVY Xrϱ<g4ĩƪS$g3Cȕ-n.;iC/O=GRЂ>Jb4ͪqC~6P$K3*9A3 +JOwR,cbtVSe`q}/1ZE?/=9!U[J ʽ,³djaL>BҷE|<)PT}W8cKʱ ~YWA_P@}+W  r Q(c}x=#eb>\}!JYm}QʶgCDHYob+}}$= *%uF O]p6TOm.z}9uBS}vgb|-I|\+\0n [-gt|ms ߋ2>on%⭶B?u$8>.&Jl+Oi}g9jy;LKאFYw]3mc"O9d*ۤ狽$lzT~9cԓ)Kf\M\kaĖ!k>Ҙ x {8Y\kʍX#8i mśYI!KCoW Ӗ:1X W61$BTχ4;)"L*ұ̇9K{6,2$mH0tYqG8@1Eh;!bB"7w"`/S5>W8{Cfa3,+,FS~$Xk VgI`e uc"kMf\{ 0ErdMg$Μ&!?NqÃr;Z fI=N6{@!Y<%.5IoAcQʸ ئr5wfct< $5\7F%}\_x `'܀2 s=B5&d+I蘍iƑS}y^qMYa'DFj3*Qɨ_{HYZ0LI\R5&}R 'ۚã N %.GxP>xRփd$帣v줪GRψ( d]Cc"͎@Rr=#X WmaWjeĩ;ӹ)&ذl W@a~6g"x~ewa| w";r='67-1a[bqÐ5^Uר;TW,EӇ5LItܿQrEsvz0E-P#L׮d u kH^xt7"=uڤtUޏ>[yWTH:&WG dr_knY~rz,_ȶ_ꙜV"OsvL4nQ !qs W`` 7ejďˠMDN0e!Wyo k^j[iwo_=K»|γ\(8N?q\W#Jź͛ PsgkpDQvk98vOxBՍ׶~u@N"ed}Ui2}/W/JwlEਖ"\ϧӑ,KFɂpw<ùrU@[\{JTbn,W}L^  l+DDø#I<K/HgǪϱ&HX(8$lfW HG* "{HR-j?,1 s sJII-%Ů=Ζyi7Ô ,^Y1 bP:FA+0tЧM^+ssۄe~;|6 ,,M8mix>7q'Y7r,}$=b'<=CփJ6QAne!xd-+m\ڕ}|U}r%o H\.G5ŤzF\JL9}9xR;e20A^;K~뿿i٤ jw~Dr^l(#G:Sɪ6v$s5*8e)^.! Ώa٩>_r|+^|:M_d nR.^&󊜚o a)'=N+OZ$DS:sr62A')Q71⋏i?_@c征KI f%E~P<|Snث=⺌AtODy;\}cMpMy;(]ȵWX ۦ7rt ?Ulz4Y^TR3Q{rE\,vE,(϶ T H ̪$mM\d=_)bl.+#NB~AYo]BfPU|ѻ^}JU.'P'C*s3'Y]ۀ6,'[YNKýN SR6!dmI1NuBrf{ ?1Â>C@Nk I|#%y5(Nj,Ё@mDDTIPy#&rlN?s:l#dD)#T'tED|ep'@%(j,:ʾUқ8 =~ o?|桒`m*E_ e\F6, s6m@Ѷ:^J2X}z#Om4x!bEΏyob[<=E\/O0OI;?c:i5y}=.&?2ȡzbX;'bn&9T1d3fu1n/h~$2Sx<k*ۙj&!XOtdK4>O\e/=2qG5=B^f I^Ϛ}`BcخGI`L ?z3YK7ٳf=6O)G`5vas4֠HV~gZњ+*>!|D 0x{TdFl2;u[cLO.l~'x:0(]M=eH6;O"Z/Te5d=Sć 2.NK,l,8\b܇%235aĈ>fF)Q<6MOӑJ/ΏM?uЃEb {6jE7AuINdyd^EDr| VQ$?$"^'+?T6?7'9D6H)ǐUb5&l\,\CtSZQkݐVQrJoA^qC(cǤ-5(k"cjOTONOI~ v: b~*`=\u Kx{UM |瘴wa٣jsTDl%m^-,hz RhS@\? 0ogn̚ )r^}& b1.={b'x]W}x*~lچ"f<]s[9lOesJ=AW 6d$f.S6iI8:TJr:@I\b <7p"sG0CiF-.Z0^j HƉՒm!5Wu)rTlKr%cg:XkdkXbz[|BG夨l1N3'9A}oBn=}w20$ }wˑ*Qc1jٙ>V5Gljj`ABbG#I-r530 w)2pF5aSn\hr0mprQmQcᙼeͳpHB^r o=\#y  SbT^-z)prڪm$. 1Z=^w "8!徐^rHVnN%ӘC({ɺb"xlMɋ6XksdφWٽNm{SfUE XqUa|ԁS20DugݦOlCbr:V=suwrmo Jrulӳ%Xyr++鵤eVZٗ+NuW nwUY9t{$5sMϹ>)HE4lq'KύgQ"T#UtИm=)4C``FпOac"REZikɺ98MǟOg,IP`_1Q׆ܹ_XSwqhiʋT/ 2_X$IW| sVpd*1N϶_w,-B"U&g@4W&k1`\zWU2-=e_hMgTodA&rc& ؒw D{@"9UE\wVၱc{J i$Itܙ.Ni f6۳ pZw5M cp] o(6eH |#+q!ٷ$4'OڂM.~WY޳a+iW$8hKbS/a~ ,)wAκ[-hrԌ>n<p1 Ƚ1 W W1OL X}oA\.gU6d+:2V0C%Wru$YHG/OK9(Nv\Œ+Td].N!#cbk0@@Γy8LlrOAl'>[ͦ \n <%fq'?-I2k%@ Хq| \׀~p+][~8ꨎ-ݴOTGI>ٴmtP)\25lehP2aAU@qٓni֧ ZlZv"狸Hl'::{Eܜߗo:#'g3g*LŘ:w{0= %_{|!x*Օm"WQ:'z 5y 9ض-:g~G*th){T*#([cȜI=7Jm`":oEUmP$qmIjS]>5‘׏^U&ŕBP4~ÉH(_nW-ѭV~'_ңC8pB0Y=f-j~S&:o>T>>%oVyQsGeܬ\%m"_ oGVn8:HЎ㺛C;jwoI`8xEx]aF﫢s.e3RRZ};r ]U6v' ϽԊ[͠j:>CE@eqiŇ";f]͌SN%'!t%LgFNX5X " + 7vt4q5+:e|: oSII;opSi'聊8ƼtHWxoAqt*9!3rhq++ Dt*#ݔڔ#&r)pf24r+(v?]τ$jm},XpP3}Wd"԰?d%۳V:հhϬ~vlJ@XjE/.`V W(Ԁ47qCt 9YhdLp:b0ǭz{hLg(Z]9֊٫ fmO_#TL719*ފ F`Tos=1y;d^|(dhEx zceLSJ1EV= "\{tsA\\+xRsy.!:?ts!*Qj“ٱ:~s`@hY5= د]C oWL҅ *u$ ({H+v_ lW8{AtLIs1AtE+jVuɂwѦeȻ"~+joOIJZ u$6 ȋE}At!-3?ݹOy_K75^ܸJukE7Z3V,qV̞[+Y1qndMBBbsG[ TSPKZV(o@YR|Z~x=ɹg|g}Xor}uٺ-P6 Lu\܂m0ʸY啖O%/:6O~擡tގMHe4~qlc}t7oZi? Pa|%1˴aN2bIq\/ӲuTZhd(4?>s=t$IENDB`nut-2.8.3/docs/images/ci/jenkins-nut-small.png0000644000200500020050000034532614553676503016143 00000000000000PNG  IHDRX=|sRGBgAMA a pHYs@@uIDATx^]U] 0k)*T޾zn@wwݝ{s﹗AKg`LnX$hD#G]]l1C-o#шCM,!JKKCUUjkk$ĈciA|}FiD#3-[ժU,<ʬC+CBuJ9 "335II1|||3JѺ@+JaaHHL/&6EDT$/&NH#qܠFjD#R÷lbR\+/wu\rrr˱nZ}EMssвU}׭ 4VHBV5kq f ?/_ BM4Qc+m\lѦV;P4]n- Yf٫':ub&p5M޼ -Ă~&mJVݶ]E ///Yg zĦAK4Vz ֮[z VZE bƍ(+-EeE%**'2%A 1sz555j-D !@t @޽ѽ{wn"^I$;h?!N׮M?oNskn}=vZTci{ fE&M'o' 6lԈzpTr6 N2 .Ħ~R "`#mjv)<wڈ;, =zhFmukTM-Z ,((@NN4XkC;w22DݺBm`_ 4rjx{|9XZjaېcFȺL#X̪Tբrs˖-1#0n8 v!3Yҩ۸ʊظa}?G3͘!e?#V8jhϐhܱ AF$Ϩ`!&4C4|}8 㩻U^s;rKՒؒWr\עeoouιzFxsNJ섉HKKٿAAAjXl? &8ڶҨKC[WZ޾¾ 'lQ E=q`I'Qm*iH)D;m2g,wz83?>11 ~ҥUݳE#-ҹ  ˋA[C}4"R@%@?_%@?j>62\_MbNʷb||" ;QҦmK}ҷh#ظaC)|Xj5"O%}m:a@yEh:C84$AVltTǪf(%ӂbdeʳ!yB I儫̦0mxIޫw/{M8| t%~׸K,=rQ/^)[v/$Hr mZ%Ia$Hva҄VHDC%MzEW_*k6KE񨪩aEzN2_ww]+'͙=?&~S*\ `YT"JK6hצ%:mV-uh!\Xj:B$MڼBdd"+'غ=9)(*.v}-_Ǵ寴T •W_N>QnqA4ysy=eʕznX^^)gWJ EXP$E"N40!P)-SRYL|U1s{FÝ,[sKLGAYv;?v EJ^^Uuh׾Cͷ~ic-No  )puÏ0o< Xȕ,9{vBpPVTVkױЪ`kzͷ~WMeJ9nMҕxX t9k{xʋ]m۵]wߍqg(ÍbڵI o3ca7ZLO=`Q]vrQ`m)I)MqzoULjfVZG UspB& ˫d$kS>c}hXha[&cXXXF5- $5YONjR)ɸ"׿&eL>:[2u[:oJ91}"efr.w7Z.w܁ȨƱFso…q Zbŋ%''NJSR+ Ebx ZDŽ]lZ+V2w(:u;y:T໅yVWx"_oj%V[QS޽l%9#&XgR%Sx>+.LQpcѣG's=!^dt0A_lv168c4̜?O%סH4\!eNw,..FV3O㘑#e_~yV-Zv+(W_ixB@ @05!fw+.  APT<c8Kxp,vU)/EEa* rPR ,SBV %Ⱥ ,cExk:ߜS|ͣB)ha+Ӌk#>>uB·)+ >/^Wodakb^9Ciߡ;pt]}ui5}.,f>r .?41jΨKӽͻiB_pPv3WTTaIwH Oi iyY9""#p‹.jF̞ՖF5c,8eڵQUQ7v M!Sʧ ~#/0J!-!*V)YUFׂzzȎJV"/(MCUIKZ4c,S\7f&ݽDhqqRJ]U61n϶ ,?P|v,ZfII+z{W:X! L>^Ǭ3@,Ij$[$)&&&Ç:iӦz7p\s{+ɹ}zvƥ睆SNА`%X}9ȵ=.o0W1w/;G%X]|!]vߐ~Lpt&l3Kp 7x|qӦNmZTL/^18M CLJ#@5۩ r|VrgAE syzNaŭ)iyży0c ԔFfFmhtw2f_Ӻ¸PP^]ȫ3ѯSN;mg*ǣNhR}Wxwy u9CkJZt#ɧ\ݛ$I2 ;[jCذaj*Q%%ehߦ%\q(CeBRBQ[4sͬ:jdEB\3ȥ$Pi4+[_`vAO0󁓤N><3_<|#YusOضmk&&]0m ͧgB*&m&[oyTM0yư|@9z}rdgN+ÑGF"77 G$lbB~HVH-q|$eu{ z}W^ŊrءL6^9sE(ݖ|ǎ\{^ "R/(5_ C`!YWL=pS6(/-W޿Nl9OjZ$XN9h>4fIÄ=%xoAR+3m./)cO3=Hdg{֯kƘ -~zt8tIClh5R' 檽%?8Lyop<ki ]$$k 6DyA6%?Χ*KS7!\PQTN8Gn[jUbE9,+91wΜ .\J:?m۶O{ Q~\riXp6nܤ˜+/wMb\v7o?B'Q& wTHKSH`Ar`Â)%7>*VKAXT ^6\Jqſ~wjlפ<ZG;m4 n9vwffA =J,SpA5l`|]A,] ĕ)AR9-H 5ٙ37KdHYd05ۚר)/AѶ ߲RU6eie͚7/ȣҤ{[6nvlٲE?5'"Ae˖[p,bP&;L6ii:8uv,]Hg$J߻^z8rn{:{GU,/14"~(DEe51oW,^9:i̟ٳgSM{:ԈC>W]y1/=klqQ8İ@\0cTŅ#lҠu%'[?mȓo0p9s5l&H+Ua,d"TLOСCFh'4"5,,B;w rsK4.lj;7 GL8}}h]hV;LKwHR(/2q09abl-hi9W_}%Zn"ɑfӦ͘=g32PELА@|$Avmv͚ky-]brVq0َZjbQm#]/]7H8^zHNw_y-s@IXY_qfq5m-ZfSE+7}$iױ7 o5 f /ڧ$ֳjhcǻco4~)$o♩8 gqQ쉿֕'<閈3&ϒ9-?~jU7B/m +eMwRr0 ׎ggDl9CF?ۦل)cqw\]-Rؚߗ$#L6|bq晽Ь70̘ ,\"^!M!>ļN}_?I/d 0tmf _3wzzj!îx)uO=v D|mڴ#.aDwJ~~vgfd`(JjZ$ iW@"u;-'OBhn AaҊuiD&vVSg.OOB .lB>Hxž㛟`Q=}j{ws]^#X䧂`I­0g}.hw3ә^t &peeM]h -_ d}Fv&H$ PZh8mZKeGyA?v_P[Rl]0Mt2fĝ7^Ih畸atx5?oGݎ˶mMy4??Oq]1YY7onlw?4SXd!alq))*n(LN2XNslg 4K6gEJ]QQb43FIŋb-uk_+2{tKX8N0Ӎ~+䑘@ n-c-3{{YC VVV}WZ$J]ĜtgԬIm. ;L6CZ~yLOCFZY4`E]Xm[W%XW|r\;\ݩM|[ƞ@cB#{1iP1!ڍܶ{gnp m{:2r|I&Bhݲ9~0o?;7&yکs'|!d㛯<_~}i!RnYA_6:ƛHlݾBZi0|Y Sπĥ5̲AcaS?4q < ;U)<iEOH9 ũm}==f ~7曳\[~MpQ²D"5r6u] ,GfA ՙqE4*kO;g_x6=x>ÏԽK[IkUW_B$`ƌ,ʕWFY`Lrɰ@eҲ (" !VX/(R}^]H" ~}kC߹|.cy9sy1w20a/]M)t|ntXXL"/H\G5^Se˺1i i7dKB$ӓagBW~&Xr7O˴xMfq1nz϶468^`oNOs֢ҫQQA$ia)s˫1e붕Gwp1氉cGp+\^<5̿WQl)[RWf&J%&6?w}Y眛K ,^-3BNm6&6AAxpӍ7[o{ッв Yr֐)Y3ofbQUg&;Y(I EE$[HH0B#)&aшoаH=Y XQr<m-“/ >gߔ= a! Vi*獛fA~A~LCg OO_b`ޑb)n)BthqˎյQ@]㈖,,m 3#궍FxՉ Wc-|2zu">>W^9"Y ҸYN6n’%[=f9&{J:Lt0[ؕfbielk׊n5RЕäʭm5c3-]zHq4-\XwPQSq 2sbmpߎO/.-}]8[Zw*kP]VeK~/‡0>+ vҝE٭ݘ\}w۾m+ -TWi Cu"ηOiXj]Y٭мG &5 ̳nX1B]VX/?l#,gM ;И|Tʉ7eF#[~zzI[SB4\qFl[ap}L}T(S^N{i>klJ.T;'QˍƉ3F"Y.`V3 4o#y0[핯JŊ/3+]0V[rek!1q6m|Ȑ#JJK,KQ~nx[fU`M?gs;Fg{`V݌?FAaμ{p: \tv 鬍O?9y{^PjLa\T^߉VAxSPP05z}ȖO‚|L< māFjZjDZzj'999. $3m7 v T#QFR, k/!jv.-Kqv w13n˰~{6^?ke6q_H6;Kmyf}7g~hcӧoISH4<ӶӇ^m1YՂ-WۄDO~-9_ĀktuUaaaq-8nf]J$+ JI-3:_~9?< <QQ AQ˭ >Y5oJJ,!'z&DTإo B/,.~~g*DWzh:%些Wg ؖ-_~_z0_\,\oS1a8`(yps$FGmXtaQg={jTUVa݆24ܜ;d}坭QՖ| Oj1RDa]g.`"Pa[mhlK X._NZ1_[s:MP/Ɯ KJ..j0)B7 o`Ѣ臓G0f]*ڶz:xfs p=\iQ[U~ :|֭>ݺX矯ЀCh1n h]($$&$zۭ8Ѻ|eU0_oKKyK2,Y[-_,mېU[z #**\g6Ku4 JEe*bxvVW,SF !]O:hC;=GZa^uΕM\U:)-j߼]Iv9ڷo '6? Pˎ^I TڢI 86kVůykH5נMW[_efl:XƧ-L۟ 說B v A{3#0#{|v^N?m}w3mwg:ldߏ:}Xtmxo7Pub{hrc[lųjq%~ϩKcoǪ5k_WO믾FLLV=;wG7+~q\ b0Hm6lܼ9ڄJ.e ٳq .VkWNr]N5?F¶ϐs`>gR,kjza,YQ᪑9H0~ئڴJD J2:0/Q)9+(]>G>j۠T mܮv)vOϾ5oIեN0-ю8h|G-9d7 ïꊢY~vջ?1<7qaIk[~AoN,LȏH.~F35~0n^G1ϵlw-EB^f@Q{U&Iq%}1bx:Ϸ.j~.F2.wD,[!׭e\NV9M{3j7$c-KMZJƭޑaV -g<5rͪ<9[x[!":::{; . V4lp6U4+K0^{5HJJR`%mێk։ zӘ܇K-֔sE &ъ(숚|ϐ/8RZg xדϙ"YY-H]:Bˤ=n }7ߥDVwg7OD`4<'2{5mφϿF!Qnlڴ_96dC$aΜQ3 꺣 !;+-uOpL"#,jISARMJ~-abf];1S7 Qxl#JN͛ƐIRY$+Z?6}WKuO?_\y@4YD"[L[ ۤk33H*_1p|P]QB._-N0L8OV h`A#777Ю#p;l+q!1!Q8DsϿ`U($o~V!,BqmaאwZɳwɳtưdsc[O݌ ǍhݭTIeU]PTqIJyvm8yEh"/9x[k?; Rx]T$2r`Vd2˽vis}QAh +nM{핗 6`4h-.._HޠQH$ɞqJdiV^oK ߡkWC iuf\v#0]UfyH6^zsFq{SS\/;M x[{pI‚qMIU++?CMBOZԁѭfR&sKLEoeSRfUq+w!(~F'fլX(ڤMӘp%t QTm&Pˑ$/&b52چ1)nڵB|f%VCm6 2!ZdfWȽ<ɝmȕsi$[ղ"*Qu?!W0>1_id{u;55MW9swͲb$dǝ>N$3?PXX$Ǯ ufGyO=֑}՟uEKWe>]"RsǍ뭆p{uo_{~HoP.HOF}|Wظa-aJTFd?e p4LcWUikR5Z.@e>(qв׽?W~HR[aMڀ$Ko~1RNFgHG 6 Y$:fw.{\_7=Y2]['j:k]EkAV2H#3ݙM^|V+op5JV\V@mNTUUfeeWhhDO?]$ø ;ndw&9s/xd$s܂Ʌ-8vcnKK!iQ~!&M-{I =ןaz L N#l0bho`wmFVYcnAuUUhr6m.d5uH/20Q߀ & ٕWɔO 0nI,4qíO{˺ 'QLN_=gKh|g̓\-$Uu{ckJvibR1mf*v1{zoPƲ/j|ez, ֥Ū-ƕƘ8&]i/NLw՚a;$ hlܪQPOF%Z!Ѻx7Oq ϥ\j"\-~VZ㰄{ އ2ދ`A GHnr3H|M۱p*]f218#tE*H}#- dN8cQϻ6oh"7oa# %ظ8a?[Y\.$UO|1$䓧d*oը Lѫ:CAq8,-R5_׿FtP_!⢮bti^~%,G)ɕ$e`ƍO/IŚu;?.*#t$>7._ B1gZMcIg+mB5bi+e E"hXXlYW``vH>q鈋ʑ,biX~j':o_@MDn mhD y6p:6ʞ?>%ܿ{F ʷº2M+dZh ,,XrzWC85.)L8P`q,|InM(7/lۺcvVfתJvxw"AD[ZYj~g9TԖD:+ps)AJaf +AQòͲlzv"}q.Z>Қ4J {⼏0{ֱmLX-f܂36 c#qⰞ`4nl\ocGjnSU0-@d>XnMMk+L%(#? `ve/;qшWmĺeK Ν]=b{!ʙlZ6ֻ-9e[m*kpΩGc`-v7T GV *VAIݶkcѢQ :ѲLJ]Dދ+X<#ønԡ]_+pc׳9!LDJf[׶a4[:oO~ E%e.bglocG4/Ɇ(di8ݖaw0'UҘqV-qڵPY9.5b"ͻH?ztZ6a1ACQTX4;~c3ynE̞93b k^R\R/m1`@2??_r̚3Orj[uTm D zoGO"B[Q ~Z7٧Vgoāh!Yvfxrr?'MB^"P3g"4,&kvu,UYYQS{+jm7D@[5[Vbgi+׳ v[1CzQ?Xŋ)jPXR~׿܂"r#dAN8& M"CTT!VW+>|uŪۜ;efLz{T(7a=e;lIB+="[qB$aQǾw[l  h aj"I%rc5kf_pn ')qRVM9qT 1.B{ؑh 8o0O@YbzEGs{kb޲ٓ)M[7ܥFҖi e'>բr(K%MhHa&!Bo?[ H?%^^4GV~g/DWP"7G5MZ'aX\qaq⸻8^qgf*P`p=ѵMip^ceB{ ?ь(6Cԭj^~W.Y3g6jKKggmA73cDII)-[<5U%6-V߽ĊGK"-aȁa`gW5tpa}`kEhh& v8{.jyS#/֭]ӤOh#gk.Neeqz<م]4JJb?gJx껅X)5yY>Slbi]_o`Zᵯ&IsPX\Al$d~#GM"F+!Mqim_fyg9)X6[ ۰ranZ`IdJqtg1渙xkA[|#}a8cRPRe[}ݼo\[ݴq#~Tw 6%9ٝPHm۶UAƻnyǛ.xރ+Muq8ԫk;8̮>}8r}+DB\v%yC ̳٪lw%$-hVĶܥ3{of>polUå~O9o +ԭ(,y?ߢr<78gpk_㇩ 1olJA^Q9J+Q%2^'g2B$Os嶌ȿĥ[iwwXɬAR!3#C[B[mܴI>b_RUT8XOsC. nR+wc_,10_ju 'Y;4p8y1iBf>e\' 9TB%EI#%֭)(CL2i$gs<\ˆ")%]DC+i0yvTX{ ^ 3O|l`t%:1cl#Z~G̏VVXcB<'sI"jn[XXj)99HKKi,@ZQ^9A&:2 m[e9J)- oWSaxn˄(ѲrpRZIqa# o]h}bWhs v)(TtJC8$[Oeu &LkŒ\TS%]"*=GJc+:^1AKd1Y?磢3 ÿ/BϴFm$@h #0>^~Fdda^a)ߊgg'?[^o'.-,(ٗ%aOEjT˵iE<;N_N,Zr5<4H1,;?aL$rb+jH\juD4M$ ޓ]Z,v}\OM ็[K&E@-|PPR"lvxI8qǿS_IJ-Y/ԙnr=NX{#篩n=6(4H-+-IcdRPe2g(+zR+jfq ^vM-H4"'ɖ.|7VJ@QTT_#&"f.>7ε>OiľaUR63}9FKU7͕sD+,cCFExkF2ϕlER>kQXy D+HCLYE5^OdD7bquqM=\ ewc⺈ᶱW~л[4u~g|H̝p:< }qy]0Ķ/-Iڷ*g`t7q .|;\xEb+9iƌc#̯eD.c#cqMmM hsrU{&3mp0[:T~~NqxMޫL$~ۡMՌnviH< ,"\?qYl7(0-r 灅 B# pDʻI~MMe wJ\v^S5Dk7b~:[>ulmmWNl$1]%5ue>K<3<<;Zz"Xh+ tih!QTV'>>gbv?yw\qn;!r5SK!9a;oת6@ iE5 Vޥyx$ 8-vJ#'[d}8bRiJ!߆hhǕkJެY<%il}g.w/oľcM| N|beo=pr=vcv2dWò,Ul#bcp}qV-#y+MvH6?8_L;JH;ͥrW5q{xB'ur&%[ au ETd(?:yzL8_@wjPDp+.\W ڹfq̴HOMw@ r쎓B6-)` .AEm^9ܶu $jм%kf6=ikQK/*WoDiy{B5~晴^->V4\N+m|go29xo& 1w\8${lhL^4a!MTbEZ1ޚ yhr'얦%kY1 pl4Zoൾo?}b"\k7⇉1sAn(@zV4 4bqH|g46ơZ~j&̊tqn9Æ-}1)nw|IظJ̛z~\qqo=ohǎJd FG*l[Ptjam_xlټ5,48aBUhv;RVa;+%[]$0jaa@<GHxߋÕ._ RqZGl bWoBn~j}+9/~Bk8Isֈc g?j*&^W3?qcAPPSAaWNQ׳pFb$2 &!=ۖ&$ ᇇWx%Q=fi yjq! BJ7VmINEna6ᑗV.% ,ϭKlXY($.#daXQŭcv1Y qlHwp81fcg5AϮqnxx1xcGL^mpݘZNii\y{m_ނ` hv| 99I>(/-G'%Q0*]$̌MiKkaQt,Hޖ3`G4$8@7Dӓ[nNI Ϸ.Yؘ( ӝ4(1ؘfm"'߻YhV%%\% bbLo]TmTNUb-'SlsQ7ڷ½ ue*y4[d('7J2rpbK'Qf**w ' SJ1uN6>__Zo]Ko_k[{]o~݆k NRb88XxF;5~Ƹv=v1ǥ1٤7ᱧfa7džSi#mNN%,', t|K3tؑ ْz}w?7wAA:Y$S4SH~hz,DR^wF| ۱}+Iݖmu:aO@xhb*+1c % ϼ? 1HAut0ajP9SWT3ʾ{FF{"am:q:Q\Yf`"lcƴ{G$iW1mH5m;%mK,|7} Vm|}A<w2_ ӳW)1Y}T\Ex- 7 ըjV2NqS}n;q\Ǚ]Q4g ɩ'h_}WdwAA13ތ YPqSfcTRa=g3wU5ĘG|d]1v߻w}GLg8GiÊr*5}MW}&~"ϨlPzunۡRNljp34l٢t7bqLpc,qΑimH~q@z BD#-w+A9KBH,XA)dUiY58889%x t]'r_j4oSI"F5tfjRHMp5c'-ޞ9Sqb񲝷 'ñiOyڰX5av fB5->̳uO>j\NqO$KR^O׷AaMQMH+*;b(ڶn.B~o} 6l;Cкe8vMoHNo):ƽ]V%PQ]X>!Re{j$&E-9<ӄQ&30Nl߾y^Eqa W>ay&ǷB'aw \˘Ziy4r4'ōFrYTUwCr)&Ƴnµ/-cMM\mӸjnj 3nWuee >j5}2/ΐ w#,87FB6UZ zܸWqv[>sMM5ݟy5DֽZqhM̼OlL1Z95v^rLǙU5&*XB9XiKqhVVL|.׌nڿ 8 YbVwt7sK<3x]1U\\%YFZđy`pݙ#⩛Ànc?@uMҲ*Ѿe0"佬aʛMҶHEzL8F90\2J"<=k7~-TXwajs 鴣JLFgvhuƮ~K8aMON:2aA*6.g7oK—B蜑L( ;j#eCh>Ҏ抳m{ĢS 5%Hsxf3QvjeCzwcWGn>|+>x^|֓x;qEgA}СMKF[{v-qڨx4<*1Ҷ P-rUnC$iut\g2Kkː3AMcĿO؈+i GY_~=gNhhF8|ur!:!FoZ)"ǯMLİ0ܿuV Jl0 ҵ+^}M$roEŨBM57Wv̳Ȩ(4OjpdV 8-*,_Ӧje͕}V9fTХnΆS$ug^E[=i9SC I~'}ؕK!I2sqbcrbxn>Z{iy$occQI6 QOnaKfV>6nMÆ-۱=-[Fhw\w6nl,VO=+˯!(y.W:;o#$4(_F}w֯gy'c8I.Kmvir5'Lf {sc^OwlL Ξ}_cг}h">~*7uoM|c,+jxƦqg9rP\iĥedc%dX-ﴳGoj'm3#1nUcYnf x>T%M(x3o?.9n7j-䭶 R Q:t`j|rM8m5[rقT˓Nm_Ԩ  .ݒAH?NȱVl V~$͛/Ĵ)Sl(DI֮mCuu.>}+̛93ºkt\ҏk2 R"fd章 7 H\4DjRS)$fG5qYpB[VQG!` lOk""uZ5Oa}goڦ鮺 Oe% g^qǣo{Isn6|]l2ii+x_?w4i~4Q'L2mena9n;a$?LmfB"CCY^eu̲CѶU x,}mKD} Xt6Xur -Hڶ%=HVޝ+Sh_2VcL]2/<'jK _ݖ ҝW|ϮQ.lnq##nz NIGUE=wÐ^hLkE%OiZn1.7{82OYo~N֨v7; 7y4"^s;a1o^.+Yw| oDqƺn99MML{3Rh e*x0|[B"P$޼<̛3 7lP wd #)Gh&[7dto94iB\sKwp 2i7+(\+ |˟HPJ$SHD]8lT w =HaUzOgz>u>{s1uLP81=5M-mQ0:p,Eu‚$.s,yŸ"Y~![1eLz 6@p ۰^z#%`-m59>Ixl1f/`o4qas32aOrr@?`kX!Z̼rsY#rph2 qJeLw}$XXh`@I1\+{ź}>JJ$y[: J:3v7E0qoxpo۞W=z}#<7j}}\tkK{g2p2YON;FX%:B2-['Q=]]np.(.-dZh#JܜUV^#;O߆Q@|GoxL0iro'xePT4bԲlqb[V*r~ɒl[K&LW Q:_٘u_T$2Tu9ݠlݰ4D6Bl$Lir;)Ҷn:FFep#KxE 8ᲄ8,H*uXRZzE`AD*)lB0>}i5nFV6 ݪ+tMl҄nsu<úA >58>5n46q]5>nŒ{x ~47[wDH/.)Aa3 !-iRٳxWGm) cv;1¹q'I ǐ=Ѳy"j9:j̷.$`Mp8v{qΦc4?*/+oJQ{jl{_(Y$C mxuꈫ.8I'IJn?s)p2rSrݲ=SIrĐcmcB\4tot<N}_X Ud30l`ǭɖ v[si@M{WGG`ܫ@[yN˗-ٳ|ϙ2ϮM`ĈVBFVHNɟ;x_|i[s q:mn)3f=m-ܴ= Z-G1󗯓F)*|Z/˱hjtjZy@6 !K}ssqNÄ)R )v&THl U"%-_6nЖq#'.I<`ErSɱf%u Jѹ]K_e ."2$Rp"cQid+pߛ?>}P*Aڗr͘| ^٘0y۠{L0ye!#ѸF[tkn-Ґ,,Glg5PHJ؇_Y_/2 {wjn/ua~ryYOI1'#Z:]ipK?캻Kcww1\ºƦ ^ ְC$ OiY9FOzcO()*A<]Ej,ֵ^}.tVB]^x(}'vnBJS${GŃ\.ҲVp..wm!0$eN02}pYoA.mk(JFVڋOEv-ly_(yx-=GLju&f2Jb!Gl$p ͸{,%$S,8Y43#BQ%B7^}?,8Gcbb,jQ"ZGV۶eƪD![?r^.ŋLo'>mDNa*Ǽ?; ND^MpD>l%YҸ&[SYn7!KQ'܄7?OAM=8ء̭_6ZG7i`. IC _8i`xX}:qig1rhLPӜdK= ٞRaKm4r[Cu 1g1ZW=b|0:L*J&\)D-b7.X0&oa9^{I'ޙ0=+Y!ɩZ[XeqyP_ɞ5ºb x#ێM9(,w1 mD2A99턣~S d#ಓ T0o`7luL"#  ?MɖyKOq҈xڳѭms1szúoFg7Ø#b7kNAA(86$ 9R r #\%oj>*f6PՒ[S3~C2J+BEn!9J>8cU5c"tWiiȍyPNx39VKbw`)w$.Y@S7܎mt'^{z7VIUd#DzycTӞ6MK}jDiܞo#J6WF \!=- >01r!ЫO_n2LS)rz,p 7?QxIP6.O3VcThݛ`UꏓNjww\k5 9]xp`0 )it)SQQӖp9;W=?OAE\ ,G=OtZ5Ŋ[qs׾۴뜗$JZ; O^&dieZb3bʫj4L[JjzqC ܋zH#=zYzaEu/>g .ő~}8S5Xbwf LHM$m~- o C;p}L/+sƱSY~ysXnb#hG=-v߼%+_]=\6uDNɐ=Fn-i0aUEubNxh.;w_y&6nMCo~kפh#cW({1cu_zԦ~C<@w{~9ޞ m 1/5ws;cN:r5LclPXPPO"MZAeE(FGEXTH» &63S̨1HV|҄lIBSEދg_VoDvn> 'L->K~|jLHJG׎1lv8 N]O:EY 6|7¥k5_ɎLCv{ -s|ߧ.Q`jcN! 8Mo-v6S? `ovkڷ|S7璢aE-?#p<m=ؕNc;} .Gz5=ѥk!-7ճ^\7p?xffINR. Z$*!j[aHMCKŧĩ#᷾o3JCs{؎PXL[rެm l/;yi(2ױ3t'cN_’W_yӦNEֽySN~,|E|{o`D[RۅfYsVp#P.+BB^j=n9lݞ(]h7׷eeL{Ļ<_JHn(tpѐu+{ +d'gH&UR)qccyLfȰ AIFb/OII }]38e\9_'B1-x%-N`SGwG[#޸e8T9p/;oeC!2qsTdk[V^Ju&Bp-ƒ}ZBs=7o;4 3eƦؚ[wf$cej1=q9L{! 6x^l޽,4P#D;}괺>@ǣ3䋐暦k[}3^-#Bk4-:9( > Af6#G!t ~Ձ43 8_;e9ӣ%xVEEEHݶU+rSel{WBԈRS17n|4FdྦྷH򞉼?5R(hsL&ٞRѕ[|`Ex橧t'9Xjݺ*((HkRvsujk~T㲃[]:voo0)M8sx\,ʼnPi yB%΢|*-0ۭ6 cu(rp}-CC6(K, ڴͩ/ ς"wy;Ġk+č`m~Ut,C&ɾ1u e{?حYLy,ӹhu陈 h zIt-W˞>qPC0/*u}cf}5~{tm~})1(21w1f^ ??+;.1<<sT|3 6K%(/)Bo5* 8),$[nKR7WK>^'[1sr ͐쮖{22v+_$_Rs6ҸW_|_ARF}[UUUja!2q$N% )\ cSTTw~~MtUo{_??<C4\=Pύy9Wx~ԋF4F|PrŭV KjoxLoOd&)9fSV4%qƫCQi z7E~c(KkG-ts$>ڶ3<]%[`.z?}."Z9e#6f`S{{HݞoJN@Dh>,2\Բeeeeu/>hfu/ bcц߹S8Qǵ6uTOPd%˵j۵@-?qyt\{i-ZٹJ\'6:2ԭx+u ~Dp?f,¶L}fJ GFf_n k jeJT7g\\/M8Cq?⇩x1r{ f!erd"eˀrm]l7SHEC_x |g5{aх[+ݻ@mX`*qz*$+dmgeI]D{(8V`6' )?=ٜO~.W`GFG(J_{7l7[rlkFl6ĉLƠpG>%i+쏛ob2D5=_mEGuLmY x쇕HwkABG#NJ.oe=y=iJ6!ךq\R\67';Y= h+L2ޭxc|td~cՅC$+v}Ab .ڪ %`$٨9j ܼ5CEg.ZSG@td8jY K0oz]T';8Eܾ+Ncw^/߸o?}+N?(3N9P#9r).)G_lŬHLn3/?? P`_4[ 'XI39 D{.yh"|qq9>Fg;cR@w  K*Jv+{N8i`䉆A8ehnQ(4dYKתUOܣ&#ԽMWø@IJ'dEh?O5w\mA۟Pw? =n"=x[9y$ZY*vW[`n!%2o a㔍ٳfoC̲C{!ZflTc9VQO-u:1KՈ[X8 1n\Y11[[aov?5qr?M-&\%]Tr0q^Ȉ4XEG!*/c\ƶ<5;"D _ھ}G=n?koCwa X$SuU:3 ^I*JCBj6h=Jj@vV啹+j>H,Y9zh8{E%j5K*uӈ=qSם_.Nve:[: h ؇hg[re&58\dDIo%x"CVjf!>yEŇV;r={߸^.u۶qjcmn3aUGc]Sm]ѺN"%NRE\bTד8 V?at 6Z ֿ^7Gێ7 AڃS_ʊ^sTl{ izj=.±6MZ"[$O# EYY3{ш4H-&P1Ȫ?$ン;o`V\Q#5m;wN栵xqV(>2"bF2sm^1RJʑ9RI 6,X I~ZL WǶ-RbdC!dwo=v?՚ 6[ײ sLא̒BδV]S]|Ʊ:~kW0MoxD(k1xCm\1/ y]ye^&\u( H8RY~:8N daSH:ଳۏDI %ضͳ۸cR u ]^QI˷_VmrHH?+^b"#0ICXG"?itڦz RYF,]wH hz ,Ӕ[EJf!$ɲ]W??R@- IjW4VW]ȇ{ȶ)[$x<+AM3SljVۢyZpZjZ[W*`$(\y;h5.b1gjX{BB]8!nnH%{q񊑡 YTb/>9yRQZ':p6VΕʿX6nm'eqFl4n;\8e[n\n[5~oXM0^|Ү ]DGLXq)qqƙݑf.ix=&ŢgeSChN-6-N7pH:ZgN:_ii("'UwXL:UZ鞹w|Y:b\ߏz-cҤ)S TT* ;)*]D,cff5{ X)V)S>Ah/0:v8 BH;񵫼 s97{/(撢.)a!h!'`yXMR}+?={EEE\.f&/Snyw[n;O65;Ąqәz +?/?T/9))g 6^Yxu: ٺ]?=[JciHcլګg#44ctGwMre+$NeW(x+ӊT. 5Mx$6leÆU~ι]sŕWa/-))䣏L ba]&i!b5dl!lC7"=+WZ={urKZ"*2 EUNvLH~s䠞qJ${ I'dZOZrߝ.X)[2G6":AjW`s S =_L#~)\R@I1QJnwueҾBTlr]ꪼ36'"e[ Su>8)[7Iel]hsYG2={r?!dJK4FOUxאRM8>b]!ץكc\ Fȷ?r+l*C%y{d0,XhvnuL~1~PՖ_IN>0_ΓjktTXByHdKRm9~x0n$f @n1o|fy˖#pХs7[|f:&(,ՠ8DWsiD?˧a(u. gA8{6XRY?d㿿Ǭ-v] 8+v4'Ecޜ "fr-+ xGܵvbKn~~~ݗ_|j.`qaa/BgBF\Ydldg2Xp)EE\0VQQA}Z<ϻKfK``X P~jʋP[Vea Y Gҹۓʂջ[/動{72 L&R%D*ry¸1ir qb)S xg6w,p+X>\HAA*mX0Ր\L ޕ83~= =8FK )Erޛ? eEwömK1յ}_}Nu0p I[^hMbwk ş⻹QQwz/ R|:n@gyy5~yLJ kH[q;=h-rQ*@ \z>72 f͛y93r-[r> `|S#Bh)̊ުN+mG=$$!Z[%A@SOFf:/(:~ݴp=xF?X1VZZ)kʇ4֪dgx?6(1Xj#܈`!yWyE%-ꖆΉNPPhuHJ0LohwޙZG%~ϴpmv?EvvfL5R!?+iM 0_OÌ߂}!@YꏏoC@`9z%11 :ct@dT9-v=AʪZZr" ~3SS_'ƌi2ظd]p] *lفۊɼT;k6d.nѣgN=/Ǝ돤1 ֛M{D60ҵ]{\ƪ`O>U&!*>DGpp e"]+3Rz[Sy a|NX^};D+7S6qA9 <>g[(*BdX#Z]V`}ų7!itqxX|IL|vrq\aFvyO'9}ks ֝{K |nyX8318$D[N'zj[1r24;2ݬnh4 7/\|%%06sbcbؗ?:p;L}g7ms-cPR^7'ԕi[w^ Z''y̆ Y*S 8}OgU˅iJsvo"3c{w8}-X$Y0II-бSzc4ؖ>ɓb ڠ(P"'EG՗$&ir՟vٙ{s uwV\V[V3%=؊Ј:e+I(]85Ũcrv32|UBwq(sxmhB!ލݗ B:k'lA]jg...>\w.4Η*|jǒZX(n,=װdclʿoAY)5318.3.c'J%)s!Vܝec\Ug'q0Xaa4uŪ*͗vV=E-hZ= {Se6oS,r[ի[=z6|yYV*F.4q 'Fhf Œӱz*+7Pv-0kV*rrL.?{ۭ~Z0~;ᶑuLn;~ڄ#l@m6>v4>uMSzp!qz@֭U"& }6c=֦{*fP]Y5޼9iFV|(Ԩ ]0aA()QY=_cǝ1ocNk( {Mͯk a߆&|GFF6`NvCI"=(M0HZ?;A"6ާ#7AZ &S52珍)hUQ]  uUM_{b^7LWv dR';H|+SޖmiY)0w3{O#m{^Zi4EW_|A!+‘UXQulww.(b(vbۍb H,v{v^l웹sgqn`[IIIA*eLvTphg~{cw`[A]Ԗ~xׅd 2Xâ.:{֭Hnb}ڽvOPr\/}v#Z,Ah!:.瞽+ȑ)UkQ87D?5<ᘫn󈑣nFօBfwȯl HZBmFhYB5.Ukj?W8Y=F༂LXU* q՗+def#59gs#{^^LK-=mgj 4,,\f-bE(- ~j9W?;=åͅ'sw XOM|3[{8}=wZeXSn]c,Q(fWؔL_hܡ.eL{chȳȘ!<[[V)lA^,Ba" kXtGޚx' b#=ccooڿo-\xiƵ݀C`.֐6h, *gr mݬkzɵځqضm鮻zӔ)ghfE[D} :ׯahn>9b5ďӅB9T+];3cQtι΢c`Q@K/-I۶-ʮݺ/;s&p-S"ٿ̦Cɇ(dݬsSmKm8\,?oiD*fN~=t83|m 0qͨj ߰/g?,l b"MKIb氚=S@_N͠k~^|{&mڶWV&G4g]0>yu%@E& saw2քŷ&Sn~!mu znkgwwYYIä?Bf-t,,**ŋJפh\U5.nuQcϭnڀGuH^FLZWh2zK?IUGT.p ƫV%knN1ٱcS^qRߩ`f,^SQ1iȐth;˪@D+g}Nc.}[n[{9eP'V-}>'6~K|[U S8ɵFdޚZAoКu[i,q&]CiVD~>,}XcLeȄp aLIoҢe(-3WrKK-B9yt(5o#4zJ7.ZƢrC @ ǑgOS:k)ċ5k,+k6Fha{߃QFd }ѫ}vZ_>e b>}t: fTcAkcBHnnܜV!nM #l矟H>:3l$:@=bݹkqa@\?t.j#F$pnuL|*+ 0B}  ɕ+H]Īv2U۶ rF^p!]wÍw\reۧ ,DIIq\񟍏H&g+,TYMGo;,eDzXLMc&BC^6j(M~psq=c! Dw'bŚ]OW>wJ"sQU7Lxc|J Xjxh E q0~Cy&k/Y!^^N/X@vԻQ Yhl e\\BB~5G>|X,K,ZEM~GE!U@ el$T@9SH?0OˣqWx HSO1dl|L9* 9z̡ډDpEA]paW1]׵{Nnéyٌ%L dl"dyF%%g+@NT#I470~yF}hO^B_LAA+UVkVXD ۽/|=O~/i_3 &&³҄Z"4Pt ٸ/_'s0(Y^Lʘ܄O6[(^>l*_w!d1C+E9y#mFS2g{X΍+"qXع5D=Zױ]AO `mOh@x{{ӊ+i߾}V|"yxz(Qjjni`!$_9pnuƏ0\Сl|sw: SثW16 ŁME䙿 D^5nx #0h斸k?F~܍XNag}E^<\*rU[k!uBH!Z߳e\frL&^*D*p$ a Be\5uD1ąeAZfh^nP80qټt23SŤ:cSHǔ, &Tn1F*$f VѮ)BEJΞX -3$_&ah"ঞWX[fwO]JsMy2 TWS3tw bs:DKԾ|55~lʑQ^NR6#pc?}5ֽ{qc7_Ϧoܰ~K`MnܘAgW[BEQAB.$4(C~RV7kB99rN^3ϥ"j6n/u쨏Ÿ~aΫ8}Kpni;1A㮾ve޽l٪թm|duW_Sp k70 dhrP+5-PZ'UqHmܵ[$:c)2,|X Ze;1 43hLƦb/ʵ[iۮt0%eJTL 7=H]ڷ պGaҴOwQllG2?DQX&n5N1oSy$~-@rOEoIݵ(zA_tӢKXU%y[W^$cOfΓ Z7]e^$ޫϗx7=S+JBb!t9g4⁲shD<>t4OucK.>>nt]eIip M8[!7}u_qE]Qտr܇n{q{?¬@;zmp6 F_QXI?=a{fϳs`">zYgݲU?xi/غ-UF !1z]ȶe3cǩ㳠 LXByrx]'K3L즴oTGLد;nӊY͐$ O!|;6*$T лo{^>kXY {ɺXV6 qcG^~<ɚcGJZ6ٟJ[wSG6Ӊ-cmrU 䛥\bse>ftA/ZN4a?ޛԞb^T1C@ 6!;(aY[4ץ[wl.3ѦM69ѭCzm +Sk^+jؼGz[?Wr_XM: nrOΧٿl-O:;,Uׯ'XRGL|vwM"49v9ڝ2՟5`K,P|;,Q K]9^ W9N p+Boq baeXB|q>ʄu#>^;Ԓdie"^@ bx7f:@L0eTn;Zc_TLMth1iֽj6.M3= 'xQ[lfC1'in vOOO.{vڝӹK3-/^r뺎ޡܠYM~k}Uǁ?pn{x{sX+Np?\kuu)VfewCs)"2n'y|쁃ep ZlõkNnc,fcIuw f9@1Jx7ӳth ]ZVqwdp%lHuv C@Mr1 c,)-f-'͠} $fIOjj2F4D16A¯}Y~o]deW{·!`kDzQ ۊd5H^ o{~74zqPNt,f Dqc4 i=N<0+]Dhh_AoV3*yppj8k=ZA?_\ި9(wMY68 ]Q 0^kfXOqOZId短s)**r]se8XUVi _i1=w< ^ѝ$0߇ -0:׋1(XnnWHYYmN-0{M4 M ,H|a;`?-gg[.ĩGғ bl[A2&}h rEz /T/#yEm<pB;b?Z4nbn Y_7kؐT7TBH/֬ͣ30mXk(3ݼy efdH:myrW ~xxW2Xq E3or݀CQD;WաSn5N'WNsT˵r:hPϩo{zWn sD=a$;r(*:ߪ*n|? Zןg@F=||66 ?h6ƸWǥ3Kg&pZ:&IݚԎ*AjίJH;S`L65om޾_qU0aM0ҫO;&$ XqšU@w/VHstcTϫlpl&nl>~ze\*߲]y :-Bn:ʽ2|,Xww)ư ^^^uڿ'Vaأ~;ٝ#Y ~?Cݰq7Qvup7uʡ?krh47*/,OXʃAO4ov? =x`U,{xE(HmM؀R1CSWFXT(qtYqvNLuoahL]j TQ%D\ ;bq~&ko}2K꺲 3 -ݱ \XU:X_zޫh+ѧ@w^61|}tLx-p`w?ypm3k=@Fʏjډv Gx.}9ݹ&ч(99hUW'GDF^{daègqY?-E*K 6]sS5 )"_-?X)! h!6֭S[׳hh4`c7?hX<7ӭ=k(V ) #Ww/ +GZ}Vf jt9*qW8 \Kz|}}el ՑF7:xGԧ uD[RtDrYma1 * {a]R]x ChCt HcBW9n;1ن i y3 25kkW6'96GtҨ .Sy{uN> yPFIfw&lPDHDRx,˥?k'(7X g𣾫R_=pOew6:;yg/x*W3l)/Vgj AATȕ:K(/s_Z6 UZDoM}L `ЙRۙ;֥,M^u _.2& }'Upˊ ZXߌK~+]r%%†7{ `1f& |$X¤md~v ebUfv\Tdx< #UL Ol(wbCPf2-''l꿏7> ]†07M tnb:< ȕjdyxmڶ DF.;z|{#) 7t/nobSY t175޳qsÏ>˩ũkrKpvkùõ7Y1[{L&4 _1n}aa?k^f谖2j޽" P nI02dgN 0a m^.|]}|R݄Z&*MkUUk!Bf4"|sYIF޷s5ҔÆ7hD>Ce\$un׊؝ҋF%d /+c:FE4]g(Nx+{;fmhp駙\?Ћ˄&uGQnN.m߶Mwo!>!b**=0i͚TI˒n<MZT5._q_k[ v#3:Z;wBc9s,yCͻ;n4xw$VMMMe=vzP1+7ݍZ@*U] B ;z &`LqB0ihBDK۴iIb'!}hjV*Q@Xz(ܷBKqX# [WP!E5al4jPN@0% pp}Ђ+ĺu~Y#EȠv$9R a0e®H @yyyY^y~h̥-uww.fBJIճN(g#~ ȹ:_99~9j(85[a8ߢck>ku ]Vf͞$|s[ߥkٚf8hax/kF ȸXv`qJX &MŴbFra՞ c&YC. &@K67"W7mf}~4b5 _zKEtï?.1[t*Tm5NoF6=voS>fl Q"3YqHJ%5Z}PVaqǎͮ8h_9nmߞE3fll!)(5rɡPF7qm?k/`fs3\yg4/?obPE4b{w=3Qv}2f!2 vi%+lXOR@PYf%ޚ.#> [)=5C4LcXբ 4 N[SHYfݯ?-*J:Ҟ=7ᲡҟRW>}>9O6s:\ +a.okoCL џ߃ î>085mA^cB?O%57E=rP6Ta__yGl‹Ftg4(WNw0q?las:Nh?ڵvK~\sj<ǡ_{[}O0`C4㕴yaV4ud^z{;_Q+۶~:rgqḴaaU^P2,99x@3dR9\^AJ,Ҩ0•ZAA ؓ⩴k2D0?}>@$h?eϿwӀ(!6B69vwlMҮ%KN0i]ꘐEfwּx1J&Cq0IݽVn\g<^h6- TƊz3ڟ.]p+084>4;' Ы\"0(5|zW3a#GX]VV5/77yy%ژ'-.ώTlm#ddQ}]:ٸ N4[[9ܵs h=4i_7 ,{!!c.l3Ͽ0ͨ V|Ӌ4 `Pɇ* Tr&Y:>DRC"k/75 )1>*㩎] ƕ;<EqK{؟Nu1Gt3ҚVoAYV^ǃ 8w짿F/^Ϸӆ{e󀔴,ʗa{qyD Z+zN0q*P"ߓ+K ƉUY N~L~=~T&t, jنbGݖr_`=277.3}4^rа}hm /.n'k1cS~nu vjSnhrZ1Q5&ݛMDk PP.ڵoo:?ҥ#F;wolW416Vldž ޫ.=5/d1ٖAABn6-雏Q w:[eNTڀ d7gDcϗ0A i7j8+lߐ2SWm\c-8G|<1؟I̟˗Ѱ)@tFeFy&::^b.MaAD1θ|EYs~~L-MP% kE11ζ}ٴ^nSEVA~r9qWn85\gYϫ܍Z#7;D6lHY!C2:vQ٫WhF!qӦMU7\sFBE,. QQ0*3BI Ѕ XhO̗5 j;s(h9=qzcbVv]}puO?t]{9];ud;wjzlGizy0mH/kQ k8E7}2bO¢6}};5zH/wiudڢvᎴ g'Ʒt@8|/F ; p=8 X.yAaaQhF.q |OW ;3;gGF@0_*5W5Qerr~kڱ=LO5* o6~zʿr~qˇ~)ڹ:?^z`2YhϞLudNNbR]v{[o3Jhh 4-(VОEHe+9DaPqžLKe2b2LE2nal.le9W#Sܼ},u~:m@WTkP4/{ԑֻk[ڵ?L{:,6I\ZՇW@BbF\8.&^x+ٞft׮{Y._^x+yz3]$ ;7Hr8[(l(;7ص?CC}筛筛7mcZڲm >==-7)7Hʅ= gu O ڕCRzzX>$)Z.z9vt uS9;P@kE wPJJ5]BBCӆytmk߾dRj7yʕٻvXBYQp*fIuE?X\[TXQEPV$A /-#ڵN^=:zc In N O֞%_oID~tP:N˦O-nӣ~VSPjs#Xۓ~]!|OЮ@MD}]/XSDzJтCѣw]Iao;C+!O1ܛ"(m.)_'{lSn.>N'앫d(@ouMvJW{}/?otZZj"m Oow&6t)61|<)UJI=*ժ!rJM-ݻsh !޿: D BBO;īOkx/l9FTĵ޿*)իЬ7pɥRm:w钟njy#*8"l۪~  䂨%:n@(ƺ]6F 6ə\]Zf KEtO~V*ʊJPfKG"A /G_HWh[A}@c F`Ś(؛ /@U1Rk/˰ pѩ5֎k{Au,'?g  )n㛃_2לj堬 Ҍ?=q Y7OGŴ W@!D?Ջw߶i@]n*3igNN>x9{r9r&Q}}=(4ԇڷ~be nq}4ŧKMt_ˉx;XK\f+)7LRKuV,WjM\|ͣ/tw`` X3.U_s oh!wa-㭙(52/TbQKM%RVd\><>)5L%a 5 n7B=.dip1 M Ja 7#+Oզed 9"ܩx@DŎ WL,D Ǒr^,9к~'H$fNiTU3i. 9RTB><1 rI Ƈ22„Ʒ}9c_(1n17mkTW[ ȵ|ڳ5/G9fq/w?}0\#eЁ-,Դeg fKA^DM~~Jn1Er_)Ud6[pJJɣ];3i4vNOtttY Gco7 ᒚZuKtLUD{z?=Gf>׊--33іj?/sBAK.8~1!BUsV+6>,{iּ2> Mե=еtg~Xm:^MZ'ƚ1 ć`:/$4at!Vl)9P+BҌdX0أldX:֟vAQ17())Mxc|#?|5c"оG yq7yyŴ}!AI/ tVv-cNӱe7K Nem&`v3Bt bgBV.1Nh'_;O<~Je{h߾lw >??tؙ G]xvV3\S5R9ݡ%,. \|D{]'2DOq)=ʷ1h ,g,Y8 4ZhbZ'ߢkP<W]J֧Kh(e#LR/EU _9՞迡c>^^{[3~wg$ch r{ÿzlڒRY u=)e-33|)N4 vf7_E 6?&x.hBj4om/ח [i}̥:2t[]OFFzk޳bٲp.(hb ]1D kyCB|Ŀ =CQ.U=1b2fVRjZ>eelѐiPzs+ڞzw hRߪQG8VutEh,g~LS7o ^ NFQa0xuӏ!㶎i"v^KΠޠ{@R1ʓ]ĤIEc򥈷k},&<\d_@_GW '2;!},LȥJiAX߃S e\V/OO^6u01g-OLJJgrs?^7wnByyYx\n @8T||X`SPp΍ڵn)miT-&`hJo͆t)_oO1K,^N߅K$MMb':` xuJ6 p{i7NpEz2=['ɡ^{L)XbysLnrc#l2I&qC-бtYѳW:O> \|iDnݯYn%Rm*Y^^e_+/..tP eeg1I1iߒڞD=?&-=\a3RiRl, 1Z颪B8ʼncrnlq|4"Y J,34{#J|X@c;1=IWhYà Fzw?%DY Y|YM6t}sƍ4P;u:{=*8rО{(!6rs2Yp͔ ZS?)Zp޽{Ǘ:H!!?x(ΝKf̬͢,j']ҙf?6?UN5\z≪O?!T)WZvJ7>g~C4j蓷191)(cG>V1[59=1*pxz@5DSIlK&4`{ [eAnN7>2cdj qBZ-ؔMAh- >l [IS0Q8Z8mvO+@iԾ}{  'snB<;7 $ ̅͘G`$ÝX_ +? =zюt=QaJ.pϧnF(,:ʡ:iziݺu.uf)8˄nD+*Ko'PV-)?{j p%X`/)֍kPhǎ>^~~+Z=mY9g /}"|1" J7zWlhYsiWhǧNQ^|Ak<- ]r&ګرJI|8@9tf-5̊P.1A}ɧ3(eKr3A:hʔ)ԳgO+&u>+}?n0S9,=1nnU'K&rAVq(ݙAY[Rȅg 쟸~Tcu= 7o/Z~=]8BʱdS?hFc.|U%6ʁ,ҁ$ cE7< ͰE6mI \X1Sm( ٹ[\u@;'7 C`aY&_X,q6 :x@Od!;T.,PfΣ&\{x›W?AZL =꜁cU\)#\viibcO~_aMި wғ@riJi,sj"[ O@"u4UѾD;/XbKi^zYjFS)OSB>,M4Iʣ=E]}CGS?L| bvzG(>!eK9*6THG~@z[ ("vp9{ؙU{8ɴgteG7Ezd%,v<B< _;t˚*bvXW)҅Rȁw!߼eg.dXAB*ȵKV]Wdu!'*E0篠K{&_o%@iraxuLa$C)e0SENtwhŨ"oMi^,1Ҥ۷MF[,U{Rye9PW~ŽCY?#tyQ6KaDAqzADyͣt:kϵpiA`i_0_~e!HPDӀ{koNܸrc0//Y7mٶL[nV -+[UZaueG_zn&Z`%L{O4r^ v?S2nCMxZ͕2X:iά.Rq_]_G K]cܘ2Ј?b޽+,y@ױ ʺIDAT N/(H1/  ?kFC_LXB6ߗvMA|=Zd-@L' F@Cc+nޤI>tY3 d˨'E?;ͶQܠ"] {L2,R)N9b=T0!K.} wWwnv:H~?aƁ~p6@)z72_~C@W ( 9"vySx:}6.:ZGP0 Nmiӟkw>=sdPK*#CdbPw(y-ZIoMF7Bvd+>Wrtqwͪ'-YۼyF{P:uLnnܘp,;r{.]("2B1؈!:&Z 5)bD ݴ_. ړ81Yv8@#k)ט\aA;GNI@Zy,hkөXZ}ݘÇ ME%ܪeHxբQp@R0k 5e,q"pG8bFS>y/[gVvgp8şv!&uoLe|#) ;$BF('bT!՜A.M>~Vp+aÔ>ƳDyfFU3vNImPٍ3C89p5J-]J3ڵkA[B94coPFv&O? Ai`ׇdU$''˯7"U+g /M%Ԍ4 |4s淔HܸFc"uomظZ(\.Թk+X#N/~P? Y{r*E-pcgo;X.vpԁ_=_n^ʯ:oRUNeTԎr*憆~/_ZYuV"p">̭OpNbP5ghbrT>aE dYq.k\Φ*Y?:_Pn~*‚ϛƜ?\j*Fu %H.h;YV//gA.{~k@}!<ٔb.g[Shߣg ?,96w Dsw}?G׿25'' ݦx8eASX,6λ+X39 5irjj*=,GK~ %_>\4={VɕEsc5^ Rxً.R:ŏ *7lΠ|np޽Fs:TdT :#^.urÁ1W3kIKL%kOsH}$,6 pn loz4=-p)jB (4@=|fzOiCb1 #)9EB+֣|* U~'aR釹)ÙXjq HϐN(iw/k}0d68?ހ\}`?);B_SH8kHkzҪ&[ ͓pA^EzvB/Ly5@k|jrU8Y[Իd1CemXL4;맟.B{ B+Vn:K 4DlVDn't7&O=!J>A[|t 7eq1罂~VÃ֭"iǟP4Q4%xCu2B0ӻ^?тhў$iH:B2eF8@ ߯,Ӆ(߈C47K - Rd;siCrk'&3DHFQ =5b|v;3iEKIJVNlJupGF#O Z.!:i9II[ڲ$I.voKV¿RVnG1$`FgD'֞&H\@8`M*(&i9hZ*?76oy6lC+Fl!["][i fZi@vrrN1hژ}̶fPΰ6aԁ _7 Tu-;tM$Kii/C (!Qcd%&|dM1&;(DQKXk53)]2ocFċϥq5+3&OL={''?%aґDK"@}goVfى˸-_b$&3~&{dؽs'lzhݲQIJ/*)*,(0+Q*枚&XcvwI}Hp;HV];kt{q^GTO&rIc_ꂊ,Zb4D[J-n 4Q ߃Pg lف<\L{\!2VVB Z0`|'$aۼslwPb\ PS@OJK d{SpidCW!sV5Gm[ /$z{zl>NMV7Fa~>7L8Z(pL89_m z?[oRK&I<( 3<ށN6~a߯h LhĖò;zpٳ=lM*zq hٲ7_.!!!B7xd!8YM4LOK`4dݻ7]}UtYgu}{ N(um2`0דh]45Ǧ"(`iO-78,ഈ\Ԫ#0zq3cSnt7R_9mXۯB Gt`&.۵}khdok@Ш( EoUFҹ-s }|ڼ}<,+(H &ླྀ] 2~ ب0j*"Â(*"XwY!\(+;,A&GLҲܳ]e.M |GQbΜ_ŜN f#גV|HY4;$1ۣYKz9;i54Fgs l6WAx.٣IdGL(Fx}ɚPFmD Û+Z, ,)+.\>h:tر1 ]]b&)))4l0*`B?>nZ,Xj03\&!7w/gӗ_~A -z.FImڴ];wEiʕa (9qh) 0@6}x@"OU7yRpO%DBpLqN~#9 |qC765 ] 6WQ\ ` h"  Cr .Zp(ܰ6Gq1NmSXjšgtBÞn(dk2G@ Eށ2q0RRHJpAaa~^2aJPP`jYOo~G+NUN8Gxy} ;w >K7o.'<$K{@Z5@9d)_g͔j :zkn $+/7x^%;ڽK#1oOkL!te`vٟS'?@ёQ4|pٜG׭׮t x/CXH ƙ[{ԩS'*ͷUԯJg+BHO//,<r5Δ a&R&i/`pBFe Aز=A^!Mr\+an %!­ܝR?5 ÑѨhAbTbT&#Ã)vvÂ)G&'R7p ;o~)x4rHRDOO?2j/l?B3Dyz9ͅw9D;׺6{60@EOETp`\kﶍ Ve0d5#BPm:ڣ &*40F}yE:?.=,yɧш#聇_jօ5|ɑ4R~%,v߃ FW_\zׄj w Ƞ?Ks̡.]Ì@y5ލ~Ҹ6u*=ܳ9+Nu>kX JLBD/5fBn׾=uЁz%^/h7zN8<@GibU V{$%/0vmn<K^Iױv (X-(q*4@ʏ `q݊B;%߈8` K]Bjj*Nʒ֢FY$Vh]r ۋL%Lt5<M8TcC]NӧoC$LҢd_n<)n_.ViRц?kxYg2V HGeČ(raw{FLYWIuLOFQn0uLD |F PYE?0rS^xAjcd4Zk$,=Mrs0@mp`XSI|!\" 2Ac*.KiرBde& =hHi켃։I*,d1Z5fCӍeyީcGJLL$&P~&**J }I!RoIYUV*`YwԐ 3VL3&(0Ӌ&QK%Y0J}̡,Rfᣀ Qe? YH ؇pʭ(p:6}[ QA}7 ;Li_K{"`rUyq{R"-O%a{Ao| W>6qcFhބB}[rasvm:c#kVO.\E0!>n8/帹Lgέ@=$^S$>77gfsV}؜Waݏ?o9 =)}R(zVdtDBmitd0vIӐXJ|0hД>t9H_h(8PXkwf-= B g,2Ɋ(A ΢oI^M/]4f45]4gm?68w6 "sfJ_}X*dBŞ2C3eeâefbC7wЁ.8mPNCX=j}rţwop!39ΜP)*Q))LYeFeTq8Jzoh( _IBAe":g*<,]pW@bM{[ٿ?ض6l@s09Y9ܘr.,`-5t#t"q#3StwUP> <8<*^ر*.+k[Ck hNՇ2QnCx .p ڽ}=ڗp:G'ލ@9^ oc!rѨxѼ|n&ݒ\j{:~5|03Z0bSjbb+l/09@Pġ74N«'|wp䨪7VPc+ݍ$*K<6@@I}~/*'h:)D'"9ń-i"c*-6.ص*= <&j`'*Gp*&G`-ơpz8UZYY2-f֭['M ?yvdP Bܥs9L.A,:KS| 3x]t`ڼ}?mufrXm' F21Gթh*KSƶ~\yss Uv6H]/xb tth0ÇI_U H _T!i4|2 yEd$郮hrVc헙 l .Ѯ.*ҴZ= Zwia, P~] @8c[ J[vsU1ȓ07Wz&"Zr5ߗ|VQT"TP Ĥ$Yޓ͗qW݋.bֽȔ8q4M ī6 0+"˓'VaV-5֢MlcMA),Kb7QX%,k&`h|Za)|*a-5}@iZ5{q>*L OAAwp6m[os=||ݞ^2 ?ʉ_T_gJ{X9L,$ڲ&k1 2ocE~dDk8\ ]!4\E!Z!q`bfJW_rhpQP-ҢքܥhۻI~ڻ3i?,=>BYӊU,XK@X.CTWUdfsfv}#ZYvۏFŸ'0Bd\\ .fj>aLn@y.}!}8-[\i!! >BCÚ Uo 0zlO$j /qd1vUt?׫$+q&C;Թ=`KY,^KھmLZ|itԳgOgdZ`L1Dp*3|U=:Ybd\c9r4V_t@ǹYl} 3UҦ^G`;Uɴ6|7sfC GA|z<<pH R\ύ#mnN]}ݵ_wI_}jKf|9EDK1@k D{ h7krCCufaŬb,|Lr!3 ; ( J'czs[G'\OE.,xn-xWp`1ZVAK"3`qBt[ 05aQp[y0' tba.[CAmtW "<*NOeҒƘ AԱSG>WϞ)3/X'%v{rsK!8\'9m3}xF%+"p}]埂jU0#.mbr,mY-@2A KB)y| wIxG˸|ihזZ} d.ߔFZ$/E%\#~(?',@]'OgQf9fs"333n~Y;YrǍ4C!׍"zBu5Ai ̞MXoR[︍^y72 Vs࿨6.w5|hJtkA#ȟ+Xs{ Z^Lf{Y.4Js dbQI`'""F>qBԨʁ/qtv%b cIA7Y5NkˠT$p6pȃ֭uО:wL dm?Cvt!@-==x d!k5 m 8 BqFQ;KOjclZǍ!٨A/+q;hn!_'~5ܨ a1,Hr |wpxG%O|[NeۇBÇ>"$v- )+۝CպsLݡw| u%Bfh.q,&Z,s43謺IvU4ng{V[xݐ$qH+`ߦ9*F#. IJfTpJJ\J2! @10n?D[hᠠ&:/*ćXEZ,ۊ)0 -0C/ ؇<}b߸С1jʗW|+5bǤ1 Yrp3(_ 鎉NX;  .]xth/}|Q&a7_X3o֘H\wH]Hs/0fu?P7 Xih,#< r>ژQ܄h {}328^/;΀q c^*!ZϰXM$i]HW2_hޕC+RAit$Z!EX&F`O*:_X%eҔ5^[w":`@I{hCU={oC~Na}>pL6hƱG xŎe#aiHs f`l<22YBAXh" $L,L,%BG&C#Yܷ w]@<OO}db2tлt;a?"޿}oY':H^)?de^ݼjം+5j;6ր1cć\8[pxLz:>I5z=0 ] Utb򶇏 Q=\? Р JvZ6漶jzTeTފ d@èbbs:IyeqIC)}ɹx>tCC_ZJk\,pi"t??Xfym~+,f?D  4xUK*č1zbL(DE#ܡuSp.vn>4h<"ȯm: sӛ"#t`TYhy#8{8rBqn6ˈY;^ e!S&E<ߥ];v#^wnƝ;vV=2!ZRz8Ll VYy93?˖a#qptX{BS3$47ߒZ(Y@>L=5cR z2#WbZ ~u`bXҡhqzC*-TRb`B] 6 f֒N%Y)TDFlFĪ+H.GE4@8&g%ʝÇU) qW? 2?+@./l1a~40~Cܩug>+K=FQ\VAfR =,8B8ЅkUe">o b-kh̤(|Ϡ؏&Q[&c?=UMW{_Su2k@Sec/x:|8l/8F^0Rh65PpXaW@͓tۯut=ql %!**Zf+ ִ@FnL!1IJK)k? 2@>GZHQqXF9){0+5Bx]9$ LEh为gdM>/=py#"-iG&8DZtY 9Wu_hw9.|uǔcq^>-c+kș)() S9IU<-,U2-caa{0\'%_].V̬>„O 3# |ZuQly ʀFCobFu=?f6mワG P4<<wX948sLŦRz ב3FNN5ةIf ѶiV j,L5 >s)h+ Oi@%W[[""hR3i\,09S R-53aH/lJ HTTi]aՈI=&d(i=ze)&lY Ytϛ7nfJKMrֻv"@,pO7p#͝3Gno;p9ʛqa;tԻ=P0<7D(jSmq;xyQ* C{x?dpKY Sȟ s+VƩ+chhF~_RWG{Pgxz&>n$o/!JhmʹB;D'vrY`wʳX[껸0Ihȅb_{r!m0!"P !(eۏV˷ ׃)d©gJxEc4 XKHHcvŲUN@%Lͭ=j?f~C|쎓/c7_)a*-D"[EE xiʋtՕW}$i?1gs/r*lO،h;t \bcMl`Q,K"NjGaa!M=<8Rѽ7]0ȎEn=)eRI-dM1]-0p@;[ZN~,0f먱 .\Pq+I<Ƅ# 8L bA|;%i _a#vfͨV)%FUm,fPEfUW8%+ZA.*+v 5ELhdǙKӘ &)iB7rkL`.U!044"z'^a[(ffg< z \e?߃bҿ(exMFk6ߛ[ ~q2ZQ2 e\ ګ|HaW|q$$Upcrs)-5o~{ ɒ)"4g ;o^w9شiS>Jiiim{BTĺef뵚 O}!rt#{O6l""X|{M4lh#o6ax%yuʛ\BCXTfwqYܒ h*u gh*,TLnTFEi4- ޅ+EuHji{l_q_? *CHq}q-h|qxAz!-fȎ;K(ڎ2FOTw4)dQa~6Gfzk;@mn$*KI{}+ZO-D6ƒͲ3RXҳ > < =m;Gvz{5. Db-WyONy{aT{d ws~{n;iƍlߖzaʢi/Z_ő^H~K.ڵˉf49roŒJA&D˕\ݫ/PaH=!Ī D;hˍ\}9 ʜ>~܀=%ioiؔ@iLuvPZ,(37 dvfl\tc ~fs1VhyE|fݛMЫE~3߬ @(&: c1fGXByqqs%WXB(Q~$Y{7i;.Z2g\P;$B_ ‹>K0d *e5\mHH;-`FY۬d R= m޴ɪ*&+/رce!nfXcGF-6L.2ڿ?ߟ^yOhؙjʦf4)l ҝ+i ;;~0/WXJ)S?uTzl_iQVIa[IIW1av]D}ACfk箪;nXB+Cz8L*(0蓏Ŧ6B#[ Y=p}Bp0(FC,ukz띷eHXUP_ƛ{Z뮿j"nFcaSZ}ɳMO*ho oAkQP<\=/5WD%-P D)1 ֪ʊX踑ӫ+kqLfrrQHv y"cXPئ-..<<(00:w$[o}{ Ԯm[ڵkؿu㲧_$a ].s"HT&C|)+Lb fxp(G ?YI6D'ݖ[(0#F&pG _\V SpqM ذxqx5rU>Rl2o_ 4lj={Ӻs#oU4YLZ 9]w jՑLi9F`-*,s=ך@g &Ľj*=1ȠU+VR޽):&Fx7ٵk³q6P 1cȾK/tmƩ:o<=dȐȊhp,AšX+,hV3b] a9@ J1${0)g0(CV`ÞGHmd,18.z))**$]r%չsg)G%%SeAda{JC e=|Í"35em8 8]=0L ~eyY<mX#(l1km5g{4>^Xb73$Y`ChhH?׻>ãBU0e hَ"I~ѭ8i+Ȝl>%Xv-'k;q@~941ݸbrux6==f6Z%}<bi⣏y\Z>d]Ӹ484 1a_P᱄RCÖ{w=ÍTR[+["Tc?Z&`1shxM&! *в2[bX M`]O>BmڴV-[qT"PJ HzG詧+Xps%Xšpoa'*݄m-@*,eU)L:$jMZ³16ˏrssnZ#5xX{{ uHAm{cKUUeģ?&֕0wߔ1[<.1Se0!{ vwI c &#G7vf4P4q?&@5YxOjThxSP=Gd-L Ң7Ld1NXYjfͭڋQ$k ʟ [JГ?-M-BC^;nF+BcD4Ν:SmZwO.NFPϥNރ([ojI,gdI+ @eT$ix g\ AQB+,tŗl++dُo&wam-xJڢ̿mYس9.rANvv]wA ,MJlnwX4<_)S.,-`bʧt/ZD׊-ʸ1j mteuRR ([8+x- oo=?E]NM܌&Ѿ ,^DY6d**$<)Fw/`s6[Xh0P k[.RZf&+~n,,]?&2M6 xL:9D0dfdPVd & P:tsFRHX/֍PXhL22(ko:gcG^x+yz_H8jM-ȤTN>",04QQRd*K˄l*.eN$؉e~f=Bd }=c9ш)HiQ"eLsi|ر_ duтEtV-#+(B1G%Myd[,AWM:uAUVdS0_eɍAfnȁ۵o'( xލ2ŧ>$qGS^zwi&f8̘={RئBc{/L8zFm[/2:<!Œfy a~|147K>$p!W@\8 ֙L!Qnu]̥RoYߎsfYY-XwOdL J[9Kdt JjMܸB!tPn^ZzToiQ!sc ݴً?`-KO:̑Ii, }cнA.%X"*zoTNPGhmK2P J3(tСkӠ\戉O}YN Y'7ėgN}ȝJ7ԀYfegG.Cʊ"\\_{sɦ@AXp.E Z5^ge^8zDx|"=RN/R/ף4SiлWo.ȶB@iX,<1ĕΕ”v0φ=yxWHcn @{KJlɂy < |_h2h\ ETqCX  vI~\C_k^̤=F]r {]o>MHn̅ˍ hNM8p++6K7qR R9V7JsRݪhLTHOg=$Yٱ/9\Oc-\O!4؃]Q]Y _@>`>dsQaU٢fǡ54֯[o~gkT> }Y3QJn!# hi`0 x[gRĬL*@u5WĚ\}XtbmS}΀`/;7&z2=W=A{2<(MG:ǩKLj˩̀=BA0kB> :x [Pr2-_YcuPڼyB?_jC" vz&#]}0Uk)<5[4uq 89 =t73yVH~X4T/?r+H٭(;u!{_TK]3<Kef$ۇiiԧO_ }s ۰=NN5j R1 Kf~I]8|i(ʒ-*U$ȶO3W^V+Rt~ԇVXAm[oEx\(zk!Sьk CSh8b2)x•[& ͂whD"+e9 ΘD8R RXȐE~Mȥr elLq2)S7^|%6Bl}t fV16tIdaBf0 3[B_ƅ`bn&RU@gH ?5YSEՋ[`-03A[oDϡp_4~L&ޫ(?RX,U=5ZfO#zN!lǶQ`΋YE727Xt'p(/Ï~*iig%^*c(k^wt-W]q%=t8%EƱ]pх58Jh/Zk(xhG\M)IqZ+&Q,0gJwTX;`ݹrɌ*Vn$遼*c᳍5Jt}E0l0;r"Ja2’w4K Ze}Iu{y3bky,tBE[ĬPF9oo/Z:6.)-R&cߟ>nv_cA0C ]-;]LKR"]8^QM'ec%2ZY C(-%&*IY`N.؁=څ!K H Gf&GEVp;C%Z iM~Z QϖK/ &RȖ7^{Mʲ(M7"<^߫tϽ qIw1W { {s _GNhFcQ#Ѣاo?}b7T1t%*e:Єj5r'ypECus*, fe\g Wou0IwR ˧&4C@LcD)2DOe>~.0S. 1u?T}]E3b;qJ42_KI1wA G6W_9Sy!Utew?@_͜I#pMrذ4ADK6~[4~O/J۵ ڞ^aթʷ\(_TY!C0XkT(ϥb\CUׁȂZwuj rG ]^y\dmiߓ"{ c5B7}~a*+-v3ߗ!۲#q-V{eӓ88QfUC(U^h괗*pp#t$ی6XZckBffL= (X˃"]k٧Uv,q$pՠpA@J s^U' t_Ӟ b^ZF 鳼Bz:#Mϑv} MWRaBs<6t@ełE١{1ĵ@ABK+d-Cԥ H{uzz+Ed}&K:ғr1&͋PIa?m1+= K^80Jbq$$B&AۂkeE8Sy\bmεK #. Z!ޣGW\/ ꓕh؜? Etl%dm԰@('h&[}!?G&L[!Qh \d_[bF{0#ƳqGFhƑF>\٠Y*P-a~K9aa&ѓK~^hKr3";vq8sOMY!\ćtZBz2-ab}<m*H#E3gC n: ;_&TfS`RPvhwP`JoBiLڃ Ku@nuapVсE#e*uqc-5Z|XݛpW㵬qs0<N 5{M2nj]JRpF$Ql6Xj7ïl=/+oALO0F?+ k?Scb- m|g]w#ьZkDR$~8=@{fnbQ+&h ){0h#Sz&sQ,xaf!pSIVZum#kg_eMidZ YY# YӔFla8jE>m8<XhRN /"[b3 i%_X04㿂:k^(Z3a1(S.ε>[Yt;cBTk\i`"Tq-4ܡ4 &rpS jH& 3OUZ+bwU/ Utm(02Fȡ>ډѻ}b2Y?ɚGXo*o?JUdp ˾د'm[;eAbh+:_m`XfVqXy&(mNG 2rWpN/F:)ēizDӦTW^ h*o\0[3(C(?xe\x9u (^ѭpr[  v۶mt͕d<5)JA1Ӗ-[Gi:r86Sۛ2Ũuq SEP! Jpx š(#;@ z sݕg$ 32^&`9%H?{B ۡ~+imZ3 \dRj3 m %߄Pe˖'??7W{ VM |I1`5,759Ov@͇aшQZҕ߁IPn~@[#r2)L6t .מFzav~mټԨ,>=:*ykOU˷9<)92 l!#&,q96oGZ [NM%;o)?{ڵoOGПnF3?ꔤ!!.ؐ)Pb*` U yzS+ i)"tqamHJP0(oO ^,8Jʈ0 P& 3 k&v"PrpUf0YOPے_u/<[xy!cp2Kc2dz5k̍:Lw!&K֔8`ܺx.dfύ֚|(/ʓTg.F4d4p~F=1>G6ՈmC{ & hz0w9;hM5'ɉhڐ, ]1'_.qfS0 pamO֯l1Nс2xS*I7LlF3NK^pх)PP=n.- %ZS q]&EnYa(IֽC30\ [p8@z@7Uݍ a1HMxaȯMwIh/dHa2 ȯmOD24lwoo0 Kqƒ, #&Ժբ`Va"ݸa1VZ-zK&=8<|`p)ay'-!%cYcT^X݌f(W IơC:%Z,;7>Q Z,L tLH4V77*Ж c/=GO C0gM6%3G;Ƞ;;_[>t#]?,Y)BҭB˙(Ko*eͻ >i3V[ 9sR%ǿ0_ KLtiOٌr M0fp9FkƵ-mm6Λ%85 Dx;֓ReNQĿ$Ix@{7f˜>Y7nhde5`d [~˭uN9\uos5tMk#{N:; CIQdᷡi.\8bI5VLz{j3j Fó,Ļf4DARZJWjױVSgY΄ _4J gD+x=a]V*$ էyJ-ĪnIaK4٨f$u.R$hParŸ+Ek&KaVx@A{՗+uoLtܬfhdaǕˉ6sVxpԵ<},?d}+CŽڋK` V6%%[=x"̀ʦȨ(dfdȲ L bF4r[2Faޏ5AY[ōrN3͍% q4]z!`d;VI#}[RxJI3yp:3qE&@k8OduMIؑā5h̜mՉɖ_Fw7!f45gĨQԵ[7WmhEcTܐCA2)"ba/DNWxY Fp+ C%q_T4- f~- xkm#`Ѥ h[n˗zy hLۖs! /?h ^޴eycȟćÅrV%;XHrO77y1@b,2հG]m{P`Rg-~AbZP @& [GI('ϰm+Taq9hF6::/a`Z4Ҧ21gf=fwU[ {X9n \\eXktgB`(]2s|//ޣ,l!_LRHlG1 A;.SbK>eaSH [pxb2 Jcsp fgo-^ +Lv0jy!+d5Ɔ}TUT&Z߃&aq6#Ugbq|\PG# V80jQW^Gf4D ܹX- fD+mh')jE?oOrbg6XRe>XOwZ$n2#A_<$%H`!w,!A/Xze3ۏ0+9XgMq3x's2 $Lw^-%.5/|[oMwmF3/UBCC]]}roBb -gZmCȵ;qц%*E3o`!Tac!(2 f>y9ZwT' f EE|6*]gi߅JX4 hBT 緻,i< N>b-hEY(2B.Pp ˄fTMa +ժۀA߲\zyUpA#3(LV6~ @*'>'r8i*+꿡L"ɡag_}EVJ跛ьFפїɺZ{W'j1Y80Bv}oTYZJ-0fCN:LS=fA[!;FmtM=XSLAs_}Vvl_6^k!yvz?t%#Į4ZL}CEJ M Q0S3~=b- X#J~w+,Teրp /[} r Td Ne'$Z*Nh\j_8ZU> hiޅ<*ڽJ3i @YA,?XьFצ@oIlk;dwZhNYp ، v=|8'] _g(;j.ZI[/{,CXI.&u%(N7L,r$" $ lAFg4/9?Gci %tCo;*.w`Q51J-&T 5vbK?V "ml;o{P2̾[Ν{朙9)+X+ޡOZ-'ݺZv!l3r@7^~Ti̡|mQPu6St"BbQ~?8 gOf\s\0g&@s抻 6`R YKF#5G[5V'o\\h+:ښU}.,\Hw{&F@`9TۑGg =wmxYfm^Z Wc-#$ Ǡlжw' P?6*o8А~:?u(ydAmhB_4Y,?` .X$;]G1czNom i7FL7ox\GcO! w>}Qj*&,1"& #\,mUƻ%'z J3.c,\墙JOp7T鮶F25Ѡp#/ˋA~hlXesQGħP\Y<^yG>jc`B^5enŽeW z`COkh 8m7hwȇk3?Oڝ)S BO,p$B1 I:ظ`< _ı^0LI H0n`~^)}ШD3d8̳p*7_>)+lhQQFtngV,r)k~Ơ6B7?/, D[iKk3L2wx?}OY0G4 R.pq 5ZA184s:OڲoYS0bt3lZ7~Km?Q{&!׎5t:gU mdc,>lk4|c+Ne|ˣ Ϙ+W96:eoLkqR]A ?{ozgi9y -,?1zik^>1m}*;;TU A_Ttj6 y~2FMg!N#XL͢16|zVaNP8gs7/C8,LTdKŦs:< "d\;G7'Zmkk hƍd8f̦@%?~'Ӑ$k|<"=_ 4X{rm6̷6, M9y^9 PgM 9Y#vTQ'k C$hf">#%p4lw)JF;}1@ &{PĉiB$}+L!pnzoߺȰZ*MMMtI'C/& w54EmԩSm@>!ne}MদL 㖀̟ w[a|^{ڴ}0@zd28*r&QԃLuV K `XdOG+~/j75 ( F+ "~]jh׮I*">kßvpTE-~C~%?ƪFy&". ŸhS34׶-kd`^2Vfq/i{>9o nP';7|@ n++@ x@PicECZ4y@-t|)3+k31$8,9s>\@;ŌVq_d,mw+>]j d~!uā8H5%,; W\E!| OYE$TmZG|G|jynp{,` gf0>Ykǧ7_J֢CÍw*s,y6Ŷ@a`(( &e{Z&oeNp|QzIϒ |0}#{d{13~_WVrTl9A&MեH?;8p4R7q{Pohp^ OI@^ ]l)zm6=Xc$a_;o~G|zA*F.xJY=82X fBIe|M(ȧ'dDqLf \.c J\DPtp&6S|C˟ fPcTT![`/eO=h?~ON&+E8X; ve)?#|'n^[jنX  .n,TE|c.L:^:Akh ;v*xe~'40Ii!AWxW׃1,*4t|!HN lP8VL{-I9O8o *@3E9x„ tYgɧBiiR&/ 3"&AB}BەE~ʷہrpnqUd|Q@=q)3ۍ5ѷ/͗_~U.+j9(QQ_Y h,lUK٦82_ҒEBq5TRHDL'!H0U-Qi#@U) PI$aL0-K.8ca( g>5dP48΋ X}{31_|3k,77,Vhv&T:r,j"E4#(*p6Q4Qݳ&;eUR]F, Z+wn\`o3Ӎ;DDD}`^ FkփPȋ:#DDx&}8W-:ڍC1h\hsA1 ׈g+Unɣ jw^Bqln pBG0cbbLf܃Ķx]s yz7 &^>C] <[^YAƅ0.h矏= .}?G=/N|HV7gUlT2GйQi-"1%k r>-52R4*ȷ,%hA`zL t%Nؗ:z'-ѷXrqLҶ܋C&$B$o\]&^㸹 =A:-(p Ot5ɷ7O|^H# +;NJJN)S&!LǟxM:UQAC(1b;p9n:ц{i(zf9dOt،0;R_z},_l]e:8DHvzEy`~ș/iG14Wn(+`P Q|aD/Ѻ{2h%&9h 1l4piL}L =6N!L&Ŏ?~Air]pbWEʞz7m~{J<$;vXkoNar=PLUi j:SXܣyYi#[!YCX0wd{w_ÜyZCcTa%%%=g;*,,f0t@Dݐ@1zQjE48&4R>:| TUjhgwסǜp_$Ĕ%Lc @2h 8~_!C<魵Z_֙@Y", (LB&*)foY{szžŠl:m\:siܸq;mhdV+нw߃^TcEMA!š:4;wN oKk+5{6k; D;]x8H29N>KhXz9x3F11*_8n(28;,D:ڈYbZCF 6g"=9)ehk%GS-X Xra*m84~.ܻ^ kmk}YsnPW=_^W<]|1@:KXjkk567~}DTǾ3އdx #džBe4Yc,BsO--JMMݶNCcaOÒhB^̣P>_%X{EoA Hr}| YXϫmhJV+?WiyR%htP6 \yȧ5aOϣ;bbnT]֯/woh-eϴi>#,AMPߝAVCBeàhV ?ĊC%e0aW~xMӷ %ʫz9|XV1tZ\JLZD93)>eU$i(*wdi_p|o  ˣG"(x]:N g 4EZmwS:_ۨbU9)44D Qbqăh}!! _?x-**ZH5))Q_d"[ԔThI)Ӎ{@Ս:W}]!XIMM Eq'@ϧa"V{MK)yeCAd|mMɆK$]"r}^}"ZtÕY ݎ77̻B >K޺5$DGX)l 5b<)$?2,5޾кT@!!.L zNIN(%5cdJFFIqfL^#115}<u:T[['N󫫪tjk|OAuf 2Z6z(c.4bLbP0rRnml\vcW_|I /\ QW8FBvf&=rHΑl֭SOӻ+潂9.2u,Mq?c:sdA WŌ/salCzxNx~ (+3.%/(ǰ%%=?lڰaŲlaälO韭hs,,d*.ߖ jo@,$ei4&Yh¢`mJBԏb` , ߄DdG1򛘘( P!PtVEӏ?RUE%Sii|0:<+pc*¹!eXH XCS媕R3QD+/;H P7-^L>g@{9'?.g4W|R[[h̘4: 4n Ɔ'Ioy,k'2|ap6 3&Y4Y3V:ߍ K7\xyTZ\p&Vn?B ZcKcr, {;@2 3I`1Fd` @ ȱGR)4. cb䐞!SKsLZ) KNIfg;!\e-o*(PCm-MMʕ+iQ1q>2<a'}֮9>sr腿$AA\s~/A`.BKYo|KکVګ&(s1tقK^|`[44_hV`?3G{7Xw9dKOVSFFntdMt9go%hh` ֛聫9|SExJgBÀpɚq"O&ZۛD^uA Wm%5oJ1~ V~'p3se־@..4Ҵ1c(I5'7&L/"#(:&i|?숰Q(MZF߆rc ظXZn=]rLYuvP3h~G(mLeF^Z'=PN,5w<$ B?]p;B`mgϙM˖.DYن Q:K>-&QL'x;4mxYZtUhi MH؉R!nɋd=t'c11/gY| Q% dAYgA3Y< s^Q$XlB2:!"\GE<簒 .BE2ц0ѶKck*QW!C¸ΝK֓ZWJJ*efez9A{\{[ ݉:fk K0#©Yt-J唹cgEckz`ho,s@N<_}u? q'd]@Yt}n'H?7P$ ..ɖ 'qcIZg`G"Z,2p%i5&Znhs>`>I: p-I5Y{FN(k:NcٕxlD?/YB` ?8968FBDbe|4eL?29r {̇M<)jL6M)SY'SڴYHP`SFs[Yt y0%@HgńfDCg  9XXL9 jXSOX B~PEE%564J=OM7J_OVz̷NA_-UA=')/ǑE,w zHfVe* HԺ hp܁A~B0zޛ"OLL^IVC1D K/Lǀ^Ab_:vA^MIC.7Q}i9[ͼQLP1 blÄ hu(>+q=_PB*U@|MIQ.-Cbc-6,6lHH}K r1)Ba^s`yY&[HSK,1 } X*$tfcI=߁'ٹ9r/*=FN**\a K£4YO]}рc=v{54A-p_b E+J>7^2?N*Rr'kjTH @.E # $4׉_B& 5!ZhA0nx붤X4IP׾+}nKϹR4Zm7knh7aLsXe}d~&ުjSTXH>| to/.7H?]+{p Ĉɓ'z7~| 2Ew^\foM[l0)!1~:8MVx1[lq&\h"dLak54̝)vpx2`-P^(ۭ|NVrs|YU ce7ځC\`֤O(k1ڛ먽kB0PUU8U'MO;1vqq Ad%—7zcc)=3Sa1}gN_8,h/@>rۭ4o< ̌L>c GR;Ɇ b&Y+yPd1Znyeڅ?!'qLoYTw(>EU0v0`5d*AɂzIǟp=S"5э*jAG4 ._̫5FO1IR{lo#WK#SS9I=~Aj$ߙQiPWII2x1G/6"4Zh_r Ĥ 3hAH~N:G M fcpp:?d_hoc\|R5:c%@N;4ȼhXZk ˜Zw3@;540yBx#AP6&rdɓ(==]@c-[ (*`how[HӺ-zay; *dմ޼\d54@-[l7,Y,`Kk)X!]%<"@ QB t0@>Z)Qs|E1j*RqBQҰu zqd,F`2u\ ϧBؐ/O&T|_ +H" _*%̾@.AyzBR9Q9}whvz7ɔd{' AD \~oZw|}xbqâ8fڥqh8e!lm! ZCCcBc{*AS+`']Vc{b[ǧhԳIז0㐑 Hh3E9Y ?a{3=|9Ĥ"]w)EYYL| `revA^8~:.YݮՎjp4W_}xAYI1!Q^@Ί"ꥡ._xݴlA54vFԇ~ݺ_(,!ZV1}/%>@-woigM%+<ܳ"dt3=ߋ3P !E,,Ѳ+Hs,Z9[׊h_꫅0W&h,'7ΙK҅ŲbhQFbx8P oD|ԭ%qh{UZy=s o6_=1A '$äYqh{"zory}@3,w`sW?*4ɱrY cȎJO]cĴr\?P@RkENrq@\qDa>,&66 AL՜7 w [76E`roYCmc1{}G͙Mvmy>QD+𕣼pr@>l , =iۓ!ip8c`f1Bkd0ݪs]n;2ȳSiPXVmT[äY^Yih$Ħ#0#"a%; BEc ЂA :NA5UUT]QD (4@ .`[K:fxre2a;6;edP m"p3 9Cl5rtcZvש}E?L =۷yq}+RCCc1#Kh kF!+F4 ,'ʡlVAC!L.-?6fBfu "㉢Ĥb3I<l 8f # "aZ?@?|abJ:bX)SNٳ_D ]GWFxA_^lÔ@s43`q 0`}[xw)""\ ޫT>_ǚ"#^v1_kE 8Y8Y4(2: &r)ʌsa.FyCuQV[kk%+ߧ8/32h-EɡX,P3rsP|nYC-h{>]{$0ZoIL&Z}^{u&!Cc/% Zbnڋד-KDSqat뭷 qm#H+"!AVm)>olm!Z%h=jˤ1aw_J)hFD -'g}N=!k#0rՔR5c #^{Ewy; b@ ^WRYYz 9LB:q28A@\7''f͚Egy'yWђKhmihIALfQVRRJUUZ_: M#nѢzZB(@S:3zX@jk9B,D*L(4"J/YX@ʳ'-H_G D34\uԶ> + srs溺,c!u6',}pH@xVlEAɐ2b ҆wҤ4vX8x'B>[|+5&FڔҼyh̙X}hH3,CsFnnZSRRE$Ii΢)RcU1'-gUk(4,邋.Sh7ãRmu5kDAs}&vRDXʞ8dh x %+ .mZH7no֮]+!<D5ԯAy@Qرb&>23(3=RRAlVGhz0 >7y>4ajh0Fz` Po5Ѽ8a_LΠƊBr$WCٷP;ZN3(:w@u:Q bb_E^zRMDj6E{pz .nTmn\1|CCsDP*᧘WWk~n&3.XpM6V<҅W@ᆳh57_s#I aEXisbhh"u,FJ&\4"KH1k,E,0m%kv;Bֻо'BU ш4Z\.:X۳uwR(?h7m:[/0Vu%okʂ32_#q)''[>]VWU=w%D)ʀ,- 7i>YgױF ׏5TUU%n;}U {IXCCc[0>W_~ (̢ Oͤx|jx5 bADVϏ=n%Zho[lZH6R(vҁ̈2 ||O ̙h-$evʨ\4n0jyyyC$#,[0 [a-<[@@b,$)hqD>Q gBuVR悔lcyW 8< H@C`j< !LXЧ AADA br R$gK6HwUz {`tX1!niEn6uQ*H ..$jG6Z[ο过\Ĉh׿z.B1AچH˥1|QdvmaK6R8p\= ʲR}ʈ)?K,>/FGFR̄}dD1[vcas m-Zow.^g!Y?u8--|-&R=|Z*..:qĤ&Q~X͗07xllŲ6>%9&LO:Hc1n^10b?yR&f:hJ,жpGQxJL ѱFv05MA+T yW)/?$Z"-[z3?(-f2l -<& 1%%=675TWWSee؆Cbz&cB/O$oÃAŗ=>}DsWJM4" 4&Ӳ)4>E֍SN*(|[eݗbZɠnҜHQL)+-.&OkcuwqK2Z N;W.;fˆN?+l<,yYbvv>. "H5Cಱ[֍ߒ51ElCԡ Ih<[l(LsAitC5Z[h9*󬆆Pf5voE7.YLG:RFs5D(d-6ۨtLqTlNF2IH|0;؃^;T^ZfŐj_wR>zqsDd8-,OF7ݼ!YBr|+S AC2)+-K)䰤t i$6>n- m7 "w}%hULyGYx |`DqiQW|ng LɄ"}au2G6))iUƈh}3gδ|6x\z"q;J+ bͳ$gu n^vìJЫa: UK7n $Ɛy@}^|5Zt@3uD#g9M\Hzaq-~O4{l&Y #zxuzQaaBÅPV 5%0k"ĭcHL' 5ljԲAXŧPVHhz]]!EYA%\b-ʋj*iR' !LY&V@X ͷ##Ҍ1︆F`bI~m|?XýVS.8Ō &8pU[N Լkjۼ\\4![G݆F30 k6))Y{SN ;>z,5t9Y˵`u͍P$󈆆a!Zݹ+mgqM7QNv&,Av "]& pZ%e?ڋb]tm+ĀA;Ю2Y8y S2eЏoreVV e~NqD wkoZqQOFPb~AR\h|x |Gޕw0+pc%Z,ەW]m{kL"sq1`p=0  mfcP<]D&R^E 2&JʁcSca)xjG,Ѣ1 ihhh 7xU.8ڛowI<\\Cא AWF()>x9`1h&TCBCd7xiô˜ǍD[VCC#s= /Г>Ms;"#I ]fQH5z&c0)1{ kznQgr#FF@m?w>j{ ҁ,Z.rthc^}PDQq("[,-o(G x03OA F$zZyt@+ h>6Le\[[+ԋ/+ I /LQyy.hI͵q䑶spmқl>+ާOV}N}iozw |Ք*ks?`8]c(#|4m/1׬Y#MX ::?8pEFEy41x4ǨP߾ 6oI զ- &aġӧ|3VUVRQ{,^hjf3OkQdd׭ FWKECCcDA0"//6aDgT qꙎc!PxZZ"bvwӨ1}4ںZqk1\D;̘q 1*2UW׭}T9L 2P(Cba^P_Zjhh 439S4X =jA®"VŃiaaD0y&BCCcv?v,^ tAWQ`6ֲbp4 h%EVCCcؠvQ|9].&rAd بYFCM/Ii&ONjW)5 J5XԌ{6QllSg~&J- 2 T1+,hm@5X06pSVV8WD baYkhX B@@Q>UW_oؽDβ8˧/HÆ7h@~eV*|GlՂcuZh ̞3[+'~ѿXYQAMD 7#Fp<:*Z zF+4DTUUenihhh^h x-HF#o`8\? p"x6ҔT12[(^V ?۲Z.;:򫡡6@C쿟'*GDз|+p#馮n ,oh]H9&.F\UגnZVі5n5444v'4mrHw6P(\-84Dʨ n8눠hc[eSdd3b/_N\|)~ ֚.H9;+ؽD@4Ĥ̙,dԬIk $$>-&I11=1Y>cZr%=̳%t hMgWPaaՐN o1hll9嗿M7nٳW^% E m.]} kfc54 YZǛ3W<۠5t/*lnJ%%Mw4 88DFl0,'۪ U"t9E$ Q?j6h 0i>2A%L_h044L,)8ΚPqԁ?-0G빙hX~})d544 h Sڋ22E<\N}W CBC&@TcMӹ/A>X/77~Zt5d544h &LM>ڙ0 DG7ψI0r\06&6|WĊ4֖!X-,/YBo6~4jhh ;4 1*2/7oLڪa ,<«hT` OB|/#8Xx4믣WxEltMM#%cEy xʦʂBSMJNmj> 'C=[_]pma4jhh4 &Ol[WUUG4444h0ghc52-\9lF7AJ iypSCU0d1  ヘekE̟EC#mvO\IjhhhxK2ŷ/Idt88dTYfC=&OBii$ |iBv8>d̑E< L+74,suTPP@?֯_/kXwW'LϬxN#ZX8^|ᅞEW^%DkDyBӃY!GFD )7/9SNn7EsQ+v1٣Vs~2SYiUTSQQ,PZZJ[# U65VXovaW^_ TMz>LVUPd 3.p&ָXqm>)33CFÚq 3nEqqDnr:ܑ>D#d׵ffgmX[rTsɶJp;FǭH9T8ﮆƈV#<ӔZw0JYzLirl,KJe"qCk2s|&(:;: \ccܫQHYj |AE07p1˲wL+^zf~~w544Fx=ϛτdo{`%:ذH#z:[P&H^a rUPev8tբk<#Z`S~u2}X\L@`(d5| k7+s{H=5f{芅WЂ+jhhh5B_?.m-S/*EsSUI@U@ш0L.7~,~ƙgUCCcA o֬^2bd*F"3;(9{i>=gY ¹pǎSN=N{ewUCCcDB ڞZn}ejjloh6i45^&/i60FΫc Sp }QQ/&ML3<>S;1(CeeeOqQUUVRMm n-UUTRUU=-8PXAmL JDHNfdol\o~n^1څ**ʩ6m$d`S8 iɬ}F6Lj0;//.EfefR\|<däo{XIENDB`nut-2.8.3/docs/images/ci/jenkins-nut-large.png0000644000200500020050000036646314553676503016132 00000000000000PNG  IHDRG95sRGBgAMA a pHYs@@uIDATx^]7~+p;ŝzRwWԽRZݕ(]6K&$2 yx F<A^^6nhvjJKM.]>x)G<'7'g5kh捴efڼiۛ_m6ڱ}!<==hϞ=r?uι4DpCxEVVִ̌tڸaamĹufm޼b*))R6aѵO?zE`mtիY/[&$zɧиIㇷoNF7_ 2<6aEk zΞtbZd ͜1gddxQQa!kL,tֽHjlxaFnXǎLtUw3:??ԔTɦJ޽RnNLLx1xyiDl`W~:.-->LΙCXc6m9eE!D 2 _}3ʰ9X0g[}lar/hxAk=o꤉?Ђg(wD;-/wh{ Mh ̘`?G0iD zPQ45jGmgO5֦h v˔?[k z4TL}?Lviޜٔ 0ʦ;}!>BQLl})>_PAdP{PP'eOvQTPtHqTT^ Fxw@x<͗_֭[fefdffPaaQ ŅP -3ԻhYTd륏;jD JZ\[2U͂-4oK:啔S z^2\ZiζlۈoZwz'Ιj?$_v_~A> MÅ\1Ϩl-J]|ItѶ zwZ-vԧeS\^IjhI_|퀤fh=LwΚ1̩*??СuoFB)!L-6J^L8 W J+h4h]9RƑF˓s鳅;;'Qŋh=ojLXDo8iԿgo.BKmD$S˘`p {:)"wkd4nzvmKSRTu ?֥i0ݧ"8!Zslwh=2YC׬^U]|阤,܍Z>70bRhbK N$?&U/?&Fl\ ͍@T.pHe */& -JN%٩TCYLUi] ;!..&vӺ% 8Ȥ _)\>⑏>YD9!Z<9TVV+//^PKkv[J`R.&T;Rg4B"(Ik OjOLf`7 e܄1Rv°hqvؼE(m;ڤ4S:&mJh]xaOڴ),p(QF4C~g{vL!W0y94򦛽;wzp@xp`?CAeeeZx:M4uN +6b-,()ENq̈́h}Y-Q,n8N"7-%P#0S* e8+rB&`+_fʏ"?~2lMW^Uޡf`[:ؖv+!~'LKvQ`` }7qݺ9{$O믗 ?z>(~swkVk[d 䋯_ݧxCxirۿ ށ›+)Nh+_ gMT?{:IpLc(Y; b!ړf(t"cEf܄Yp ۖUH;JJcͣ3gRvv6Ә1Щv]vV lOU^o20)Feu.] q'v Cxp |&mۆǔ>7dd&| ƙ]YT;@{($%y [XZɝDǨcBth6a U{hszqPR.]HCg42:/觟VPOF%h>N~6%]~ Vz1څoazdΙ}l5:"R6huI+Y{lU^Qk` %thua1$:TlUTѪݹک!W;1ɶa֟bZfy; 1W ,ӇZ)]s@7]z<0D>R8I g䣏 Yta̵cB<% l-["b*fe_P(7@͇K-:91WQjKmaq.tSױ092B~iZYt4jY669`;""m-(j?ڼZpR~~>E}ZQ(\V š){k`:j vjx& $Qwh,n- 36ڵ/FQJ\=3YqJ! [;>M^1[~Ytҵ͕1xCpvT?=C0e |#edk:;ӎ8>㚊F[FPl5: ,8jDA٢8vUT-6G,ro\6Yu=e 5fSYA%Y[)]ZPí~HHH:60syxHhyO|O-qZ:Gcjurbz<'٢3t紟Gt{Ԫ劸0A]aM%RmEO;Ղ1^tBm+窪 Zvm MvYfVZH{t=uIjlxpC|/K6__S:ӀVQkupbzm D:=u9]gټжCJr-Jj t9MwJiL*(eE=/XL\LhjbY(ɠs$']`W!]XVIOM^G<0ŗ\6ṗ^>O<=dfgޘ ʤ@wS"J ``sPc'߀`%#Y0* İV %8tNI}Nܑ/}m1x^UXF6eP^ql+}}Oft1MdQp|Yx'[61ǣ̏iEB,3 kڎ+˩ Gd(['lnօ4]VVQ~<Ǎr1~ZŞ1"kbPl {;ISTBb{1Ua$%0I Z3 AA~t mX:vbLvfq|P:EO\pI8c7eGEv9>*Z-f!N9;8⨻nyhիVf~՗!+;x'0 R MC'PMk*wqF=Imu r5 rQHKgY3"+O9#nc#Y8̙'C'PSkwZ2%榭Mřjc Göd 3oWk5MXә=^^ۥE4D^ޮOʜӳc_^wg C+z] s~b r,ڒQP+FGәgvƍõ f0$g:["g\,/<wDıU%{c6MWF;ٍJOp솅8#c % 2n9;kqweOwPjNLt])"(_Qbnd؞Nee%%aL>*#UN0(GoԷlC}dћ[lGzp΢萃GuFBlƏǏN߇os"BXJ1T> P0mU7mVecLApays.G!*/Dkv?ӨBhƍWw;R8m_WSNNS0Ƕ; 6ˍ_/ᖌddeRUE\)c'EҊ_993CSzCpG!Y?wmʗ` Qơc?fy`L"%0ɢvhPJMJLM#\i=2McQ"$?lqkcXqapuk (wEeߘFSW廬'l'83M 5͖-mK<jP#a*ˎw/mYd`ΝU{9xCxHցi+.L S[ju@@d,uG^>>ECgBDn:}Q~Eʘ0~%S~! /)yph]zj8NvIҝnўxb{!Yo7~mخi|˱B5nֽ}a .dS)#[A!>dmlR`Mv~{Tc?0aݟVK—+z'QZ5Y/$I?yfŝ?EaS_ӱ["8gcIaRnr-6V83? 6ъTV>WjY<.4dHKjڍN(ŋwЎ5 vq!q*[6R޺ܤ8LA05106޾٦;yB{p#Bj!==}!LԽDQQT^^ ;Tuov6^lC11"SFC~~jO_c>w ͨIwd75?ؼ 4 u~ ˭l-f8y ڂw~s Jh-_Radg9%Cݺ5֒qj͎3֯Oj*S&)Rv86gKF]\@k׀$LJxиI/ʫբCv`NMIʤL6Jyƕ_XX uI p 8 8eä b8|l~yP',^ݨ<ʇ&j `ECkT1˛Zj%DۻOo:CBC=(@^^^7^}eGB0gc& b#0"b:IT|]r;s;pk'R8pVDb-aU=:FGiiХ~YVnKAݾ}ٟ"eZ%BTϠ5kRoGc֔q50~%ҿp0!x6kRy/?i)$$$?7-OV{phaŊ̥)S&pk-I7 ` %䱬ׇékntߠԥKOↇm!Z8AZp 6NW[C^ڜBr J-AvsQpp]5uwޙ%sE70QaƯ:H9]sTSQF m-Wn²*qoZ Lxm.X@;wJNNտF殡U 62*]~5 ~XHs`ݠ`ҵ+]z٥tiA=l*d+/}q Bm3kN7a! )y'巺f9"9Ȧ@'2w?~~ `[-SB8ԯ/&-3=ҙd.c;t%cG=/@)yŗEs?>{aƍՓLS&FkVB& "yk`jXJJ˸U __h,C)&*B4738/>OYyϋ0[!M-\<~EYo c3Hޭ{7s> h3O>^=~ro@_os*UXwsY_-TɊu5p M06Zu{teryگ~p>WܹܶٻNB#U`ӰB\ =MQ+ԄYqaOEi1n[-noˡ@83&hH9shҏ?%T Y%o0Ee+*e&mZPIԦeSj@͓SB\41>ޑRߛ+#%ySMٹyEY;%vJLeҖ)I{\S}Kը޽7iFˋ s{Ak(n]q\G;mlFD./[*8Jd&P!j7UɁ=\?X~N$\,_BtS!vnVmEf2nvV_{m48 ԯ9PM6eғODhN7Q1w-ۈ2DԧU/;ll[5W_[,=tߤ5TT>Ͼ=zE j%%%ճfΤO?ϛOyh3j4reqV vjߊCuM(I<)kUܨpcGXp,*A4Tgg:"^RjQ1k9vTZj-]v ۗҙ ^8 ҙgE~;nd̃C ͛ڵk㏾ݶm!2.;6IusXcT]d hi8zO)(azFpGt#aG\Kn``4uFiv ;wp=Q怕u.`ˎߟ-_q=7 d!Z8CW4C(]_flenkUE[SgWK;lڵoǔyh@yyEiS`Ax50(PAt!ƀ*ee$ :b:&oPQuq V5= e8~IK4VW?c[l#Ld"ŏ#Z_[PQI0k%]Mt#"h=C]Y'HZulXzz!rTP 2ğ8\·+Ѳ[_2T.ekrr>ŲOC8s?6RM=J?=тŋUy=}1$$DuzX5|]^ᢒRjKq"spj׮T &u4\8PyV6)ch6=LwІi%4cbJNˠ zaf@W]}5> < ?ʤR}_ 7,*A5LjVAlqA1)IrŲ!ov [}mȸf "pY¯W-*5G!>xpEgl'Hcmn 0Ȍ*LBe%Tܻ3Ѫ)"xֵ*ӓغeKc?ϩ(8\$"` *t_E;i]qԩCk q6Lq8?VϤ_Hs 66r kLqMr5j͚5^~ ˗- k-~ͨgy̍2A,<(:Bw c'8F!?ߚ&Ɵ&EEp".,)_ۈ-N~ q;_\%gX] M:@vqK"8lʝ8~>x:vEqtǨ|IUTkhմ2[_ĩa9T-CR J*螉kTF|BB՟f^TT~+*b4XTĀ 76l]|EtUWS߾}huxlĐ#ϦĄX*e8I'ytXxGESm1;TrZzeq }?m19/<lxe=3;]}ڂNN[T;mcj',tv"C豋R-r;4[m7vY!^+>lT|TbVZ#oeC<߅:bʕBS&O`,tRcM5+W^4x`ZA ]*J#F O4d*PQ D%*$C%<`u58!״P02 mDqm:4of96FyNf~ҟ en d(++k~YOn`̜1/Ҿ,2FhC~L榠`+Y# kچ|T8U{ 0~is HipzTĶ5 IseCN!GHPŧ,9"']MMe؉·K.FW]ѓ 0nl素alUWMyyN78w`GpP'>joIT}hN.6r!WOr+l=ʭm89.QyQ>dSAi%fe0dplrHΝ;ǏG~|P JbXAeC?.+6чf 1_)--]OP ӭ' KwkG؄:4ihLriL2}~9͹8@ʡ;Jo? Yͮ^>q4*(,@.k<믧'~ SɕGO>>[P0A򯪉v[6 p6VDn<69 "K>z$ryJSqk"5rquh>m.`]a.(З9)M&ǁ~ppȔeJ~>έQthV,-$*} #o% sdr(%8_laؚ4'*+y;ih庍.qppw} ڶe+vv Vl9iwi\Ia wOƍE3GUXXL[$ѭ_D>Bo1t qpH+'cOUĄ\IGe`T>#\ H#/_gJzcW4J.=p%\sHN/2EGGUٸz*-nE~\-0khk $7 1UIxk*E6 ?HQ &LʶbI\"@ |ƯU~;LI3\_  {OÇR&,9r9 0YVњ"rי;ҵ'$̐&ǫAT16_m,~-3AOYkr^MeTYVJ wҘK //V3fL^k!X^aäoV:gEa Heei.@Yg=ظq' z;2Aϩ ~D&;fX~}(4G-p28$ɶ!JM^%ETc;U)2J91{.@ >/zKlJh1ACk8vnsZSl`#ơ +ُ?[<W@Fs$+[DMH3c82WmΈtš:3, TVkB-hB98:RSR}xgi֭eo_0Qz uם2M% +#B;wҜyi6C{}ALh0B?TBS$_^BETvuU4!XinTgǝ7&aStd8-^A_c]V}{'^z%ϊV͓N;gv@֎fr_H Q5 M 6Uߛi[zW"CGm#Ӊ_pm2/6(oq!nH׬Gz6=vd1(±fIaCKhIQF,uo2LV M鬁# |: Χ&v>\J>_YylH}H+m3d ;?4ە+VPJJ -\ȣK$''oݲ5g۵#ZqE; | /1,@JZ6Pl͈%zie8QY&nbTYauk@܈d% jBXxKUrͱVm'LFE4"ܪV3ӏ > 2ubA-Bmt92mHy~:%䳨L\:W_۸_۪s#M[q9o/Di_+qp>|p ׋ٜC嶁ޞ? <̛;K/qc$|]7$ mΣ_y;<9#&;im|by Qbm\l̽tW˻lA Ո+Uhx6KڹH:mN=~unߜ ܿ(ȃVWTFv$bƴ{6whQ]3XUU7S~ޣzBƒU:\ې^d\ 1Hǭ1jp` =?'JmAlթ'WB q|Z5OŒ[k*eĶg\SUݣ'CCl< Q|+j*nڵ˱;C6)` #?q6c4F8G5J/V2q#\xC{r2[ub+6{9O23}1FsiD' oA~EcS]"5Z5)2JJ;~,Q%F ic@xIFj*XH"Br & %dA\m[,[]8ui7aU/o.Y0|~uֆFoԽ? H#b7O8zWS9iݸqMa3gQPPgrrNY@4ƾ8uҞ TeWp3X`{f ck۲)~t$%5]`5Bk`?0c4ڵYmWنk3tu|tg tD&+X:WQ$NF˶td,cqr|xcY`&NW?~5Dc7tC|FqTƊUUeHDŽCUǘB6gY11SLx.u+<2.bI%3nk$ }W~#;dv#qX3Xj XHINo7=(- ~,!Y(74mjMY+N>~u2IЪjEckO1TTX$\OElU):/\UfT }f##q\49s~qo^~E=GޘT(3"B#HJK6BRňLuy/wȶ8A8&;N!ޔ m 0퀛mt䕜~E'McM؉&ߋF^Յ@aRQF]#o8/E.aVj˅҄TfE r53w綡W[re ^f|%.vMh9eOgn%7׊ôLfĭ:֙hQ/Z8H{ z-))~q(5!Y<5&&xq+% ,Mk9)㤟hr Qغy3eF)KTflcC5SuӬ,ΗRK-rDGקWGzKy7vq%x'hܹ ԂshBddEGJm {Q^f9I /NH'*6nđtHEB&8J94ءEh[TTB#\iO0>qE`,<̗~]{yGj$ Ԧjbqk~F\Bl>[P-Զr2P1*i%0Rl`#-!Walpu d6w!~oa oLЮh_zye[D4b3փvB/< >LH|xZkd]v 8TZtyy9B T|jz >d\{*ʩrdzjNr,y;ŀ(77u/mݲUxꅕ+WhB6Q\硕.ܮ؝[juvۗ :QmijAh[ :Wȴ-X[!SBVuf -MJJHn"#@MɛI։H庠j-㋭IRŨ0D$w6 9rzT\~Z۫]qj?5@h 2\ 8?.$3iT1+QLDm!UoRuf"~\6΍{SzS~eojo&wz1&J>^SOBͳД?["$k@DGa:~= 麋;X8Q/eTu+Q}t%ܱ\~ t=Ѝt0x~zz䡇jԎ;vܷ|S8D"5iFaNvK[Ruҡ i 7 +aP֧^Die~֪l["텏ie5Hn5 _Bj̝!1.1aLdj:݊XYf3ҭMvނn.)nѺLmuY3ƖXڏ{lbS(h65M6f+@MMMQ +/>nB*-Q_Q WYRF}j }@2si`.[8a-۷|KK= ׯku v+=菹׷fYe!sh40,h9  a$Ƕ& iwfTՂl8UrkneCo}M WoGAv2ӱhwlFo??zt|,nuZ­dmc;RlUnU2s6aZ|Swk4PB,W@ Fn#JHmlV @FE?CG1ed 9z4 Waiڣh96Q |ӧ7=5jg&Cee?h aÏlXV*W|?zTp7 Ljp8Ҫ(ɣ"{/G*'ڴj*-+PcO&A;v@{%뻪>L.eLDxE!A7cclqf{:=tz䓩awJDRB[얦UFdύW%,c͚`.@e؏|a%`SCTMmi҅LUm{MsSg|^RVje L˱D\:H`Unv nK .mŹ1`8 y7@?/7umhѲ٫W_hXD/8݂P/"RXH=)(b ٘NL'Nk׭޲iRqi ۓ. s\U5$ IPx16!` r@Ե=6j$`uco9^zEڶuk끅͛7kH[ullһu[1WQ ~s`D E[\k'UƤ[UMYp#=LڜK9EاhŖ4>ÂZA䉍[ް#y3Zn+k5<8=cQRb -Fh \J#uG@ԗd[]´4_zm7_ץPLD*nKQ X.b`jVJU1\]qc%JDyk5Gbci0F5X1MVe3گW*n]uNyk-҅'KT.P}3WږXOŰW1{0( P0VW ?m# ȄaZ pZ|EʎlZ> hYc ֐(n,*:{ڷkoG;>c&d- YhīVeojpZS7,W8(綂EOǟ|`3s=&W]z~Z>bq/?L<3ݯ6_65'F||f۵9#W$=gf!Um@MObY,PڞI9oHu႒ z}lf Y 'չXrt v҃o~Ev")+oC=t b Dޑ_u-Y)c>ӆ) T;-naY9?vhߨƠmӣ]sySFgHPB<;G[ '"Q24hasdƍVFft#5۷Ӊ'O{5{#3dD47 ;.R0`|(2S!A/+Vg*|AK.<^SJ^\T{/f4|6ɪD5yy1F0]9 K?z13qWQd絈:y## ^#*J?k;la)4120>^RrlNՂ[H_N[<.31}5mtSci-￵+=st2k[{,d39M{ϧ'ynñ_z7_ rjD=ԟ mnu&8_}u> A)m%[i32Bz j:~\*|=vȣ4pp0x\{r&XB7=1ݠEzhHdS}jXr*~-YM# GُRK8u-M:m&h B)77{t@C%=6T+J]pU8 x>^'SVZ"cmss:[waq_Ɔ8l|;`o^6#hӦ)9(g ODW([wY致bNd*VFAq%\MI徠rJ)7 {/d{z6Ծq$Ň0ڴZM* #N286UGV8+ߦ|ԽGkAґޣs璿_;!"~4>xCЀ0)PDDtjJj_@$+^'Goӧ+RkDPMVIӌًQevV,S Ջ(b"U&aCO(\ LG{B_/`{.;{Nn8{Sӵ}v|0ҥiC3e]ZR&XilFQY%}(mu-ߛ yf[|3gﯹ%*4y25mhޕGW>mؑb胗R L/,V6s8ljY ~ a7gYe_N]xɊtJKo`V!12Nقޙ"! 2m-²>[np^˯|t{vuV?\-+Iq!X d4JhIIIԱcGjѲ95nܘ"(6.VGy֭[')(0>|q{lwxETUʣ*|-l+m,Vi&fw4ebWS| X\0H`tnۂJݣ jef7>LXk& l}U 7(u~ĶΩ;g7}ܾL޴)[q E&4}ÏY2?wOm#AMDͷЗ_>mה^4i' VlqG FtDbo E=48CD{[;AtRXp1~>F9 ?p+ U~\rGqKf٬XEt/O2)5%6iBZ|"2,< .(e 8o[5:Yܛh+k1U|-RQՔ\ҍ:6 Yu.r⵵ozͅ{SXk`ukv7'Y]m !Nyqĵwe)-Mv 3>6vK@َ?wF{.4j[d؞IjAX5HKt8]y\p^IlђApɓNJIIYK{AGZQQ.Z,>~5\C\r1ӛ""#D#NZnw渀Ҝ# .mb\4:bU2qv敥ye  z]uDy_,+Q8z^GjݹcGF| 5 SOm-Tccj_6S~FDۿe1e)ӊ4*Ek ;nE]וB)g|TVVyúQb4HdM7ұj""̗9_[yD_ۈpC.FZU=qqh4b/F&gH\v'~˭BHQtd5mB}kLԚn;~ӱ4S!)229 Ǧ{|#ޭɗۘ:U|kc`2mo:²Jg3Аe6ljP[+[}kyyq]Z,:PL+016NNaoyƊ5+.,WXA_-bA>=я0ᩏiwew+♬q@m;_-e=Hy>i Zm0,iD%ty'҃]"d`_GИ'^GW"]ԺyL!c֕|#M7nF-g/lHٴ@S6/Xv7'v 9&^~yU_\Q…Su͸~6?D%>YձB^tRR_05k誫hASW2 [ N1giD᡾ϤG[qݣgj*ԙ,↭BF&l~跌 rWGu= )'3iK鳯kȏ17Oǵ)cVMid5}~˔) /N-;'Qȏ^נSǺ$''W?Ôc L<_m83i~;R4]zzez2#Voȣɨ{eD\n0x^Gˠk0Luu<;t:.؊Tp#~) [!~ԬI(єߟS7ԝonQ8nȕWZZî n;wcb {oo)4wP7 7\O *@x'3+vIlL:ƾJ ;>Bz̖a lV;OS.8],V?sgOca/a )tOҕ("4T oLMEx&8jFW <ܝAR2[.n[3[uϜ|+ J@u gؘ~ʚ+˝n٪u# J} VGLLq7|F{tpg=*Pa`MߘMw;ֆPz>Գ[.AܳiK= ފDtPweЅ70CԼIISQ\Xnu"N۩ȕ-~ S2pX8ֽj?,S>kO񟯤ǟ}gC4W*T1٫wg(3(Q+Ah ۭL,a\þ]j# M[?sg܆>V?O #+>`7O=|sOY ɻ ‹~R|պVȟ|r 5X _\$]JGou*-Y%\{qtǢsO&6=9: cFR"|eJZp~GaNN~M[%KG'7l#DnNJg ?;n)=,gvlOu:XS Tg5䋶(vm/WPazmVhUiʪ{gnrny==#/Z `V of_I?B+Wb74U -]Íykð1&[81})sdqUQi$Cc^j:qqZLyEB–)*B/(OeQqړ7Y'5=LȲ;M+"#6\j(!1l5lll k{Ez-a'6x(JeH?g]/4$Σ/M<μq>9r7ͧ_^M2B=ձfb5}ku:ʶO x:\c [QnegN[v^+ N.+_MO0Nm4^fi|-VDgi- mHDۯRj{O֐,ﺋ#x&W& ͣ?[߰I_,4T0cJ{*dOa'9eWFvAW?B+| 1bןGow"*yGs OI TuHubހ;.zk8 DAz(m*}t&/rrx\N:m@W ejJ* [E4t+ISew/B;m'lAv3]S s8;TĵVi;*dJeS7&u(zu2!R +}mUpcCǂFm![6&ʍ5YB_kq1qvc?kXJ+~1@ ").^j$Zn'N2Ԑ.2wG5ѮY͝W6JRɞ}Q@&8̙)h8Y9}jEU<(G#PǼ|}@p Mu-^5/ M6:2F?~#q">\|-{ڣeԺycu2df P/0KMI\F UPMO:'Nڴl^E!^~i0]rIG 7FҬ rq |(h8rm,hH23A mj*Y[sn4ڀj?.կ6ЫR!L2ng?OlFDAJ7;}(te]}׷ O } +ݷ\ uV4mgwqK*#q1H L!$&}HfNn_{ >q-hyѕXǫ8x+R x{zy nP_<=\/<<| j]XvѢeKA`ڋO3N/;R3ðJ=lA`uY,[Rrexk[xHs,o.K7(ljBmc=h?7Y0f ߽[-ltEN͕a!Q=[4]7Gmc}tSnMƲ`w.3Z'Fmi* q9NLh7;ĽrM&]tZ2S<qiԫm-lN"w]3caKk׬.;pypC,jiiÆvܾ04ʪJ &!F#hʭg~F];3͸?z"ؕ]l9]wHj2.N:ҠAd$EA,+V+;c |wx>On˖͔fzRlUN fMHJ?ޟ7#/ք">W"̒ ݴmkm U:4վZSPׇc}f4_/-s~M'ҷHz :b ӭnDaSԳcRQ)*_d٬.ihȵ_* ǹhh xd6%ֽG|T(rԵu纰` & L,,'4$[]b6vG00C@E!nݺ[_/¹1mlEw^o,{v%mߩՖU҅g 㺷wae؃ V+*t|*D[4ZAl. {^v<𧦍cޮU2>.^f((qt>J*ڲ#ZwϱˤK9 ms*xiN~n)7BUa N"pV;8ڝB&}5ѥm r[4Yv;4VEXq|8VFWnT~fdӯ/OăMmһ^Byo)iW=`/2 k֕mhW$۶q#T&o˖-߰QJ8?΁$]*jXsV_5SVVAq?B]{DTfHَlk Md*z;Y q5GhkTKmN62Klwv*- NW!6f =6}R{oDWEfqПgі%f9ݐ#H}# Cj !1d*j'-/_l :l%vҭJYv8Y~?Qm:wѮaIi6nZM7KesG TF9PyYlӇzgmZ4b-R] ӑ=e]| p~a.u*[+p]X<}u 6P0 S.DՐ%,PF ĭmn\dYL5?_o  u삧 ĩl)2O[w&ԚTeQUK}1YqŀԽm s0QUdl4Z$mڭ##]6 iTӮ"?iu,~][kw_D QxXW Np.CKZ# >#BhڣѺ" ܨ!!!bdfeRrrJgl%B^-DPˤ ?gSW'444`+5?2 Udf̔ \rdr &Z`QOaAۯp6;[=k _p׃la&ȊfM|5Gq~:YïDN6+i֢Utc^},߹ѯ{a8lEtJ֮G6{ Q*&>+چL=UX[Hv7OlM]t\gAG؁=i#PRf8yG^es(x$lC-[ Òh333 bxNqy! DUXp ߹m4"e}3S <*DY9ZԡH }|C #x`4Z9|{TQ ڱM='3Ҏ.MHL.23C1rmNNqg:3DžSh ^㺄C,ʣe)]Іw sʍIW?D>"ڲ3<ڲ#LKϾ9{=]r4hUWPBrܖ Zf ~4Gpm'!Pڪ\T y®EU(|M.|p1y׉\9 6my 7~q;%N®=zRRfG?%(Ob+--Ҹ!QZ\BLh5kG1k7Ԙ&ojB!_3/ϟ6@hnڰo DQƍ)?~k.ԧ]/ sB7rZɑ 6d\a䵅c6a7kKdwUKˉYůK>>:c!{V|NW0Mk&K4=2Z~sP\QF*&N%Z5e+0$7nESfew/;>gW9jvHC-n#0q0-K)wCbG[<#?AF!ګ+heC6R/.h^}RiфjF6TnG>AάD!aŀtT8@YgRjzhLI^<p_3X]j;ՙ<4̽F告VmZkn^?b3w.frkHS6noawSQ1^QwT-QL<{=s:k6S.+7w?rq݃q BI#ϊ4LUp;ԔW SWPJW 0ϥ<>@tRy`9vɯ|dRF4B2]հ8v-ջw_sEyņ+aR,TbwCӈXqs|fi.F^z׈5XJ_KXR2}! ֳ Xl7kE7PPtX/(O$%&R #7~c\tڍsݜXw-V[dT[ߛm8mZ϶8I.TV/ nv'Υ_n~3ziE }Nkh%'E,LmU٨nxq: 3 rw;gVQaQ;{c#ϥ;KVr q8mqhh[Tu֍p zOhhY8G{.Zګ]yjvh\xf/Ot܊2a1# Z$ ;uև2\}Xˋ[ˊpsM)>6`_n)#YH ZbN~,ڕILJD΅d}1g<"|mѬh-rלP87⇆4e㔣 b (lno"mrl6Fflm`3gN]DMT?3kwS-~GW=4mO}@_>wyd;$PN̡J̲^aV$8*̐qw>Nt +űw6R^6.w^{6]w0Tz%v6H>Z y##-0Dڥ~ni2anPG[J.{Mh?3jo!ߧLhڵ6MGY)*ckdX5kky~#lUv\:(tu\ȍCb+ A# |`3k6˂h}*>Ǐ|ӵkCؾMsӧeѤ?j'3jHB |d}hҤv)Z\m69 acMsCVg+ b6[VQIkwogҝDanCC=zr5ĥ'S|9vd/douM~˰jl[ H;OSyW b#/<(t֦]i'閗3#cު4y@Wg#bK7bY~}D;qtq}aqX Wv-)="]_^jJj+$V69,USYEg ?g,m;Se[= $OnٞpA\]ꬢ:Ggi=k mږ?"8';15_$ v r*fk Dn 1mr:{*&,^H M^$gSQ{cQBBW@>boSN)}SD"ECe=Q`Y.n_!7jUN=>LUW;&{3G|x\eW:_tѯWR~cpx._蝉i{*96rPB5kh؜B`ֽ!OW}=RYi)н$ByYC s$*vq~2}ݶQN턯oI>y0DQ! `~G]K28b1)JA=UQEeϸ4iN޾Ϫ]PN&,}a]ՔW'n@;.=[~g-]p cZQnz8嶌HMj-ZGg}^Ʊ w郏!|fpwF6=9f"/s}_ngOȓïrn8K`_FoOXWڐ[wĤfO`DoV?2$[nP"9i{i zdmV`u:6:BE> KGX+)<"N9zKDu.86 9oH s_Uw^;F@֩-ujߊxW&> 7IE}@ ޺u}4}ڥRJx O; oZN}VZZ [@{;xM|Zlm]9Oɭi g %rM*˸NpU8N-?K^OҶ}tlִS貇ޥ_f-=/,[,?2؁k1nɷv\F?0ޒK}[JYE%"v@1` jxD;W_xybH_ eFH>>69WY^N' G-7iL~c>E l5ăyRtb޸m7|!@y j_-J2 &ta,9'5f4!J:Bw?ڵȺu`baGm_1pߕ{w!_-ZmvOwJ۶kM؝L0Yj⼡8f]4qaoiXpVEtͣhZs8K[􅻨U8z4蓟gR^=np|t^ĨkK ?8Tp?ތm4aIS۟,u3*y:X6}p$Ѿ+otvXuZ 7DMe%B6$IP$kcJUC5g `/ ^MPYE74Be]zڰnrЯGziɚt/ǓFGd6Ŷr-yU2GVcfni볙p%g长rq8*=IΙm#ڞK:v]{Ѿ>_{I 0sOUte1ڡn{o`dT)cw}@#<5ƲbNj^zk4eodr4fm(*\}{wNб"PT5׈XUYJ%TUCyԱMӵh ; 590>W{tp!bJ;iΝK o׻7:>Y} -[mۄ>;ƌF;%?jWh<qN HPFyZ?:r\G>~ँ~=艷g2s^q=T^ `aۮI*D%4M4}ޟ'BITnl9:8O/{oT~Tݽ?i +SkNNdook:r/1x94]Y&4tx2l!BSi0S-@iYjٌ?x*)-'.bnkShե UƷZ_g((p_ }YQ.UQyq>PiA,LEg <{yp:DGxH^R_t{W x+lvIƦM^ M ' ~8.ke}``NGy)}s AFcf~nmvu<6Q=nb:]̩dg3JR]RpE}4Nɟ*o`;" zVZ-W)u ׋'ςItm-A~!Z,|z,s(N,2|Jd0ڻ\dQEP` wf -,#=vlF۶nufڱ};ef-A>|~zU߈|$ALςq <ǞH[6ӟ>c y6JO;rɶE˖ӜVVivh߾FaVʢ}[եKk矝H>N='W'RG?Ɵţpđx =  +ER `Ń>^(Ůqlbـ e&3;r}ȇNy5cc*c-e-\E-&p|8!! o^N3YdoF ݚHQ??dCg-7-7es4ol9m-?,^DK/lbZh!-7fLJ ͣ];s^&y1{Rs|׷ʊD`(F fUVXUG9418!h B___t"c-G0m2,E3̊qLJkVYNC2'1t?{X  iƼŏ5"#ڬ8g87M}K5v|X6rɤtlbn9x>u=$euMCFNph!/.{]RADלHލ.Uˬ NhF:%)Vru L^A=N2IB^މLQa,z7^z:nLe}_/&Zlfbcu-:[\NNYOR  AA~4xp[s``H1 dqZB=@_?9Hωvҏ?V?uBtGe\zA~[|<F^a"bƁlʍk|RP|qQ!U2#Ź;Xl>{Z8g_V{=|wZmjF; )jLʩ5ʲ&bY.4L;Z\ZF;/ ۍp$$WK} Nq4b@O%@jzOGu^3E7?&]s+tɭy#}{fh}8~c.ߴS_>e i*mZGp΋Gأbfeᐇ՚ӦԮG0sV_-0 ^ye}ʼn[T7$UMtX&.H͡H,r )eo% V5=Tڧ($.*b`_}bhԨ4>b&ZN>-%DKp-W- FJ+g&; Wo}{Nd#iwpٳ{ax::|w$b 4Iq(A[AYc7CϳdImREKW9Lii<VlB$蔃.Fpoߙ* xPCvN+D Eʌ\;.Gŗ{gqےiъ  |c1'GN HHrw!Тed!:_sYl/D|ؙib rY2dM:6*\xIm@ DGFpz 4(v|2π-r_ŏ]nܮrwI1:w5oJg݊8BYgfoXuE"-aa股~.d`$Ķ˝^ kfWШ7Rh<B(QFFbmAtЃ jÕ-4˫NFƖl8ɾZڐZPlhAB۶:U%#Yl2DΑFddz>x nڸ;,+A&Yy-yy@`]A=VG_cqikLbEXaƵΘibQ"ӘԤsY Tʘ;iF' ̓r9'G0i +>7k+g\M&H Ր?>kc6slt8==*ީ%k&VZ]-DZF~7icʰk{ix[]{S|n6"csp'ҫ/>? "Wֿo?{·Dsm9-h@;nz!~*&U|,# ^e:ȣp{w~wRRܯH>mcHO@tl|zv*Z\s8ŗG:'M !ԏ:5Vǩcʷ8HO2Y}A_?!Z̼hh9h!:7m.#-^L!sUe%瞥~pYg]lܘ#$rGn?v;3ФOƏSOiNqq2 ceԡVX81#PۀEu>]]q"|p~&W ~@=fl91Uwӥ%Ӓe@ŀM籨{uK?<.%ćR#>N'ka<ʪ%Ͱ-GďF&W[C[knO74vm"U+68y8f;tfMYhKl̶Iu>O^࠳Biii#>D ,HU /^\CDFt1 l}i)--* q`:gC|Q vya0%iFT{D:ief!_Uxd.;W>~͆mk3$>G3",BCqah~o3iMqb|`o7<,st#s Y;_QFfhସFĿԶEcƮ !\ m,2z۩KTrU_ ެmsepr9SO'/1SU_4kN@>42֩sŴ[ڙAU^٨ѕd4;襟W̚a{s^+D6mǃm6)\?:x8D+O?(Sk$kPt!A(W.l>LKBLmJl4/Htnߚ.<$1=F~y3KBf7njyHu| +(,U shVL@ x׉rP.)]FmQN HZg ׉JJJyi0k &kh M3b mݼ1M4oWф</6Itcx<$鸊|yԼzԿ?3/6&QCbkVӾhtƳkyp[(/Qtk5aV<̍cahv*?,-7nl;By,r|n&Ӥq+mVEPvˉæ..^ͤ-k*ӑᡔ-U ЙgvAjL{b2?ΚǶ@_}-'n?vfK?䜚t͵d@=mzi~-Y[sHx`Gy-9^Ij׾=vzH{iO9~xU#j @GUQ42! dy;_rrkGkh^љ >P̵Q߱n3ϤyعcG믾hWcƜHݺƢob"v+pܲNV =7Ts'8V<-3ܜ2(9=wIzy ?l/z||*i%WGcDhёʶ{QQQR٦ލ6\ ݕj}i  n[Ѷ]/ *Y7 9?ƴkmŇcF@kp:Xݡu%eҲUe΋|`Sq| [ԲYL1@>q1kՔ^LndB^Qsq1xB,|V@:.K1s{UNlW\)?It^+ޥsԦuF(v]gbu 3e9 LvIi%æ:7-(vDE")铩,r\1Cbz|*Ry"I}INjڴk;:# zMv- 2fT {Lzq u +$k?[|7`cЫY nfT \kWwˠnqϯRd3b⏓µOhdddT?xI1 ; ąivP%`fsex(`*]Qq ?/}69TKT.NuC/˧N/=@ڴZ"%Dd0}kIJbm8M4w;Tq$FODOuZ \t2}מ#R 8,l3?qBsL>P8@90LJ{oI5ڵvS}ƤY9<#ח`)QgЏE۵$p]cʕ+Q/i]jӒ%iRv[FmnɌa/LK|-Qn_•%}tޙ'V /)Z/#OxUQ@"(L3Aсn z;c&q/_a^E2!̭,2LAyeA{ҵ"){7lwpL"̕l8X`0Uj6GRw\\AAAXŃϧ0Xld/xGˁyl liFdv6LCZfU,y ۞1q\z[l7Όj*e~~e_УG<=P^2Yc"9+G;PDț6mڤWS~jHPk,M{Я\ӯ>kEeu6O>{#%ŋWꫢ<.k|8_+fnѼ =Mܑ'*'H608H|F]y7(Ƈ錋o;|;QHh9MX.9j+ܰ"i'ЎL.ϪJMX>!Q81x>x".!4Hs S 8)Sۦqَz2}Vr 8 W:Јca@ z72*bY8޵d03ӧLj!`~ υ9v͚,*-U;z -n#lA#Ů!7nm߄q5\ÕHD6#+q97hXڒ}KٹuegT?zԲey n;έ@:|8m\Zz{%郿R1+Bd[3WqQ9:%` q61aU2(g R# j+:0YZt@`l[ /P2ޱݔ168>"Ή#\/bJLfeqAK-H0*A sWVDY9K۶'S]BW(MyUWqmiȀce]ʚ.r$++S^Gņf}GҦmy=ԁkak*\4cPָ$0R'ڴh̃ ;|qh򞯼/;(9 ?J(F2bn3BP %HF8x^;RBrx1} x'%EU+cTn#00q6ȌfpW(]K;m6׻FtwyC]4T 3n?ޟ mjhk='ѐ͵ԁdkfPvvWqumFhwfGSQEUͶF\ӗZ1ֆ,m2BZN#گ <[ZԦD1뮽~Zt`D[oi=S)c3_+]]?`;@F?xۍ8i&VW@<2vJYY4xOۢ3QeI٥A(٣bfr7w.-]H_WlC#Eompս`PxzE˖pW,nVWnuo7cE9?6n\16aATʣ|wDY`橧e@?3uhwE6n|]`V?c],nT QP  QTDlEQQQ)QZ-{jcnnsM(WH$JB{J^SVO7*^ilYYA7=#Yח0ܔc`(N%]. /l;Gݲ-B=zԠ>%'zp*vJkMҽvE]D.Ŋ~F3d=Ўjy;vuwFJ#c&H*-^nj٪58nyJb˜ƮЭ*ѮXwW_~)QRQ @5@DŽp \e^D& ,fBe8,{C[,0Þw?#999 ҘY0CA!Qzs7t&?Z$jٴ.EEDbP'B_c2VBoB\))_ݱ }6P#[h/hI*:K9j!W d3QA%5SӃ^zM7Ҕɓ\,$bT]W~;HY"NJ7 YYFz1ñ5x*;Do+1?|A(Ty`ݼ+<Ǜ&cg'5mJuO`/1ʈr #% }v?#ZH`L^_ڢ5G;R͚}7tѭC)U7؟Mo-9L)$.z/4"A?˹~mY׍Pi *+-JT (:E?vԣU}u72.fk*/PƁ;q0;'we-׀ޠr`i8wQ||1S6ݡ{2핀X}EQr^rT)X %!OSz#`aO0ufac@o4w¸bn귾7c)pɓ>}xqt;{&RNb_ڤPB߯ܯD͚4xp' * d~dQV^˜!sWؙq[ok wbZz?UO=M}nGLl=?Je֯/vvw;RQtA$<_Hk\%=(7&II1za7muPN‚|=1`.3 +c(ةD21F*0kStHa!i}Eʒ+8/@ޣTm̰Ԫq](3?Wߛ%+(qBulASrj;5Zo5TM :'] _uVhG/}UBUS]tm)!!$١=4 }BNY]Fe~Il? % U#7.D,:ț_Wr mHzSx)`Jfu3O3nAQdnku\|p2%ka%F9E7hJʲݟN[\GWM8l8r$Vܧpk~'5oܤi3mAyDqwRvٺ4P`qSMsCt(>ÌdS(z 8v4a{ EzGGO UNm)19])ҧ)L-!(0"QRj\| /[`$+3G;nLS_,t[q*b#QXHǨQl4˟ɃZ,W^H[:z"'ms-ո0}Ã3VZUeJ)y?Ӳ4,)O f2젬3Ĭ[l{A[^LOٞg@&hܑ̘ц^Ih5x=GG.xRۺa3eʧ6Ͷ[zC'P>\`qCIX"|d[硤zozթtQ7N<؅3\mpD2}*5Hc=nrUyB1ڹͥ˖ٽ9Ea[N 59LAe\t Ҫ0uc .횋ĊCNkXAytߝ7Pú1t-WӄQM!g-Z(d:-7tbՑnf=o{~ wO|Myv+8p1nNjդ.ʒ-:=0_4~7\څg#٢`1Job-QZI-=r uA8;3#ޙeB yZw+-sߛK4Kk4 q ~]֔(KwRf;65if e@ΎyQ h„ԢeHwK>`0k гZeX:T#ćR3MiO y.$C)(0D}@]Y^Nsݙ48EVhсtt܃]+;+~_bӍzwOP)ş|H & 2!$f*USb}a.sBCdE'N=qzf%0İ24O{p\:iL]C&f,[ȵwY9=_S>e:y#}n(aޘ'd\}(/ tM{5.4(gAc|I,Z_xqR -\=O~sgCX&{5\g1c]C9E'uU?v[kmXAWDf$S`0v@knTfQ SlV:XmlZސ&OI!OOm.\MuCNN>JЯCd_u5 ҙ5M}(6ȓr m 4qAyk,'z[kz԰Qu?F@;'OsUv4>`E==ߨF'=ك*wgH0E;ʣPTrB`jXd 7Dn`\R&$ yyԯWMI&a)`S3)5#KqvN W#+w=BP1 {4v mFnqL u 5CǾ\G^T%j{9_M)UR}a],J VR|1Ǝ3lepCG(Q}(= sJiVct7;@U"ݝYP4'=>5KhZ-䇲8z mKHH̶9ve5 Dm6VvKmG>f k6/YC@!jGNd黍 ;tMO :tM>;j9L|˗ݻKl՚j4oD<5{}yJfAPsWV*c&k9a^I\(rYMJd4l֙5V CW+F$b,~@1[#:ZzB RFFXJ)͍2SУDNoany7+SfJ ei]oKiRf)B`Xl \.@,Ɍaޟl%.߶u ` *&2ށ& GfО=)ZU2F{h4(Y(+{ ܭl~'9"$ċ{M؃ЎT(/^Ay@2eE}X?~i͚EЧRpZE(>>.ۛBo/9BRK.k7ez鶾mȏ%Z3+lvV*Y@/~3=t sf,3 ‚!b,&,`X\`?s]vyg4ATspZj͢+ݢ%_ḆF4&łdej_jP,$Y!ƺ+8w89R57OyV&PCF9>h[rKV"npM%2n*F/XZt~u0ULI ێ0vvlJJN!wת'zzy= 䓭TPAdٕfoTƿ3+fׯnocwuӘ]sM-rp1G?ɏE`vfO:Xq㩒n,(=M[^wUrǭ5be 돱Y@GpI.1LZ!`ѽv@旄=$C>:=*hWeX$YzSCvK]e̵7-XsvL dX'|a73+NNj`Z F* L4rw}<^E|9BULWƾwǽ/y\:!ظ+egW)wVJȟ]wެ?K8;;QA4eJOz,eK=TxѴƞ$,5[<ذ~ YVP5 [̏ZVs\- fOFvV>ݓZA^,(aœG?ajԵ^SC 3ڿ-= &ۂ( #b[\Ƚ%yY#733E^  ;DrN\UNfs8@:#4Ch3kᡝ(d@pvj0jnWP\( j+G=c&rTXu~2.2qðUsd~NjYA':xkq3U1Ifsnvvm>N77W^MՔa?c!MKvNdj. 5]矴~:!ƣc/(PV p% LhA5-hNPIVJ0 Z7)[:1+(?DΥGruS;k9d1deՊ*|. ڼmq< s3,kحWPi@=2[z+1edep(a!3ׂ4}e]dJ;]֞ӧsӻ q$-59bgmbB;t"]dW])7X t}nڵaZĹZ?{ Ǐ?Rm1:5+4eݪl1++ c82UbǕڷNSt>}RH01RPzQv),Нfm&mfS'͛OjpkYbӀ {0;?N{MPxL(?%e֟&=k5%'i=үM6 Ί.[.Ài KO CqUao%emRRՍfuIظ^,=G$=\y"?u^N)Xi%[B@D9"_/[e=4b0x\?h& !!FEC\J:hg^bL4\p"+Ҷ9hV+933ɭO[ޙ9[.~DknIíDkao$+k1ugpǯ٨QF70խ$uDw6B)fk%&hCf?'?+,@3C>ּ&-=MU F -cx[ mvͷ&5bq QN6$S v)g"Eyo,`"]r!ngٴe-^Y*f BWg\=,j Hsw88|Jn߹SQG"&=NlK?FMo~^N %3\oB9h5o\m1\,O0ZqDe1N*Oj)#dà ڵS;aͺI itCinv*k}7dҫ?6 {(zk@1g6`ǁ5_T~L&Vt^?nvd^ڑKڅrhzMN'N^w]wmKfχ 9$^Ԅ\`CH,{f!V RD.|HM jOF7R_b/pRB"NUʕ۽,ݦe8 /̱b VА1hU[1z|pa@fI y 'ّz٭[%Ԫ]> M5koxKbǏ+{rR@1Y_'a\\dwvУu`֚!Zn.iͦۻ ip> 2;|"9O6^93ح_ܡÅFPx=ҏ>k<=ugK} eD(gvp20qKkh1=b {zґÇiɒźmàڢU+ݤaΜ]pQ +.7`]+kʟuكFF{֬=~aS/f'Zyv.\tr {}G0ל6k={hSiQ/^QVrOEP.Ft c߬,VV rk|<fxaEkJzt*1^LԽXbvӎ ?[=|X,ƹ~zz*Cyy„S2ڲ,hzjtz)4|4%2E2G`{'?KG=DƋ=k p-vFѩÊhvQGn>ru1g`ˣG-F%G?4-vЊQigwV`h4 b?ie#)zTvjQd:Q> -dDPk<~|G.?'NW3dx}nӫH K/.~omDsM,Mڮ6L+ LrVj DD>Wk#7SZ Ab bՆ]i~JJM@-צL3[`.x:r"^+pPRC):2T'oS(-=Xl5/Y# \0G6Ԧá^hl5f1ǔK+O]>,[~_6CEA92%4@Y3;QJ&#cd4{iӸbHOO}[A ϙ|r'?X3tt pUi[U/tv ͛G Pze6ȏByZY&2?,ܔ`0`;kQ)k#GRwtͤ- J:pkܡu]Lv[ >qx[oNƘTlpX(sozq+-]*I-&|;X/,Ďfܲ m}ՉLq#K E `6 >u[!.,ȩA=n/8GST2G^VS7empR{H(#H`{|I5qBDy֯EvmCyBO0Wct~2ufnnzï~GOIxNޱ` f;PNtwrP+D+'S&My4;U)|?6nXov߾hkoo)*R= goЛʶfZ3VY̢5{PfZ.ԴY% 7kR@=;kwSx* ~ < Z3ps֙l-ɡOkڬbQQ*st)Yk 5U4cO(|N_IllMU&HD B+FNN ֎)pܪ=TrZ&%S)߫VIuѧS'o>Go~SWYU!bH(gZhM9lz跥ktuhՈY.d؞t:>YPc"!pcGO¬qX?~g]խ,y͵ݻur:ukyrU}yf;G:U~?%Zʏެ%ZF<- }=e~Xeg${vl:uAة{bQEaM6xG#D萈pnfw{Xe\~M_fb,B jD5[SƵE ڹ|=ܰC$H `6M}ёsL~vE/ Org'*RPs4>ƌkh2r$ O1w||ȗ%FONLJ krxeȺ~U6>؄Bz>.9]k|}}雹ߡ_vA\ ֬^oݺ+t:͕ U#fhaמ5Jo~k0 BЛݴ=1hv\GظVO h^뮛;y7h.Zs#'?cĢ aݵkW=PZ*+9r/@ suEP: Y%[z#0}4S3nj[0CX;Xaa!kG^#Ŕń珞=" 8(70,of2;VMQdx`ѐyzpub?>>^Rb>K`t;Atex;Cgb-SԆN $]z2DY~]{f)chZ ۇ^z̄](GGN{ˢ(H`zA~>$eX7=9~!Nq;EeKcPQ:/HOO?~u+){iB>lGh3;rSLFf;csG蕽~XpqVտHnX#*# z]) 5 !`^{vn)ޥO'N~ZB}b7 ̹ݘ[pf+MMˤd D*HCZF%pG'95R3)+$0|\`(% #Kn޸ˊU".MtUP ٿO~n8Cj~0U ?# 3I?_YU=Q7 x9F8H!-v;-w#%fЩ:|촬[^#:h,zsctu 0YHȈS "݅x i',yEQ'g/W# 8y=UW|!O]x0O򤾔*g]Fk{l\7S>;'[7PbƏnz7/q_ӑ^X{V&r"t[~ޝA=`jΙ5xw@ W@ X5!t qto3lf!1LqETD(xծE~%`Ό} Hg>g.jnYr@ dR!:H Jr ŏ{ϧ3Vi3Cp0ꇪ#X!}aZ c@ s}!UcAԱMcy7|9OYxcU[M#qPgQV#l7շ|ҝF}@uy|":tΦ={_͔Nl_|~DeKwZ[`vRFkjkѯb& nli~N7f,wRTfSC~ t#nb5n&Ǐkg\795"2٫;\>; y&* VC6"Ove=,Ej,gZhlm+loq4(Sv-NݚLLVLVHR%)L֔e&ͫj TC:襡Kg K{]cVP2!W\SN@uJ5O==bСܩF+ ͮJUavPh' q7cf73i֚Y3^k%f+w(݌@nP,VPvA{ be {]A;1Y+&ˑ6#>>x˖-兓J "]]\& m9YS_c@H) *Ґq~H05@j!y)-UsU%I6&K@*/"}%$.QH̰&Py}Y݋[ж@Av0M4&0b(ٲ3,2 j[FxO&f uҋӓ"s§mњOpp cw{+7"NV7qkݝhUmՇN=뺍v'3Q,ꀕU `f$ hgvl?EVJ)K׍ %fM94W ^_=JP¶m48@3X%BViONr[]va ٬HXi-=5p&CzbB@(0~$Зƅҳt3KYljaقab .fd% q[) 07yܼ\.xŁ=7ibҭhÆ~.!F'4=`v`o~G)0T0[CcGW:VhA{aMYincԿ짙3WܬBi˯Β=e Vϊt] аѳƼlK/oF"~ 񇂄ac{qZ0siʄni˅N%ЉSq2/h ]% #h0#0l9luP˫v$%?Yl4hǞ#2k1yI 7}p|PZфq@46|sHx ï fLؘ#۫ }0ize@Y霓cm?}׉~YN%Em07ΏlpupFF=jGڹ9^>xiǾa-[t}RsQRt%FOiN;kǨЗUzwk{ Sٙ9~;@{fhAE?Y)X4TnnZ62inWwOEf^رcǏcf< 9cD(B/m@aKƹ6*"NH"'N4J0yǥq2P0EB]ߪ t$`ZIف)kY}0.'4?r3w(dX0\tc3̷GW'UnW+e+c̗Nk2úCႅX?=V (}vQ4GKۦ2ye{Lab%5t6Dn6t-[FkvppM]0vgd]v2|O!CyG!ʹwo2y[{F Y+(7< zPv:lΪ%j0Y:!1C4QHIɦ^CK6Хk7zq+/r>[]=wm?1\WP%n,tCsS$؉f'Ӈt*`aPKcףvf3 W{eGAb< %V&I0QvvstFnWI6ɪl!GOK|dS=z[-=^T#*:nD}oLtkLu)hTԌȰ 纄E`O.p+0gTׯM\IPRw~7vNl|e4<QbѢ>C cI_-  _7,z#̞3g ~kbF991,Ch-]^ffG٨?{~t#k LK,Jo_n C&zhqi4g::?Qs`M111/'N*4a"2DրF#GPFm^qb\'WUB⤟aqtNTH nىO~Q:|= ,WƖ ؗc ukלF>~8T*[8۟Sǹ-LoEr!|y$%uGqC+W.i`70A\k9,ʘbt1㔩@y`3ą@2V3.$&\;x|S0' R}i,JHjdexuեEKBF;#}f_~~wd /w<*K> Ylep33[Uf=(kxv1\hK7Ky*=`4^4ʮ$<@b?-Z[N}2OVn*}OE`h 󋿙3#s>f LR+7^TTaȪն[s Q\Yo7Fdb okDJ_0 1ZyHk7o^.R%[1[R҆E=I>oimP:k6a6ɶUӺ7 Rjya!E|drps֌"Ce?Hstcxsy.:@)1)xoMƨPyÌE+w pj}G-zԵ[7$ZUk.y`РG0DIDATmVPOII&ڿ?&9UVެ1Tu;rv? k|B S(zA̬<͞Yc5Y4M|~U-SwuƱ߈6mZ fӲj[ V2 ] a9|  Uí;Sܶs0C휘Ut?-$D_ojT_NaI7 G0,N:Ýkℂ?6unDV!%8lOeDJAiT1ja-,wa欀Acͣ+-=K/Xa}3,cF|1NXU hݺ勷ߝvoFBroOQҬY\ A^=fgN=^ pv ;20qԟ5uXق{W}ῴq1SBSOeuK-5>tl02Z!ذT4UT2nØ dhպmČ֢fX\YYj(hIFi ź<*6ƈӔ|ic˰-+ǜKߦ?-9[ # *^Szvo(Ft2؋YY@P qU "/g?^D\\Z u1ݻW|~PLLnh1o.z_i㔖+ϑ ՕݔB-P_?Fe׍ШQb씽<6vzwY)6J4S;J_ь0'*4j܄aCwe0a]{k/p{=O wbSgQ.tv@s KX8[VCB!q!iti+Wٝe%7`嵵[97BirG)8П4/ l=c_{ ݶ8_w㳨V@Xɯ{(t* =?54ٙ`tFF?( ٬l^? ic]ԩKWƤIJhԫږ͛ɕ A 0,>Q<~u6TM  )fۙa~gd32cVTv bO40;W=y&EiiYgӎԡUC K.,`Mנ::,:$ax{MBy΃t*>Y[ʕ%/H#P&1+ivhNAQ!\H7f6\so}MGN2VpQ(4:UZ+ B˫M7S^VvWMǏ{䟿v5hgm$={XKwwG`arVFV5Gl6)t`W*G/mMUܐv{ݥUF+YZd^τS5/?3<̧2[st>츕z3b(0@?_Jc&Ѐz7,PB^W0 L~Ն]4d4ي$Mɴ}A`Wثץr#=={S߮|?HYjQԨU-R~ 0(ȓ2m."#}E.ZF0k-?oao$X@U_5Gae@l~B;MJ̧̦;D}n?1؏u+0@ۋ~AH@C"",WaW]R*U`a=11](*Ы}3D(W}894$:~*LǎD~g— H`,_G/NLNg|-9\5P;`CXBڵFiK=:O& Jv) w?;CZflvo^?/{gqZU^2@nͧWO)W^p)8ʘ֭L68—n aԤl}:v IqvU~~,zQFZafkck,bS~ݍf7i֔N7TD`]vn'VYcGϯWW`7گ?ɒ =NO}E 4 G&G@3x]W9h*2OcC>oH!ArU[4ɋnC-בr ]Z$ kQZn d%$>L@"mȐ-w .GDҸ3hAC.J*3 <-9dKFc]%Y&?\cbiuUnv5Wh_z׆uk,T/wjե6}ʖ3ˍ6dE+_@DDDr=ΓCnn!h߾dZ.9QQWmz=ҫhze;AC[fPv}PI~LF'Nq~N"g3nN<;h!KN/LrUUѝ+T]Vb0Zf`4Y*TZqg 3u%Y4jJ RA~~ͨ\XI7(Ʀܔ=,i9z`^MM'ݩd ҸIp9ӝ?#soтŸؘh 瞌0\ yनTMLLhXfdOI`Fdj{jܪ h%؁yefӣwD/ [V"ۅc m=O6nC(nwTƒ)W3Th0#}`!A~T=}~qT/M9Z-0ºB̌\D@o>xEa %s9ڂjB&|J\)dӝ7w rq* m.烻x CXƇ:T/d$aA'Wg]h g 9P+R!yƌ,"Ձ4{DžPG/*h}9og#f 4e oŪ焿-5Qnl#<\6j-&8[wgǻÏ^[Wp6lXbǶm B>eOKŀ/NhCB xQx 1'ڊQM쭟%OUIXrq4tԅ N1tsu+ {nGaZ9spN:?~e>޵Kw^:ڿo791*:z=3Xg[^A??6Ah-SFd&GL1SN?eȍ)"p`I(w>f}կSLR3&Tqh{>xf=)3$GbKM٬YLRSc~(;HvY#?O=)gަp^O{Ղ=R))t}ѻO,j33Od`Om1ިq㳞Lp߽k?0wHϠĄR;y ^GA!u:@Oz=kWQ jf`B/7\eZêdU É`Ƴpx?K(9yie[7q#58_m\b xcZn1,Bf:ȏOы>SdG;-8~\/Q U>\<Ο5٦RVf楜r^z=ǵ]y Ҵ9wͷfqylt=3h/''Ӌ_xZh Xqv-C7O'2^}⯾)\ Ϸk֠\ DI;PНf&!*60`hRrr9(sy>W9[/ZI/O 9nlsX9[Rt\} ?p#'闧}Le (5u^oCy{հ.Kuq)єo'*u҅> \o]SN23L9մ2İ%7&'˾Z @p,〾7[o|[}ηs^lb.ZJ/!GtO,ːjyT5 0[x:H/Mv="\.|lA0q'3{}زXp/5fzQc_êxD4|LH66 >y*_A%ϳ7?RnV.p 4qDjժ#G;Sߡ^wEhBH3ڑ3^3d:N9Y9Mß{wApr"}|]A[l[B)f@ z *Wiooܰ2@P[CbjX)Y_n@pe*n8%i@~`L;_%lZW]6PI u}|ld\֎3Ћ!f3Z0|X3T9†2ٕgL{u!,1p'̶rJr8~A2J %VFEGӬ9nz6Q0}bV5gSOIeq)ꞑ&fRN,M z@w-?e'dPzi_E-fzu%aZCVs\=qX}'g+D1 7RP7ĺxf\1aб ۩< gfӢLQjg`;ϧ&˺ љJ{'3gJS?Qz,0c5t:O are/nU[M33x3HpNF"^GN՜)n&2lU¶dUdD˝Q)NT*NgF !l- ܔWΛo+ 8iܸq4f 0[{ R>~erJ ^X-,r"2 Nn3} =೎#O =Cu3e1W92r܁Pn3'd ah̵iSw훓qJ W1P C:e*?SA՜1`49}1D:CwFmePtrb*"'W@ fq]ih5rbߥgWiYh$O?R۶m- : P1*b)?/H?)>.Zjּ*{՜QaQ>qa_}K[o s-Ѯ]:t@> R\%ЈӠx;p\fg][ o hu we  @cܙ0gW;|M-: 2Y͊T@ypBdirPBEd ~GwկhH`D݇⬁rC|_or"NBכ:NC^FoeU2`Ø.A 8 ŮڸyL= vlaUsuShv"Ot}ԛd(~eEF{8?qX'_9b k 7,Q0S؆Nm$WgWt/(?qw 9hM1p-mw5;Qu.p nTޚ 1tjAZ8GjT?2jQu@I_ 7&S5Bm E5^"=-h4)/&ۿo_Z|03ܞptro*'I ?eQ!X6!7L 9þIӦ&Y=2ڒ lPj@iy_`U83vu4@"8_H2s} &8'~幹1Ꮳ~NY& c?lc%A1\>zOo@s`R8GGNv\&1 u)ёx1G"q0š1}3 .SUH#),a͕j׫K4`;ybG A~L/=˒ƍCK)4s(!9hرvy*ǏӃ;O5ȑihi+tBp|>C;{]styڋy4N{:mݶ\9\NԤYS֋X"-/~QWk,EDFsQթ@cUcvʶ)ʧ.CSPWCle;ҽ0@Qc$懌l<1vۗPSRR1lŬ 4%LSN6=Pm# A>}40bHxpm7U^]}9:z,"/.4i$jTy1ݸlJȐ4K$ZZѕEsa}q-n100(@_J@}DOvZ4嗩Q´0ƒ<.Y5)ᖒF?~w\GsF$Bi&]eWBCdOwrF HO yj֩#̉2(g:q>YZ4}YP_`(ja+i[F/LA?tb\9UǨ/E??jWgؚREb@ )ЉB9 l&WVH!TX C(N`G(?-1[n>ßtl-=I> 50l*4e{.BجC`.w0e9}8kEjD)\_N=;״Fb)Gyш4߈7+J d>3zWԴYSHa{y[&;;~Hbp ̔fϙCޘ8]MFBBB̋JbG &PDx%$&=$Gu7kP#X;PW3g'+d!)CU@'Qsuec2'Mr;//NŠ,e#ߑG#U },bO9%XkbY{A9ĒKYqTkfa!:fÏn]j7%0͍+0_7MO&s|l1ӯOOFjӢ13,%%e!Y_F#D$gsp;dz嫶*e=uj1DFZ6k7zKZȡ 9C~_Ejރ sg}h뮃znZu\4wmk&$[עLjԧvב}f$:fbbl?5UUY[Y4n۷RW !zT{.3 wN{]nӮC{zXll :5Q\Zs)#,YX.b1&%&kFZW^{U#CLmqwYfMB7t]+\,?d6gf/_]@}?p@ܧ >۾('+3=FGS,D8!G\~:>Nm'|*يˉJk1c܃; &< ^~FMNgpׅoPeA%'Za4?#v ۹MB%)  /%&_!^Le7yQe i pc7ᰐ`l[ѭS )84ݝ\NVKbFA{%mձ/)}aڼ8|٬*L@ Sɴi~K#ԽH\ $HB ֠W5VMRH?z{/E*BxC/Ab.I̖wD;v"^nc3^*Pe@ϸ3X%3kOc)tjtZ/WQ6إ no8(J—cי}% @t墌p#.P 4υ SN4QS$Ffz:wLqY$pJ89_m,Zn=M>`&%8a%=0)S?O۵ɰCr,:8͕=^A(NVFJo鯿y䠠 a=0Lf7m,sIZm4#1ӦMxk\QEw0-tSlUr2Z'M: Ӑ To ظ1gV <,`{kP1u LgM?kpn̎?F'}'  HԬQ]L)?5C\ 4>*=$H!f,.R:7+6Зю== eiC%@Ev>̎pnTDխE!(ûLPNJ,Af$F LO%1sO 8^A :MLv\ V#Wq 2g{>[ bFwv.nwY_ӵ]w>")\(p=|0TYPadO(Fi@#7--UXAYiYRW,AR]x }4gDb1s0nرz![{20RS)?~uSJkOSi܄7dҊ >8a ~igEHزaY@ڬUXys[c3rPa[^}5Z|dxKV6і͛iƍrE*&E` &yhܹ35nXҀJkEbA;T 抎>/hC`ņz8&RMLϡCÁ :, TR (AKbizǍME𜸷oŭ_IeFE1 H8g7$}dq7x7ڱ0aG IZ/t wgk  -FH8x3'Z asw+s 1̅1aL!i.sABd!H8n1e'f-lt(`bY,"ٯN@ hf3bt̰F1_#|6~.~Cz؂+ҦM7s# j։%tJKI5)Q[f`<(?8ji9%٨-r45$E\"u~@p&z#'\!ee2N{BR eOPC$$GD~~y=N&uT&yR Q /KyٜCHna͌+C"Ëy p $X#e :E jɿ@Mp>.#hbFi`qEJ v7qaTzDϿ8JayBR -k-ss63'khIԩK糚Ti8g8p 0sadu Z0=HXHiܼsZ)48Xҙ&ŐnƍQZ63`~'""B:`hCݖ3~0T|Q6=$/nh!Nݻt-F3:;ub) c1|,$UW*0Xˡ~d=)US+;7n}NĐ IoZޥ5T:dPѳ'͙=_M !WUQP&A c44:<՗|#zÆ?tPY!nb?g N: " ^6̝5VrvmP'b¨YK-YC?, :mq\Qf0ho=$](`&Gj:} 8sگa[ǡ>l=}9l:0s:pRQ.+1 I@ +͹R!/K+F+e} 0_0B?%:K_5}8Ӹ7&H!Tf"=J_~=HIIݷsiu̳ЭRi@:Щ+VVڃV` ~ofϖS2p=X)*p@0,22R[a%6$:|S}H*TrGZbHScX)C x.` *Q ҷiٴYuC8ƙP7lM"*?TRW7*ɢBS2 {/֔oӽܫżȑ#Gh=uV:cǏ}!4PA|0c0߉ qn%+Or#:aQ:8>&X߫ < 6{Сua'\nFSa !p:0w-o3N#a#X(tlH0=m?H.:o3!3-;h, iNR&52]L+ CoZf3לēaH A!_q^oNAb[eQhgd/&&5lԨ>{рU Zp!:f 7WqcNm˦^aS#szпC~0CV>=ޖ -D UΘ1Cv|W &WZXxOciibI֪U%4iV#*L(iа_༼-ضM2s_.41&Q %+WI_t/ +6kO^a()fXKgN2瑟Ayl!PQNHO. 3!KQ #P0>uZzII,f;r6o, M*f0aZ~rw瘘&9.M'vCvw^*[X|m=:ӎ=Ghtt"raH0֨`frTH*ŗ0k2s}Yti@ wqP|&K}Z&^̄!٪5%_ՀvF8?!F0_U\O56z@qPr$xxJݱ s9l3c_9y|~^:_hckz]^#s#GHRQ);i#c7 mʕ4פ y)wG񲱎-\̧"ne}Y,8p@=}u6B_`( ?Zzճ iAZq!n]%4͛g1ԠޫUjT+h|  ߆TiY/ K+lgN절 +M?P0!nb^SF*dm3ܬ;03/HAڞ4zT~}ipG)JkNxϽ$C˜ xpdF7$6QÏ08]oK+zqIRP7@(u0s,Ċ:h?RzF9\1߇e憁kpWp0`ΓT߲f+u`벲4ӆ2r $:-,:Bdw(a V6.A)!$ř^ ܡ㭌iy#)ʕTPZkڵkϦ*~ڸa#u֕%oȗ;\f&b+`Zxrǖ5V #Pz0^aIo(zzzѩ'i_Ӣdsmڴ[nh!4$M'hƷtgbiR82zt1=1Z<߭Yksf@DҘ~EgD#ܘ7>4nK"B:gl EdJ\b Yt+ U3s7>Ly'8hPq0\n]zGo oo CbG58DEEmo3HՕ-D=&RSPDq8e WVDŽyCV6mxBU,DA $ XqY}i``ңֈh2L~ʇsi9`Y{;BSȽLX󕺁",:;~,baMN/RDjWnߚ\<}l\ '-,/ rmUr GE9yiG|Y C* Uч 8?cfۍKhVEkYnW:vEVIV-01Yd)};gٽG-uڕnjJYI! P;72SL\L>BQ^vLG'UvEj&mciϣV1׆smCwZڸn}2lUQ/#Frt&f vFAݻwoK%бҤڶ ǘfcJʛr3breiܹ#n7pӅrT6EAAZL`[f-b"ϕsO'Ir qNq=LTsXeuR2E;K EقqbX AXޣGwjݺ콓dA#ߘ7z Ο,FAbTuLVZr bs'kQZþTb: 'HՈ)",|(4'miED9KB8,"èN#?XE:0jӜEyGKn!&%g$K~\W"OfR˳D5By+ "Ѻ;%ҏ즓+BQq*^ ܩ8>qy5>pD}65%y=ۄU!7uj7'̜5"GJ12s k_Ez[7U١ccUXu5'G8kpZGe@T>KnV98mX>7'@&z<6V B3Fbbȟ$5H7䏝!%0~rg7eb pF?efӻI=$k5.d('8\J .c8і)2:,:{S9H2n?on&93~Za'DB#Yv qbbK~AչH՜4& wxS#/;SÔ̜Aҭ|ha{{mdOH` c2:B\ 7- Ȉ՘+zyTph,ctq^6r|f{tؘh C, *`P-oP ̔0 A(J[7xrY%I=,Bň2OQzI@L~>pc։O"ͫMyL@QWs@E4Phhn{i v]jxu˖>XKm[o EO<@U'4;?O@_͙u^Ɛ}NJ4_ < R5Y}{s+(+R",VOIJ3%TRRl} mٍ~QـI19Lر57?z_++˥ӔGEٙ:f28Ϗ%aNR]px,9{N PFl1>dV`LJnai<͍#fGqLY9 =m1'('@DNDiC0|ȝtعpxиOeT@б'GG FP=sO hW ˈҳ8Lm@CPp0}5k5oѼ"t,[燴>q?Qzuqܷw_ #GпK##S=̴ͫk0pg~F-}o' ~KA 1c?xBV dbh 5qwЊIE 蕄Ta"~ u`bH԰H"q[!EEr!,fF/DOI'Xi2HU7,];HyLVۇRڱ ϷOfbT {Bm<3>\Я>Dbۏ`WjA-Xgr"\t ѸT:u[~Αa¹/"4jA)`T{_,;a}5rj\M$AV˂_1RUy䣏ߜ4INUEM1w cԩ4or"L4z[7l.@aW?OɇSCm^  ZтX05 V6bupi/(ɂ:+L!M;q{S4j3(!L:ffa*fE8{x,oC^?{+Sk"=i[F8FZ Yer1oސ`w!?`0{y;sʺZNYb 9$K{sMTyRr@KLOV4Q@ǹOc=՝4Nˆ fXei8O*80yG"W/_6 G i-K]/JqCo8\bs?^ڢ* CõX6}~?NZ;ԡ`YxGNٲsUyT~kHƳDa/&@&V2T̍2T rD/: *%u!&3NeuLV,V `N{pS9ksGï*5\n.nTD`n.-NOi4qz4gr:?_Jx#vIpg,_Р *l=)s!aa7\'bH@XVCMYY} MO/I +]\/#jwQ\u i5l>:uM~MK/``BWyP&t~5aΠc\(ҏͣwNƿAǸt}4wQU EWp> nzrc4bhyRY5 8|&C"!}B:E( 6=HJ1Xk)&۠t+f Iޑ |9 ~QzzSa4uK_Μc\ЭWu p XC}'@:q4TUJghhg/K>eXPpL(a5̿^.ۂЩpb$Tta[zf(,5b5ijhXu@T2b%- 0ˣ̜ j1THFg[,3r>IyYrHEqvkE=c*OYrWQ 7anL<38< `˲CZx&UC `n1ͅ_*r: #B`E˖r2)lU`:EÏP¼썮] P Bw} gsZK\rv3;&6/zL0SB(0j/uӇ~>/;#\T{&3r& WtfN0fdRh؅C꿕ţF\f8[I{` 5f}M=KnIOO[~+D"<RbtCItw}&y߷?i NWPy03چ J%b28."$lpB r YS`M)D#DiV. d,7 Ş2)77Ly͝ =Yx@:=WH>L0g.\qVx -5"TpD0j)I35b*r\꣫Ak w5feX'&SE̝^,2BK5j֔.$YO'3I1H wЁطnݚ>c9 )99n' uD.$`0Xl8Moĉtqܹ)3;X\֫_bG@r친@(X$S Qvv+sߜ\o dBJ"3Z۝4hۜl߾Q(..Nmcݹ}٬V!䧏>=@cჇ'ۄBA1X|{۶4lH#}|0[<re ʀoFrG b!~:И]%qO7 E졆lPf0RnJeդ2.齰 N{^hdXPn䫖6oPE0U7DI2FE0D 3Vb)浄ك 001O3Ɲ-RXr2/=QSɲR-paNs#+\=}v 6WgLڢ=o0{eS@|0mzŌJKl9k P5u?3tQ[QGU&LLҘ78pzIھmŷ]q\Rhʛo{?}3{[O>IoT~}+f3<<Y\bp3$GQ8`nHlt 0;<#:AB(-W&@w2dufTt c ~pߎ-̡Ӳ4z&.^K4;-fh-K` (&u$K0 3 ӨP_\m!?,gk7.YR2g\oEgp~0d *q{ kbAAATHxt0mci~0H,cvD-$7~  `2\-bN<`M99ئDw~M09B۷}%Q1]؅Eឧ̷`N12H MC:dcJJ?2M糚0!\}yŔp3ObH0tYGYPqve;Q oOˌ {X}eiLf&鈡@ZqDz,iР>RfMeN/%)/^")lP# EU[o>lYcO<2VzJF8N*8̡}ٗ_ș ٢`aÄF@1jtjשCg| ۄ^U `icYQ=0= ]"¢k ~]@Oowr wpy8{O:ٗ4V+QPD9?;rNb4&:.Ռhffg wTPP`ۙONN |5mQFԤIc!X>(mۆVԘԤ[{+ b\.Ɛ9QG$if'X,(}\1ĺ,N5{GXztwX"͖8!s_yrG[ _g5'rqK '>ujU@Lq}2lb)޺{@Z`Xݺq?&,-q|}TlD٧ht*E]9ޣ05kֈn`x7!!֬ZM۴Յ\wgԩ4axNVٯ_?}|WpâN6ml.]^;r@VV WȌb!A,)DŽf3Z˵9B78lp!HD.ϔņ*LcRR=a!Q-w7ar=@n E.fUŧbJDkPևoAV&MS(N&N;Q>3L!)kTP70+l`؋'@֔p Ғ:CuڴF@fr!ƈ9P,պ6'񤄣3|!c`nF􁎆=G>駟XW3bb~A>ըOW$ȚE"@K0qFf,ݶ]JҀҵݸjJ}x7>>2֘mKVxu }Y4zKE\/252)^\`%\uB\&{mc W? ;&>w̢ZCqvs:Wa .;[; HY虁c?=9C"V7Bꪫ((0֭K5k2$@A(XQ/Ы"/FW¨23P3e Ӑ"4Ze[M.3\v%œ N"u)N(3X;gOoréPn-DR]?BӲ ghW^ #x N1>i :wr Y~>ZSCi_͗G£(u!L7YG ׊itoя? qWWg^zQNW#)s,y0\c'g!˼>^E3ԻkE~+(=~QzFXxz{ h06yؼFR z~X `yYT  1a&y3y9,U{\[31 gɠ0ʧ,,%ɟfҷ"-BCYnz!3S2R O] w[죄[F [."7i܄֫+VcT}7jj&jzסjӉb䬌8!qƞYaa&Iye3 jhT0{DS`fe^$~\(~o -{k1]g^c!`k;"$'?dd͌ IQoSQNL-p[~v:[H'XдlRUb|v- 3f*q{6L|\<_ºvR,nA!իVҐǟt-&/OO1yzmN'O2L| F;a„ז/[JIMM [IZ{Sn_^ ngѭ"LأY\}tbdH,hg?$!&&XƮ3ۼ0ZܭatZD8$&$P͚5e XP: sFT$/of02۶BCdTvv,6iֆ"FFw0L.J!5Pm)vLS⎍ (bf,[˄ٖU9^XPڭǷVc{uXa3et RΆ빈_A|F'*OwFNƟm)R<w@.RD23Ye]xld d(ba_3韜\<S9c"0lFݮZL9?7\$G,|ByP֬weIy|rCzُy*reF\,j@YY&%'s .?>~\)f i/],ګcDFӋFI=9tkQ *ԠM6\-$ڈ3c3볍8\>!g\٭(NPAgm\٫}vكLs.~2@r;V6JR+CfOLrPD190}ѧ|*f@# b I4陡OÇ)*6Vl!p1'7^R% KK<5,aW`ʑa3,;sט#]0ٝL1>@&Bu +j:Y΂daќ#O+˞岏sؠYW]E{/b=%`Rtzӳ BSʜCt m1v.Lۣi¾ʴ0J5OFIAMXD4&j6?0bx"k|Eʠ7ңLpCi /ށk98>h L9MmXeSf~#GL0¤n![ԏ2:swޑl{OKә>Sc ށhʕAXMLNv/X.kwΜL)#GS [[Se:`nnalU} |hdG+L||lOfe6zdF$yy4kl̶W\~=32Ż)SCq&u*>J j'E aPϗzɅ_|Ayfj駜J_~+[nO:B1Krh*-{ WVv3{rf;kD.m2kԊ@}cL 96,Plm--GoP&Xޝy2)kT9gJ9Vaͣ^zY>6$Apw! 7} 1qL}?@VA0:38_gš*/Y}ަ.hŝU?ΘOa0;â2 rѴ3G_qerL/%ôFA PF;o({fdm;Y?рC}@+.y)CJiL=4uG`N'H?G7^wm"طqúBD;g=d]@7x)5}̟)e1nO a$b1?.QyfИxU3 5ѶבsGkCxa(vTS SJ&iz GeIxG0bky,tRD[ĨP1#sq_DD8~qǂq`L! $"uhCD(8 ÌAV rǀ7Od~፺LH7(M.j*52=XdO-^HJ Kw1Cϙ=bvd/M$H 3w҄Y2K ڒHymM)%'Xʝ[w#.tCc%O;_-,bT 2ymZ][^C7fYa481ϛ|RDbOƗY'mjaM"`6>Wy!t1+FϿSOkֆ`ZN'X{Wޢ;éd*ZH0L O&VڬF- ȧVqFHGcm55O.>5~,~dۣ T:C̳[y=GFC q JW"~Eif.#c)jDA([y(ԙpnVdT5"[AW^n6)\C<!^s M.g/ieJXr3cBN@|IJvN- Y!k8pׅ;Ѕ&8 j%' R/TүͭTL445t]Y ]^Z%?7zEۅ"„gҼ?FѱZ,H]XZhʁf(HoO?WZ`4y2%긴D"n2?ewadʏަ:XbЙk1 oM98Jfq$1UAk͍ tCTV _@C:mw~G>HQ\6|D1c(uF|!YQ]Y郼E 9R2l͕,d#} G']d Bf?q' EMu3ɋ9Myh~s,ЬZ ,a}ZJ_xϘd)? 6UWnO< `pM={.Ld!(VQm=]SRA3Z-L~x%Q0dqD,P3.I -t%8 Oǽ+#<Kӽ>)3vf7WvH#Ą@b Y :c-W%,T<)1poc] mGiHHQk@೦P-T q݋M*σuS}eI*lL܈ ?r71 ͋@!ma0sgbMoj^*d#3eLdOWE k+ƹKp$<}Efk҈ D?L֮zkx1eOLxEFE`ǯ&ZI01S݋>^1 j5W:Lvh*}y +䯓~R  ێqgFFKߣ+B: f!F71?s ťe 9F;QօiIL@1`0׿ސ9 a+8 |˼.})p0|_*۴Bvq1E#\wpf餱6&teG 2 Rͣ4l|Rdk藟EBq}2MF ;S){ߊ# :C[jx&viB]f tTģѪU.kJECcG):k͖A-V,Li_W @Y24jNCX@yY3aQ 5`ƿJ̏0WpRxl/m3w?c%P>j&xz'H[MN 'H55|v@R),aшzZ 򕟁APa@Y#jl\&,::}oNɇg#0wt-kxg/ZLV&7:O/"9T彼@{F!0dUSz)[X"#gJѠ Eńp/2Ҁ<#CӸC5(IlX)PǮFjhe {[P| RD aQ"ȼP>@^,8JΈ0 ƲPg8׎9qI"(e8TFE2Yg ( ^JN{p8ovA*}8i9fYvI-'X;ܨ3xadMYS _♫?zD FkMo[4Ԉ)ċaNEF adQ14~`2Ywg/^L+ a47_sRz)dHx܃)f4MxؘlǓf.]X (H~_|9dKHjh J(-=MEb+VL+<[5.4ME7.ah*}O@q>X+̤"TsO8MΔF!h^LȜB8r& 3 24l{D==RYdi1Q$d {+Z- F%GFEwL?Y+֒W^I=`!ЙFEErjZB9YM RbvSU1 05BX )[52.?&=>˗Igo sYv 5Sٲ:W,?rt֙Y+hEj?{"zdr "OPg-iu&qS]5Օm1n(葓"M`f 9tŗвkX+X1g[CcW_\2Ο??(B 1nbjnn34!X¨̘6HLX;(@9,LjϗmKgYGd4ŤdtJ wSDh!豼JQ=&[,ĬBuQÚrBN___doqkAQ)&Lo=r M#NYDqkCۅÄK,Pa.۞s@3!އ|5nUa/ᣍeT `KϦsXhHvZz a9<++!@1so7m,y01/2*>Q^AAͧTG΃~q 1y`i)7[ 3z쮮zsA 8mOLԩ{炥aMuӯ3#^NQ~ 8?@I7ų&*`I8[1 ð踠d mPqe_+ ^9shܹ2 }^ Z-ej槤]i:^j4}?N>6VAPџ MwS!v%[@ (&ouy |VRd\OܮtWD>Ǣ?sk/sQʙ'L,ud(_qIę#k&9 @X7{dz,b(DJ¶+@èQQ H|@u /ϑ@Hd-'ϥI /v_[ZhZhs]QfmIQwKD|F! 7|C|oY~D@~h}m~s##n[C␖w ´H_߻』 VDx2r!~lkKallZ0loAMFc#ZBԡQII k=Mz4y3n]lqu ֢Ey +?Ј UU `B !ʚ[ &8xZ <.ILmZP OdCk֬K/֮[+Kk륤I(e=x ZA-0HjK e1kG  岎=P4t"YXGg_鋁<8}WbjX}-C pn?J]  @ 9 BV! Sc&b$y ˙<Ф!~&x\H1I), Z-[dU_OvK⫯ҥ_.`d24_hhrFEƂFp[Ik?@̈J1gBD#]7|EAEPFt{.cY ;W|No hKkxݖꘃӌƌekni3曵 W#s>| |CÁt̔ɴ bA4rY2Fb9Tr$}T0¶scf82._/?I#Q)e6ɏ=|aJ@ ?ɚ,#YHk95b-&Vn]>9w4eTWkTmh .gTܗS&;=AYPdin} "Mޭ@A02qayf]yMroQ8I8o+<֨"D;q^>sYBFLlAm 8fBM~F+$;8-#ӇpPϚk+d_I G 5]I7atW aAQiĵ"4}!.& ];$39"J=@9uipÝ2&@CgȰ?0l-ut{藦fqk3{xCN> Uo! l^,1M̙~)ༀSF{-QՖ|Yg^PۋLRG̉So ԝcG% Mpl6Ph4(-a2fš8刉W%e5NoeM1[Qݾh";k>h a#{ #L̑Y9 NC ,e\#8 =E:C).>#w<(mĻOhIm:h}5⫘0X ahMu&1>'#R AZčr;"7>z޻zǩ9DB 1Mp.7߈[h5U_ z0F7kZ'̢') }pm%%f~dkY_4"0G>;-_)dodOHgWi=x="'sv3 $R&Y][xpIKWa234jh/+JJJ21 7zslE.\'86PUQx/0[̘GƴެBh;MCQeU ?}kE+|B5Bj`RTķu0_eۍ2O&805{CTOZpǵX}˪)̉Q(䷅{)yj_n(أx43+\WQ Jgl 0>AF.VF3¢b(kޡO_ MýOx"YvmZEuo'4ht]wL Fb#:fϙ#jZaa7XHdp#U%cbh?SCr?glC7 ]iA*+BbE H &ckJO;w]C?6Ѿ \C#1 !ch=yh|-(*!vUb"UUpnR_Ǎ ֑Ia Qm ߱3zSlh:&[8>OQUv2f@x&Q];=@:Нbު́Oa 5԰',@]A,:GSRX44vkrک6Pہ(&Lo7e]w`t?5V  u CBe!;3mdc-?jr$sa`Qg"B@и֕0>Moߵ~`2sVyX #4(.=S4+V~$ޡOZ-'݊rv!l2r@7^~?T~̡ }($Zj*MMs"b.*8xkC=??p= sM L "nr3(g11")C HшMcC U'Q.np4ljU}& ;d^ئfGew:-ҧQ7ɂ5[n[w@xYA O8GW}@Fg#8~3yL' GԆ!kO{12S 8XA= E``V$9܏?@Wj k@uU5KcIQ IbNŠ-ky`2AOC1b%=naxz%/́p|MA4rYd fa4qXD%FF3MR],?֕nok,⋴ ֓+wafҕ21}]v6m.#m~=˖.ˠNdMլ41/y'@a7XTya |ksL`" d[҇StV 6 ';,7Ip(|@@X_K~^]D%$uԹFFhXsJm0~4ל94ehhƍ?Q 4z>]RMIh4/؊2G9/x3|0sUY(acx)"L ޯ,mުR?PM&bwqg{8Ɔ.lv:<.bQ;PUN |dԏǃ fn5-+iw]Y<223A~@FP}o;#( H >u7&ӓN'97qM"C S[,0 8RG"o/,;~w gG24*R9ynmI}3iNWfe"&N3qA/=q`!ZWSMn`mIq=Xe2x8Y><}$? '[U:s$ӱ-9aF, 6R~԰y 64v@[-5;w-}5~`pTSC!Nʎ8 L1Q?Vw_y UK Vpp E]A ML=-XpD^CklF <>x}3+2_3XtQqKx 4$苊Jf?}[ƨ~8;ik)Yc jhb5ɘj|&vnRa5mk,dQLrh]|3?KϱA0 V zSTTDG v:qqPn3(dDχgin2֞ 7[Ipa~=B w,X#n,ΥL1DIXvY*fA;L%1D<+PX[$K(oIj L5AĦQ}Y1k«dv#`!k !ٙNkdrPI|O7}=2@?v&gM=6nF&XoB%@Zق eI@ ?hiϗ%D8Z,$׸c4nNc |5ã;ZWVHM ťBvjLX!?Pua t]w5خD 7}:/ J INW7׃,4n-$Z#@d"EI0؞Z#쎆J?p~-Aq eRt0b _ns@9}25:(~ٯpB('gT%@v!ܸ!#M!aPQ& }Pm`t@,¸T2 auE4tetWW]IsCu8i"sOLMNyyi&XL4ćy -_޾3DXBA78rS3n.{FE_V1I4&Nτ1> qPdo `+h⪥s)u,;^@6Tyo`m L  -f& t"pV/VFLr405Ji[*zWio7,2bXBe0XX1&'i8]A8 )6njCǟp<~*iRҀ-[o| i;h@bANƀ59HgG˳veQI{t #ފ"r寓oX}? c=?tRbb@HVwM>g[_ -ZYH7HkTGV5Z PCۣb(&tTXKZ;HȀ@4b 21 *@E 25{h AxP'=&Qi4; faZ\H3 1rɠ8hp$/Z)gb{Fm\oo,PVJsE+4Ẅ́BΟO/YB_g4M{fhVY]՗_{aM PaF7]) u׋y-yCv:4+o3QfH/*A#ŋ醛n؁ mr*}w#ڈWNj`-bY]Oչ, ,,c&^I*Rwu㈩ ptP' (aQq=15Os<~E23Pdz,8GZ@prΛB]'dT0CH@HK1$ CLf9YD$l+` 3S9ܮ0WM/ehPAMfѸ&2r4 v3{DA" Z}W_u}g“l'\] >~_Q Y1iy{hhlvJ>cd.JKSi!@oԻUu2=C`O>*% 1p; nB&ieԯQ ZKpnF6p~LcL =>N!L&f?~Air^pb7 }1o ڑPqرQiIvȑ#`r]LUi R:#(?7OܧuYi nlbz#[!Yo42`BbM:~߽aμ1S*v~~~ 6o,k;` 1iFLh =(en* yLvO'A-Mn>e~TSR`hgvǡݜp_$̔%Lc 9E bsJ=U%=+Kx:(k\DeU$XX Hk07w/R!MGs chԨQ>D>42+ѝ߁~T먑dQ`}NwHX]Mf';ꔐ,~ &{7y$@CccU3N=M#b峄F +s_h-.&=)}B"ň\c:aBZ+maMLrh K)2g6Iꩱc B?UQI=v#2 PgMic#-JII[dة?~|}Zר?Ei 1|.-J.m ѓ)seY7?sB ,}%ф$őG J?I"}<u~&Hzz]CSZ ԃPWVJB/Зw5E?iS  xZ@x":ORtLʫ $Xnܸ;믴q͓?3g SNܠ>P?G_~ifC"_p+`87 |'kΉb.n'BdYbY&Dѱ2*e< sR[Bȓ2 w:CEӞ{3\HJk)iCAD|oM%VI17%.%]_镽}G~tp"3DIDP ;+3w\Z#&rf'4S@;Ų<)$?2U+5mށкԆs<2IbawPRr2r>''%FLQQ2 %##]̤3&/ӑ_g~Pp`UD 656Ryy8/-))/-;1񒗅2#k%9-҈1ByK Zo7Q|\2 (=-]~X@"BمC^Zu+mUB%EŔGBPج䃹x ̍rrC ˰@8ч/S]F?\x"^|A"-@_t)=xF8{Zz%xa#Fp`@6駞yD"(--N=4_"ʸP񬮪[ɣ e BF +`~?ɢAʚM7IN@USN z.5cxuJmUu5$nPTZN'0oV$~& x3҈,B9 ~BJ3ʿ@N#o2${X6iB+ŲaIILq,|{=ԁ{k) |먪&X&e|rZrɥiG9&"#C =A+>RP_Æ3?'AQנa'I 0W[WKg~:s9Kک (sUK镗_MLvй\@gLb ̃ϸF[UFf>op0ɖK ܆kN:q3ACc_+1L -*r=~\Ň5P1џh#wTVDBXKaAb]b5;.*f487}#<́ ]f]hii4IuXN3ZEDDRTtӂ[WaP`yisc Zz }9LYym(m>2J[8hJX+`A_8dKBSM$ <4o`Zv(#+p!j_YQAs}$t@{> Cbc[x\t1%XQ3v:28!yFM% 8!qB,n:C-#441?ēKR4 |)x>,hf̧yF@M5T`kͥQ)H ]dwev(DD>ƖrQcEspZ:Z0ֺS(3+ B0@~*ULT6[Y^JX: wҖ-t˨@-&6`n}A*[yګ1JAw{gvvyם x*d_O67khCd OHS)cP(u^26qLŏڍFPdZ6 N)'ΡSx<:h:Injg!P51"6X#"L_z*tq5o^5hAu`aA,+ SuU䳗I_t^n_vt7ko^x%okZܫ6UN^#Xʷ;~u$3+2]Muj\48lF}v!Ym"OH{O߉8Ŷs;WǀAbqPZ\|7USAڌd 1`.>L0V M]۱߉1V6̏hlgkx&C"͛s80q0Q \O$Ū{1'`4q$c5S`Qb*fҮ4+0K|#zd wY<#&g5~LJJJoO .>q]~mYE A$y_6| !,l#`9*JF<_ށ}'?I (ĴCJUB/*@Ȉ՗l`bdGT$fAAaY3D UMrE0Z8ߡb^:fjzK._o:#|C3ΤK/vz>-[|F&N(*sN[puiGSx&kk~/0~]tzZC nlqh@o2:@<0ρ\(CZ/fPs!p<€#] ubI*rM5Z ~M2T:mz=! sh 6j0o(H]G0^$L%2'wfW_@7^wιtd[zUjJy~zs&F?7{n`^X~wq5Y<4jhX GupՊ10;mXI7* 6RՖͲ__Y*d /kmnʚ+ ,& .D#殭 wC* eh++e2 D2~_Rڌ}ICq^?L(L|MU35+FaUl8Rl NxFv>k`UVvB ɔWNxvyYnjjX+\܋ժp϶omum)(o>39ugb:E"0H[UJͫ;37UbB.^xF%#F!|-1)0.B'Thil̿N-M)YCu(tiʐmX aèVmnrJEzP_L@)sj[;f"vj0}O }ԃZ)Q]s|QoT]Oay zqĄ5=aĉr6!h.2x bC|7g\l:fgA9s|dihMyoꚫ`cP,nXA,BY4N,0- DkrhL?|nW""h|jit֊>q,voX aR;.gfDD$(Ϝ^Q>22 6)Sl0G#J br,ѢC[Ntw}о Rƍצ2YM$woV:,Oŋmf֖N&Zqi=? d*DPcRiA2Pf d0 B(S@=h~^  F LxH+a9B"duM̍8< ʱUPrjؔ{}j MMEr ĤD+ ~LXw԰\=B-z:ڗihRD {q3-fs_4yѰD%〮vB0Πer0E=R |H*.2PB|.gffR[S+#j-E8e^^}K/=Sot߰~TO}jSU=p74q0X)##o ]iG]%ƛoO:IF/1h4H 1GE::SigҹgM{.h1-: 9I'qK'q\/Қ5kd"`u7ދ (O .->qhW@ sk#Ѷ(('+mF)mURea)l|\PіbŠru5!u԰ C%" | x&A:p@q߽Z&%LF79ѐ/oX+ϿM|a: ŋԵK-'!hl*O# XcapX []* ijlK,EgkWV h~#|=  ڈ5 |J Gpē~~Hj:xr=!MYE6sׯss=xv5q43+i ZԧaKNN1nbsFDRFVy _ǂ>y^YÆ X.S(k=PfݮՎ$p4_~^Y?B#)n^ǯqj*ʕ@ _* ϧk-TCc`P}8kVn>ea>ѷq0Dˀ]{jkr⑕{{ :ѢLO:ShTE.ttDݚolž‹+.sy^%\"A? ܿ3Ac<ԟ#:gb{zz..F4: ùZ|c{l"Ōc~ [OI>vܫc';("<|&XCcA&_'=1B'$äYsh":orl|);mhhhl-B@fb9(3>!䫕evmlۑ|ֈ^J(&\!&mڼ.* 4H8 {"dvcau5ժݘU}j Тo_Hz'<7z ン3RCCc1"Kh ֌B W hX.O̕Kؐ5Ƈ4C\0?Z ~m̈́D6S}M GX&^sW 75*غu Tz~'ǟ {7PZu ? JYqĮ]54vv"4;F*~yS"*? ϡ e#=ArwU<5sGx{ w {pױ,~A؜N .p?^x*{6 ?%FWנD D4j`cs޹tƢECrTVC}}ً{ߣX?32hGJF&0YbW~ C)\Wv (zisEwECTY^o{W^e24QSɑڳkMśɝl "Bb$oQK5A_t1mޜ+$GM7!%="~ꩦF֫rX_wG8eQFz:egg|)rZ0_666z):iHAƠH{tt/AΘp=:ɩjh Dh1D9P>QFZB[l⼁CK^WJc8HIPFWD ->BO&n !`)f;6Y@j* sѲͫp# ֓=n TH@|~>4ajh ` +hDky2FP˜AEn8cZ]԰'!/ #G/HYYY"Xw5E9//s9WH&<%FMh%_CU ֦Fn\1CCsĦUeO1WWk|^3^p4sLC[x.L", ΂BͥWL~-7jV$ }1XbqV !Aw?گ*JMKNRĂ  ;SəMc):xf),hۼY;%oo:mU%"ha. /flm-d粋{/|mR]D|h+XS䞞!MÆeKd>94ҒRۤ}7EXa0'+ ֨JJJ#A 9"eDУPNNN?Ub `}/bE\@,-N` vLɤ8|5b!v87-_.x X5XkOq3#vGD$\TGj2g"rѸԪiӧɈÇj<ؾk I nt*X@yCSUZ2C8cgϙC?$;\`#FDh"X{ BTSmb̚6Y\Y*6MCXەK<24\ɴ-./hd[`_Y9hxs(U2ag)J/\zmܸqގ='A,Z- .4 3 l8ys?+;h pd54!N2Fme-G@8C FmSf_ 7?[(Fv/wBp@26l؁PBh#2 H#B|AEBX7iEyYwZnuK#_q^閛mژm7to?jhUz`U`+ UD $j=(mK֑AL={}d54!Goqbj&`5 0)=C4YN( 2;6[@а](B3vIo&pϨPH4bϵW_K|DE#(zQ }mX\EHYH6H!?a2NMM| kv-[?ZJˣ qXä:&Qkh,fq>&&bXFLcƎfI,ͻ444c@ LMZ_WkhT,9xˤ0kTA`#Z[S.rL_~K-]{(- b2mFUZy& 199^.55T\\,up}U}Uhaď8^C⦡?_}ЧX4x 6{D#L&{\+ضSVD1UGu"Ht= -i4‚ F/_e 61 9L8 21;?:dlbbL A!s!{ou7hǥK,."ayz4(Z]Y7Wt UK׭]+$D3DKjf 6q}N:.tL #+)^i6M]Fm),lW瞧͛7K(4\e58S sX'$EeB/*c. k^Ǘ_~I\}̓p)3#K hCW\qkS3" 7o]khh L =Im]p_^~j `)bƄe_x=)BT[jظ󨹶5qL}!yfh`-LXm(m0lDп>qD 鯧LPk4 b)CvĄD󌆆Fa!ZyE^bq5аl1MXp&[ \EL앵Pkd? b䭮:tm+ĀA;Ю' 2Y8y S2eЏoF ϑ[Y%YCCC?B64 /ƿ+.Nj3‘DH@8h2* rɵ ߺU_Qe;5lr 7[fQ :5|:_d//kokw,`oDeKl/ w턉d..^=&Atl g#Zj[\Z [~k$߅IJKxroXgg ! $&%iG z2t]h0Ntm^{%^`WkHL I+#C}a1h&TaV5k}v580m7I'4ZhK5jhh h @BBO=31<"#"I`뽦 9MXDm@vւ++*h E<$ŜrV4`&W);|xy&-74jhh hѶ>v߃^f- /-}j: 4]w>0:(ذn"[3--o mG ( Ǎ'e A֭c &^`ɶ˯kpi̘1"џuHxt8{ڬ -<3bQE 6jQ ]dAh _XX陱5444v 4III:ȶX}yQ:sF)(*+rDE_ae}@7J3hMAH+*#"ڬ,JKK ZSDihhh4n%RRRl 8vUWٞ{3?GO?,}=tι{Υ#FWCm M: :>w_A"˷YM6O㊡e<64v1#GrU1{g9/h݁QQQX-..Ns3)"2ҧ)Sԏ? |m̘Ϩcw8oru\X8,}mm4"")==F[^Q.n-5444 h'fTE Co@Jg">aV ނ`ںnh:4Z,,0bQGXi544h{hA0{6F":I Xq>|:{ Uao߼~v\D1r$M>o!t.vŊT:Pt&bV74G!pRfAV@M B5{5y<>M nذA i44ZT֊ l\\xRT%77 ̐;hNF111~fOE+mw n3# Ԕ9KJMʫ(}@5X0v`ٔ)тX@?X7gBPyGhlc#OUTVg4444v.4degF  pvЛy! ijm5|@+M{CjA|¹rjhh4,X@+'~ѿX\TD?~JD w3Fp>*2JўF+w4DTRRbihhh\h }):*JV 41F^p``x>>0O2Z(^V ?NmYVq^D;@=lM>MтHwߋ(ǢCvQ1!6jm3YB*j)GF j\JrƨeM|eYVCCCcgBABBmΜ91BS۸a BaFiHYG8EEt\[W+"""ş1F@}w}tY7"K h)ggeG;h0'!1cs& 5D|j ,nh@hny}'|rz'hUWy]@ˮYFO>m޼YjXq:)#34PDFE0( t0">Tuhx!)Boo&o)-yTlkK 5T[7Okcܸq0҇~뒒R󌆆& 3e ]ptteW =O֭xACf%y`"&X,b=1LphH`$ 4] I1pǴ'Ĥlj(  5&M9{̡&PJj*%&& qud̑E8 L+}@yymذ~Zfc?I]w544xgڗ\tUU҂VMfUAnjiކa9hQ.E_}2UG XWޜ rsdڴi8PiSslf9{Ehjhh xhA5a;Łl1YbŒ # AiiMYeP2kѬGs!fHS{bc6{QIAڅ [>7k .V+բNGhfM^҄wX18oM/j:B] A-Xm(99٧J/s`hJw$L pJa"qCk2sx'$Z[ ZuuZHYj xAfįcelzY^jhh ha5޻Z Jt@ X0F C+}X9oM@(^cջBw䪠H/.Tȣ1x j?믾bb!H~Ǽ\߀׫lk@ꡬ1,N_x>]pEpܡ뭆ƠXòzO\1b2Z17Um w4" SF% wjhh :h5ȰaÆ~^5ܯe.̫MM $x[O @51H}j`9Yk1r$qQt1GSajhh Jh5QQ^^ZZFW|W2"w4/b{"`9p}r'|7wc\LEuTCCcPC !\*).2&r*)*3S Zȱ;"ŵސW@q-)Q11*9sX !-vֶc.LuTThB|6G͛i}F6Lj0{>w U,m5+3bn7:[}]444v??ܖ)#IENDB`nut-2.8.3/docs/images/ci/AppVeyor_logo-ar21.png0000644000200500020050000000611114777534445016110 00000000000000PNG  IHDRx<~ pHYsodtEXtSoftwarewww.inkscape.org< IDATxp\u?]e4Xjdb!28XZ0 <%@˯ƀ!%i8𳄶5[^YeL!06&:`Kz+PRɶ?Zryi;}VT89eN p\9eN p\9eN p\9p2t9SFm5b>ٶ][L+7@."}>OfvL*`uiǸkVDścXB}k?θگgZ8L@n^SY]d+ )h~z ŅHl }AIGKOD|Q~{ @ ׵{<%Wb1i+ZL 6"1zGx˙i;+՝!bPXÈB*&I) O GÅ:zGNtC"+ݨb)Οo+dRw1X$mɫw,;Q4R9 m8uӼnF?}LW:щx(ze ]ZP\E;4x]g t(:xj~>8b Ύ.omR,'r+ wEy ߟ{ Q[mTi`r-Ïmd-` W9٫;t3˱Y5bckӆVz'{:Eh{bM ?^Ɵ4DGbt{F;E?؜cjuzNH݄2 拹aWs"OvT(Q9G逵.G#TXһ ]3ф/K"dnB$ٷ4ʪ٤*[2[ݓ V~Ȃ{Ī2l#348,,>gؿ̍jo^-}(7O1g2 7NgmF;**Eu7וReH2u+)pgU9L6;j_K8@Tf+rI:WH\("pmg,FΞ1a+ Z#72m{J](hF m;{ +T~У 㹫r4bS 2|%z |)p}45Cmk}~ۀMx2d^&ld*n^ӳcyv+@_K{#x Q&%fTXocw WWd=~AVwOCwJ݆(Ǖ՟jFU )2ж6t62U'!zQ#ҭ@hܘQp]"2Iv-UWj ʍWX)pE4d ԄU uѶLc:˘({ #VSRj,,S1YfYpi|BԹHhNb94Z(UE+ ]*ToV>)/'d^&7;pa#rh*Hٱc>u7;j+*aLކB(+kܘ Dl3]Vc"<%݈sKzw=SpbymGXZޱqtVծԩ1rd:T¹9L*602sx)Pv%WnG#ɾ/j̬fĒ]"f4:>\xWn(K?"g{( rcg" ]+"+-ɕۑjT1;CG¾y 76,2hhxHayٽCџ\2VDVGxLn9]l\,vWI* l+ºt5+"lm?۽ EtŌZW){[\i5rӑIِ8a3?uQv]Ԣyݩh'7c;\^;X^:;jtjgLk)?~x++D)k@: 0.X6:v5}وTK.?;2bSLkI,3.m145Zw0u&z#3_l"muI@rSDŽ c92r@v{b6A,WJzcvGW!\5Y1`NDVR8vJx˂Վ9Ȧ"f{ڋ)XG5(--KO7X9fݮTUvx?FHC+`FW{AL'0S8<ï }0FUhS6J7xOWFL6 r5Ewr~;LZ,ܺ5{sDL5^qtSNA`JK2' .s˜@2' .s˜@2' .s˜@2'?@D{fIENDB`nut-2.8.3/docs/images/ci/jenkins-nut-large-squared.png0000644000200500020050000037000114553676503017553 00000000000000PNG  IHDR䈯sRGBgAMA a pHYs@@uIDATx^]nPEJW^J jhnd޼oB%d2$'7ɐ~Fڶm(((xk,^Dԭ{{>i:x%Z gP~^ހ%ӪU+hUjJWғ<7~ڵ~ZBxffefdжmP:y>Ku"''g\vV&X6 \zlr@ii)Q90[nG׍#:,ZXXXg`m%5Zx!͛;WHc=I&[._dJl_|~}h-,,,q掛3{͝=&NO111eeePIq1jL[ޣg#9yh%Z |3E 7z oI\ڲe m޴S~^L`v `ӈayAY@tt 2퓰DkaaaI_0ӦNC**ʅ["}h-,,,vL7O0Ѧҡ lCS)-F-6J^LxuQʫhĄe42h}iQ&F63697z[歷ߙ*}h-,,,bRL\=+-?z?ȳg{.BKmA6I2 `WW?}EȲ靉hʺO"c0u4SMл~|s"}h-,,,sǏ;蛯ldL 7d/_8R{5 ռx.]!E?Di+%U%S$F҈:S&LZԺuNlb_)O֭Y?xZ0>Lbd!(%:TK^g۠7R]`OŒwbzǹ 3Nݒ.AܾrFF-{!w)nDkaaaU+WEay2ak{ŗ=s{=,ZXX{ڴA%ş'MРEM R,`jIC+^d映p M Tp&=]TWQuEU ,ΧB(̡r6[*h+oc(G1tn3>xMTQiv)1ɽ)&\&Nn˳Dž",';2ٮ^K-X=7^n_/^A2%DӁwXjF>wW\(HnFэ[Sxbc aR  e" jƗL]୕BЄA%,73 ! tکj3=aYba/DQ^dpNt|Bx2ia? -g~}DkaaaɃ}Bg͜u-1HT?R e4B(i[mޑBcP~ cx NpyK7QI:*ܸRi¥EZ:t<<ݜ_Jo[F3f+ tٽh,o"Jo\kodNJC9r3ɧFî6kv,ZXXWפq`lEEnH]GSR`ԌȔBAa,(}/p\ǩ\U%2\,b&`+d*"=t nH_)Uޡl`{:+!~Lҳ7Pxx8}=r=z{1,ZXX(((hk߸q?^K^ж ԯu-lM9kk))s_ IW8q.![O@xt_Xv,haEI!͙6Zz`Hz>/C#BsRrty#59%ծM,"""OxO߾wK^ K4222ƽsx oBtddMT(k٫Qj:H1-:PHtL Qԝ4@w0yu+b0'́OڜbZWV^!6mM8rss)))?; md-ggԵy`TzI.O2跥"?`#:Wfh-,Q0DwXvss kZZaԎ i"!BKu!ƧPJ֚ч- q^c3PP!:o4hUfmPvR̙AI' :P{AuH>}lK)HMtyt]! h-,A$;uGƃOZkӍ~eS&a^Zd"8En`xy}jAV߱ ^"@VEVZ)X;5&&vц_Jϥ^nJϻ1a4cP'oq += /Ǟ|zeh -,,$SNI͝3x9-=5 l(["b*feMHD4ŶD-Nq91lSkK]a.tS߱092B~i:Ytk4jVМu9669`;..n+(ZZqSaa!UVT9}P N¡Z~qCSxGy\V-//-|h{ \faa7;#|^6*K{zL<9?OдLh:{lR>ߦ<Eo\LHp5*uXcx}+:;k2dѺ7M6ڵ9GEE}\&*:++͘Jg cM;r5L1+g6x}bKeM^fB( &TTTG/[_I %I0Wtt/BM) Kv:F^ZQwXGT߱VG0P˫.9Xxs<-ʴq„d= f1M,9sj톭N]+\scN<Ӻv^{,ZXm~ /i:l8M"O;S( Li&mm61#C;պSp׊-p|WUMͬ=b/wJҊý&+fk@N&L۪,'p [ j5V9^կiiS?" ]',,, X%>mCIK<@$.8 uNv::]oՕO#rE\G0')CE7*բ jHҍtBچ4j33#BȮM(U[VQΒTqlicb-7㭿͞gIvg-Z,Ң=ؓaՃw闟vejzlT&bÃNNlWڒR{ dx 0yh}i2|@I]aՓ./zAY%M_MEeUN,_VtMe{E_짟΢| .?U"I~eQ)T)ypΫm.GG/b .g;C{8c d ^]e**DžӅ}QV ]XK$u<tE*! \Qa&-ȰbX(#et9Ns|c]+Ҝ 2 J+e^a@}l$c}̬YhR9e~`Zf1G%eLTS]IEy"ӷE>rc.L.w~?2ڻ"5XXXX`=wF|Έ!EEZ9"k"RrC(s.&ҬMxUHDWlׁo˩Dk8f9❃Ezeaa;/2-\pG??s 6,H^;l0,jdrsJ5մJG}o4&Q_@>]"NOY4g].k#\c;S۶I.sLJ{2c5svת#?,SnnƂT6ylG?,ˢom|ࡇXXX')/x>2@_MfaMXӡ=ܭŵBO˼scG^qwg C'z} }U9:NMLOFMj/qUb1`I4xN՜.Z*n-ZUNWQުy*-/pǃUO6xޓޣg 72cE{3Z = d=`Mv{=E_޳i ]{hkJf5$+F;`EPC)Y{jD٧#v=E}Za;0h;m1:]<(Ry*, K2h]vYSSSSѮƓ 6̙%OZۨwVP9nSVZ%R`H,BZ ;xy-V # ///|skK{$a+xo3ZK0/q@S rF\(j$ԕA'nƃQL9L#8qKm/M-Bع1؈3zRR ʘj|G20x_~qɰPpa/tW)w1a w״u۱koxD{ jٶO%Yc{cCuا^M)B>cb! ),.b7fQ~eTwۨ gmX7126АQ20|.&mwcn 0k=$Kޝ⠉uEol֌TWWSsLs<ɧ<9eʉ8Yw@I]:mTh,zscUYQKHKNZ{H'n^zHK*N84j|`(BxUE"fǴYMa<0ytF+NyP-ޘO-ˠ*!Hc7^9uh?J҄9YƆHeYnb\~ wd'$ VUȅ0vp =#//75,<|O?}Jj1$Cn%lR "ӡ!c7>("LeLh)ˀiu=`';O9co+3muTG!٠ 6~eؾi|˱B5nν}andS)#WA)5Rdo;Zd駽5-\wߎ~3jZrQ*!NMeO!Yq%:uWtNC&Xd҄s!%[iG`u8MGnUu=̏GH!ʹ4]6UTP[r6U_k2iTVYyKqqt];/K/ k۟Fo-JA{ɏ*~?aZ$rIF*ܨd?YUS4m֌=kGKxaɈaҥ5K/Ҭ3iʕTZRBTQYAB; |&70UJaaL¡Ԯ};:蠃{ϞԵkWj٪~E\>vƢ Fs{7mw2Cl(eg-p T;kAk?ypd ovBv]}Uvt&ٵv7muC):3#}xfmW_} R>'G8imOeWܰpv1ezٛhl-PWr?EŞšULƎ3g֭]'#\<7 Q>4Qc| 5>Rݕ0[#6f+ M6B}#:Z;*:=^yqNYСpIlq*;R(_{~Ef=ϯ6e*3ZKXkFm1$4D*ih _RA+˩(66AG~;tu}c]wF%ٽ1 "G2v X "9VYMx4XhgFjpH^Ԥ*X!rqqh'[1^?p\XZN\EsWЦ^UW㾡 ēre=X*.<pMGumL ,*ɮwↇm!Z8AZr 6N_[C^笺bl|/Av1zPdd}ŵ_$ExH ]5QaƯ9I;]sPI*X'ژ_F/]E[UƩA/oI3` n3?`J7oտF毡5U 62*]}5 ~QXH s`݈Hֽ;tCk+%Yy;Y0E5]T?۲;] p} d??GKdpK)!K_BsݐO__@Lin0}t':ZPN X>'zZOKc垏6l@Yqz΂渕C''١۶VSTUuZZ>@)yy9S?[XbE_FӘѿE&@^XC9Vo n@UB82"(88b(-9Q4hJJ2/,̬KRNn"LszHdW!*Ϫ_QECX ŵك;:Sj#ռro@K-UXs`-Tɉ5p M06Zw}aW'`^vʃ <{)БCb͈kӍ"<W{kB8X"D*9pkǯډUKWa*Dcmۉ ۮŗ_ޗV <+G~{VeoKY1w-2DԧU/;\;W_[YdQ3}GM=8Zm(++4q"}4}t*,ȧp&Wm N%%?;5W׼=mo"#\M,ٰHڞ;/LLI tчEgH]:!P߆?*t i4q,f\$;YaO5~O?M]v٣4_>ژu]S/Тz&1ViwqYw6'Ŷr mBl%7TdVqN9&q+'C@o+&Ӛ-'ӝD.CIړ"wuZpݰ!n{n=IR"V5M~LO *[' *=dEF.+ɇ1R*X/LXC؈>Pɰk *f] |{цud B5xVFqqTTT,cR9|]~)ԭ[/2ړ 6b06nX>~3_F2)5׈Ohт~Y2t"͝чZR7/ZPfqeX.yDb*E5ށ!Ssr9P |~gÉnWTGW|m#8[[mdVlȤwJ᯾c04d-*w| eձ/hB7tʗaؚ\LUfVM+/Kȍ=Ne 2-Yp˨nXhm}Kbcc?Ѣ .CqqQM<}.ӛXEP񠽂\C s=.R:䐾dRxNJvC;JӒ jđN?ߠrNjݭ8!>ztmOuسL%gdPN^!#`(CVnN/?ȑ`݌ڄ,?ͮO|WΩ ?ڍ#ó٘U8zX_ 3i+mpp/nbɯȄ!5ᚈ%PhcDQno l2Q-Xw-lDaƀ nCwv(EFl4LG@e{#FFTZRI>:SZ;Ғ$G[+i@.#SyVaېu:lb *ZyL@llܬ~ykr50a|͛A'% v,*itp|1-*z@jߡ=tSxÍD W'ȹޑ.9d:Aibγi{%ʮm7ciCeѤ`k +??Id&;3H{o+GU.\ZYV񪞲_~eéYMk>UL\`;2fڀ:A"2 ͱYGnQ6Qr¥l /4X N7-TmLp {lC~pj?2Q6w\}-jXⱑZ5;mޒ&eo d(.{ [w3&NWsh_hNގB=UǭFn!(D%TYKEh_!CO?wȿ6lP;W_|)TB'4Vkee%$$Q ' e&lA h|8>3ZleddI :aA Σ=:Pe96rγcp1 FSj \L߰_sdG7:$r20±Ck=K(*2+!),>+rCrej>L?^=uk7HU5ndž!a+Ɗȼݕ%=8dǂ@QD OY#nMBF6wU6`ÃWVUӇL^,n_{:܌&HR?_`xb|xAd eK!ASbtV,-$*} #% sdr(#8_laؚ`,lR¤hq Dűr!tۣ&҄˸yyWcC[A @Ϋ\ qc vVTm״xI|urtѽ9$ 23jvs<5UDwŅ?W`)_LS:?EZвe+8uPv?"}KzMP`O=YF,$4R㎥[nY`B{{Xa2m:{w#685* ))1Jd`0p m+|eUVkVJcEAuvqc감@2'%Ҭ5u`1?wܷ?ǎ}g+wڴl~)j/0:4iWZSdhan"gh,L#tһz,:j@NL,EhG=~# qGfe=3s᷿%k<$A˴hC?4uIXeR h|ĉ+n K]_Ӿi"2|_C:8\!nGWɑG9a: qbm!|68ȱ}]hP)L KAA>M49Sv;L ZԃSO}GidW'sA Qҳ~ cmɡGdW".ӣ[ԩ}gV h7)L9rOUܜW12{|4Gk K1PÈeu0;%Z/d brl{σ Yt*㺤Ƈ]F[j~g)/'W,Ɉ"jղ% 6]=Zjh*L'ẸŋY ?_05H"5k/;jj$JVNo[ul0E,TZAC!**u4ڰ)K6PC]0>mٲf̚i͛7Yŋ8@ʣJ@o֭?Qm6uj_@! uTN@,UT38{9:38lv8!F06o~e4[֯[Kfϒ׀.%VЦ$'ЋAwx+ XRg* Ep/JJ˩kCP׎-LKH}GsOMUUUL76m-/6䕪jZbʯ{t\1B(82ձJ+`2ë½9!i"y{=>XJݚd]aƭV2b[3Z)í<_Mo3g 9By௺Q(SVJ 3~WfvR4e#ώ'2X yBRR.Bw`5Z?jnvy- ZFH0ܼys[‹.d5E\l)Ϡ'?]VS$ Q ]蕧A29>TަV2sJ6бWTQjr<ՙf/\Aҳe%=gʔ)+ոfHZjx#P6\7ƍM݁ :ETO;UVpT p65rǡ=QxX\O6#ڛ#\Ɩܪ\ ~;1cPP#:zh+ƃ)>Sx1WϬat۰L+PVVIeߍqb ]{a2m =[/ɈSM @DHC3!sl1m'c@~ [ǿ>2& be&GO-Z{ynh} /yT? H#b7<-掭}fèydyPz^{UVh&oiS<^f%VU, Н%G`5Z\G8!].jqQs~wdɏ9^Un_Փ/ƩnS#+~_W'MWc?q5\htnJI\׭d\2P\g'!r_̸(4]j[\lqc`uB2`th50kgzZLa_}0zif41 yǟGSzFyyE-?ϡ^Dx?;]O%%՘U n-G煚 jaQ1ulۂ5II2}./5sO?C_~Z7cvƍpqqjeLFMժ,PZ"l6/Fd3U0˷ ~{HF -lu41q !dhCeЄil#<~$zo8dKmBh%s:QF!e5^}b|nE.ȸ\,MH/"Wc@:6pW.VrB̔Ů -p ,~}٭ZquLq:@&{-¬3K{}bMDkHn0M:^L2E(11\jcRRߋ2MZ_pu4]F:Qq t禳F*0FahTʡ-BRU8J}Gd1ؽ} ;S@#\& h.-Uew6[]?rm-4iZ'O۵J]Nm+.C~V" #͆=RrK mr6c㩴v`@#~jd\HflӨ%clWڂCץcps"Evm#m}uf s=Ѿk5o[4Y_G}5hM7weB& 4Lt˗.+_D\q|G 'Dqݩ⊳߶@w,q$}?|tcw /[^*.*rEذ~>j]ăV|v=*>׫ni YT:T!MՑVQ9{%Lxګ(2AگZmq+WTB7<<iMfCpCH@&eL*4YZg"Vt&; ~ӡy*ukT_s"sl [=f-Lٞkņ1rOU y8_l6wA6ꒆ1W~c:fLK/ ﯢ7Ve ƍ&+Z)ǁEMcǍ ⊣>b8fe7sOk/=ԗz*UQeuEt _u: M\':&Ze^RlҎX҃>--k5>]fډR8FBàQ`6~Mrl i 6eA;-S)QvA4c y&,3v1S逮N4!TQ| @xG[Tm̜};jW>}ͱ{Pl5 Se(E!Cʫڍ{ #wAe%6V6R G\"IT١ pMp#ǘ2r4UtaӴ-2 <ēmBE@Էo(! jL@+*ѿќ7IÆXtT"y]è6nspUUV@[+Ko#GʪKqkL4[_߷GFR7ӢNZ7v] &ٸ8w &"cTk后נmDZ1u [.tH =ʕʵU+K`Z#"ASr;?fPv;2Xpi/Ώ؈[/&OȻqP2B֭O]pz~K= #- +"^"6)$ˤ;zdR!h@* +WRa~>WCz}]E|eaﰪd!U3b ;UЍQ@FRXTylۜqB+A$}Ju V4N`x4QcD[:ho4^;r..H_\G6۪i2}t?Du27S~ům_ O{Gm}N:r@L؈e Wͥŋ;-k5#|KōEC'{mRph'L߱5$ x2ȝ]7]N[*]UeV_AEK!6c~G~-\XtI8kO(PeQkawP{FI{Jq(iCڀ$[]nu̱wvO~0al`aO @f*$t֬94o" vvBeB/yTTPk|`KjEFR]^ȃAC7QC!LqLxWNuϼރ)cLu%Եc4y-A_Ljw_.>"WHHPϺO6[\({3Mlh6p8l?^DY9e:QPTJsF1t}鬻_?Z*_qq@֤i6bV [)Yƶ]i L%SNo:ǎ ޴4iv>㾌ӧ\zTZ\,Mh<=_^{jaLd+B3>NR1rPIVSyY4:hfZY- =]7§UhqeųI1LBHTr [+#t R@>āNHXAKްq edPfV.eeq4b͛Ш1!l7 =б}d.ÑCMO߲B7܇;QnwZ Kk@\܈g{"L:n&m 0X&>'8ohO*M1)؞<%쇔h/BP׃:c0Wp.$( me⁠^0J˔BOM(%GQf)t@ԣmj8^^ `s(nY' yoVaүr8l#\ܺD}l2xilgUݣ*1OynnM|O>V+P E:S|GaWɇ֭]G'Ndmf>-\JKKdZXMQHG ]'ztiO8FG] &يbZoہZĝG`h8sǤɃ2E}^~SrjD۟ nt(8_|q: ։%[i32Bz (Xܳg __@;yat=:S`ើh5]_V͢GAҐM bǩf60#e? ze-}umE&с2 'Rtx0%EMѼ& 5 eZE<}iӅղzelU{IViiحI˯Ki_9@AF^x3uTF1''GVN7MT36-EC>O]ziCq#+XW5b/q)bp~a@AAB@AV(̡ՙ? 9~r5UVk#>Or(94:M=Ǵ1u(;lTҥkWz䷬m[#knjS>&Ti\T#ճI+^cO*z{:ZΦJ7[ zZDĽMwn*bŷo,KM/|L뷨~RQR瓣iB^uʡcl#ǠZ<.ˣYiʹ|U=B,4Hj8?5 ҜBmU4WcUN7XkZ]LW*\倁Kf-pݱ}fά9\сx!Gc!Wȑ &!o,֖-UjUbUi;w+ȤȐ?LbwN76얮\KY9rLJm[CfT}U%Bqi5 P7tϖhȽdGUJ~錳ڻ g7W^yAp1ԦM;v-=T])*|X\dk؛z}]8Z2.b I23qmL+iؓӦ<}77PW5 Y致bNd*VFQi5-XKffI羠r) {g*d{bvԱI<Ɔ1ZM* #q^286U_s5-~~z]kzM>u*yp"GÍ7 hbddQLlLAoIc@ұ }?d]:a~E*5|jh4jx0y&7\Je #30SRB<w!tCid`c![gHd"|_)`~:7\W3oOM~TsdнNrƷ iM=b%-4s]wot;8quW. nF5it}Dm;~j5ŕfTP˸aC:!F6' +2ϞI%UhIGjEJqd]vȖZEhae.^sϿZYF/?pJR`{b:aͩsԪuKjҤ %'PrJh -]TQUTVRDxCtA=2Z˖rU#kgXigJ<5KWӈ1chӧr] AB|kVmS:`v<^1Pvn>]x}Hh,1FW01 Qa΁r NGϞti9㴚S&kq7ߜ˳T+se{_ nJwLr♙}1ː^XAMH2~m}xtءʹDΦ>[}ԡ={NG"utъ:7Q5^#@S7D\D'cPOU 7qtwd&9Iwּ 0rY-{[}c}hCѫM =qj5XEBs[Lm2lfзsS\wwn#Z1&g͍]G&NWt*^...XV{A't" 6< :tСԻwoj٪%%$$Hɴ|rZhљؼy? EZxV%@ ׅ琸>y:ckc2-ĂN $dL":7gвU(&:R^QR pυt}P Eysm>sP"dս˝}Meg'I1QI׭ۑldAw) 8_׉f ֖)4!'+%ڊ;qr:tISj$k(+{5_l9]6ۻcc#e,cugtGup]{%yrJܙ]}hnj]s7Ӗ-[m^БVUUqteyK}8r' -;qs\XX(֋idlqJ"wf̫ x|,jѓڌ!4'~Mz㽯X#(P@{|":6lɢSn_'QP2Θs%FS3?N=v  z>ݩm,TVp֏*e+Da./u+h";TgSeݟ~ZEm mR$.>wB?Ϡ:pt):&9ޘJ&^C=5NDɂlʗ봅:Vmi4kK8KBnHj:"nߎw|&P,@ġ IN5T(5ȈJfMMģU9oF]:%֭5{cSkqtRm}F10ԶNHvqE5|ttܥW6^:[s kq}Z,:PL+116i,1G#SÁqak<VZ\JEEϟ?^x9 =|~&<!-6|W`< 7׸vfisX{aO@E*Dk\wT㎃UXn%9t%cσ`ы-fw_5`J e m ԫKuhM; SXDqVB!A# j?l[φm a~n#N:EŕWPAY49u^kۥȔyV4>FeJs-[vV.V.ZۦuؼysGyyΊۺU܆SN>^x%_AiӨ\v~AbJѢJsC^JcFbWѬ9|2`EozV.ʴXZ4 ƵA^~]S4ileM)N#k~ahq\T 8 (5) wU9m+˧M/ツ:o!_XTBLTFGQѓw_F<+uarţ|0<̤OyyW6k5^k?n`qS 񯋳VI!tWf 98׸׭Dj|[p4w%ä,JZΡYG=0>z@7=?b-/Q*4Y 2ܞaJfAs`>=1xvt8 \GF8#yR@i>^ˣBEh,1z?:'D8pzܐ+]$uA$'&%n^뮾/@AH#;vHW]u% et8T`_ztbAT; iExxmڒIW(Y⢣幪|A!oՌZHeBJ癛d-LJtuPm|-SgDa!TYxG~:q3lLeNtl;HCY ?}4^ў{ngnG5埿H 8:4؜Ưȥy QBt߽}WoϷn},'͗z<ܳ =tQ{SOǞ|}lllʳ 'u_w5}Y#kZ>ōBst Y{]/(c1;wL&ڞ ڲrDT]nȚlPx1zO?Xd19bRci^taSԼiE6ƵƇTNˀkѼ+BmD1rfzi씹!dՏ mi;;w=E^KCMt9?( +9~A"Iۋ_X=;SK<؃£Be<fm/WX&ON )i[=2&;z5JlE,eܰ~NT'+;s&q?=PuWTzZ̟PLz!_E-> NnW}6*]u0}[i[V^oy G(HaWO)f*\O`".yCS!2r5H8 { {#k¾Ūc3^{sd1xH6V*ġgn'ﺔt0&RAQcJ( J*;w8q%ԢY ȵt1DMq12wNG0k0MqyZ#Jku˺H6995Ӂt "=IӕLBg2Er/NYT@n{r!|t:yt ۧ^3yn}&Q T(=5p7lG{y08{f2=zIcDz)Lk BxKF]>P>A3ίd B[[/:grB ?+%BA3fGBvzSedINN~,2ϗЙ#z#Q$Ubqc<2e_o f ".YDc@{6;@cRU]:R]X=`NW_JC4ps6bWU>:efSPPAyy|m<%V'|?;%п̩kJ诙W麇SRc nIo}6u%$(HO4<gHnpvp#\UȔ\ *G's!`ԅMaPxu+ pbD `i~s F%ro`_݅hj~g!!/Ш0Z${T1_,̢ŋop]&k:UX;\vgarb@ʈXŇՔ/Zlb\ =st'KEN8-ܸ׼?遛.mSc{ѢL;Cb@STbzИr:?VK  D*G+N:~ZoODfN%:)xi)TqcCǂF![6&ʍ5YB_q1qn>kX茋~G uyJ,tԱi]Odک!1|dЀ(z]hM:Nm =SL;qc~p!r ,h;VW @ a4q4kbּԪj(4zᡫ餣z=k/--ל%SLf-[h ׻j73TӡΉ6[hQ;uJ=;3Ɔ:Nj#i SZ|8a!Aj4ZvhJO^wQzxԷ[;jߠA鿉KNkF[@ZhLpu8d6i%.Wabkӕ7Ao#)6p*)@[rg+;~}h`{=ÏKRxޅzCFci3%{CMa1DEP%>J@\0~;7^wsiA(5wAӞtEetX4_OuC6=/R?mXXSUWF{SM!L2no?̬YOlCDAMW>z&4 N>ҝW O } +ݷ\ uV4mgqK*#q1Ϥ/MLX/4)zHf^n_ ӰW-hyїXǫ8x璋/Q hby nP<=\/66"‚jY1XUk79dKA`s/;R3Ži=lAxXrY,[Rrexkݲ8qXA\2z''n Ԅ`z~tם}()9\o c$iZCTDȎGYo$ޞ ioлOLzёڵl"-wX2ˌf*CKqpq CkS8q/XMW:,Vuşv$*5u޼P[F2+u{?N?x~~)9 ﺋw%0f>H?lHO"EMn"4' q4_̐'OxA׵te?#hЂϡ;e˖}_p7D5̌Z˩Kt衇1HfΞC/Wvxη\ɦ%SxxTC-\&׆`^oTU],vwx~hnrOMu ի(.I+P "g$IW^ٝz?lC KE}ۯE%#gintj}uiiOHp5NNmZ~k.VOVNI_ }et]m#; H:Gi-U2zEJ+ᒆv\噭0}f'7HM=m)=2A݅>l'؁Ig K {5Ο?OV#TAu͢׬YGӦ_/¹1mlEw^7N|:m,gنi_,>i0ܳ +S1ZmXh `eӆ< _+MD3OF_ܕ"vF}p͘z1>j -9?|=p˕;/ү_߾z~=_;o?p&`=]"k[q}!@m+FP_15~q2neC>oWҵwOև6M/~]=GQwbgS;gȨMڻ˱E5֮`mdN))tA]S˻ٺL 6R#41WSUyl/({i٘:q0~x 6Nc"!_`O렮pJnӤI_-v$z@8jxh[%hpu fppjB;w~@p4=~m4tZh|.~H&}@]By'PǶ9-5n׬^c?ktfM t*ӶS ~D%/)tvj]d <_}w!謣9."kmǫ4jk?sv\!Sm'.{M0*+1uC+NukνssŸlQDHNNѮ݃h(++K%۷o'!y:7w%h ZݪY gCvqMӎE(5kD=XvmPp|pP2CF͛H䘹JWD9VaaTCӴ`2/]N2/˯a6yyTG y^tޮ*0dK: bWW!7з~־>r[4Yv{4VE8q|8VFWnT~fc/ϣYɃM%wGmyo)iW,kוi^K֮F4L ֭[ A]||yǗ)p~;MIT۰款j; E|?p'S6 poMd[Wٶl"+P(Ի͛6?!9m-jɶ˩FON#s݉ j?;F,ƸGHjȌ_<8~w6}$Zfc׷5r /aQM!{U=LœWB햴 Ret}ӈOWׇ=O]M][77|V-Q7<{(6.]i^K.mV񉺕VIeG; TF9QeElӇzgZ5b-wםR] ۙN?PٻxW^?CCiX,"3Qະx o x^U/1ȵIjmRQq!D5']F!5RWKXšl[/rsʙk!O;SRdxG} :'lvPkR:cmFU-׆|Ù@~Hh"c!Qm+mTn=qqrI6n)AQ/ɢ׽-t9uzt84p0J˃mF M6pGEEM7o,wW\0e4(jM]ztg#F%XQgэ},-\ jG&|h2|Vn!U1N܀O*>ytS鯿k8 t='֋޹2jg!NucǓe >] РUhn^K\_TqwYX;;'k%*ڜ/6o[F^W_ 9F9ljv?OW_սtᛟOT*c{Liбv>DfM7ͯb ۰E^9*{wӈXqs|e5 =\ dmk |-MҒ)%9Ki$ >bHG]͜"B`- !q(H}"qd sMk@q?]`;?'ŸFUU'gN0@vM"Em/ UʍS?k}{98pnďTi)bcc7P>y D 0lfʔ-"Erl5MS?B(.YN_K׽5]4b$Z.r KvnC[eȓ{[:C %9TiY6 =+ ܊GR78nQq=3b= FO+NB!ցJǿ3QQI>q$~ġe摈_ԯ-1MX& rS~Y4Swa"_nj+h%.MGY)*ck|Lhvky!#Tv\:(tup΍Cb+ hA# `3Wɂh;}*>0 (BukCر]KJJoȡQO:;^gԐ>,дi3R@1+ Za]r@m漵z-\<>hيjZ>^j"t?ҫMݐwϹ,X&MqѱuN*< ;+~]1,s%mg=*G먲Zǫ1]ҵgŃ]Jk zts_ s?=oHSQ< y+#P>vW"T:ڷ~SsõQvVSt"0JJw$T hpP&Bj9E# |۪ȳLf yyF'Wp\}J qt]Mٴrf9qݍSXE>/..`/J*i@ON+٨c{w乑tk?i\*)U6!Գg2]}uJKwGO?ݺI0]xlhBs۸L1V,+7䆜UaQcr*ǣ6SVīXC@<.Z1t#ϓPagp5kFi]:96rPB kh;b`DGGoѳ? ^AN]A&C4Jv*+*\+6ޟ'Pw:p.m߶uAjٚ 8f##(!.JrTQ^E^ S} R蓀 FGu-JuA=UTPUuϸ5kArn]U K]&Ô%鋉(O5at5=/:xc(sNGmom<+OG@[X aZQ=nz8vHMͯk]J'n^&7щHব\zdH㟦Py2>sڏ4Ū'_q~3'^;Qu!;Ǒ[?- k_̓'S!L(ÞʿӐGf F|\DU{TEYFޟбs'Rm)%< W꧝w v> +#)F?ԗF>a-]xɜSGɭYj g %rM*˸NpU9NK颻__O־}tPʧc{ߠ&ͥ܂=),[,?2؁k1nɷvÿA1N^O7|N9%%"v=@E1`ڵ{G =_OG*1-(S7Z; PS @xՕt~ԺeF7fW\3H<"q"ђ΋uT~!28'*gޜA~^=\LlAg=h_|W^zQ:;:mքɥ2!sw'IP5e55<$۾I>V.mɫ8JF6>q-[˄+7>c w8ғ.uAԩswb$ڗ_x^f'l]h(hAn0\N۪+T!ՠm3O>5&b70(} 5fodr4f(!V}{7lʤ/б"hPmkVu qku9Uֲ<*.ȥӁۉV B_!>wF9j7*:_@t3mܰao;d'рߺow`F@vЃ}㏏Ç 'G ;fΗ!pQ/;JCbЗ5OGCõ13 VSN=7z/񷾡Ah\t*/0 K]פjlw²Jzו4~'BIT~ \<@hHW^ySXLAyyyTVV&SA=&X=g}@x96p{<ˋi[pLuUԦu :#BJQNO pvtLMwvT h$*"ùs s4[haY~ZZf5Wu(;Kmr4๣SWIg;<&B&rf]RU%\:ԥCK*.)qw?}:rD*MXN-OSf9cO[k˻uYkLJ%K\S}>W.^LvJ(ZҀ ]#lN_|~<{NԬY+^ ?2g\_K*"c)ץᶂ‰-P6J)(J0 YJa/L 1,zփ :sҙg`u$0b3_wLíKDl Jzq2ZѽB^<6By@ !*Y/HϺ}xD;kn:}# .!5'1neƁWZÍ 9oP|iI1U3#Ź;Xl>iz1o$Ztu{ .p=i4oْ }9N<G.82q%4@ >y]*,,pdI]REZPO,)L<VlB$#".Fpې. x`OCn^ΫDbEʌ\;.G~gqUk7)zρMߏg2of 8)<#/"EX\\J}>f]. ᄅm b{I/kT'u"#p֤bEGh^} y2 4*|2π-_ŏ[nܾrwY)zwlMچ{p1܆Z mL0F#I$4p`qB@,Kxm7li[E[B<@:8!Y௫s#99.@<Z-vfyɑ=u"Sؒm"YBӋjmdd v(%%G5wq gͺl.A[I#>>a}k S]bem7B9i;_M>uiL)Je:* wxiHEqA/_+;>(Pt#ۄt=НOM<5e, 7u\ S&[ `R߹] :zpU9Q?"F>sc r۵n*P C̽6a# ?''c_B=fʹJJk_H ȯ?ֈ=2ڞ;K6\'<}dҧEO=ُl+q_wB]DMHƼˏTm ۔UE<~*0&U|,#  ^e:ĎtC#q{~wl"Mx #K>!s:+ Q iګ=`ҵ1Z%k ҢCK{>m*B׊̌Ϛh/$3̛n֭[#Hrs?%'Qɖh"ޛĝ1MuMX`|GuAi̱f*{ٴ|2xr/4Hx-_X,@Q1EiʬE|J?>.9:Gh/C/|H/ Z}OG4_?&qw3  վ%; {j?|iּeg a۫:SپB( DJ*hgoM%xJ5߶>4ڻqʩk+VI!\1 ;~c)ƍ#3Ѩ;;%,Q[ `r؞@mZwtQ< \:+ܒ/qH(We/[_I?f/((nrjRA\w`iNIU739+*`s )L3 +'Q$H.իV #Xٹ 񋗯g_Ast>b(:*B(lV._&NO_|?'12,Z)'(V6KMςoIz#s='zsM׈:ڷjB9ysVA#Ă"`A[\@oDjO\=؟}(btwӖ͛@,^pJǎCׅv.mB ք937#A<$کܸU^c5'sPmMI=Vڬ2p k?UF7M7TPcqRU?ztOFňG.VNc8Z{o^2ȝxZfytu~K?w pUbb P/`![}9r I}g;}t;:ԸI'm^_fZVn,?TQs[ݦ_W`=b]Eϱ&[\ < .K::.U>qA (%:T☼[򫼎 z:^DO>؄=S-]}N:;o@-VJ]]ٳfqmj1W$NYC.1wXt[USƳJJl>^=[YrqlWw߭wӌnGDLR;>z rq+'~u(38D.?,'.F4d]锓;SLLL@i_е9q@+>Hi̪"ž&5}6"Kau͝1"kfT |V7ɠ{IDHȏ/>l-7՜ܜԴ#5GnCVVV=w-j`鸀`sx8ݘJ\f(UfB!W6Bfҕ?ɕI*顮zNz #L(] ca鎫bmR_v K3iVh%wE %X7pp:|Nlh- ;\Wa?C`=z4ڷkڧ4{v}@1rۄ;2c -_xpe pO=@O CBCWQ2m}b)r atqAH{lPfF1eEBt8uiH5X!59炍I69%.kd}]VVEW{A5 Mզ^q[ĖٮMޯU0=Mڼ OkĿBA_}-+t}?`싩d;Q t%e/)-tt~ 'V3t=xUB|ЙckM|Z*)/ Df$ ǔ3䰾tGV /+;/#OǂekySP@"(LF2A9]I7L1:b`/cE6e6N+i]. lqjBƀho ""x(k=lw{vy0mf!`Ba%0Wql[#9nm7G^¶WFLDddm^[$M!nyc+4=L @#8Tzt啽).{e?̙V3Dq o> ".kf~]D K.KmA~#~~MwX->#5}{}6_=D;k欚_|QI40:Z^wc]:Vu@|L­Z6G;pDɆGF?3.μv:soy+PTt9MX;Xj,ܰi'ЎlHݢຐW<+5%LbLjXA\.aG uN_sщ4t@/6e{/F'.n%k׀ uaX;fh Xw)5o}KM<0~Z0قt3鎝0.]UE>vwAwt(*( X !-("***"ݱ]s]Xbvݩ;w9c譙_=(!)SR31oѐ'_N5 La ytu׫d`eI1t(Q!Y?Iӆ^@0Bڰ  G)5ثznsS5Sm81o-YQ޽sJP:s ?tyÿ2ڢ. ]1?oBL^~Grq<+C^x%n{& ETijze({٠0Ni 壌ڏe6k O)`ۀc1]b uQGUat0?: _]()bT]XzmCEWۖ޽ lWhrsFS~~bYpzNT=gf.uD3bk?M^8Z̞TU@XX8]sMG~t U2ڙϤW}C0?5bpp̻Z^F=ف3tx:]ՒnjaI V ;vcߦb(OVc |[cYBrO X \׭]K[7ȯ+!<1^{:it@T;*={HrGJŸ\ Ymy==^+Ʈ,uƽhr/(VO|}s.mt)tV|~#A(W& )y'lPLM3[<ިt{rgeJ ʯďf]_ B|qSFnF89,q'gygK]hemww'ի}A_9>ߍG%SZ o/@=,u)Vl,&;TVU;صdS ČVdoYF3R%qrP%pP6MmIPjԋ/ŏ}m*ݪp9{GIE5BY*p!7[/L,0ߛ -mw#W7m5 {^h(2Hcf =D1O;˟͙_ :ku"-C>yBF|5X qt0|uV4[T CEh(lJHJSGOI'/\uȟ8DLMf;׋:{Q-7lLӦNwPsa[u] ~0ef`8E*Qx`'Pfei4ŨJ촟SĬ( ;FPEw\ t|OНN$TL}k<&LIß@}GMK˥K$)DzQp_GZd}rEKDF#vڵu+o&[Zn>p0>Z~>]}N8 S'׍؆6n8Z^^;u׷Jx9#55x)2i:;(Zɶ^fƨ*4TZؼI=jۺ62qggrrvtkC^-i,Dq?Wˡ9X@5ISL'ċ^5+Z\-P p- :aP8%g_Q"w0QyfeaĤ4mJ@/YW W-KQA yS퓣I i ~u UEBYc:u4~4Xn,19ʏQ)Ji4܏ sj<4- r*0W~Ӎ騂3=M{O:q~IO<ю&M%g#`1[#d]HL̦wvkD6VLo;H߮>$R%jF@VWyTQ0y_y34ôm>d+8؇3=pO mGJ9 y֭Dr[ܣ[W) Yy&fm˂v~L`9cʪf,$b[RXH21=frʽt44sST34@$]_0hE s~s15۳T+: 6?W[+Pt|W{GYz{пvҫo2.fk*/PƁ;p0;'Wy-׀?/r`i8wgP\\,0S/CRm0-+>R03,KuCC5bF–a2' zdǀh. "q@E忍\h7޴})pScp'Pvb oެPF߭>0G4th* d~dQ~V^˜cO"ؘqr[nm w#bZ SO=MoWTt=?*g6n,6tuCB;RQtA$<_Hkڠ%=(&qt za7'msXN‚|=1@_.䳔 +c(ę 1Ba*0kStHa!i}Dʒ+8/@ޣTmԦi}(3?Vmߛ++(qBelASRJ;5ZO5TM3:;] _}vhG/]uBSCt;(>>$١=4 }BNYMFezIl?3% U#.D,9ȓ&,_Wr }pzۛRh)`JfuVԳO씽!C:Pxnke\|hia%ZFE7hxJ̴ޟN-[E%o6a;HW}ieS-Z lּods=wwsϧkT!dƧa: il=K[xhJɮD&;( ;e15Y^P4*'Nn85 _Acv玌6 H:D?- vag?v/ծiӚ;:0ն'O%7_ܜ ԭCKXxD$Dy=5Ew|5Mza 8ԴLZM1ߧ3|}V&Ho0}Xh=Zl 68lPȋ3.dzV (UEP`Fi% <b/΂a|tzg[ 1dzaw4kΩ~o*,-,-ͺ,v\ 2xǮ2wYSݍJ9XuѺNW1ZAֈ&MIZT}*,1@=5kŨK(%#i3m<o $Ődq(eXJ3;jC ם[bhohWL&[ GFCҽ;3sw\mVO7Rok;U lѣG?C0, L>fB28(@ TWBd\(Ȋ`O4l(f{0㴌LgBae /kސH,b;tnהrIj̲6n'efcYNM137t"ycҒqu0T5awqNA9.8P/?w;m6tjya==HƉ`0se^ 9`6Jphe A5O?H.:qm5:lM^^͝[QOl7VeiLREك.LUÿztIaU*r aٹv{c:7 ڎݵ\S5-GJ kgn*ND}mZh$z;wJg8~]r{U:_Af|g| fk` dܝAjw+Bq~.S}X aa "z%PNxsce j8q*o#;|=KԶV!3T˜bXje֕g0P( Pz0ҬnrB:R4eJoz|h[pǵ[se/qf0[yᗠeuHEPjh6mndۛ|4fl _|?B6ʇvJKӷcl ;uKO :uK^;j9L|+W쥽{KnӖr 5kDNZDJ6O1ʖ]iFy]yO>CRAN86FB nټ.N߭nswcVVsHb OÎh Za¶?C=af0i*Йݣ{yCJh0fg ^(111!.lڴûɽ /e={I xvJ YOl#Д,ZVnH~.]E91ڌޟI8~#E&FBϘf tA0J<%Ώb@PAp!8"CU[uj;7hT[4` ɒ,bn\5]R~UYC-ו~pQ&͢2Cl`VJm)M\:/wc߼cǎ[5jp#~a?efK"+it{:VJTʝg]7+GGj(MMڕ,_ ;VrӝКܕе&{6n<%&!4xpےQJ`TalL6"/G4ԶM-`A ޵ 欬=?Y_ō]t ٴQ-r溃2T>p:_uO&Rj:{yc7yyP$K4c#W_~%n9Lmּmw9H7iTs6Zn't{@-ROMv ͺ^&u}=MړkSGe0 Z{0?A'nQ:ڷ'u!?X6EV8mќw oz\݀ju`[,Yd3Ml BnҎW_uM7~t@4,2d 鱳};O/%wdqs,+<#)͕v9D1IX)n@X+D|f(K֬W^[C^aUNLm%.}h=t,> js.`;NKBnFAp5Y"ƳFxk)ùN措e# hM"V!dׇp{hb%w9%hͤkKYт3{l ?倇|s}<1,!,*wi~M)QO K7Sd4hFۆ땾xPf+{Vi9kWfpK| І"".Իa߰0mr\.4s^cRST믴y,zȖ+3[ț\iXe\ְ,%L<9\Ȫ#Ngt+'YcX RVM9Iu'{ ! ( I̴ "6lRSQUnmEZEOVG RRȉ3@ >.T5TXOO7FogJY NCK:tdv޽Ir^ f;QOYw3PVtKKqSf n˃#7{WQ@au Wx~ M4:Ng&ҩs-zβUZIop4JwjRԼyMo6°eiQ6ڌ t&u/j)))~ 8A;cX^^Sئlkcۇ:u9֐ Ye~%ٳW=zOVi)/Lim0fliċFNi[;vLn7K f/\HYO4[{126*tCWB e˶=l:re %+ yL\qq͐+3 btكs>J~V6GU@ P8of/O{q:}J.PzGqGezehir` BѲ4&tR{TM!#7nnLWў ͍oM6n;5 Oӟnr2ڱ⢲,ܐJ30#-oV:ufz*xҡ_htto%%'7 q`;H2bwU 'g:t!,8 sXU4l r6iޞ9\#{y׉ \eXzg)19M[mfs5 |-Zt}%r3ړ'Nr%`U)E \@aiWI0YcU z$N,Z:Dʼn>۲pu{Wpa> .A!\fGO҆:0V@P LKc#K?g]:~8 ;t Go~v={loZt(qֽU%&zi-Gr{*tQZ|n[0jF7i?0\*yG7%ʁh23+yZgfi?&7ѯ^f1=;f5kD ?& ىVF={ do!;gz5ege߾XZ&`ŗǬ]2(7]b:uEPLr±oQliKD95^U@59-xs:FVXp kPn$cF& &>P؞I+tej;m7| M`{DO*ə7]MfF{Pf5bb -_4ER2h7o7PW16An\oVM?Bղ"vu /ѢE%W!0D*fҫbR5KeOSZ+`ͥ+;0?,lfu{їh5R<VN=}ĉTizף0g? ffuxG4b2EHNH*7SߚdIִRFmjjJ?rڵ냕+.qC1T=~/ڴuM~o.:,@|<{+(+84f0x{DY s}RlB NNMS1maYؙsh䄏iegU-e0HO}&5mXK/Pï^ 3ouP@=0~G+# G @Q{x%`ƨҾ}ZVD.^-Zڠ˗?lմ`6A+F1YT*7 f?dʏGiGfŊ ʬGBSgt]ZɈx_y ]:ĝNJ/GIGd ,_^ sX BT$4iژ?QOXeZEytg"?^KRXp w^y89ɼZR`Ý`k6-;RbJ5zjմ.egfX< p9''ұSqr]!"0K80LiYTb |aj9fa@ھuvM@xG`k'K9zndo%跿шfɼ((`cf66K&XU@=v?JΠӳ` җJ{3c9 iiiSl*=|p=EG$eooBin],r3Y)'<DkiaSh'+1 }vb9b]D[ɻik~hi/홚MsZKǏ'qGډ=jW%Xrs/VpK`pv-5c8 +鵷Ӡ U Rءih+OJ=:;E^ӭ0M!o!%BŰiꭲ=Ҙ`3e,n'Da|JbfԎaCn9!d@5kѣGӶ!|}}_GuZpl͞tgMae|_C)GK3z{a,v 3{ݣS ǎP~;ZH[, 1e0Ckϻ  5ց.jsqޜ&1z9z8f` ކ$1-WT:LvWX$q)Gmaڱ5IQ5F"+A!l&}J헹CH]XS+*z_Q/*qwe oH+"W(,QFtX,j2 mX7ގq=@чʁ%8a"ʥle |Öч_B؝Գs+/@bw ek z57V:+.?Q`]ѻ͚Q˖-iGo~cwYU!bH(gZhE9}o~rU}y&;{:U~L?%ɚ,%ZF< }U=e雒~Xee${vlz!ܥ{bQ aK6#/ BŃaa4ݲ|,ʸ K:-HI*zyC8 Ԋ kM늄 cFZiH2`AAAl> ]׫3eee,_>@>NTG';"<#- h|Wկ#gfKbx7KxQX?Պo[,Çz_A+#,cI;Spݽ}̓i(#gZ|8:[*"4&0ej |H|l %q91껈7x{{ E삸1[%+{W_i-tXF&Næ=kdzh'z?Va7iO{bďr3-fz(fa]7+whۯ7О==FO}^jR={4RSpEXɑx l,,̖(s}A?gؖv W cbы {S&'^0`/v6,JOKǎqt^87VRӌ|l -Xڋ`gt禘Mv`gǏ2+{yZ),1hvlG= mMu{-= f(fpS0ȥӁqbO|17iZXVS:nc5c hMݩ M&d|jރ,}\ˌ![e:2ńI=COuh`,8LA8+ru[_=j±HG*SuGRkB Z$С/KF/MeXw'OsU1*41WAqI"=TLNRJgQfvth sA\P`4(K,rsc&UFP}2JȔiNȊcwn׌f3rcGNJRP~7P\ ںU@\֯_GYY*ZLHstw;g2PM[eY*4G[U|_ F?7v^x*8d+ݠ?aJݠi &w3h`К9ᙑK-dbXcC֬Xݙ,`ɋ0d}˗-RqxYaCHg- vHLZĒ-Ȣ&RQt*`3@c{D=HVX [CY:Wم;G_#hb0|*.d &J]z=L eԸ^EEShPa{$(O^@8a2hzKa?qpȞr(9-Cݼ/?6D {Ej*R 5k$UVט)Ka4Ύ2l0<4>Ydi܌z-;ǨwΛJdBnvmuPa;v[!c99ӛ(VLT2Kr_GKcBqq]Ec"žvӚ[Ԃ xG] 0YHȈ3ȷ"݅x Gh'yEQ'W#t;'k7PbƏnx7/q_Ӟ^遘{Vii97xEt;bqn?w^?ou"s~~~4<C{S[NpljQZ)"g-PbG<| :ODgC*ߕm=N5w*xQS%5qPe{Ә)ݦ1zfÆ?N-0X)ivP KRF;Qc !37,OݟM̚Z,1[Cf<SpRf5ӨLn+h t ɢ~]4孷W]nLh⊷mF8Id )Y.eJzܖs;e0Vo4Ǔ" iw4Y2Y^ GQlc2"*҇kpZA"0%= 둻oo Z6ս*%m khDc#B-K0(h_[C,NyazeY ^XcZy/M vqnkeWJf8}MSRBb"YF٫wW^{].*:}:LXX,- v`FvfnLxSn TzPb֔]3q5n/e5@ѣ%lMáC45"*nӖ>4.epa?1 +GzdH\ ^He(&֏{ӄz6Зnb)+P-l1[Ll@l!xICfeǂ.b^37/^:m1K2 Ƅ7KۦrxgSZ5EB<)A_,z% ~R`ObR! <-#Z4CONw!LVLVa|\W1(e.mu8bvܘž ڱ]@]zUDEGEQ^:Ӫӄl͔{HAqAI?uS({&?be2QnfdV&we6-Y* 2 t򫙵pAX+k7ј)-y_tC;ҭ;͙7 5z^,/C׭aSsbe~x ~Qq{  y{S>"D==ݨݍFE;h lUw(6Qe8BjRaNV‘lryxb?8UH~rZX{o/Mc+.$HlD1=0/T.+S[9',Ea?AdZU385 7\ˆH[Y20Y񳔬Qg07knJ|\C{5m,GMbqѿA].MYBObi{G䎇R%S`4ȁt+lO30XY–Ze9Hs欕Y:ӘWƽΒ=e -UagyD Ƙ 4cҜ )܌)҈Sgbe^6d*:F`F`jr2H5WY 0IM>^hѮ}dl&=vo?쭑4}|S:q@46|sHx ï fLؘ#з}0izu`Y霝c?}ׁ~^Em07ΏlssF#F8;x'~ѪV[tϣRsQRt%FOiN;KǨЗUzwK{ Sٙ9~;@{;fh,AE?Y)X4Tnn.ZѦmО{\ݓ>b['1'O8̚yrFʉP; %_R)Ln%8qDžslD0TD#1O$N4J+0yǥq2P0EBY]ߪ Yt$`ZIف)vhݐ}d0.'4?s"9ߑ;xAEp,.NUW{z{iۣwFӓ"74AW c1J`\w5~Ma]!pB,\>z;}4G[2ye[Lab%5zmmZ8Bqq>\`"(ڳg]. ,6t>J'qe3*hhh]Ai6Wfv|ONכ̀a6 fKwV%,QfɯBrr}:}uA/}%.ׇuVܴwϞ-Gfځ *aK:d.$Gb ((vY! XX˦ C"Uǖ{3be#@IU iL$ە`t)]ju;dq~B{kӃjEPMh]m7.W5VMR@\pru#>]d~ ^ݩ%t]gxC7<zhP_60[VH#.C,h-{:$d6]ڒ``rfc/iĐ'&1W}aK~YkU+W6amK:Ewm%0 F?F=Yc`ZbPzeiuUe7@NJs7С i?zYaE;NR@I?#b 3R7 u]߻ ͜tB[䙯-/@ܱ/><-ѡ%~N9,qRp"/pr"sA0@\09 ur2D8j2牓@ůP8IDAT !H8ZP4^q]>KpV(cČSB]Q #L\غX̸@pQD<4mM=|54:HTb|U%( lǫߠ>-]\2r]>/3S#h8^yqQV 4U &+џү2GYÃ3B[XXSYQv%Uiҽr}wzWۛx*3 ?}2c"Z0lD?83q5?HE^m1w{gəzjD9,A Hi V TTW)F iֽO+Ep+s^JXHg9ǀ-KGc}0lͦ"ٶi^_:b&!Q!߰@J #q7,HӣpSnQar^Dxp cz ocN6E?7%&pװqu/:oѾp>ο#\W-PAaaaDf - )11L K@V候7w C Fd-ݬ+`Oh4|jeV/z3kLV&!!~V<(s eλ<~3fX[L$m=.z@d*7l-&LJ1-W0&n2n ,liA !z{yRdrKI>T5dq YXB'Lkf2 )aOl\ /+& URH$% U oa(( ;0gJ-l])sl鑅^z [`3⋱w0u¢J0,Jm/_{7i2;sg<_4wN1BKenЀW1SOWfy/N SgifhMff[0a`K}/m|B#iݦmOf9rD ->xX*KE˪~@*vQ#gaL²rh͆֬fX\Yj (hYB/ Ų<VƈӔ=ic˰-3EϿM~\.sUGjTpmamP e7ó!aA⪘AAt YD8 õ*cܿns"--㠻hF;b=ÿ5')5-W=%+Y) ) t ~ʦQN[){yai^?;0(Rbm08hzMv/Ya-NThҴ_LJ=uԭ`&k-p{-\KwbSgQ.T1t%,-!!kl2Ӓoҭ`PjvmKZ6V*u7wW-”ܘ97`T.4Ң0_FTi03) :|bye-4_8%xvt{.YKpC`#y:K jpgBCè_~ 5ogkO:ۖ +P\\&թu+ue̛n0YaGF7W{4;Sn(G5uXM0kG޼$͛v4?+qu֭սz1eʔ?0c4xm֭ ܠQrse'H5 3ٝL0?g#KԹs'Bw+x+NA xyPjj&qlٲujӘ#B0 mXX0IkYua:-bbf̒$` ͂b(NKpH Ϩ.$h3Z.9`y[_ѱq2 {~a>8ͅ,Fdʂ(c@=*{]r7~￝sm},m#GRYꊫ]ͣP03Z&+]# ̚#d2ݔN=4;3<5Mi|O`Oѷlm;O}Owڽ]ܻftn+{ h5[Qjcqu K66.r"zn SMcFгOGXh-Iq^p#?3_򮢀D,=TJJ͐,4"f&t!Zq 4wE&%#:f\*7Abg^DujSHl/vEUc`\,t2O/˓ 94TWtD?^XwEדyJ Ń4=#Gԣlz2b(0oJe&Рz7,PB^W2JL~ͦ=4l ي$T34#uzԦeCd3pֲu:'~#"Yl,/;}jrhܹԪu _1iii._|ɷNkne 'Rfa(}NU)D*cɠIhѢ%Kii^cK-\n88Vn1R #_c[,Jў`q{]}NHR,Azf:u=رS+4֯[O, :Y$;V<*m=zH fқiZ&@רw( ZĮ(+onE) =\~e8ދGQ^fyb.3t:&Se_ml|0G;;/~NJh̽8;Rp?zSX0@_*ہ/lcmtinq5rYюԩ9fXqw [H^z@s]Lt·:>uy3Y.| }?~M7ih&Є|<ȍ"fRi߇hS/)[tjש=6 ^uuk'}|?1gdj(_j<}әܹ w7g0B͌U҂b$W}1{X[oͱ̾emm^}NWPAH#)smVUa*FǛEFR6V˿h.qP@2';WnA Qam7]K09mA6Kr`e! >EYH5hΛzR:K8b6ÊU_b!`,`CZp} `ѓ#.43 LyC fo7ٺÆ?C^~tݺR`iӆVvhϋ~]*Lxp<<4F!LσBC($UΜ>5j}}}WP H#<|pqJ41M~TXVhqhRHL6ĄTSĀ9LmɝXMkmC)#JȦ_I7&?o/Yy~qݵHR=s:Hb%RE`љE!<ؾw4s2n"tLt_^*v.Tܜ'9(u=+e!LAj( <(<\x6v?|RHvvCk0bUHX_iOČNe6e|  \ 1t-(S(ݴ`?b4fI|BxIcuF|VMV6{oWmڶ;sp]bΜ⟼z__~^D{]|||ײC~7%DDFndkl+OO=9L-{hGu~~D˔Q$Y8ѹS>>Tg&яrcH<Xp̝A բ; tpTqh>8f<])#+G"ĶY;"إm+Q,w]]mJFAq=&ȗzS%l;Mt"({FRwߟqYflKf͜Q%nntUIcǍ٤i V%8ݳ_{SBB| OO Jq= V6RuiɸegB8,%2P=` Wְ*Yw9ip"c4,9GGVp G; bxc4a CMHQo|L63ePLqzit&&\L@~NKӂ7MR]YmJ efd\(7۷cu=zmԨ1͘!C.68_9sOϞ5\)>5Rp+tfWoGתEw3ޛ9F?2>q 1y*4KӡUi}t.zrƽJ!W0o׮E bc1vqPНd&!*χf0Z5kH6eڼsUK^WͦB $lh˜-nA:.> tz8Gб+3ir2 :Xs' <=jX:dڜo'*u֍> 2\o=Q*` m. t+mŦK< 8;(8(h |NPvdQNN/}LliWrvr&O//tfszzծ]zI]E~&+ έh֭[-iW;ULڜFYpwVVV.֖SL67m5 E 1lͣ i@48h)?֭>[Av9@6B1y?E9[V _~ng@/xeH<[b-<;~NNl.V> kŸ^lY,sE=Ă aUmWP썴K_=M<ڴicblF`eQwhoQn.3Z/*#""vWlJNl=G={89GPKrrwm۶o$j7LsG۫Y7cmś7m2 a!T0DGQ?Vb~"(\[|>NΠxaZn_h0X|;PϮWb$+gk ! >z M;.ɸg?4/=~_9Y CfgVc(B+ZLq )r(e31Q0JoCNCXbN mՔ\q )~a"9ZKQ >i]Ŭ*1w\9񩧞SR=#M#HIM]X޷Z~,GʊO 1/n YQhYaqutsaE'T<W`cX7p $Ņ&2 !7pKNy,\(#fHxyڵS|kи,{@Av*½NJO3sx/4q3VCәbՎ /[q.@jRZ2X#lV{=1b:>K0f+^|_ʀt8|'cC++GJ!~5bW#`dj҄HѲY2`kfakAa,~oʸg辻nLfVj9GZ[;z֟3͝{}d !$ 6oT^zncKa+#sU ^>w:r yQ G.X0MN_1w Π])I{Y$qް3&PfSWgCyjiYejl12Z%I}Ծ}{//>w RZZ:.:F,뮿կGy؊Oe fZZk\K-Z]xC *,ʧ"; ÏoS0z-a1Y@1SNѧ"CX7'nǎLMM{h϶]{]LL[oq^W؊iԑ^x&=ôb_]+># }ZH<՗ŧˢd5yrqΖk,kҙNRᮌ9 ya;~~~blq G* Cn\a\&Y (7N(|z#!Uj?QXHhT9oiò ;zfYT (7T~0СQ!'"(l}=4SN^J%Y#5аi83 hP gW x7 ma^.yE6.'@PXds׍yR/𥋝s*`Pqun..#;4nоQkrvt K7Bs_q]qVZaג 0/?QF婩 7oEg% ~ޭJ ã4\0>}o!L,&kRJCjZ>KֿצoΤf+Lhʕdr{>Q5@o'ђ?EeGb5mތ\3a]w0 f͛SHhtbpSTxpfhK+0C~"Vd!ԕH~!u&또:sԞD-„?&9edHjaO g-r{јgD ±}#=:z:޴K2a9NK ċ< )+_=»⿭ܓUG;瑫0Eu|6*;`UQ~yDQT= DlQO ʹ?gKAùrVTJP/"...)n,sXQY~_1Q9UT1ar]nԠQ#c '6ܐnCϿҳ,Nx}m޼;Bs|A?LJƏA`ɪr9y<ݸy&.֮[K>FIcƼLSߜJ+[E1i(n*5:e h/8}r \ԬEs֋X"-/~QWk, s5@c`vʺm)ʧ.CSPWC~[C ˆdAN K\fUAV10iђƌy) qA0NoJCnծ)D e EI.HE_\̈́( Yub}H>QHn $[|f%5SNRH6F#;C/6sy^1}z}b{uE?RU6{bօˋofNv=plm= AF ϕf5kQ/7;'<%fϞ-7tᥗ^)SPȃ5E`Vjz_߾"1jӦd.ւ.ژӄ~QMtS=ď *;9_Ρ4p:tx!zrذ2r 4ʗE``` r3Z,58(̹f2+%,:,SYeᎌFstFÃ+,LQ^GiKZFVHWoEI`8bNtvcw庮T+"D^Hz/Ps7bp":r<~9J,`E5Ҁ43i kݝ{Ne-^clef6!VVozK:kB1D)b Ŝ7tuϞ.ȼtfYL4#pquDzm8ںe+hٜ&M)=z\I~:.o!YHgro0;wO?ѭ" Ѭ| v֍֬YC-6HYYY$[|֩htʔ ')shÅwܙzAܵye -ߕqqpG b6>sԟF?W4^B8nnrږWf`4hI^"QP];r;fɀ`B"P~ RgH4S(hlvЭQqoǟ"H20Pq\#gZ@"R"xRܮS'nԯwGzT$HpCr*s. mIؓCw%+76SbJcq ^ 5$\˗\\?cV0cJyItjo f[d .XwqmHl9F17^KŨ ͜ 6-K O`#~~qխ[Ƽ 5iTVyFT\Xv%K9,jJ%O~~ WIlٲ;AWsՠ ʝ}SÞɼ3sb ʙ@kgܡ䶏a8֧&9pg}V2ء=J>.lXjڰv-h / f0wCU1|ǧ!h5AĀb+SSr$ lpTX Euȯ^3rcC g_)?51[n>#un+=}Jk0`YTa@[ a=dHSN;xp}]td(ܚ]ӑ4&?/E#|#Ы}H *y/?!`frTL"ٸ2s}\؀ehxO)K5rg>[ 4l IXEKON9lKlsw}(;B1[ v=w'ħڔh~8 hõ(aMYߕ-$L09_Ri"an9 0,dp#y1S7>bzc$qu 2-n* ю3&MDaa/`|sԠic,vҿ_S`%pC]JKX;p IV DUuvNLV&ԩQ6uh݄ކjوԩ)i#*<#}uTN~ExR6ϝ n{{-{ir Ҁ޵I[1=H EjHmf$gabl/5EUY[Yf~4n0JW !zT{.3 wx]nӡSGzXtt 5Q\Z)#,YX.b1&&$kFmڶW_'qӑD&VKbgϞW6pt@#YUKc.ebb3EFC/,>:$nߟFm_A'cǎR"N#.SXrilA'J"rbF.w+]r3ڼ,r8#.|* * >8jEY;/΅ ?V $X4$oz3E9(kÍF=&fsCYmCIm[6`vw"fpٙ,aUң$νGiCtJb0LB)(%іe.P"qE s8 jTu)i^}Ӄ7%,ac1+W4R i#:S&+3lѨEFr5fos0`h R#KD.]{҆K9ZO}9;* ݈ _;B(,_w}(1)YdI>.1♙Mdap4,ҷ -EtK~uqyp> |Z\J^y6".\(p=z(tYP#dO(Fi@#755EXAYiYRẂAR]l9}4gADb1s>}zE.]JՓ ? F+I K L9،Teb?-k0lw۩_~T~;K+ZAk׮e) cIACNsNrn^++r`<FБzUW,7  ̦%fl6 ;{ J`1ƅ J A,L*;-KmTn6E5C)<,׉"VDK2 i׽8h=> 7Kh_ SvcI_AC=b%{¬HӶ@QjTcHi>k+GTx:zIVF "{PIfed. ٵ?e`)Oʌ9.*ㅺփ7N& TYY){~i|E&r 4*ou%8@&L]vQ7ѣdk]FqFJrnJ wmiDjѪ%M,bס@Z',B:1c=3 [v0, HK#1wWnk`A.<VѸ^-ɇQ߾}eesJZ*mۺl,Wb"\`2ga]RӦM% PV.TSO`!?ܰA/f i )*H961-pO Ne+PAH}k5F-INY7,HEr` n\IeFE1 O8g7ȟ|=dq'x7@?ڵ(|aG IZ/t wgk  -FH8x3'Z asu)s 1̅1al!yk)s~Bd! Hٰҏy:f0,YHq?' aG{>̯3,Qײ>"_Ð8ڲe+FznHa1Y:$FɒGʯR{ 4L>Rh{ 3*m%3& 7@ǎh! `FX#iS$>q[yƒ3Yb'!(3jDݰQ#jҸ1mV_/H(7iz.92@!@^*|3VKF*0(v0ڎܛy>"XZcݝW@ߥg<:w`ʏB^'ϐH`ȃCLq[VRҾ(;@QI[%*QWDg':xbR QfV.3:4 $(PffT%-_h/o=OLRz؟Lɝ_|t[KeBr8O9ݸYw<3Af ?;/[i ?<ѺbEyP9y6޳[b1CüS}W7z-*R>Ci*+A JXsEJL- \E^QrD 86ΙR=PcIPhÆ^{ys^.܄prUeyБ:F@CS} )G8bw>8lCő&SAu,tBIVHڷ!gR cozQB-զ?ou:~ɿYi>P1C G+}y%G3SxyvǙ>˰?mbfas這 vxmr8_HH 8oƇ/7_iUu }-930ڎ:U+|t 9_HPG^,~WX kHޘ$ #|RɊ(v &&%ҷ, 73>C @9 MҁN ,ͮZJ@ok6C~[+}=ob Չ뱏J٠`نa +!@b`7hGա W;ҢZZ-$B:cCD.@ *Q 67YYu]8ƑW6nKΞ~"*?UTRg*ΤSL9 gdH _4iߦ{Wycǎht;;'NB7i9`N'`=5 # !5JEuFCV\Ft-L.(4 'p|M>1W;2x6gfm[C hN2cv-RQ#C^~thQ|ZV&FN'FPيϟ2b{\t*fBGjwXҜL`}z3X-m(D UΚ5Kv|W &WZXxO'i޼hebI"֩S%4iV#*L(_4]h؊xp^^ґܯ;D*SBhrtm {V(8Pߧeџ9d} @8D'n0(EGFI1B_܀:q8mݺUT:~a&|b/ôLaG`d7 ٙ߅_[yoa%ݷ[J=ө?Oaa̘Cԩ2T/aNw1r#ALNgm@ӵL<< CUkKyXvpzǝ<%F0_U\Ona6z@qPr89Kݱ slOb_9y||m޴Β.Rf0-< YAcK˺5kQSph0=sz$k 7K Khw=4h钥2vͷJ-[R&\[@Jk3F1`4^Z $Sy[wkעz`ڜ*T&ߦgo9"]cVlnL@ݐ'0`!3Y7DgmQ~.dQ.K,JZE48_>=أSvuuXQ G5NLrEbEO?Enzd=Ϙ"U,d1w~:zUΝe8EաGez bD`yLcV,?'vN7ؗڴi#$cU );SI'\< B"Gz52:09VU_ @)Y\ޞ2,\TX¨БؽMxoaHH4@>t/KXU@IN@vҹªl=Fuhl| 3^mV|_Wo ː=:{OpMr4lQ^26J 9)F* |ԘdڛFykf}V.*@xG<4Ïbve׭YK/l9j4MgabP ag4[{`:ݻw/-k2D:wQtU"S|D,QEyS.#}&_]̴4Hb.XP<깑}# 9 >N͌- *`<_32iI&y|{lg&^u(u7MVs+ e,3 s啒q,ټ\ʍ?)  R^zR۶md '< !ƼcLp}0Z"jRo/f#Zh9iR9F& G' U+2֍ eddӷ,8|RV Ⱀ\+ݏ`)UNsiV- TΟ,q2]v^ZkPM.Jf"DH;N GA|z9؏:q\ R2e\\ ډmJr2 r?{ FxoioN=O3w. :cd?z󭷈Po۳CGm ~ 9j ^^^؏ QapZGe@T>KnV+Hlڸ7&@&z|6V> Ӥ9 NHH, 8* ֮^S<{#zosM9h`U:{PR,҂9/Y3gM؊Ciwq'<)nnsXYTN+ɠCW$%߇"ĴW ^葻13;DwyV.ΥL8`_\,*?$ ̽zDQh)LQ*8%NΠq`.K-` 1¶Q ~WSn *`&p6P!!!ԲeKjܸ5kڌkG޸7C!$080Z.4)*|Ț MBZxH#]Ҩ)R똿]D[3$5uŘ#e +n8 ! xbIw*BX;) &[i g)mZy08_GT8Kꖋyw|H"t-.clf%jhb(3lٱ |y4)!M$dӐ8Q"3Z,3* tLvu5瑡CU ˬ' Xf 3_C#.zaŶ+ y;oN<) PT,w`?fE& a9KA92b!4nKM"'WmX+; ̿f+Wc9|Oa 3U$\4@w,tY0`H8XBhQ.}s>CU-LpbݨtIL^0RcRFG˗üySt)JS%`.bM58>YlРI}dX^0U bʶ >椽RU$hX}6FY.k$'UAU Tx` = ş tSQs:IymN<,c~:œ,PgQw0 ^¦{Y8..no߶?Rl[d&?wI~7Nቓ&ї^a)Lc/qihj:q&VPV& D0Y"FgeKZ[ 0?ܺ&I1Lر57?z_+˥O Y3`usa0'A cKr>$cyy;;sdn+0MqE74B,Yy'q}MK2rGp̬]9 =m1'(L'@DNDiC0μ|̝49qxиWeT@б;FG _?PV<{4r@N>ÃUߦer(釀@r\j٪ee>QX_sVgCK2 RY pAښ;y{_o~bޗg2=Gp)8YPDR4=l):GF s "߸kp^agR}~^*( _;h;pBR9q qXϋHUUJⓏ>.~sۋ;UAc71N3gNwX0iTwS?aV{޴e]>?$w@O Np ?L7,,\V+ 1AF$M"9ce3YPVgXz(y'8.c/bF UbFR,%>B1lm,}!q`VNFwvQ9yn8u@H0 -ғWyh`@Ő5Y* qa8 s7z{>iO$?74ӝ 1OYhq) ^Ӫ0 (#$ix::fIR1awXg}>m`LϿ}^ʘ1Xq.a w̦NB{N&;u4afi#h{\ÇQ{Z^}5v+L00l0(R8LasuRt+0]0bf2d5QJp.ƋʄÐnp=` ,XwcO$淹pmdz>|g<(-X.w̖+(a2oo 8h1bUQstK[`b%C(C\M5;]/G䝕R0X'n2R)58v&:sB]-?T <~TrsrB&zssiYZ}@cN'N1 KL~6FXlA9$:T@smWz&,\會0n8uO_!9V`H@|XVCMYY} s0^.@V(;9?yB@w$i5l>:7M|u/(k!@ A:rңմr8sA,K?_q;M6^wޥ&MV]AUh7h j[3]F iiZ*mvH=$℩yL?cq*+w~ XzPi5WHՆ`[:Lj>K* ?V4}T6M] ^ϒJP0rfy3d3T[48Hrx StSr38/S(.w UcL%IOW>KNs*xaA&̜3ɳqEvH oER=\X/$P0" FZn-/bZE &?XJ>5v)@1X āώxy!d(7 ǟ|R+ vڨq}C98Vx"DSlJ=l 7}Yg"wRx)k+Q5wS$g? V+sJUJU*8gjAw1EGEaaTM%Jl@V:r C`eP ,Sy۷p1.ބaByǴWdZ,bCAΞRݽ3Ke0)gKxEg3hOf@|pXtt4\=k[]єLgs+iLq&ܯysv4E7ߟYJ$f`ėU O 7'O{ヒ3 _}E'Mr'mܸT"[(*+H8'  rUIH8# 6'-Y(8|sك( qslX9\ ͢QVXQ 6(+khZh dhc D^!T[VK,.'r $s8{ɰ;JUM*f'p$ _g;H{X̄\FfΌab{ەCK2Lz#!MbizRK͢%Y9%A0Гu:IA%bwziT/NӶJc޳,).?i7`rѷjiep4@n2ބd y5\1ڀjx$ZfO<:viH?$HM|uڵsIUoE ?W acvKl1'~`d9ئDw~M4;F;v}3ze `UY)-CS $Cwz#v=YM@ܐ?@̀24yj3鈡@ZqDz,iԨ!ReN/91-[.)lP# M\NeؿY!)ɾ(?vж=LLU1Q͚45qE-OWXM{ɾ,y*`LX{-G~RYaИ- 1BkFGnz4sMLXUP OϜ>ZhChȃҕ!+ j Ŕ.vgW`[ zxρP3GW7Y"j4  (ge2ZI1TUDlj9Zt,l!9y Lv'I)'_A@pM[dd5kT֣=J۷c(5*: +5at!9։: C`#׆1dNI:t+Xw3ũfxqw ?P*~ǁ%, S2w[Ough4wxu~ບq0=NR ;pS77\-k<ͽ ŋ׭'/~|c"bRW} [_&sL7#ŤLsuW g^¸׭['fxZf-m׎kf sF!һӧӤ 9}ɗ^[ px7[^ +5cƌݺu{ѣY1Zi3\!Ӌ&VB* h/ ݌݊ `d;L6T`VsgB거 긺+pyrE)r~*aQ H(99J^{n6p j֬ԣ<` ЩyZҥkg&} 2$4t1wJF>X`ĝ {pȚ7go?r }` 5Q3^'Mkm!bhR {oNK8 :G7,;& gAh#|SO?M~ya 8-3;,*.OzUo Y[Dq'#7ofmGݥ$ (nݻэkV6gwh=3aنo%wQ͝Kc^|eWǿFÆ?E5++6Yhb_^{Y̡ʽna[}bO5Rs`({.BTg Lr6dei29) 3Lg&Yf_HÞFW]uPvZx]$(%khh(= 4nܫ>btn (l*`D!SXTlefrҙ3T T;Y`aI>8 { п  4(Y*A':L6/3a!;&d1Ox6/%rk[&F,U|H+RiJ}%"$1K衇21UH P(#@Qp>J5nҘz&pͨ~rZn F :n&=zPv](e; TNJOGYf.TɝG^8\⩆F[P$o/+EӇ2N0ⰷ]<\%o^0Zy%f,k\KwygU 9)'˖$kblo0Up|ꦎt`j(79LzG=EuԑV؎qEwF֭Y#nxF?SVX׭[W-(vje7N[naԩW`N4鵕+$3f&&$m\ F//plXw2DC&QMN^:1 $ނ\j [~j&XƮ3ۼ0Zܭa4ZD8$Sڵe XP: sՌ '/Of02wdTVV,6jю {#ۇ;]s$'WW VZe$QzqFTMf2 el˪/(XqmI])yˍ=:,2B,lg\/Op>sC#q)c; _R ",/:d.PxD~"i`7Q`KSNj%FKP"اaʫ/zz䂣^C?@Cc\0v#Wd! 6g,Fs6r}ws"#1U\p^Ǐ wpN1yA`Xt0h}EF8frh ( ,{ђ>ag*zK'$,bl\e֛- oNR\bYhkpajD􃎢 {+Œ*m<%y7a8 Әj]_m~0`z|$YA-njǙl+@$&=km]s mq|@>k}(.g4baKs1Џ lQ?sΡ_TVU>CO>4sC}O%3c3aǥJz ި. }䙆FWhl;FTx+XFI0rgj;Ntb" Ԡ xX +(4:< ·q 9v`_ü\kK 1i3iE 3WG7fCs=O>Kә g ށRiٲeAYMJI6/X.kw=#Oԑk-,"Rsd:`nnflQ} |h1dG+L||lOfe?=2 #c<<5k'̖mW\~=s2Ż)SA&u*>JM j'<Ō#@meE,T"yEfDO>4qϋ ~!/c- .6n+VN;櫯YyȠz+Fߣ󯄁IT|-Z@% ͩ$GX.#rmw'`vA DtQ+OcOF -rlY1 Ax\BYx`1zw@IS`(eXn#Yp`qɈȫ0;&H~Xdfw8B^c0G.sII=S@0n0eX&˙T%{D$,˱B7&9UE 32?EFF{~~17zd yO%q,HgVtBq0ArJz!2Q}_/Bif\ Ra;x" oUGbIGmtRCU"|jRdrNޕOpt3v^DG\.&E>x̝1 [d4Ag)As|,;G<4qPǥH wCX>1bcD;M Nn:U\giWȼRMgr&?9LcZ{X_wK :R9~f)72G,n$>upXd`Oz00ZMѹyaD9ӦO<`pw=CeG,N3Ҧnħ |o+Օ>;kX^4Sxj&Ґl~D#e\"BЦtqɺp~QS]#Č`D0nQihl $Z`?+ 4V> hF@LX-7@pxg`Ŕh+ 7lU08& EXH'I|~Z[OזT L7zkE-=W=^s!L(Yr<Ԅa‹iҼe@K k6 OFLNL t  \kTWW/ WӸa@UB8R<; ˷@:Jw@Xoa~/|dj4ǠU-ks9y >8HHTǽ3Ï8\ _k5zm.H?H @{.nbR}({ |.0SNg>x֎򝳈b  ~OSu9խ\pvhb-jYTc(g3/1;4L2_ ަF7xn2IbҥKe 2XHj댵\T[gP}ĶB'uhZ{!)<1[QϚfSCLS1ė[u/.IFҪ<E% 3#&Pd/4/yhXϝ5;C˫y Lɒi<2}E<%䪭 N=FH#6gOJHAQ <.4Ffͩ{(MAQ,K>@ U%ҺIR8ەp@~kTy q)YH0Mx(f4/d`3v9`^ᰀm9G%猔~%Y@FLi{V:QQQ#oK?J+ߟ>:SHZAK7k\AZ׎*ZV)7f"GRk!E~y^DR'p2) d1k ۮ4&J, @>\byBx ZZ^|HnjY(:#WG] eXWMue$n)5fdn$wB]vŴ d jn2Vds J-<,?mpw>Z,\͉r&$kX5Vk#)\ r !CҼe0=Z7f,ocR)dM o&! 1kP<ϔ;yGW?@vKpާVN}1(0Iޢg~Za) wh>3muhpے* nl+aXR-dC1O\8~O>7L^4}ƞR V%v:X/BE~}yV4?6}y?rIAdPk!Ymą$1t |;t 7 FsxL; ^5Cr1Қ}&pjc!=|4G8 3" Om%5' 1 2Q_̍_$ 2bh&8o>?fxM>XFNűah|FZEC+Vú7n7l<&y$ ͮ *XLA8(AyB"h\q}ŗl GC+={6͙3G&K5#ZQC#A\)iacdgZ)+Mߩ~υ '$f'CTqѧd (y.#OY*a5~:Σբf0Ѳ@h%@-k/?(P&r:`(?zǸ$H˕5{Es <2MPQaq"^paK KB aoܨ(ad$>AvtLvYgH $z)Pʤ /v_[ZhZh(H~6;P%"H>#͐Ev ￧?Xih'zEq=0:P#F?F{ܨHa(*W&80n=,B0D=LFw$)FpIvڍTZpyjј{u0;mwAL1ѵ.Qװ<``-Z4HbPZ`1֑#sB-5;mQiw;0J+[#] D;_9ݦ@qr iU䠿& ^J4RwؙPYdP&РiP.SyHC>) }_F_ \{Z;TZ.`ws4٠(y+| P0"8kIcoEe%/w,C Dxo0e>&6pj7m$S}@z:SW^_.r!#B#uDŐ#:e.7,50x2ZbFV9"m(QD{8-2**0]uB^رsze@[̽XË첼P9hH_f`F>cYK3H5ْ&lh[d8>H7u\5Št?`]eeV44C~{@Gd~)\ Q')頽Α`k.3"O(  2sVtpt7=`d}+0aLIL\XONwjO 32(;+KS^V&ӂ0 $ye%o樆'QxbG#l79`fOxr&7wb_D>l9R'̯n ;ӡLΧX&c2m;54#&1{hRnᆑeج?L*j 0 %Ղ{|dGS=TE0aZK|0ѥ@A02qayf]yMrGF)ppRyQeE'&w@Xb%}W^]]8!ق~f;p><"%,BDf"L/B=kz| $f< 1guj:Y釓o?j-3:đÂdӇkEhBB<W$ M$.`Ih&GJEfzr 0ED8dLFb633v_" #΁1x#\~b*KwY'~A` b@ob΄KVL2r6|-On/6:r+2Az=J9&NASw>g2K)GBYi؂mhP[h*X6+&^֛09ګ7ne`Z%n ۖ݉LY{}7з>IΚL#…=f繦voLms^B󨩪Ob׃86JHYx:1g Pp?H1H7Àfwk\,#}ВʯgIpp|шU@|p}?Ҋ{Y;Gb@IťLn;ʇᒖêeaе"4h]/F᭪FT_C ~%OyqȢcXx')%5@Cc`xɧ">kbhkM^K|%pn5wU}?Pp[70+.Zɘ/-cJ6GM 7 ,HDH74ٺ&g齻Lf*9^c;ugdfwb O;iX[QQ..mbf׬9!1B@QsM%)PxT$RX,8 Q?Qq{mnaqi?A?UčX4~_ #3ۀI Ld/~y?ݸj8>rpaPkwh"46\@wu&FcGymϽ간ջiWn+kܶn%ށ`T<@pQFp m{[ clOO$%, 7R7e :1)cd,aAp䱔↍Q:;PUN |dԏǃ fn熕-+i]Y<22Iz@F{m;#rˇk3?/\Qt -=%@No\&FVm "Q eKōߑ"ч J%|a[[RD?-ǩ"oFEәYn8ȥӌAm>l\K>PX@TkYaApC/߲ a0HiVqb“Xϖc0u #]nՏT'jذ\k\`vRk֭Kɵq}~`pTcC!Nʎ8 L1Q?Vw_y YK krp E]A ;LLO<͛?D^C#8DxՉO[ v/,YLZ EE@A-cd?m45lN5sk |1d I>V7`d<q2d wYb4ؔ4Ѻf~2cMa,Y.Zm}}hd0vG9;̠iH5>1Btu 4X{r3̷6, M9+/{\AhcY>5F.Hͬb+iyxl1-?1~7-獴Ҙk.x_54Ĭ\i V]lUD|%I/ ڡQq{\C6'%>ƪFqcEGzihq׋k12bd vm&:'[7|A[INnHx@ m􇨸[MEy 4p 0P 3\D>kht>#Z㏣w=t|. ۏbFDڸ)`2 Qֶ;e HX2LF<8H5%,; W\E! Oظ,£EJ֬/{#}CiR)78w,`tDҘ9sF3 W_}MլS3tQ1kaQFrGkS冁U>Q, Q0QML ˘`:-a~G^ygӧ1rM>#'w0'Hä@o_7ಃ3w]5pw|g?7jA(uM OOH5n٦Gk +n|K>y x?lw 80ݙ-4S!cDlC(.h82k-MvaW ,H%2"*mEg0aBk99<>O7+[IZ@`VJ֭~ FRDjL![/d y{9|37~K^, eƑ!e;pYp7הQci<42@ڱ<ak$rhC}.9""D L#@jѮCcqjecBχL'pzdч-Zl@Y^ 08nN:? ޡOxg?37X@}Y]᧩Zskh{y`5Y0;i`"Z'\G'Re0h$g'q k d]y m*`ҭe E3AqT_V̚rY=XH`ժBHv&挱hgV>颯[=\ԾqǎLY@ufE&! J͛?_}ۏMF|z\ds"N2x+^>F0W[9</kue؀X\ $jn,TEcU&L@w}S>'Z_o/y6SZXMrzu}=/I;Ǐh!1Ъ!D")O4a6TAh9 #e(b8-Na ^ A8ě'SXB WBy|'rrDGS1kXBd+1J eBa\ЈPfxvOqL 4!p%^ &0\gP @CGZƍO_y%]~Օ4{e]牓&Ҝ]v㎔GׯYtȓx٬m@>C߹+J̼E|zW[ɂ\A-ueE2R4v+7,hAx`zLi t%J7&Kn _gg[!!^7vqlkC9Mլ;-R=!H6Tɷ=N|]H'"{ +7))9&LOX??q=/S$;Zbhdg(zTr$gฆwuÅ eF'&ҵ/G=Pkl?o(!!A{Gx1A ,MZFSL"zV,a5>`Œ x+X9Gk5aOQ9c(,Sc4dz%,3EeR#}'ZN!})E+ qM.0M;$9 C0lUKOOBV 20>ѿj||,C"X jj65 YL3w)# q_o E諽檫Ĥ?ed;hllOwzY[Lrɢ?vt?ALcUSwyW%[w9P:5aQHq" $VA>r.|ZQ)A=ۊ ײƺA |aD/Q2h%&s4BAbp h>25E2|:0Hny% d}O(R| [;kkBaG]W&ّ#GJ_aG亣h ]j/,륥tS 1k>Lޙ]| zTSR`hgv͜p_$̔%Lc 9D bvqJ=U=+Kx:(k\DeU$XX lOk07w/R!CG-X@Ge5G؇FfE Y[w;1֯z=r,o Wk+dq{ߺzkhh)ik;SE;\x8xH09N>KhXJ9pv2B;71*_8.hLqP,DڈYĴ,A찱:ysf5a-cY}7 ?(󵧰QoZ҃3zg"߿{ -H -i :D^M&ƒdEs+]ZRE,\TdQ 'S<0Vmo~fB ,}%ф$őG J?I"}<u|&Hzz]CSZ ԃPgVJB/Лw5E]?iS  xZ@hBZף)&6NFU`,q׭[K?#Zv-mܘ'SfΜ)L",A|&;q= jq=.KDFqF'Vr寖p=^!H'otI']K1111/ /j{駃BYbYKbdT240ŧox~-(/@^2G-ԔTiq)22w@卺 ~J,򤬬"hEn.${^u|Ď 2g lkdw˥KĘ^PHHK/K."M/miѧ|tp"3DN?FR *KW\Z\xluf'4S@;Ų{ <)$?2Y+5-ށкԆs<2Ib?N)),QJj EG4 1:̘ NGbbk|Aq9T-DvSyy8/-))/-;1񒗅2#k%9-҈1ByK Z7SB|qڍEo]pOy77rB5`@xO}l-f|F^$٪jذB衜P~ H+~/RZtY[Cc*{A~~ۉOVX8-|p&QtGE-E1,06=2mL&#>"SEÅ[W^DJd!¤-K1B{ƀ}{Jp*! A!/c`HHLx&$R<egobb HDH7*X`05[UQ֐ ,D+Ka HLg j!Y!X/ $7'r,@ f Y):@edfԒa9Lˆ%$3ƳBJP ,jSrn`I%K蒋/5L|?1qQe0}| r-_%*އ6{- "UD s鯿N8Q׃p_m]-~it9g6^K#^,i3̵W]Mh`ŵ}ه9|>c[`xE̗^4 :M=rsu#I4_diD~`6L\w-w ^z_mp51p` oQ,sas*> ]?rWMhK/)/U߫+Ə_#޼obF#~c7ޅ`օFN#TҘ1\ddED;-@`u-[ [;7V+VYgdw^7Nݕҧ!Uӌ/ ! #4X^y5:m$_wƩ;o#vy8QfvBԼ=lODI|* l}ǖ |<]rEhF'Qdֆ}5d E;iܲn+EHd3hS|̂&}\J8˜j$ $X_C5, 6\ !JI䩭ڍ|װ .BG2ц1Ѻ@"rWIpN 4z֕JYY~NV|[Ry G6lK/ AiәhX VUL@Mdu0 o.T>.y![;oqd]wEO~nISO.ɑNu: n1VؒRDEN>$j4ͰwD P!0[np0ɲ&,Xm im2_Q-}>lih hl1Nٮjbd>_O6ƵY-!̜eE$QN{S})s?Q}(mn26iLJ%ځGPTz N)R&ΦܹR̹x<\p-_dm1cn!T -B ' V ((&4$ꗞ p/hD`Mb1,(c ZI>aXX08 BEET]U-eW>׬^-}]qpM[^yEZ꠯M" @&LWSiaZ/5c x]Hb[/$c@-pƙlg{>57:!v9Ao9p* Rc]7> *b9o&%@S1vUU\yXRp#'wZ-Pɭ54CPu?[/X(%s+W|.b?w?('~]ztwK/@_}%m{g05qDwVsښ]uK[£4YD@^{р}wA0zi=%`?@G¬kH?k7R}ELOf`Պ7x0"] C h:@0؞@_'| ! ׄhY<$AկӦJ@9F me+ #r84a2&g}N懯b-)-i?7lo| t 7ҹgCg-:S/[&VpĈ7|fk"}~_3 |JHLO2@pS/a…V+B_CKw۔ _nUMdUA^$/5k;\噱)*2V.}CH?4YmML"G3U[AZy L@%%%@#Tޏ7N>@yyL6c#_zE):62dFwʔ)0ALw}9tgzahᢅ4 ,ɧc G}V@vQ$Jc{5?54qW=#2B_<7Dа#1PuI5 X2~ ?0bJh +qr7@>* eh++e2 D2~@P=ICq^?L(L|U35uKFaU\8Rl NxFvk`UvN6B I))WNxvyYnltHx.jUgK˷6 7D_~o#)GO|r$*%yl*)1IFgkhRUf{YgyNLz>c[T >ZhZ0/SsS#yA .q!J42;rAjt0*E9l䪫yѰԗm"/,bwȜZ:繘.Liӂp`:OcD2`^Qii;|7~eddȆ9Иgz4b;Ԧ\.D?2@6W0|s#HVMk+҅8aޣIVC hxk0u$[nu?̵Df~.V|A (!_;@ TE_-9(|.ɧqBQҰA}༆@l{8kdč0aD4OyB4>x]Oxز%˙<F3tf[F  e hDp4Wl[>ZhiWnwfA"Z\LF1K~)dn-F%D ,\[ojin `` BB 5&D=eRJMMaM ԍ25H ڍ; pjw$:#8+$pAVM܈@KY gMiGݧ_-w0JJNHpo7$ˍ|G ECxi/o:hs_`-p1X rʆcA; M#Fb :(22B38r0K[*# p@EV𹜕#TJmMb B@yyyW_+o%}p~횵TSm8< 8h&jEpѐ/ѯ][;Уh'I'KJtYgЇe\V ט̬hQ~I/%%ELnjoMEL| `zev`ջpNlmt{dwEuRV;*}м_}5d!f z|?XQ|s/8]xWP >ƠhVX}D*&cgo<0`~OdM#+`Y0@vZ~V++GrXCx9DG=OݣcĴrX pՆpu2$kEYY97)0BYu,`CT6{{,\KmxN9CCfb-efe'dx7*`!Q qG%ET[Sc\i R0R/X+h&:p?Җqy}pJ0/HV\Es@0w&6 !LobPӾ6b5o$7ߨa D@^M7 -7%a#ZAc e;P#6j3f$,X#3)~@;mt30T-iF|5%lExSlDbT`ly}[ }Z]UIU*r64r:JޯL%%ZnT7_}[T4lX..]kSUE n4mAtDIIɉ%t˃aBho 9V7cڒd(>tx nN]>ӄ"(8ڴzt6PyMLņ6kV$!W&6q,VC\ai5Zh@6h ll NAe%%T]TD (4@ %@qcEhy6e2a;ȧ' ˡ{'=cjhh h3 9Cl7r8q4Dlƺ   P1@57+пBv䭵AbpQ4!L51S1F 72I%'RdT,ʣRM$g6~'6imC pY]bm1re3乖xߋȚ b9tD XHMk9:|b_8"%F8RVپoGY#z+sD=~zrThp@;D1ɆۍT>tcZfm3BFW_-Ky2oVc=;ffa-D!d5 4\+{! hkX i0`~$ %'6@55L*?ca{]_yԨ`s-zWPaRD8L__~5L]Ci֭3 P0P +ezwEc J2 :hEHu%hL($TbDU~xCH7(&6Gzg"y 0j↗`;r*cY9!]s ~Ž"tV8mN70 4J#8ACi5P0c;s ‡10>-|Hqqq~fd/>Z_C\}Mm᠍"܈#h̙4v8ʤ &R]U-i/bqD-|رtӬY4jhl% ʏK.i{'m!4=LqSk6H Uea!Zzy#WGDkλ|IH _N7v-?SQD ޡaBBat=Pv̜&dbjϥ. iYR`_,|R(-A mh˨ƍFWij n*֔p.4&LH .]w蛆e<7n4jhle ʏګn{())"amRʄYgT]Gx@DVcFjW=<*+*O[nMP7ãRyi)kDAy&6SDHcm) ({kx 뮡_V^M?-[L4C=4[+yD5ԯ􀄣X3K#G3qzF:eeeSVFr٬VGh#}scGІ|m8Є1@1(?Ϋ kAcRdr&Um aMBTs2=Υ\VSPxW*)K#$&&>sd9s'w'3R&6E%FcY:H 8WQh vd0a.N҇@j[ GiCЛo>Cy7ɪ|);ڰky}-hmhxnHL"oqBh0- [a⬥ !xY9^|e-}| }9BJ-79=jrD+J-ܨjX+4qe8y V ?\|^]C\U[{=^{̙3 m0񪺊/n8 )oFmoÏ?p#F aEXQ `š[Q44Gz}lʫ(-=M?8IH &hD+FKѱ3SOgAکn;4u4JEt\o\HMZe;~-䥆5P.jUW,=#3SE17;' ˑp)|s ih%tK.:o4K aOV{AQcG@Q rWE!,~=ŠH_} ?"YY[,. prd#5¢JpW(D瞡?vKK)ZcB Ŏۑ>Z&""\oPSm904f VM>MF>Gy]gMBqSJҒ* 9ԽcL5jh  Ji>bHJLNL 0,B%yLn?3 x\ y1@m i|e/.4]T#H3LMًF9fqK9LQ;/SVFF&|)kʫ?ƍgHO<jlvAόY`1[7C-X@X,HpkdD;eT=z1Jn AȂ~*\'.leڵpuDqɬ]VC`jԆ)p34Vh!\EqH-B@tQ!F\40h嘪3/* 1b$Z"-zzQ"4[>dL-MnUZy& 1%%[o55mT\\,up}U}Uhaď8^U⦡1?/hl@IװFcȑCY7VL3QvD1YGu+"Ht?{i4‚xybЀM2dҕ+WmoǴ$™GD[VCC6m't瞣ǞzeEEFJa=."sMs TWVT2Ѯy3H9hLXSv\_-L4Zn$igh111vC^e- .g$Z.rth|`޽yPDvj964!DfZZAZP03?N@ Ӄ֮^#M=)m_urogј1cD?됺xt8۬ -"0bQE 6jQ dAhv _XX鞱54444ɶ}϶Y}{q:sh?I)(*+t:EE_ae}@uJ3hMAH+*#"lJOOo'ZSDihhh4nRSSmvUW^x%s/@Ͼk/۷/~ ˷YM6믆㊡e<64qi#Fg=Lпkhhh4ne`qh[\\/9cǙ)ꗟPLC5;+LȿW34`4444h;ϙ#[R\L7 M)Fl6q|m̘ϨcUCqꛎc!P|ZZ"bӨ:myEhu]ŌT_]b R 1V'pB[lkk \FF7 >Ku?F@n.lc̞n`U5TQ tP+Cۇ4pG=Ѫ7o^F;h1r$M>o!t.vҥT:Pt&bV757G!,hVQjhh 4`fQ@. ڵkܐFC]?Iihi'`NjW)5 J5X6ṇ‚3ƶ&SQllSW_~%J*LH/CB)-5Uq⒒.ӯ*::dP 4=mihhhlKh N%тX@-]7gᬅZ+ XZGL4hhhhl;h ɶ;ϧ/Hժ7hC@AbV*|GlՂsZD;0oJF#ZaQIIvawh!XE*0y*iLyBBpX9poZkͼljʯƶ&ahiҟD∈~IEW_u {SІ $l,23IQ]]vКի M t:i޼y/ q`롢_酶 \| kfc54Y^kkki]w}F% m0v5׽]~=4ݡ0y҃T p\\T%|X {,DOF@^c!Shj$?  pt㜃5U+ȃ`Z,a.2ўwtkh8ieeg yx==L CM<ƚs@Bcٱ4^nn.}=tej7h3fmΜ9bP*E?F[Ya8oF< & ҉t ~ژnl_]+#\`^kwަ&Y ~&igS)~׸n:ZX[U2 ;"ҊF$'Q4bGMޛ.rz矧s?ϖIVCCߡvbϽ8pc(7^e TD۵t]wÏ=Jo˶.6g]l `544 4P?6~~ZW̤:pZךiFFz~`Z:(:l-55uhdƐ&]wU YM sN%%2D" L#@CCCcCƼRit OQqoO_Tt41VSa^VUJ$} MpDHVb5444`5f#].?"ˆoJF% m k0w[Ge,+II&oy1v#*:چAQ=}C Mx|[0xS!m*ȣj`[9ݪxZ 'ƍ>[g444464p|!\h8c+/^zEZzċ "6+Yσy`Aƀ2 õ"Ϣ!/Ҥv5444ƀG-hŷ/Id-  5&M;Ϧ&PjZ%%% qud̑E8 L+nܲ@yy]~wZrcC=|i]544<x."!Z& ̪92"FMÇ ArQ(##C4-ދb=`e87<7jH9RiY)mܘ'%Jc}7;g9/CuXCCc@C AḵִT\\,d f\h&ָXqmNH-RX#a88bƍ2h7>.(D&dXmhpZAp:DS5k&ykzWWWG gjhh xhA5HmۓO'P/~+|CT˔&`j)R||uDDP*1Z+ȗ=!,_ת]UBʊwGs S"(>!^6 7n<9멆Ơ`Cmy7RIq11SIQ17J(B])ԾOHDlI׌49jhh ha_k[zamm-]֏x\k7lqdz)(3 ÇETy_DVj#IENDB`nut-2.8.3/docs/images/ci/OC_logo_merged_140x26.png0000644000200500020050000001142014777534445016347 00000000000000PNG  IHDRe`sRGBgAMA a pHYs+tEXtSoftwarewww.inkscape.org<IDAThC[xU='mHB z^DtC*RDPA +EHC !N2Lo@WV1-}yϹ3J7H$Z"v:;jK@૖h2s"6\ Ioĝ, :UV,Ps H#CH; -AA䄟h oHEZle*kpJVJ! 9PB* *V5f(pzw@|l{5΂/\-A[E0`0f0_JMc!Ɠ{J??o(X,N-vV,#,H* jJWeV Vb|R2<AmJٝ8a)A iA*сq*b%'bJO&yXl6z⍖Qgx*(dR"`xM|JV %J(XLz5.V)1haѺɟ[䎀,(OEB@x =3a#89z+DxJ|]\<>UPVU`^ Z11:MÉwb5;E/rnd"$aHg E0 "^vpT׮YBD5d  k{`qL6.].se TT[OH; W0{5RNApkKĆ{jC&> m"}-N[-&C18~gT* RJrj~ꆙ ˏq1]!+5чIA zoRĄEZ01 8.9Df4?"zrZz %U(q~:տ׍үct3ܥ?ﯮ1~x֏è&TKv+Ფ>$_`JDBv.[zezI"]wGQK? E9.:L6Qo7XD{sA.E,7#D?v;m_~b; >~ ՘E^] `ɋ mB:pݰ]hA#c6F-о?!3zS8FZ-M<=$c@>r n~g\UL(f?v:m=U@vnHCwI@17m8_ ԫ-% m]Yo's{ӢPTV C̉C;J>O+afLℓQyݎ5H#fZ88K@e_&Qd3Dw_/z;(4u ǬW?u_":&kE N\88-a)m?!k(GÖOʵ2 PW˜_RD>XQ\2I>G[EMaߓ4k$^; =o KJ0cF5p_ z+Z#[}[p^*0jغ4-s8QfhݏKٞ&8`]f0NEX!aIVZue0Dg,oN\~Ig"VQu]qpN_N$-' 72 ˬI'X~sX"QW=_eV|t]%l+kv3c=J9,6럔|wZgf>h ։2le=N;35#,eQw/Qe;nw0χ4_%ƮUgç,{cþ1G9v=l;Μ$-q=@LdoIHkP؅L7<@ ? jb.rwr=CG.90MCzsF]ȥx# ffd\ly>X"vGP_Wa+2;+©{B .~ epbrDGlƏُu-(X3KG3H;Iw+ߌr mҔT՟=ݰf#|C("D̻'5yE8N>I~gG4`R+zIV ?k?\F0rQxRShh1G~ޔ+aG~JsCw{sgsKF/ sPJpeC"/!4RZrZHJ *1J;\*9H{wk:*sKP@Z("*^^!HT'`3BWsbwCM|Tq!' z I낺> Jު0: tJL+KI%G!sl}a  ݰ⍿#=i tL-"з[+lyD*u8x<c?S(Xmv$كŔ+PDn U1 (R)`T 唶 uAûWFr\fb,.T2!=6R Iu#Lܪ{drޗ^f͍QRwF_ɛ)'vl*iОv6w!]rNjU=,Dc6[nwe6[5 a0[HJN? f !;olC@ oOv("is.vyݥ%i2PKaV^j%NI-X5z|n\<{RPP9l4kEFZ 8ՀbPO*vh&khtrBZ! D {5uXοn#b1=w[0oVtmHKNd_I)7{5>8lĭĆ` ٪ULڷĖ r y" -zj8|1LO{7o' D*J}{)5hѢ-qX7TUix>ˣ1꬘b RhJЮ8v)PШp ]<-'[ 6.EnWmQ5G'Zca#~ v]k/D[+w㥷wԹ8BpL6՟OMM0O&9S?^Aqؾ$oiVMܾO;';}*iB"w eB|}8}:Bi0Dl"ҍ VwXH)&`1ɕIa~{Rƃ8wW_.v)H|9v ڜY9< L|c>. ֥C@}C)wZ!ym[vײWXZz s:8i/YEUv)5l3TelWޤ$MYi=fj;I!|&2 ;2f^{uVmr+ IlnfQ .ْ5kbKSMq̓) }'2 SiXplS=vF?ths* Z4 yiIbh?o ҄KΌ=K)(Z4[PJ6BT$)#EMvr # ;*ޔO+`iM_SG#+ɃD3PƨbWxH5( ё5SPQ-v V8HH &X&*[nDA{OֈXK}pi)[esHUfddpL `v0N*/MV]y7L"zZ#h9# Űn A"CIPQ;"NaFi*zRJyyO'68j=o&76XMY]Hp6_V*ɲ߽:ZCu+qEvTIENDB`nut-2.8.3/docs/images/ci/jenkins-nut.txt0000644000200500020050000000247114777767434015073 00000000000000The jenkins-nut resources (images and CSS) were prepared for deployment of https://ci.networkupstools.org (C) 2021-2024 by Jim Klimov Customized Jenkins+NUT logo derived from NUT resources and https://www.jenkins.io/images/logos/hyderabad/hyderabad256.png as published at https://www.jenkins.io/artwork/ collection under https://creativecommons.org/licenses/by-sa/3.0/ license The resulting image comes in a few versions as was needed by different design consumers (Jenkins banner, Github Auth, etc.) and include the base image on white background trimmed to the rectangle it occupies, same on transparent background, also same with padding to be a square canvas (as used in avatars), and a downscaled image for the Jenkins dashboard banner. There are variants in several resolutions available, and options with a larger or smaller NUT logo served on the Jenkins butler's plate. The fosshost_org_Host_Dark_56px.png was downscaled from resources at https://fosshost.org/media/ to fit into the Jenkins dashboard banner and remain readable. Thanks to Fosshost for providing the machines involved in the new NUT CI farm! Logos of CI hosting companies and other organizations which help the NUT project in daily operations were downloaded in 2023 for the Acknowledgements chapter in the top-level `README.adoc`. nut-2.8.3/docs/images/ci/jenkins-nut-large-256px.png0000644000200500020050000014401714553676503017001 00000000000000PNG  IHDR)sRGBgAMA a pHYs@@uǤIDATx^}`WnFP  kC6ls{7N2ddd4<{t>M>rdzRRR,23ٽ6o!evv͢")';ǶCNSPllYIq}B=G|J wHMM rK:_ haצMQQQvfffrs)7/JKJLKJJԔИw~7lаmw#2"#Gg2,,8(0 25*2%{edB*..® FFdnbDfl3),|rqq1jЏ>vKq Bm6_眓wυ SӚynRVZXXTdTL\L--̌Ԅ,Mʜma| 6Hc]L%-Zzm_Cw%222X[?wZO>}dvɎVCA2!fU „Ɂ ډ}9r?z%?Lf~!% IMдG8h5-⿃p!sg4>ʕiiN999ݐLM]m-5p"[ S&|c!f숃ʨLz(~%PsҾ+D0Lv0J/+9z++>yn{I[;` ox{QqKwB\"nQ]ZyQ[/;r kV!o\ Мfg]K7}5;9]P\JYEtj=jԉ޹[^^n+r ي%uvf6D*KzcS321 SsK2b9TLYI1*-.B*-*<*)̧R*_MX'fVh GOCf©^#GKu;`Io5`?Le_Ą ioAH{+3&x##!t3k;tp%d~[2f$cs 27\VZʄ^L@A.PAV*&ESnJ<f @\$W( Ԙ(99G:?uh,q2@;$ 6^_[^׸Cwƕ@sgLxżDz֭wn vvLFdmN ['YbSTŰj bQE9LJ ?MiLǎEPzф."Qe=!ԢSS:fԘLXbۆpH'NUw5A8Dޭuj@>6RTwj҆l=7U@O@1\҇UA f! DSO~,9ؗF7%#aX2lg#F~u;0[U8cɢ_FmݼS'O+*R„Pߦ.jmt3]#_rnڎ_O*qVq]W VE?E%t9.%ĘT^ulBӧE},{r+3y,Llha?%ʕ~w؄|p&-w?)A_Sg]hlf&jk.{F`(.L8VU08TU9t1&Pdyݻ 0JJʦ+5'&w'hk KYp0O~C?e%FW~le fńV[5qyhgvmp_wjd%fƬCw,J˶8+F A8Gmvz~>Ԉ$ek NfIup7#ʌbftmSљԺu5vy`G*u;h׳eƖM&-^ dȮ;xٶ=C[QdiʭzvNҢH|tUBJ 42@V^Tzo 쐤, ϤV w-$..6lHDɸrb(iKKweCSrCTjf?x7||\ !JV&zS j0;Јeog,_OaWL*FJV}UU@%UL@ RrOaI0cv4p`3vh`;w^c$/]R#wRZyʈR q^+]?d?Yrv9 0cʫ}_}ٯ>t>ziE֗z>&⸵L^=G W2X3IlVev8ՄӉLHww69K)11c㘲D<97@2Z.ܫ 9ۘSB|\6o۲R/fN1ā>V ؾu͛~ع}ۤl#?ڳ as<5_f#6" ކkT5 i*xx9t8("2X6(ƍih_rqFp| $FM\!Yr<|NTRb~Oĕ,F|#ǎ'*jw$0Ựe^pߵsDz}{vOgi|-s$͛"y5Yw~*?kL|D1j B@J<;!-v\t/ lDw՚FRJǏ/6>Q5+a mottݵ9YQvv]@'&q?JO?Konڰ~tAAy; ?·w SĶ>a1A/'v!U a5Ralť3@%Νѽ%S, \i[+TVޡMM ЃCD1+YFOҳsޏѭ =҇)l:p H3!SLE_ȹY{a|( c6: /ౣG?pkmFZZ #6x9:u_.8 '++ml;߲eKjѢ5k֌]\XZZ))wJ} T&b{Wgam`w^򗃉@l,`+?|I cWĩ X:HE l2:m.ƒ{bАc5}ICŬ ^TIsk@"O6% ϿlG@#/_v|rK;;B9|P^~p*&5ɂ%9:8R=zfge!'$8qwMNNN9m%[ 3:r1G&X-]'樈 hR'o%5fަUnS`\ Bb+[ʿKKIȬB}>.F& [Ҹqmg&:/K_~3߳+k<_GܚJ E9Y/ A]PB 6\>a}3^|eMbϟws)={=222`7V/-a%V*eV1?y6aЫW3E?sqsۋ+|?/?fMѰ|n>`cdTL?_7~lkn@ ~:+!)# T:;[tNW{vݴ)V:+~HGpB儭9ib+~:쵠|J\.g$C<=<ڝ|}=UTy4wN SF4SU3XR.+T&d'EQNBd'ۃzwr͠bI Ů D8:3#Pan6J%bC?⫛^yi(eܳ{K[l4++w-WP&˝v]S& Ys I\E ɩK.`EQzfPsQtZ:xw}ӦMcx}l>l!B oВlܔnZeԯ-B+4UWfn ~A J[eQF/C[Pdn-Z˳.~HKˡٳSpp=ύhCSNQpJU_2*ˡ :F2~?o._uSΫqIbCl WT} #[G?:rc0"ngdҕH:v<>~A43kV-wc3f|ڱS:n%#Xkzz%%N[{,ek-Ҧ 롭bGߩ++:ʙb+%av#Qo;~Lɩԭ[CzɞW+u hx}h7:Cq]hЈ? rllޜb*\f5m| ͠#%%u=w߻o֡C[IK[W WӃPʲ&NqIͣ+!q}E$P WͤW9ǎy?7~_,)w_zYGir¶63fu1d}]QK1KwAbD.L@s+ n0 <*@N]a%oi] {hE曛( !dgeNN!P Z:*~խ+ J )+>V]ԇ| wpΝ;ڇGՈޞZlA]vk؛LM⸶UR$<%ѡght?H *?Y9{wYOb[] @ѩMP "\S ;l6ih&Y I$Hʥ?w#a S&YZ-Ζdܔ[0t.c]9|`ۆ`?W؈^SUFy[q~?kGp/.d+w;-󈊊2:st+ڹ+AC6l؀D=ztz9B~̶w F,|Pdf㲒P yČ ȉ l:{ýK.O|1z d>} UW|we#İ>%hKzLwʻdc/B.խW40?sd-W}44#ғNfs)<>\.Ej;hfe4nR_anY3g 煇)##Gc[rK|˷Wܰˈi #V*Jyp5"|`15 _O[97;+aw-Yprpoz zOOzٙcQVcbbiǮݴC1С7WhؠJ%P48?JХaUq@E70;O\!5I\rttl~Æ?7F.?QXo=~|+:u*ermFb8>zEb[J]Rmx-ha]cdKNWᗒ%}n_݃H>tT7FyƐ hqkE2|bGFtӂo)2[MySCO!~x6| FT7E3)ۘR@\&jՊEN->-3,8Xz7n,͛? ДRRRiێﵴvj”]?v}; jռ1BTz@K sEʃb ~=|PorŊOMIqruw'WW eQvafMM&H RBL%!:/^1 RIA_g 4{Z&&׳I]:H W~H} +BNg%fC g;~g~.ܭWfİ[/@*Բ5 p@B}K%]wn߆u 7޶u?Wu>ژ;O3g+tYJNN&sf?1^rv{+Vqk,0o/FѤz"==j#>=Q5? &X+ab)ld!eQV>WZainɟ+Jڲ]abTj)2!rH&= Jջ6RjzuA8rz (&hQUBg'q#Og[O c(ڳ/DB6ԽucɃ!Op j@]ҹzvq_B-8 c 1 S?OS7א. և|깔 ;4'l-ŨP6(d`Vdnj<_˹ʂs0#LJ֭+[^O7SXx @3 ߌyeM7X&jT$ } ʂޜ97Ʀr柵k p%0-ZȒW77kW=^N\$D2)F%'Q(vAiYZE֙6b,j țlqCk74 K6i-ȗj fU;gW&|4?{d쬬Wt|ۉ?,,;6&f˙ӧ{E b/ (g&Y!"<@.͜q?_)JLR6G?FJ{\`kaa,?۷eggɇjْ k Y,aO C*4J)Z{ 1iDs"Hf} ~ee+էL^nf<1@_e/[a| ‚|ZeeI0myS44%_Y@q]yWą`jF(e"nň[-#;KvlD)^^qۉ%Wj"Tm/jK\ւ`*ğDÆ&m%;dg .?K쎏Ȉp:q3V`&a%GIQ3m&|]% 8c3KVdljQ5Mg+CS,iԭS Z 3I-7JHH.(' ;!:nghDI}~qJ))-^'8krWlzyoa)C﻽1?=p3xqa ~_H;S3U~RsКgإHOB')pR٨=pz&Do=~[6o~驧s:C Dӳ}D\BU|{FfJ%*\>7SҩkZɪOM{(0$ۖ2+ !.!Y_zFׯVq <4y훅^J^^wOE4!_s|tJqOXj<M\mWBCvwFiov ym8pF'nE֑ nPPF2iiO{6 `,ƊmMckN]l y:0SdRZ\$vjn1\_n8ݪ1\>oo;O:88079n CشaTe;zwlN8XyQaC҇v8=U_Iu4L,lV* Kn:I㖑%L9eƴ(8,R/ dYpVV? p&'%S6~^WzΜ9uϡj~}|xRʀfSX+P6ĔF \:@ M_GRxJTb37)͘ўc6O޻_cܢB,EӸ9 ~97ihKB{Tk&`KRQ J~[4u ȷ39:؛WTTh fr|H9J[N!t!,Qꝝ$j4Ȇl(GөOS6~~c5-';w9t%=ê=ΎpЭQFhgР4t0x Ur1pi.lo IkM?AUt1;+ԥ} +i? _*><֧y|w=JNNpv ZD|t:}:A겇%ճS(=V eճ_Loł֬ "4gkjZߍ mU;OZu^qBL_\WA3;œՄ&mF5aQvnjM&MGެ1&|7hxIgTp5p /GG !jWa~3Q\\Oo۾ϒ;yhe]+zGiҤO>Ժukj޼PtT̉>79ءwŅT\&ܾ3w;FH @AzxtD”*tÚ}CBL:gԖZ7w 3A2s$ݪ] (H8ŭ~#`"w3X 1#|h4֬6ݼɛLAaYA'R63!R?MPϑqS)!Q" .߲X=.^3L/͚E?#M5nHvIOKˁWh׮yqqR(0ѿCB4+6+}Eɩi2d@UC.**8|p, u dD1ii[ӛ>@ f?CkG_$jy()):G HKKdem:LQ2zu:KQԇ -Kڎ~h޾. 403w^. h~?2\,k# |z>L9%m['%dD{TfX1+IABh\ ռ? b9GN38FC>Lf>@+7Dщs)zζ"Ucz]PUR99i14w+Y/o)[)/ ŧ~KJJ22j[BII/߷s4`'!Ku1dJkC_*QAR׀W|?d'ײ1}3L].[6{ufJ(;<ƺmaIJ3UU*)aQ}nk@EO<юܸ)&q٨?:RYcD^rwsQ-X+g'( UD1t|:-_E}pv. +n)jz-.!{m7-^~Є16#MщZzT@s7:'~&d۶bP)?p? 6L2o߹23v/kK3*)&&Cߤ'Tjָ0@ jѴϜ>lvogi,Jyjhdg`b(6&"1Vߍ춱w%=N} }C4ahOjЋlE3BnuSk'p FGdгC(Q)C:ҳww<06bf{\5!>4oޜƎ+@vS .6̤(9"z6֖ܣICJxwT D׊mGq{)RІWI`}?${MqEVõ1<<RlHy8)U"N>~ûOіg_A }f=~? ם{ˉKZ& +s+^SV.5fkXXBA4=mw$7=1gUNV>wWߩ" 6Q٩ΉۖfAW8w=meܶ*ې|؍A6X--%!=w6ʨWr|:co;?"Yۻ&[yК0B0\=.]N:| ';krsf*p9;Q1g?S[Ӗ߾EfӇo>KaP*ߧlτc rT$ 6Ai4tdthOօ|hK|u5-:u}99)5 աΉe˖7>68T.]=jQ'dg sw"LU:J"9a$м.t 33LVʳBbAZ&Am쐶*aT ҥ]}M>O=T XYR-hNV.6SX3AL^\o0⾚A4=X2^aW"((kIq{v] ZF] L#>ɂ SxA.3~Q4e_͈w135`dsY@ܷ Xy\!N]ɆaAYY\'>؎+*] qQRgA_>זvNĭJ R`ѺG("\b' Wn/o(;S7~zWx(VdaÆaR` ^KCJ\1^ɣrPGы`y© AXqFxTaoM+OC/! h3}}Ct[Шq @V۬1,1#a:VSR9Ez@+FӶ}hǁBHƨKXMj84ǻq[قA @1dJ/,(քѫ؄g,}u(zf@N~z˕c] 9jI+k޽^Ӭ 9cFqf}jZ:7v.KJ״Q=C5 sҦ]uWvtd_F, 2.6Qr{Ӵh#$6^U3r'b=iqNhK(?Jx,mw^f=zc?_W}A#'NKڀO}s׉K"Wl!nJ}٠S!|JN-f7K+/4z%\!@.#f+eeoo*N?,413#CYIGGJLL4L)rف Eh Ʌv8Mihvj L, Ld:'zK۹rk=x4f!bOT;S.dn$&*+ 95ƶ>H#|h6L6\ `ŕxg)z} zEw(svL!!)?C+E\ѓ]V6ֈ/*? @sRvn}0> e hGͼa0T?*&62R\MBLC{4lX͝գΈ֭67m599a ?0%4FoXߝ,rb3v5bj޴Ų\`5Z@^>wvISX#8WpC5*شFچw!4H) 2.alDS X}~~1ɴzzu+hMtJfwYڶ| 2IG[l (&32 iηWdOWGd4q0:!{ j&R5Sf&ͯj N/=rdՏ?|WJJN=pMج'. Wk|fM0 rzPj4AAVf#^Nh`҂ڷmI!qys!7'\ pppH΅:fS%bi~-~تvW ̲Sa*}[陯҂T`$ed4l\]uko_3:CVi:)F#r vrZ>E &0 4to^NvQk߮`L *Φ2#l4dR~Nι^7NPZ'o,0pߖ-˪xA|M AJɶ^zYNNԯWgGN_2Tkar3 ,:9ê BMˇw`VЗLYf'oYq-Fl ۪[ JJFg_×iHyU71s};Wzzq?e=Q˔WVAҗK}]c9vG"_>OבW篠J{&^n#]JJg2C:gO?P_X_pq ^PThj` yaFST6?x̰~"u,^m>fDk`>kv]%*ʟ-6-ShDJij>p_~xí6p) r,(O$&R-MK6-Jwk.,?Zؐ=_3Hy FM3'5<=zQzŴeòs=m-5y2H5ghM_#(Vk$*l6)OOE!س{H}sfovXia8޺Q:;/vߩ uhTyO]Bw h|>Nf4fP7)lhc`K[ DOLUJzaUG_}ه/J^j3YX*eQU9uP}X.3zˉ RLzan ,E]l=\iohǑs7`rsՊYK49rW׉hZu*UXmKٲ@W6p1-SN/mZs / /,:x]zފYm7[[245>9)BC($(B)!;T6VC#\]W}W6cҗl>'bhQwG~g#FԨ#M Y;.VԹg*Nj<EkN cu6ZA oh 9E"m+7&Ç99}#O Lh3#>BGǎ .9u89p.^8OYJB:77݁rҩ0'pon4qL?N9|Vo/ gDŽ:_'QCX}_j{zE4/鱗GU3orX/FL?)aڨ> 6l3j-AlllD:SռUcX?ѐ~ړ~eRGs!k*>]=4_Cwd,fg3կc)"NQ^\7ل&˯#z;kKorg"X$;#oeeƒ[`͝5_I:{G~lLL|ø)OLLx’m[N@[^ȣLY[,Ppyڶm )(Li<ǎwF+aub`8}l=mu.\ԴL_ƾziY;av~] ԍit.@Y^=}!; I,e:3!'&{[ka(8(˟<5J&oF]?nũ* TZN>8s϶?~&2P? (9+B-!L+{+|Y;^6ҊYm^}LNJ]<6&ׯ1}_6̴)Ra$ʜFuiD<9xLv^!8ƄM̵ 'ݏ^qvvl=0p՝ 5MK\h=3PlhlFJl3j|͂ RTL%w5-Y />O>)M{3ᇼ0Fׁ3?nw+(Ͱ~gPG~=σK~QXC߾ bckIw=888dm~/4H n ԋ؄߫GO\eTCA1=4 >NBJ*guSS2g0Z'rmK=6&F;ɷ=w|FkO'j>KmVM%hh>SR6^(߾gGD!lc%\wJ KKW^zQ o~`}ym1w) @cՒDSF&$Fnaa&m.y6vэM8ya)*K*J'+<YCE(ϟHCvbҾ%=rpZ+Wd=7e+(\⩨ȨjPh\c~gW M ǏUS}k$T 7HBu+ŪetwOjRApRrE:}GY[ 9Y77zλszkˢIځq=9vV#v?m;+mm-hݨCtL4aennwm Ȼi/6:sp}{tܿoȈ0|՘5B7!bcc{ϻ.?oG@SCT:n旟}~yuVfa6l֘F GH|0|ߠPLl,uЊzki$йIq~ eB=5&4;=hCoߺ5n ߅ћI=W~ dLj VeXxfF&WM>+;=<233OR&HѰQ-y ťw3k]T~lo0#,,v4@qQ)9qGԖ"ڷK.ˡGXŷ#k+cGٜ|kt!I:,ÑcOe%O6C,hELBmbvmxhDk7jZct84M4၃/] Ҟ=;|J%%Z[]ښ =T"|k+K,RFItJ0t׻wzC.)R‹gPJF.},>3=3J!W[skBL P[Xpk'eU pCğncbb={9cssNe:UDpg,slB7z>"߈YzX.xwH&A.E)ݢi}nfL7f> 'Hoznj*v *=fvN}j P`B,Tq?і|ts M7zؿy9E皠Y^^h[I8/ ,KUvU# S s__c.hw>hycz)P-[wgN-[;^(Yv֬%taRMf+bCD~m3#(}::Sv&P:ܰU; ȴy%?/:!߰~CW~ua UK%TFThiՌ&3LY@'N_ϾGw쥂ُ|{˽$t%cS-^`C*>o̼S-'`(1Q~Y٨Fl@Q'[5¢s(91aE  v!pE9 S*TbH]hl hN `Tbl`o۪VŜ|#:|ɔ>Ò2RNxA?_Fdq{}x7eC[ $gтMD2-JQ(?hoH EQg͎:tl,DNS';鍗^yUAMPc oq鹳PS ngjocX+BLp̉H715NQԬQ=C fлBO"b-18DgdU4IHvJlX*ÉՃ%zLBBw4g?z5""j?τWU-cR6kv˗S١tiQGu[G mFIC_[&~•Y‡56*knQ ߿͞ݟ=|ǰn{)@7d ?xNa^?FF,iԮԆU}ɗR||fPo'vT4WXB'0Zu&RZP^i]Yϡ"쫐>3Q暡F* ۴ac}MG;0яt}BŅYNvԵs[i?KLK+\P14lݩMSmE8JZ7oTqPatg'ƨ`^O#KsP.hcI=k׬`yl}+|ɧ~uptGe鏡?0+z5V WuW&|b[㗔bN |}]YYzPFRQH2I=uq tI:0Abc=0~āB;IG9xCs}HH̓JOmx#AЅ Q'_۶ko@@]{iӖqwwPq_O݅\Ktd§?_gg_Zx6}tio_)*ԒX‹q-}ȁ賷o=&=z  ({FE0=T;ҼEb~? BpW.08S QP JJL1Zv:::{(9_Y)v*70Nu5zak-`nš^]bCGͮ"zݚ^|;͝;:vd͔3hAOd&VTLQIq2Śzl;*/'PzvZ,9Cm srk\h#}=Á'B9scLi7捛>8{持\]2^ń-,b4:1 )BďO-;!W1 ;mgZu#4/&Tz(FD\aeՠZGn &S3|ڲ9T7 \ ׮)襽!_ #&z*֜m믇ѐM[nIBjC;^?w6Nf͖8E(=
  • SmN?xS2(:6AܘzFG=W|Kzrjn6\&VmjI͛'~ڴTAy;;ڑe PYc PkUGb֭]K.u/*yL u<ē5oɽ}{*T!^!J2P|X<}z;= io?UEМ6M@mm.@|IOX)N-=h=ɻЄQAa1m\RS wCg_mݥGğc{KkLMn' \ @ۢz%\bا|F}/WM,*<e.]эo`b]"[]5 ,"*ApI*9ΊA?cVjP_ ..ߺ5T=2U*-5 #G6O>@&&ggUSY.)AC 7又=xwj*uBFFqޖ&L̓^KY5ҮLƌ=kOʺ*Gdۈz`^=}2\9P%1 +؍YyJ)C=:p\Q&$X_ݮ@2Af`5Ym$ pRTl0KOPEfLb43};w ffWWz _d0, kW&6ٱKݨHFl5.^uFT>H7'xzSOƍWUwJJԳWSYPAo~t89L}=>ltVIѡbSqau_ȬrRW9l~Y^ Z5=~}lەQQN*)H/^ ?[BYEw5fGU;.! aj=k0 8eKYAn4hUGG -_ }x?=4 FuH Th^| }i260 5Mt$JspavA]GE{A9Pį\iąU}JcMuccg԰#k*왳L,jq)DGp=jpdSeG&0Oeu@ԙ TE4m>*Zоw_GO\mZ4 K1rEčPa(KǏ̕&7vۯkhp٭G!^PQBlk׌]ߧÆmڸW_ 1cCwZW\ZΈV ZVf] P4iD3AhݣAPõb$ >rbiiI!"H3OY.L}]E4aRբ- ShS.ljs2! ؞k7"evg^:zL2O|,ukv38+YrysӾP-+JfX۷n{I};Vi^}9SsPNzF @«01 a` stZq4 :Vs| 0AƒI\ p_ ׅĤ gYh#>61v,ZҤ> -ywW(zsn)Ͼ]J1 5;i5.Hg5>,z11ːX{Ketb6iʣ?}wz AI %e/t๪ߧ&@ bX @:_7mH..quׄ{X&xGoPG9*^@S]NL̢9KNCO~ Y{ukֶD!̹LswA%} Ǩzń)Z8w9GM7l F  `bU~햃Ǻ==t%JKGG!;f͘HOʤ)pۯeMH_Vl6fԇꍖr@Xپ}-[*={L˭m,Z_޽Hh RkXtlq ?u80<#կlRN.WKK'333z=z>ݭ{ϵmr]_ loI64IYp @{ظߙ8W:.:Qff IYlu^vקswf~S}[vRӔw<-AW)*&Q,[>FOGSw(|e}8} }_vA2~} P:Zzk & "GKҐC?䓿XԓOdc:wm=*Je诋SW&4W |. [w,>rkEޭ[Dg1r3s׮U*scGcI.cֿA"t\/P,HAeOHJ#@c1yI.2I^ԾtZ CkD"ɈU\^OMKOF];wF:HS ?o0=$;#O{]+NM;\$ջ_~Έx뭷.DGdY_6zh~mQݕ.\#D4%5VVtq*~Ouk3ѳӻO:jZ0o{7";}D_V9徆({~Nˢ=9.FC)Hٹy!b =2.*).o5!aUV_B\ ؎ mRNgyh?aNrA˗܇fʪ"Q ]Un]l}YZ,׮UitE532--u5<-5֮9#7ó_ͻeo `&_-:QڮVB5Q#o,FIk'WPLCIʌ:O7'42~n! C8= c)86~_AD֌Gxܔ]ZRmZΠ;D<̧GQC颅 v7h[rC aj/[d{"6EF@=vqr(En[\+]JAwvi,0qXYeŒz?᫏Pnm%\ 0"9/!)UΕNL0#;kYlOWb*>*sfz\t>=RKJٸ^e&?~;j:ǑÇld۶n}d-$ʋO!օbÉ261YuX`0F0#v0p}e,4xH3GC"& qqqSgn~~ZVR@a+Ȅ%5k<ob&|e4a~cm>[BPe2I(C؋`a#+ON^zf=q/5f6?l,pW*61ݴ atm>f>"s;.٫w-ZZpB}A|9Y!̀te0j-L#>! )q١WHK5p͖pik܃@\\&-\xҀ6oР&|@(Z{ɹr֖&Tݨz #uPt;t쬡#OU!N~e6vý,BW'z"?Z;͚#zK~׋uLj\k_Bu6<wTޑf-] k! un߱%<>}w/}IOrHpB0_npO[1z? h_)bڿ?n?]@.n%#cT~=x\+oTSyqP\ʥ9?r Kջy+!um[5iƍڿ0kH4:r$Zңܬm0h~R7G?-_-Xչ<԰qjN%ťt90^} rswゃCտQ 2d捛k|8g'd+n @ fO T 3~ \QV ϲz~?XVvk߲Jb),ͨsOQ1JQIqdT f+"&B.#c)++fL-gTMOK`Sm~9u-‚.604cG3ɿkǎ&?~?4$ķȤy[/@'jޛt\JK.Š:!--X=-a+3Qqe6l9#PTsl WknS gjnlO۶^Tp|H6~y'{o~z {`ƷucGUjfJd5Q)3[٧ *(xnB>aj34mT=)yP r~=ڊ$ 7.-x/bekXK29X CE'?2ܲ̕&{߆n{Lsqu 177ʶʷ4ؿ?)!L;ET[XZq+D_f{_Bq X3v恃L|||`wÃmeeEWz ]M;jPG?JLW*%_|!z{pYL ?>kwW?&K'd<;}1"P2` 0+yӸ UZ>lue 7`KΧ:Nb*f* W/poJrRgY(V|cmmFn6j+GiY`k&*YPvN!egPbB6EESRr6dʷ`kgGKkӷM&=0,0zWVJpvӐ$&&8ֶ_۶k?i槇Yo̷xIWNn) lbl u6 p !fsus|I6toto͚5*MhC@yw{Ot'f+}M76}XeO` U:Kن lMABUVԵ[wp``A;we/zYK733he/]P`' tWVȿ9y85-'9筙tncR0zߚ.GR=OWzEtPZ`ЮCg˟V޵}O2??LJ74-ZrEi34lgK.-,,tS/ Y:i&L/;ܭ^*E]mm%-2(6fҶ<5poZrwQIf`m h(ϗ8:ⱁ]-(\jE! ذĹEʌ &MEajrXGM .(1`if+_ ,e_iiiVڜ[0lVӆU)6"QvV6޳5lL}F ҌӰaÈ@\(>x}ڹx9}͜,u֕9e hf`{4]*Pb*6;8)2kԺE2`x oojkmER˔[t0d)2#,S矘lҿBhDϢ b#'6u 8v_^g*)ytG})%WTQTqֲώa)fB:9;?0[ OaQfJQnz#-U_99SNhQ!ܞ|JSmD2Їs>‚Bsşqb ôi'Sƍ@sѺu(2"w?‹dogWm>Q ^E!'{zEӦMke@z,y_ [C;huo^``cM mllScFH`%3Z\89`S &2L+ȳ%muX|yт93eΒ[q?=Wc#W"UqrYQ>c4,]ɻ(@_KߧfRߢUPs3s|y &2Dq|C[g\ +WM+_43'k KŘ+Ȅ9ߥ>Ν>KUO`ܵm͝1Lz(+5~dDu L(Ϝ?<է7kK9LqhD1dΚ_;?!#Vհi%c"UV9PBSaJkhJ⋹ STZ"~c35mX6^{͒B˴:ZCs+ gqn Y8?f6WB2#P$ ]wjqLA@?eC4}H\a+B\ n vޡ8zȕZO|ysx %! W\*o/ǧʒj>;w#XKJA:k9gp[}j֬)=3W?PccbdbRKڶmr%9::^u˙gh"Ӊ!=4c ri_ƽe|)%ʚCFgA՞uYeBrtrW_{ #~yl:W5FSf7_50ۦ[q{ܾ.Wɫ#No^ b+!M\DMU6b П3{{t:M~`2ysWVhV|k~'4._ AkƏOӧOo]@ɉҏDat`~[}Don$TTFiA(a jps{!IdʹJbK 5VA]uh%WuR Xoii!Z&`VÞ8uE%TȻMNͱyg9 `33G93gqwU%둛Ӽ |FP\㙈YZlIUċ,!zf<_=Ļf'_&c/<:󾳶~F_ZaS-घuY9t>#ӷ/3aE^Zj aJH5Zb%|9̸S(HF>"""hΜ92Z/~1ݢAN?Ξ=șF# #E0q߿?hт&3޷o^[@ل2'ps&.S5Vٍ7a&MM0oHZysNb_0/ʎ SC@5dNGi2**(Pb yZu]ϤdO]Q# DZ'ģ9QcUsη;WsrXoNN-:57yQ8?*pg j ;3ӏ/7n" f&`τU W6ӺhPǎXO),COMI ]QJN/fiرԭ[%2N[=֛oBCJt׸Bv@T6,H<=*Rx#ŷ+7hny9}h#'ݹKzwi]t3.Bv*8WY278IL8څ8AGPx/hO-6N~Ϸ eϿm< {;. Ashmj*,6oO6vdEf/6M 5PC)2zJ-q|-?@nIl0ss rPA|XœΡ Þz`na=iH*[t.n"b?:L.T7W&N# Zt&KkZ.deXbB(n*-*R/6֊NM؈OӦŸg6mڴN_XckZ^FxG?_e%U/~FcǍ!Æ^`iBHՈ_hԟCC%k5i ƿ;j@j+ٽjZM*;~LCwwP-nQ,Emj%UR,\ȣrvYPdgQnf *>%ղ"c %VBmĉ4)RYڍ(p2~JNNv}o+ܐ,mN2ؚN:+=>eږޞ+ V8073inƺQЮF}HL#Dl#3./glXCv\8I( Z;Ԕ70BN;ſtrrSggҥ}Uӷ}&=p Dx2-[=26kj`lZ3b&)::O@w@2v&qM>qō߿>[qu':9vNWr{lsV.7Ĕ웴&]c5@ K Jgկ2*,Kr$? Lؽ{ҫA|NrK׀<ڐFrYCP/0b::P} I)4qmSSE((g76(}`p͞idjBLo -JLDf/zyQkk2.)z+!9N=f:8 M(33j˪mScJ@.YT wįŒ)C .w0NhLÑ{R)^{ӏϘYnфG,=mvEmڴِm|iЃ˜CKԪU3 zɓ7Q¸m! KU*۔f,->*'z)31 P;[g1nJjY$!k(2#0$ss*ϋe'cnlДpW]?o\ny2/#+7o2@et$C^ Ч8!Ⴧ>_~{e/b_OX>׶]3_xȑ {u֭[]>}|Y`g~JqƆ)׮G>L;m)S:+L3峞Z뭷\8xwzzQiq|tPU=T3 G٬W|EicΎpp LAOOф h@eAXX83Cc%v+L8*kNnf; bcKo@NMryńgŒW7V~lF?uVeܰ8{݋-ZgnG%ėr57k%׏|?v\] zϜ>M|hIC {շo~Թ*7wPMUqnVz3c2zGʺs=D֭J@;eRc_71~ɟ mʃi̧N6rĚgggtzݷ abD1fdF&NϪ:F iј$5P*?& 0sz.mrKs71s5)=ݧi④G]GQ˖-} sˎe)eDGG;o%^}50܃Xs>MkV}N@q{zi7 >b߮sfn3j5j;k;TԟU,]<|_#*XE*` d5B,u W)ʾ| ߏa\\] ۂ!م$$aCeL--z~ӞCR>Cȧk`T765'SnT &0rآY6Ħ@NB hݬm0߮?ERh&}m>(vx4.0vy]O[vI?? I5 p;647hbzhQ+w`K+V|nRn@%.JOBj͖ƦW6Cj&b9ָu{ ^!11pG)iE,7_O= mݲ H-Zi}vhڭ/9zaZjjy[ړO xY6T*LQẔ 35ffrZ:{PfJ3$0ST.]ܵV|sP){rހP`DmX{… evtލ-,BXeW|||}uzYԳgO4xV~j~۶mO1pS\J=moʂ:,]y-&8(_60妉\CACJ~I&%vYYSРqiҟ;7mLWگ08 { ذZ_Ț35sv#sl򜕣(- nz,{(`$CyBk4F aa-\e˕=ظ7 }ee=JEZxWc2wRb&(?Hf<4ō2I #paC&?)F%ڨиzwܿ/ja8ȏ%G5GY!K,WĄeijn*JO)}lmUű4<B;gFԬG?",-&2DME{WϞdmkKM7qwMz"g:_$ ػ"'KF<@LJ32N]fb[oI?P 7n܏}K _~{/Sɍ 1-hb̄h÷;:RI~.VCgN֭[K#&6l29?vܸn' }0::  Dyѹ"!$P887߾a _HhrZW"[S@E-dտBqv J~gnOo<߷D^oܞ*0?~֪+)>1|'+J˜=SETflFtR4PT|-ꓩnXMgDh@63 _<{zy>}ǎ*O /l.^e]CIsUK1m;+) ef9|#\Vx.&`'\LmР0HLڭefdΏdP+s'_WBs&~,V o8y_xٵsݥK>|>MCc$U<)TPiWtl%c]Ddd$zE&h(h^}4z/;wRFr7 o>LJNgC\-$dKss@0毟@cqd7tbĊ4bizp"3V]pȶeQvEկ}% 9x(=ϟgsA$/{YXʺH cYw#39j@j`jDVU,4l*" XExxj:ȡé{/`PXwWc)DrMaU {?C[YRFƛd5zZݭ**W{u"Vܯ 8?n}&Pn# Wy`-eLK'ٮ fPM2%fd׬=bP_+`iiH/ β2lSPߞ=eX*=̭m,*-'ΒX]z\;g0P_AyΫ$1J@]zH@|@Z0Y] ۗ,^l 0)ɳ@vǦOt]XXXI+Sswޥg>K?2]V楥b WղVZ%=cpuU%3%Ns+6 鏴\,kÒ3 e+1"uu/YZ fKNDyU0#ȑ>}$'=p[zP&֛C6{b/D÷]ɹ;u}=ocw2tJ@rmӍ!7ئ K+yEMRRR/;)TIޗP˯V>m9p4x7 Hxl5֕PK8ukԜ%srC֟tZ,*6Av픙OV\O>zrY2glrsnсlX 3 ɩY;az@礧T{Pfu30w*޾B Xmz UҌ\+gD\J ϙ`k 406鿃I{UyГ?E" 1s)tA9N) hwP >O:`k@\}u$V*yVqւoR_{YbJ3dt*:7j̘,"iwN2ʰe"ߊ_F%yTN?]z7 ?glƄo ߆lsm]wU=ׂOj mݲMNc0hN2sniXWLU&rbK'sbP)AU.z5&yz;SH:+k;t(ylƌ%AZwqq)랻?ҵAtc2 鯊Y@MO㊢%ڏ6 7'WZyL9 g^f&[6}lf&+Rs1kQ.fHH edVll oJv.hSБOzX]=GAr fCF5ph+ډk4` rz=WO]/+p`EY 6|ќ:Ƽ:@888jmyLgɻNѡYs֐_A=΂ Ԩ:?5ϖ۶ I'Q&\Lj@ÅA` e !{vtHc,dyդO&-;\IgQAR G ï4\Zw&Ɖ6`YJ^-srB(?N@>}5o޼Fˋ:[ou)+#А#]LnUi1ءQ!A(1Je*^ig1WdnlF)gf老9߲V^%H$M@᧏PnF*Ky7C Ԕ';f;8Ro?RFB,4lǵ> s8ʳYLb?/-H&71Q/ ˱c c].*Sl#SO_ӧ{&3gNj%e˖ګEAWFcE_-\WycZ3B@vL<TV[;0by*.cK Yq ;u LuI~(E%,H4nL\Evhrh7jSy\XCHˊ S&"nt2QņP~blYƌfn$*0&,lD[ QMp*2& HqJuy]gbN<3j5}yb + VU:Yˁ%+GC(vɆ+j5`afܾ6spD~T`Ŭ^DRw_thp;7O ;uD 3tyiO綬akRanBu(HV tJZ{7cϕvr~\\Wf=ZṂSQ~LFhڇI`Й\@?A%r#+ܸq1ƾ/>W_U05"sΞA`RrUҽ)W2OdjK=gɃ\խ^ ZE7/0eCMJq]T|AIaArfF| qE 儌EfVLfvVT@8/:Ha: c|VO{hsфɏ2Xvb?cH[<-V"Z {$ uS<3xs [BX0c˗-_ƕHv[n䮶^K8>~2,&%:% *%Ժ4TH (~l~`azL ҫHO3 3E}g׼#'By( O, ۵o/>l0YVGRb"[{.5dl Úi冪F@'qh#G*ԓk 5n1n ŹZ_zv2]`YJS~w)W8NZLz*oQ$vl8L JtFF W]$ hB J6Ĩn&h8ۯ)32kHWyAxED&@4WӶ x*32Ɉ dS{1\ݎ/WPW>vqIє  q2SƘ0(lT{@vzѵ+K @*.Y[&LOϞMݺw#kkk yNW?~N<%}nnrJF<:2N:8ٷ6!ǜ0e gn1ckܸq5jw7lL<)C9΋+WШTBnt LnP *DQ%4S GOBL`dkkKֶ6dog/89;tǖ,-J [6F,1ǿ('"5zٽ0YsBXԥk7BCi 67w&`U[_ L*` ( b'FPsCffw3K45/SRS*(2Ϝt@7lx8{-s>{}׻cֵ+_OmPAZ _+",BNYfdU!u/tbC'~]>}u332ܖLh 9-a$]h5i'Vm)_҈Coan%QFe[ClΚ۽999#+-0U Dx=JEE,Fhj͛T4v/k#r3;wׇncz套\F ιpn`|p0`[5ʽt8/r >-s<'T[_1mPgSa&M>sC{dذk UC&\u^VTPX%EcM cP!;N>iiμ4t0:[3,D3 pyH$&&E+ = ]𠨨}@(B9#қr"||>͝7w&͟?w^1UlfKX 0;[bL!f3O_,UQ~x5K'ILLbk9P`X0.4CX44h#T^C >۫RIl.:׊b,Щp{)666;Cz?ذq={ 3FG GCD 9H⌱q tȔVއ+7=ſ'"Q 'B~>>.WH4h1.oiQiҔ)4n5ĝHmTCQW+-e\T 3gr-FCPO~%oq__ȬJac-]HP'͹JKLQ!.,)̧ҬT+ФɓًM ^Xs^`J* #c0 lkkG#Wr>:0wã?,0~5C~+yq..,'N#IA2凙L݋'Oxڌ[!h[ϯ7 wU#hCn6݁ERb(Ax`!wnׇ2ey KK¼L=_󣀆R/Aͭ+G|R jF\_[U0G~Ѹ<5 AS{]ƍٳ4}D,Z8n츱#||}23$xj~ ɟR9UxCnVB`gGŦqa 3F8"e_y YF]cx|Ryc}8b~ pc|us'gL-2|{!Lo|=+|>dZ~=3{J,DiK1X1$(bH埭{}fߧUptR~cJvSy_5q/[Ќ^"CܡT?+S i׎kwܙ=9g`,ۧo_PX_W@2i Hp-kU=SGY,=#ܔ!ϖ?F`+eS ,D$ݠ !-D,Z|.~  *8X R_A/:BEDCgDJ-~,7yz5Ѐa!nn&[QaTKBx/WS?T?GAܲ.4~ZM.T !&Hv}iT^ {ixIz\A=.%FU8bV-=P"^\|p=*Ra _b\*B/!%978\B?Ёi߾'~>!^sc`hC1ERFj@ (8(k^(E>榾tǎw6bC֭9~ӕE:R]+4m sք 1쒥/6=|EfTNqQ|,KnlGE]v}F.\lS &(@,\ذ0`3ڹ"v@`@Yͳ bXpy5zzyO~¨a͚_ro\.n< .RqF2͚3־B,cEN/ZBYӇ[ݽd,?c+?ePŸ;w/q/ls)`:W/oNIڋkENCԹ㍹[3iUPGx;u1*jb^"q>Ӆ.z{)3]BHi?:,&:8d :uY oX+_^B",7Սٴ̌Ln [ZӴiS)00ɺ5ݺ%-mmG2c*ZF:xpM&qxU6MI$,ؤ[h]{Kκ"9fkdoݽTC>x1^F!Ν:4d᪞^=9::y\h0nc|~8'"4yq/XѸB#5LQՑ1d_}whۚyn&عR{Vsݵg7C~t@T驩j oPıj7YҀBeDSWQc U=BaAA7,DJ/QL-*`t bfY{{. ?ե,0)F7o|k#Gދvz7binIv\ P*r$ݹM}>X@bCҗ_~ɵ A9Hs&9{99;_WKJreLLLvjBBerr2t絲䜅ݺuL/wp8&E㯊IqNX~c,PWtB4+ ѰO_ash…&?`|6|0'D(ŋ>6}^WC8᧰gϞc"f=еe˖]EլԬ(ĘkI^Cw+_׌e)($΂OP,X2OFׂٱsj{y7'L°|MT#0eGD,;erj58 J [Zwb 1dV!9}*G >|6o...< ӗ7ma ;lܸ[laDL5 2d1=6SĶR8*U/+R})NAWhni䢔>PebCE|{H`[ǎ= S`=pСCL9>1qB:_V#CZ\;O˿QHʏ=ǽ\^0߆']Wlpz1|+TaLT ^^^#|Ŋk>;uhʢjAYvA">aJGEE^#oe˻-4 bkDc0-B #}W zcf>KB u3^ !~)u w.?"J\PC4*+qr꘰oV]3vo K'zMel K": "< z*҂z%[7{y54=bE>&%5‚B!9 &ص{7yfq z57HHN˖._ 64JHŽdɳ޲aO7jhF׆f̞e՚5>u͟o慵CC(|h(wű4;ʔSN/G_NNs߉6 _BkA9}M 7>q Xo)~W oBq4iiCN:_$4)O2s= 9k5-T)%K2[4j?(,R #ӤzK.J JL4}s95čy;rUcǎÄt4iRc,~~( ?w0SmK 8 {~ЦM[6N+3ƥIlA" OǏ566-_|fϜ9s\ KbHE:(GH7H_tiFHVXa;[D:2~$*t7EzEwEZZzµS6NtLqL2ҕ3Zak=ja.`#=.ңC2WXa aHwZ1p "=93JB5Bb޽v8G#R]뭰·HGڬ5m;FF]p2 Wo g"ݒIޕ 4>bƬ5Z|V^'| T7tR~!z?r/Vpάm$-x\Hz 0]0OXOJV|ftEOc QHQqzݍϸ1ەѾ]H)Oy{YvwfH!f|L_P>3$ [U)wxHsq<-$2YseG/ Ɍj:b6aq(&xk;a@cXk.9Xo|GetNHjYHSB0 ٫5!Cz̵4xοRi,O!i磃g%Ch!6҉_o1!m%k9( Iڬ6Pwzn{'@ <~AB@\Jkz,OHyE7r_?2p/ N`7d^/-Wv Pn1襍<0ZC<011Mvƴ{2$<7\_T9!g{L_Iz.x,A c`kf=q}3utH[4'[ߺdBcR_Y B.؟T1sZ?-,wkHf:ڱ 15-qWACkW1XޗawIC/[4!abe`#Ksr>s:0Gi9 yÎLmVtf,"WXr4xyO;&Cߦ~qŸc&b-"`It](V;LtSpkW d6w|ow^Y4:ɎvM|-K23f/OI=i(-MOŹLJ7 ?|i4#%X̘f\as##%Rey9|'Lm­SP/ÂFXTG@Ô,C #zŇ)&'TuVha Lm_2'|W9F 6a=ik!Z޺b`}֐3%~2gO8>7L\*OiKx#q3Bm^|b fŔQgϹb¹΁=g,g͘c,A3N8wٲFAM(S-Hf &%lhC.Ʋ.\k4acz /LJ.9~1c[eS,C>e;c_n3M{cX 8j3QfYF#KԤAjMr&IMRz?5ߢȟ6oeUIsQ3t6rhǢ,u>8C}&cE_PXTE mX]Z:e}ipbcߘVLٝZ;B}hqc%:aٍMS޸&x%)0EXT9S ה*|ӕfl<Ǯ1l4` Yb%}˵C.:B8&4RGb Y9 Lm]scF4UkosQԬYבbؿ=itmYCj&Ck mpJ}x4Y|aD:3ů,I0kHؔŽquhtSTя &mr郌=fݳ}[E[sjSA?0e4h;->A"dž"M3D w 4Qsݹ@j0̓J󘡁uM7a7,b9tB!D!W1&z̥*%5†D7GLMERfn ր8$X,F9i?|;haVĆ"ضNK!l iO5 47 mֺ0 f&X5Q.(PVNPazjcDm8E)&mM޹ߒcԢW5ˎ%OZWc__yO\."| %\~ P]PMlloՎDQ \=2l% hUϡ-ao̤wq@[>lpy$+oC3l!j},L[A3Z~Y!`:tfr?Q80P .@Z+ m|7Ga`i4cgXN7i`fJ|$ڴ0橔G %fLiL0_]"MfI( L!i cJA濨hmS2̱0*h\"XT kMELf+\ܕ]G}0\IIx*XGn$eD=aLza~X$ }O>0ė4YIi!I& 7c ,V+ZPsO"44%=mmᣩY+6eHf.$z_;ܟ^CLEDHS}Ƅ&3+0m]P*%L [m??Y E~j到\6Av= =.2E ќgB-M&A+02o 뉡vT tU#~@[\``j>nf?3='&XH(k{31O!kAlZ% (FWf؞/BLPs浸w˼Z- .>Rk*kK2tBGZH0 4>cNݐ/H\f=ƛ̂WLrDcNKΤ7SYnٟ S5 Ta}9 恵&ȂZ2;AH51(/Z3=(p0Z_]?Bk1*J 7Sv.$k漰\|W}q{!TpkRG`q%:W0KjJ@4+"mSb2yV^ѷhG1_Wa"mقuȄмYa9(9_~!IOyckHoo}:]]# QQ9Q5A-U2헒J|h:]OYa&f1 `I4P0!Rn"#i)u@LKv+l rstʏxo RNreۧ.m3l,Hu#_,7t1 l.7U~:N]r}&3E¿DpwbZv X59 \ؤ/U!pxIwb[)VXa|\'O>IENDB`nut-2.8.3/docs/images/ci/GitHub-Mark-ea2971cee799.png0000644000200500020050000001612114777534445016470 00000000000000PNG  IHDR00/]PLTE~~~}}}|||{{{zzzyyyxxxwwwvvwuuvttutttsssrrrqqqpppooonnnmmmllmkkljjkiijiiihhhgggfffeeedddcccbbcaab``a__`^^_]]^]]]\\\[[[ZZZYYYXXYWWXVVWUUVTTUSSTRRSRRRQQQPPPOOONNNMMNLLMKKLJJKIIJHHIGGHGGGFFFEEEDDDCCDBBCAAB@@A??@>>?==><<=<<<;;;:::99:889778667556445334223112111000//0../--.,,-++,**+))*(()''(&&'&&&%%&$$%##$""#!!" ! IDATx ϙE%:%ɭ,Q)*\KVU*(B^qmTnB+e2&F5f9Fsys~|o(RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ) TmtEA#ǛKVoڹPhxiFӷCIP~V~nΚ zSjP{S>Řeڨ%Cy^(CN;]E(oMh+ oej3- 霍c+RUo~-;_@N!/\"q(75ttS(Ý2pePJzv> ZrS*jΤLhei5}@㔡[i}օ2Ct6P~AniDxJgtmI6u^*+e ;Z#+C9)ځB9;qz·=WMzG-UcP )72&meћԇwK=+$(QiKi[AIG /%ZvP/'U,C JGubvY&}PIz,H?^*?Omm.[@E'at~6,T,ϭwP#T @E oTǽ]TQo=R@Z@ԅ~!+I\C+P%#H['@+U1BkTZs*[BUքJԯ$2φӾ:ݍ~Vc#U)A-U:.mU_N g|Kf_QE,!|TQ.|TQR>*JREJR2T1 _h%TߩEcm3l@J *K ?E?l*|m!uw'j~O%hsBGT"2OD%dI71&GĄ*mtlxl*Q'n %k9-[}K*J!-X﹖VIUF˟'uϩV E)z}AcuJQV DKt׬5+ifD<߻ ѴfG9xEZ*T ٦kkhѳ?Т?!jWl`T7}Mx|m{<? AZS0V5At{M?# 'WKo;,ܳhbxBBZTXy%a?vmTQKα Y#&Ѫ+ĨO^Ԧ ,JiE{#6#h2pl6buʫk^ rNz/oXuezIhĮwYwH~ +գeNfݞ[U|z/ e\,Z \r.QC ,N ݞiі2>++QpI2>цBÅNϧ'p)e&| שpRށOp{)f)|6IJ1(&KWK9C.)'M9p)&anwJ VE*aJjDQORXGE_CQRPw(b ?V%. K;(qrJ[ 2paJ V-p)'U~E5:R2{(zUn/%̈́VQ )iKIcUr(4Tpl"%ukM(1h*%0W>ׇ@4 >WՂy.Y3-uGa4|rނyVSN&l9@9@4gPP0M; j^0`9==~Qn3mL;d^&\iaڡ;U-D[tBUaiʮ->F_M=FdhGhf0Z&m2֗6Ʉ^]+M^ٮ]Y-.al% 풝 ͢mImft=i`xPlڧLW. ܐG䔃fN-wi0ke!V|I{i:Kh$˴׾vfimhࣉYA`.\Bm{0;.wcm7P?L- ;/\.8r"\*aa:` ܢt::"%Θ=:dƳtH+*iS g1&׆kM-SEV9^mWhFY7m|6O.a\zMw0"W%^4d-cy0XS{pŽGw2&s;&HT:A1m`lM<ävOW}g^9h=4ŕpՌľ+P锓qЬ ra'.(ԁ)@I*mԧ.Yz&JR#  ipNRPJS i:µ6G o7Ց+|%87RV$A,zJFnnYedT&Y 7k(|z:72ipMgX )]ic.ܭA!U ;ͤ) υMf46WGnucahpƺ(N`5ʮ |N3րbT$8M icQ'aܯFe7Zs:촎&QЍϤ%Sa[inJNC]V\[[ohT'8/Ђ/aw3:O8aم+*aT-QlƬ.춉q<Fg})}=8bZ1Kj0*9gX`lSNmx] +acc< $aTBX ep=5 E(^FoЊs1gT& 'Iw3*DI  8QF#%;Flg?8'cIu~FcNk#zpF 𬞌Ƒ8@U,k1g2.zæ3Q a W8NJ 2*lb2PK:WӾOk(\HksNjqh0OֳQk:. Ro/#6n1[rE!#.1)h ;0y0NΈn7IL%/e4 ̤3&×*cf*§jf2bwx̚atF1r[Zl~.9ȅUvG3 ;`iNg`7hPdT>!fz 7^&K[@׫Q . T ȍ<|qJS_mtu#PNd1#erZE18#~+xhȃC-[!j' *a)!kY iPVun8dOjP&H'q5r5O"c@ 1ZMc 6& o%PfrF Ӆx)PtFg"4?2(SU,_%Nᯄ>jIvϾ|L(h퇃3K5c`Ύ%c΃RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)RJ)ns3:JIENDB`nut-2.8.3/docs/images/ci/DO_Powered_by_Badge_blue_140pxW.png0000644000200500020050000000653214777534445020424 00000000000000PNG  IHDRO$tgAMA a cHRMz&u0`:pQ<PLTE-etRNSPѯz< *{FGt[:5;\JHY.T)c^+aN|8C2D!M`9kw?Ixo fA0Z4s i]r'QL $e6/u=7 U%_ShKE͒"p Ob1dWyqj@V(->فRmń~޺л,&}#v3MU_bKGDj6tIME , a8IDATHǭyXS@\#`RP/(4 TQ@(D,e)օVyP$UP* -.E*+vn}jQ[ܬΗffrfwYBQ yÆidl2653# ZR~%ѶRQz 4v Iי2zx}!F0쐆;D֎( Ed8iK3]Lf γXWe63Ǎvqw~O,qxy#̎h;] !@O1OCa GD.Xtrbsۈ+W-q1^vholX+aXK5^*F|I& %J ؚmuFhwL`eFYKoFjF;2wf:Zi$dM ex uk^~$ɛ*H`-4I{hKc}>٣ݧYۙO20*SKg>麃*6Ib,ĸhG.+<ĠʈAQUY*wSaZITM1r#1, j䈩-qmɑ9;xkgbq,joƻ`FLw4D7qW!؛IX&[˵s:Rh^ S>ȫ)o9AЪ2x6Vx]fAa~V>y씄3@.M$_Eȗ1g}EFO'Kt9A$ଓVUzZҨ}68E ܴ _ߐ&i3pW.^hK,}ʷړcm:䣙 +EDQj2;@P)mC{.]?n2\7Yuf /Ye%]aE  PU .I҂;ớU,5,*FI^FҘD̏PS!}s>L ,;1CHvCʢF{h`oz%0'Y5Ƈ΂?m~!1A'xqjٲtoo,uxE-BGJnp U̇aP/_=$pPifup0E[{씇~ CobndFU?"&Z@^\N C1P%|+{` ^6j3imOY &0KZjKgQV1Ϩ29_({G[{ݬ*0-5D'=:F Oj`. ~gl Of@E{a`3dlF σIL+04SedApZ`*qrT0T (Q@ ƮÞ34>]_g~U"-B3 >n~b b 2̄p)r aZ:0,·{0EsJx . )M2 'E9aXsE9$%' gqv}P_uj/׌?2%L^!1C[vhemlI~WQ”[G $40–GgZ1@  =/#cU0(oeA[Pߞz&hlގA0Dx=D2v^P8ir#\Z- 0ܷ塞y&`Sz;B? ^gѻp{<Č{׉/uͱtw?ȳ6%7m=ֶߪKЭ9'E Ǟ{ SAS(°펜q?؛(~u4F+c&C[QP[JdaN0'n%qKMǹe<:Q|ɞ/>YWNեC!u=~IL[d p?g~2h@{u)2\V햼6"+?wG?kqHf0k L|/Sw zh__/~LL W};ćGE7=Q= %tEXtdate:create2023-11-20T16:36:05+00:00s!%tEXtdate:modify2023-11-20T16:36:05+00:00._tEXtSoftwareAdobe ImageReadyqe<IENDB`nut-2.8.3/docs/images/ci/fosshost_org_Host_Light_309px.png0000644000200500020050000023015414777767434020402 00000000000000PNG  IHDR5n6sRGBgAMA a pHYsodIDATx^$U0CPr9g$HA  Uի "Ad%g 99Tוϻ^U]]>Tjɓ'Zc쑟OgD~:#ΈtF3#Oν[7h}z|7u7L;v&LOo#_JsDعn& 0Ĥ"O# 3o&§Eyh:Y1lF4I?jD^1,|0gZ?y>hΕ5uDQ$yu-pl|eGyr>-ȳE"gD0Z&i_~~1s*9LrJ\/ Z_G 0ģC_6Dμ_9h B t0,t<&[Y6۶rt'Mo1c-้|A Uqo{W8q[_`T/zG~oIV3<1DC;ԑ'u ю+MShi"`ыL:ս˟s9ʣw=3' #j#O!="_ʇ_q4GA!UaFF@ӘЮ&L8U?^bbr=wls_q4G):mdD 5¢n5"Oݡu؀:#&QGECQW]E!W§M$Ϡyʔ)[7-1ՍyPG@]|3oMSh0HD$y':ugZ#"FP$XǤu4:"O!=!1Ο>"GPw]Y}o'O<#"FnkUR/cs4h#"Mj,kD1!F.gt o7xý~}7O*d;uTky\&!fU ~| BǏomDPG@]G!PgƎh9 ]_ab-D~FGuD|SO=n}s34?QiHs/{'W\8֯6l3(i>e}_yc{;CZSO=7|O6QGtW_}='p{Z:w 'UVYZ]1^:Ĩ% dgu&Mrv[뗷*!(w[^1-ʌ1EsϹ|ͭ_?hߘFGuTWEFA?㮻w&M{5爈nƈJA@ry{=C_?̋f~v>h.ed AŇ 2Guu  ~^uˢ1v%=޽A% a7yR:6IX>qZ{ESATi$rxODǠ#,lS>n`Cu{キ>gy|hBw5[Schm2ψ~>;g>^{y+[[6 ah( 衴ƬB-EY6g? ٲʸȋSwG&0y4p~~y 7&2<U5+μ 'Q_ &CD~O;W2z 믿:F;ĆqQdLGK@CqE) (su[K4\CP1Qg?&aȧ֛?M@4a&yVWX:&6XhQGE:^ ڲ?v@6ͦ@VW=tu?Yj:@q`\8aBŠ5OktOsSO='r)>_Ǹsa Twc ޑ#E+)/Btdee,Ik 3<;=eBvFN>-?\ȗR$~8>/m6F>yx)(.Oy~;Ku,?%\nF_'w K/Җ[ng&NO Ȇz׿ o1wW_ݽ=1|Y}JvKLC^hWyG֢1 !SN>)[L2vw?;ru .`![J 3y≯sBlg}vB _mnLE}i<$'6Cv5L3y۫|!Ψs: ~p }Nvȷ=cuSHƷ4fǯьVXafAo6C ,s |d{I'yxivԠNL-:QFFKD P?{Yd$ک %@G?YdU20A?O|>DNDb-ܗe;B蛤=쳽k 2-1 beN;~B2'ښɑ>>.bgo'{Y6 !ް=4xLo h~{.x4U/ٳ #d FNq0 xW| & ,IHUGE'K~a$h 9̠!v \vqG_'&NX :hĻYrq- 6}cjG ۪0BO>vhȨ{2˓룏>sͯ~+gEqW&YL3nueːT琏|0m>`rhk.0_j| ] .uY>n(G|>F;fcPXx}@. 6w}*% /+Yb.+w*]@ `ӱw $n]|>;8D0#Aa$YE]{~]3$UXhOkv!q3h`0{VBw5&ԡO% 1> f$0_^~p,Ei/aKtʙX;H@\Iןt 8 ;æj /va,UC@Ouy %K|\}+_,"@?ַOeLb퓟Ekgc<;K>`L&3KÓNYyo:[Lj[߃>؏4<}SyH|3Vwr\xGG@uDŐ' A28XJfCe3kKU?3Gs֫`88 KM`PH 0ќ33<'<|bڱ;6`:Wslbw{+&l##mfӟe@YPQ Ʃ8{@ D(Yu~ShՌNV,9.Ņ]\B(\5 d xLȃ8Xgp n9//``Ea AE⥨,DVvNm7-6 PH~6m]cm%mhGkAфbyAV&] +lˎ <+ +|BG0%Xd2iQM{0_>[ "Bn&w,d;! 9`v{dISHQr hbAц40L?|xU4 ş86Ot;@2kc#,Ah8b0FME'%OaKD!g9/@M?`dRMѤ`O<є#g,LW+/6;اZm|.<\j ,_ !NлdM:~?Oō϶0nJ&}# g8 _p7vG 2Ұ1 11m I:0ZT!"7,2a$c+;cw]9c ę-0eB;IwXXgb3/sk}0/s$;  GYp#%[4;Aq<'%x16 ȭri/[@GTf J$"OΛtxUR > xY[U5hQ_=/`!aØ #V1h9 MlyFhI³qEĖ ؕl7 dT4@46^f2 g蔁5f?H2Y3n{dI@ٰaD9 _@C*/ y r<AB_fPryP 1dp% *v9#[߻EV}('„0hT"`/dbW+<,c #x' j:$[o%r,>V55˥/EL@hqHl}7T5cr9(vU3X|cEl^y FW"#glͱ E/rLYo1֡Ҩx"@<՟1g,w5f4Y'=crǵc iJ1ğz69E3FFK#7Ea}(0g9JL:@Gd!$`DHYB8Ar! =o 8m"4!pd hvyIj$njepD2IdKP vlA=d=Km86fU$Ndj.dAmIj%HE`SxI+HvTL$1fA 6dbA=3$% p4=%W18~ڳ_< U ]؆[gN`=)4,sϱ{.ϒoc+fq\%.+V@|y;DZD<3OqlK`=9UOYG?Ԧ^#<ȟ'úNHܫnCVȁ3>፱ρ*c=4WC>Ŏ>CȀ9| 3<؆ `3j:y, O1x-tlYB}SϙdħoAsj/$g`K!&,"C7sȢ#AcIFPT'q*ox5 VG][c q!1& 셿_۞]Y, nmƻTE~`)^ #` FaT>c E(,8 83Ψ|@ 0Ӈ hpJ* 2H20d$T|aY{ Pc 7^F4ځDD6Tl@!gb'I [+!qŠ'v$4c;9LO(zl}Oi5g`č=،nPU)2yB?L,2(a=œ$OS5H^Ҁ&I PtR9M`3$-1K̩6˽'v"|cca\؍ D1ȤSg‰AQ,EA&dn,ςk"~йH|Z] |~ 9~OT^bu/7A؈A`V\ApS/Πr!|:E|^GxM1ߑcHvr1˞ k ƊkN,; 'IҽWl|OߑؾWc ŴHߥ.߷w/+za7n6#*T~H2D$/ .#~7)KF&QV*CU`D`AH@*Vi${-'c%`J^ZUi& %.qeR\c=x g+ *q(4bldQщ _ޚB2F gݰM跞POMfKEdaCG}9 T t\x7O"c05ȈzW ^ci2 mبS<#B+_K}Nd )ziׁhqAj6r>FЫHtn lቁ ZY[tr>%foh7/sM0TO۰=¶᠅zn@p0rv$! {S;O>D'[/v|,h䪚PD~ 8 ¦H1 Y 4s>d\^G(>/߂KE  #9`el \u{ +Gz+h9#KFڇ1osb:D#Wl \~ nB|H'H>@.|N,uTt٥ax6o"c;tWA@UɃl)(8LAY$6I ye휒 z $L<=a'7 J:[2q))96e 8l.4FXS6<{dh1gp[.S$-4@yY5ܦfRH1˾P.7ʣGYgv.Z9ѥfaeTz'P'BsQ?d)?#L~be俢N?67(fX>$X-umK~@Uh_tU{Kn"Gi6 YHuBF{Vؠǁmb`VA U,vhpp- B(73G݂dIɜrFનɖ'% }h`Q&Z^`ýir tv;Ϳ~>& u,H[t'7n,!O.Uk8\oc6/ȉ\a-wYю7xW&.Č?5|=t?яO'860ƜEU6,EyDmCXe_!ˮȨ| L #c/I~a l:4.P|1P"s:7(Rd`lЂOR[ #"h5H-#W"`ۄval20bǰgPWDLap9,O%Ƃ Š.K"gW,xb4+XȊ@Nd?rQJ}o-/YOUyxB6Z/-#1&],yHXჇosr~_nK.P'_Җem9׾//}Kt|7~_=K/,dBU oBA|N7M~58-_e6sD/`巟oqv; $O'Pd;.z6 %`ċ=ˬd?.Ў_a?}#MJQ)}b4ֿ9{ma7l`(4e𰛼qWiRt_Y@:+BqYLEgP_aσ7åڜ\<؎p1!¥zUO3@坲o{ퟆ? uk7xkD^ThO"믿p q2-XdCMreŽWr(nGDwau0_ti4"O7 tiNьen×IQ,(/N6Ϣ/؟ro2sooM:J+uHW[mw;̳?w}$hȢ~!T;r:M:CWDÇ'4ؔW;o^XY /";|+CD=?("Ggp˾lH Sϥ?ec8uG\~,FۗMeR"ft!F{uߋgIB~]1f9ɻ,hut^F󧦠LC/t%JCXx uQX#j .E1Tks8r3U*lj;O4%Є`xO뮻UFm_g{>> Ncp/xِN"nUp }C͈h|H@>(fEAa4/0OQF ?D 2i $L\W%de6SLpc,["†L9DO]g.Ke,3^!c AFꂪ`pL-f&œG!+М'f^SEic tS3(|>)80NFQo[E q(|]I}` ؂r BR0W)0v T@I躟o.%(B<=o5xYdĠ8|\*\N`[{aK$Fx74Qr/NV{ +ȭƑK%y<=DF5$@ e{yWiFSş_ \FviVb%X\e;2rp2o 7Rd!;e@zWy1UI|7\ Dsuו6y)4iNGH6NQ0sk n/# X[@\gB?U@FMr$8EUκiF/.3H4>-&o]rG6Cs?aE aM6a7u _6fɽ,Øl;b?7ڀșjxS9Qgd&{t*OZwẽ2m[%d4S0$O bH]^\"bC8}=~ۉ,ȇaS[˨s~W5=тd+C: ݇㨲ƊQc Τjx'"?0KQ}|Rt<0'RN?L PI4kmBE`M L\r/U Z?f'Yn44[LdhǓ9r!li튾wTvTyRaQ؂ |i-38cO8z'YĠ󅿐/:K/W?tB;ln5PU9>s9ǝwywT yD47LrQg8\myF>,ϥ^C~UKL8IYkCyIqWFN:/q'pk״ךּF6-9,}S^Ri?59 +_V N}pqE|UDn|׈"}r FPz PF Ip8h19)3_A/p-ne*[n)WA6GE@ȇh6%T6$`+W@Iqf:m`xoX2赠VQ aaD=@|Egtvڛ*O!o|&71"^zwL1q S63\\veA_Ώ|axy)a@ oV1ZtUCwRhAs=@t.eՂQYu ȇͩqsD&S}0~wܑ/d5=Jk>l|Q>ߺ5aHP4χ' I(r9E2% +(\\@?o{P@? AC8cK d%1@VZ|¤RBHD2ǖrZzꩾY)Wr 33AAei,#xn~|"٘/h'?>7%|`=;9磊űPqvflɖ )Hb$䙺'd_˟-w >Q!q3WqOQ#=ip ߡN~GtWGs=7w/,~IYѨڱQHnewb(_1I\Z{~G6xa2_s5xא:^.ۍ5aD@|{N`wmdG', d]BYc9&!N fˬ$ IJ 9IvL0x hS#al3$0V %2 .†T w4ƣArbb k̙g^Rd | "ΊZ0!x0;i]4_~bƓȱ)$tl /۸"~+bȽG\Zokgn} `l zMWQ~|"Y yeڄ}0<1qΤg[ЇUA1,C~ߎ:RGP/:&νi6P8av7v3 l!/Sϱ1/ַs/-l_glϱOEk9:nD 2n~*n Ξ2ԸUA[7%O{| `MbrB>LI:묳~ kxy~;(#o1 qPNI~%f q&*4 *(r?٪dS>L .P?~!;[G a\rG~ 'gwō@y4(j .+&ԪaOg$ȏv ~"ǴûgWiX [E7D|c#G`b&;Q'y|% 5u]K ig?OI+ЗU=UBLn-3q|Pp Vdc67?2g#-fW > 9&̄1KX=XЁƊ4je'?I t1ߣc♉ \:#;@11X8>cĖc^{Y{A}^K@Sgq0O˔c(=㸬C8#Ɍ2q'蛚P87E{HU:!&yY9֏`鉠g9GV4gyo؞ANك!9SXxH|AFe@H>]RF3vv.Yi:`B?XxL[zv!/CŮ >EEWAFC2dOv_/l}49ĩ}u]}–{h638d|U|tKx_y{F٢_赮Ҁr'/mXʇ Nhw&[/G9b ʽI,A;7~4ု HYﰭfz=i_@~d3lA|s6eC|! r؉&ڊ4-a{c֕'~d\ B{ib+KhAdXqG?Ql&D>=GȪ7 1 Ҹp &(f!bNLg;A4mrxU-ɅJ P_Gj'rEvNV[msO߰Ty[|pg?p+Z:&^.0t? ?@UW)ވaj6sX,851 cP>d5W5'?` *Q6ȎklG1b4{3LNņWv\ !q_ ʼMA*'6h [uQMYegq/a$ be⊣<ۧMm`IsC23% :aJ 4OM]ĀPqfB+iȇ#6SlOAbpCX3_#g#I{ہPgՓ%b! vȆ4 (+Dp[=OU\k|c)]@u;% KzG3twqB/ݑoKNb΢ng=D?:P K|`4_O,_о%`IBi9e^™R.SiTwF{ W!ֻMg}XKc_Dvx'h4EC@=F& _j{ɱ$#P` dL߫7#AG!oC6z?iz/ |z#SwO~]4W_ےmv8g쭚DE,I'[Uc ~,hװa6c7DBAaۋT*J66092lAH ؀nd /lAsvA4Zpe,",?%,(EOIlljdKɇ !>ˎoa6l 2g-p^5@t8#E$N-:AȤdI>m\il@Oe+z45d0?";Wng:6Llπetco#/3Y~.%h,_eBI[3em*,t 54'k1() ȾteAML:qdyY>q6.Dĝb|[X'Ϫ?aWufA1b %ِϪE ; KtW/vNz_[_A>K؏+ [Tɯ|D/:Ol# m޹2N:ƱOG!8ɈotFku@L/Gnֱd+ؖ] 6'^[,蔥S)^cRcj&b{r$=6y?>Dw u z'# P!gft+ p(8!,űzH2 kƛS8^z 96#Yj];`Sb;!?%“eK?P6ȧg5hC:2co&A5߰32B;a/lH,Y;lIH|^gf_?̶2IC%im? ٰgQ<4'zO&ȸY7xNW:MeqӇM0E<6GK?-MȢ7ɍo1(nmE0Ad{]bH|(zdSBʽȄl^=?\!yِU5W@ȡ @~eȑ2?m4Zr@ s Z[9_| 7w9:g|6[Y b[ &TωwkZxA6rj:߳OM'G`_dU۱? d{xDO$ ;~ * 2B#v?~glO6DVl!;s07I^ɟH\m; |" iSLp??>x k #wv`/lw؉{bbh~ŸY|(? b%ToTme_: {a[| *C6^!rR/d$ {>MZ`vlHV2O>MWI4?a48XIT*(8F :Y[?:Az~RӁ%=d-Qv`FdE|Ȁ|VNv3!Aհ]Xb'dA.HB!¦~H,]|[Te?t%! Ue!!av )4};݁*^&SLBS>ƠN'dCC,>T"t’ϊ[M^t$'GVE<!ςdC&H5F IxH>-࿗t9dd'wl-Eri YTd2K6ObXGK8g;z+1Flp|;~5Z~b N87(\Ɓ:N%a,3NĺX7'R@[ HEzߒK86 G:7m}TcHNug.EWevB>*<NP.%`hG^xmsH[I!ʐOY~Kn{v?lkR]xMPB(%4BsLu-&#Tn?owƍs?[ns1,ٞ W'hMbdȂa7bQfco@g}?n|^y0]򃪲S壮 |E]eGuF~4t"/g'NOGc2ٞchBS1(rta7`lOԺaf︗bkET:&W6ԹMb7PgyfAxMUh-{A%dT0uFM@l#"r )ŨIEi6_|T-I4 |auO~#^QpIS.i%ASMҫEys t9B \aX.3KSh59q7 p߯2LU5EB?-jz`PH aEr$F}Cvv~vUiƤazYкB: V5zy"g':HKXߛFi 4=[Y u-z~{K/} &x4Lnr>8qB -俗A.W*]&mn%;k7x=cGO^x^s/Ofao9 ]r /_FP+ /UKXwZ.GOA'N!xmټ{noEYv ]+B:$+拽Bʫ`$/~3؜{$62ōMj$OW_u%yrLR<{kYܘDo&$'N}yuSZMMbtL+>]H;Yuyq 51 9Kc8#uJM7|ns3dvqamF9A?[oHNcO*9S݁Qhgvwu')؞& .VXa2ˌ$ikB.ͮ[}~Y䷢uYGl꫻W\O`3~M-Wk^V,nG4EANy'nV]uUkId5ҥ!gKdZ\=eO svov#} ̒g!t9]_[ܸ{uc?޽4{cZnM$N~Zb3,~wM7[1Vvgy/VYek%\ҍ;fm G$L2]~!aCّ٭jvk0%DaX?s1r8pI''=!I7p׿E,nv뭷? ) `Rc`we]gY*1>tگ)hǫlIKf?vUg5mrV?u|B;u][[uG9"҅|Kvm7ꫯ v/:)1%RҟDgp…q$^asגfa~^;pwks=w`2n 7t[lcR*ǥ#_WZ[FgV~ p .pZ[N<đW &`%4?=q)G]K7~ 09Waڏ%vc]g[_ydM;/n~jc 89UW]5rS?Ι p/b^)F53[[vzqnyh}pa$BHKt"4}g=7gyHo^MbmucuӪ EX'b7gwaO.ڭ"/P{47[[F30Z@D-FlqQ$i,">zU`u]}Ϳ*U A^д-[n9o->@G8[/}e/~ibP#OȄ8GLY77ws3>@Ԥyy=kLL8M:nٰ};{v6[p%͎;clƲWyN;?lm4Gi?Q. 1KfeVgqFkG? ΄#5y+ʆ,|I&,I(W\qM^KAv}wE β(#g?ˇ ܞɀHESRllY:d7  +t_W}ibnFwAC=w} ʶtH&S1 UhPoԾYꩧO~ O'k_׽Y<;G_(G/tn!-,}Sч6 _%l+w G^&Ov3n-psLE0&c±Ǻ9\ӍOIkc5ɤxW~ſyp/K"iJ<VĆ ,#FBI](jtPWX;,l€($@^K.q_ٔ`hSH'tJ٘q\pAB EY-݉|wyݜsfi&=| ΜZ78)Ľ5 B:֖偧v ,l-@Lg<&v6Z_ne[n"h iNX9HlGM !r!4ҟ {i 7to]#6,ÖUgkSD3\mR&_?OɫK.q[jQlA}U^S݊t++&f#:FlkQj(q<&3M .bf:YBȠp$ @ *eocwH#BPAj]}V8Fze5|[?_FwU6|sw!"V^ бg?'M4e &&L'ʻ)iXـux㩁X&e8Aպi=橧c=uXveƏ?dDE;}P#kgLzP.>l!c鯺-կ |i>ڽޖUڳ~eWr|Zg_s1e>iE]Zʭʯ4?4lS8>I{{3b2 YЫjS-Ir%O;KV4A]&d-e"$HP=>S%dhF (2hPYf3:AG/CA6Ԓx<2lM/n0 rCGxOK %|ˉ 쪂eؕ]Qp ]ФNJ!a1 jO)մ(PE)$f؀K7+')YC%;Xw kfmܗTߨB@G6 U0 US1 d#;yO5nOw1e΃w^t3I9t/'cZ75kXKJv3%pB̑4s={w/ƕ;"ȽlXؔMqY[<(2䝈8 k7]k4`لߐ<,F|AKM`I H:>5cod;찃׏ H=UYB7e?`h6leeKgL\B@3:Avَ4p4؅A-OU #F8M琔XHf 9[Y+LUXc5ܷ-oKx-#QwB@'J/KK,ۍ6ȭZ>QjPs*J*^{m)ExG(g?(3%+Zlnxoaj6d;6Bؘ/vH[n_EloLKVUF2)vԆ:?#7bSNqnLMx+c /\i%RK_ܽH ~E 2LMl7&-rnlF{uf|\zA6a{"AvmŴ~Ky;=|8wX1#hy F>AVYsƇ{Ov%18&٦l<4{`uݛs9|^$ d)tIn_݊I\$ɟ[{* /|;}ks?^M_?e>8j~ms+KӅ|_WAVW]uZ{ɏ jN o,45g:0Q#9Nd6YIM " !T1lR&WsWwhp@(QND|VPD3>Ӹ9'AE:mIyo;hm'Nt{-5pBY>d3lCAU l[<9v:Bl@<<Ȁ}c/$>kxPQb3z lhrD60 Ed*v(aT~ȊqdQn VI2,r)knj+RKŤH [v)FEX34ۣ5<7{1#to캫?װŏU29v?6> kb]TnMӁxvSAʭ,!Ėg?g/ #Wl2񀎩cQ;ufe$V,J7e1@ߊocژOda43 U?!3O9W (!$ 92_AACQ@h`h\q$9^zi½g1ЏA18k$ZM<~ɛR5+Yn,SvQ?Bqy1M# hnuo~&XdXZ;FF>n x%O tMG{թttu/$ ~u)<{8 'N6(k5j+3ɐGec4C:ajT!/K>rd#Hbo̓re`ʢK<=n|ĤsʑPXu[m ccz#9ֽIce܏=fOۅsYgWޚkWE#WM "c<| _ܲ&]KR~,#"ȭj}m@9ZB<}X=;QBA I:=~VЅd+a~4ՅlYG{R,lyhgy~&{ +~.Zߡw*( |Ɠ*g}5L.) >Bt]$]vǦhL2Uvpj#^5Qè8yD@Q >YFlGl8؟1/xmCym թa({B>zcZ{驧ܪfNx3yo7 $5LHKKamdrݴjp_]v{e]ܘD\}w\>B-)crۊo?dg_ys^~h(u8nmckjYHi5ʶʯ֎~c+$[٤H"*,[^{i1ֱFB KHs& >)tUԴdl̮{-aBVWQe /^koИL jY ; TH9N^ ,-ҿoKidCQ6&%{͋s9g6E}g44,uFb 6BݶC{63>@/l{Q,[;Hnf;I4oLznkm'>ExYi:bkb!F bTuNdM061PuN ɫ5lI3z?ocY;^dBߣ+8\ _96 ЮslJ=yAee嫂P^碼C06Sf^O9Np>9.,d$l) Hۆ +ªfَ&z.U.3iZŴ id?H e8oB{. v^p/g6:6d". Bhł(+OH6T$%yqwL;,['XdW`G8e~[M7KRT?4'OGdk[R^>؟jrj\XX7_;.rK%Y>կ&#l6L~ņn8۬d<迲DZ Wr/ `Gl1FY &{Ґiь6`IfG93U\}U81KE(]?cr|UTULų*/?EpG*YJ>Z hl'z}QXZYۅ2 j^`ZmlaրF6 8n^pW6(k0c}X;ئQ56sy5夯*P 6u]1xSY-s>E{m9Fj$D5.Mnag)ʑiV5mvvq֑cD3p49j 1;& Ie {ȹؑE{~Qm" jax'pVĪW$vgYdIUE[%"ų}*965 )4'/1Mc 㩠Pݧl L6SQo1QƼ+lE~K JяCEĀ h4)r/mE//Ju2[Eh+p ]uUk|CrH畋 bRQLVTD_wgb 6pZ{·\?S%K$_yp]^x;:IqeBdoʭ{}RO 1 cHՠU0wAO(D{ޞ`Rɷ"{,%gM YD hm.Sy1yW/ * *3yAz*f$۰@׵ʲ_hˋU@6PܠkōA /WvL44w kAĠg3}/'mkmn{xQRZQULǃx!N!SbFj&[vE"c|Vc+5a(/| mYd3We0g#^4, b8 alH1^"#~3pQHx$9- MjEj|!kvkopQGVef)s\QކAiY Y4bHн6 j󂁃^@6 f¸,UĨ5D<_g>伪!_UߊLqͭ[9n4eIQ.6P/؀vX]Bm3k/'S6lne8xw! RP HOUCq9bV [, ϥZ o#1咞bP%t /y[m*[i v őƃM V{Sy&l:J9mϲ @{iŴlXx4B疰M rˑ)GͦB1BM#unNs3⮃vcXb?d[/[/,ȢgI=u][`d?QGy{ȧ_iK)? 6c,b$ڼJ>Jshs>6&WDvb8bj]}H!Yl̍W 6Y!`YIyI?)UBW1{鬗4FYYR"z}۱i*@ȑܣCش[HߡYSljMNSn3lmm{i-|Q}#n寊:,|iM ߑW,&i>bcuoMܕ/i oY+k^Nk`͡Է[_eKt-~R7 Q13)뮻Z[frjDr#1)٩H5UCa(4/N>do,Ay j T| a0R4puنmլ`Kt>Yk?/*mʼnl`5I -Xj`c݂Xdj&E<7cΜz}+޷ah{חo{6<, 72A ZOBװ6ϐar+9Sy5U9ɯ[*wfy;*0!WS^XNBE⩡*.AMMHJ@`XEUM0ޱnny *SE RC*aӨª,E*wQL!=^BA^æ1Խ6P6( C@jm}IӲ緶̎>)7~BԄ4U bk+3&]~[75EUzQ8Esk?amȑvB6jTe[]/mD!N^ 6C LTB)[[eIg]vpCM셰 *$:ȋN;DyFpw,q7;`UH d?6w{"6;[kjgK? D;u5n[/%3S@+vAȇIHr?0]qHcW$OH Äz? e5a}6bǦOEaBI֜] /IA7y"7OIAHD6aC$[dTQ%qf]^e2eʔ%/hr T;}Df.ڧ?"6[Gl/;q`m #0JK?l3,~,"Dm[ Z[fǣ!x䗢iA/Hůj\?<6}o1~WYvmR$KrKk}T [_rnDD7 㐁$Gh)t̎mvd $%Ɂ\PZAE~},#C*L.%e]oװYFWu/@eOĥCyK9(wFjHg)k~٧_o r3o=[[[[fë^na XU4 d6#j:+[`?aW1}7ؠHrӸSO9 T!rrH~"it|ɮn!$|1 ?n!MN+gy2*﫣٫AND*>ȫJ!ifFw_QD2lmO{gL@PT-<ʋ /ПeTXegvdBgYkZ[e$_Gr{85B]AeA2!rfV]սԹ<*M?CHc_rkY9+c7dEDdAl J6Yr9[PDx!,&ABF rS=Ȑ**:è //He'7v/KΊ} 8cG} Ve5/CZ|[Bկ~p&vHd4B k8NӨ:7_Q_g7vY|"v֗D@h >]n9]VpU b}e-lCwʭ0Hdxs&K.IJ[TTTUL{n"R._j+Q voXxw\i)K~!+?d\oE;ؤ n$GYA) jn!( [/&>hklxyu}|jad?U,,T0TaU~_U/bIC=b1Ȉ @ Y6ɓ[[f/W!e с 9k:X&,Tx䲄_cgyZ(_3;3ujZMEA 6a"f饗nm] ?2qME$ӠɕaV]S8Inam n^b f̃74ʀ7W7jߊ\8%WDD?!IF2E^|VV0A28A仼{+)8fUP@>:T@ӟ>+|GQ k2ojd}hR}j)l t#K!MmٶN~:Mo,45nasj/r[o07g{5V^_*UL4~V99SBl6I$)|ꩧoy%a-PBSȻQمF<Û[LUPi˴+n7O?U[X˖h'C36O{{/ xw'~;cu5i' *~DbM_wGdŸ-͞8s +$ T4rcPlLWTʃW_~?}~_|#G?G1BPka!>c뮻n.귿G?7pNBdH24߮/HAZ!'dc{V2#a4zDΆqzgWe|W WoL0ao&Ng9ntte]- (|yUH04 ci?1HZJ\O?tkloF-(+j@,oRW‹mA]uU ^yw<^](j2dG|F6G:G j3̆WtLaxs^?C "l?I:ZA_ٟxU6޺0+,K}tSM7WCl_V)S[c__=#)%"b41FE0fkP}6 *E\YߎD'Xx lT©q/<3r-6`UD!|}C{VpǀKe>$4{~ת< KU`כo չ@D,ylU vmr^xL}=/ڡiv9*q./+0V\qE?8$no8ja{+Pynwh ~\d?rG^KȺsgAes|H&'K0F^Kt%`L>i7]ġc]~YwZǾ ,["W8L^zŷz0Td0gC}<[nG9 ^aɓA%}ShmW\ں{|:IHlonp~9TS R퀀}LY~_` /}W:f;hbvz`VҥQGDB/<;;yh6?Qtɏ4J._׭#Ö8Sf.#;[ד|Cim }Fո>>K,4gul&>eu_ah0rIIBx3"'K89O` >I 7뭷?e'4tm0 w|gu>,!~YWr0CFgLr)[nwy}RmI93\Zi*&y$`N_rˀWoB&Ȁ.Hryf#>]FMhb΍܊]2>@7n*ɽu4cqָגWɊێBW_h_ڟ]"cE9@L$_tESOuIIU\!eX>r~0Cs I}٥$R!%tY31,ᷬ6|³g5VϬs%yV0CI2ay'¿d`Ngb߸8d@[D9E^MK0t= ` ـA 7[:Ril@eV,xW;[0rWg5JhfjG΀͘䖪roņz&7A䡝ܼ9H;z./18'"oP?V<#gò>S˜3`xG5ίVdZj˃fm(UlbQBg)3y@Vo$ɀ^ife/:ā8%ދ-؈ܽ>{׺!jDU,_q} ؀"z W6`RGS{gd7.̀-n|2̃7X Ku:Qβ5F ',7[ii5;pK\}8}c g"}4GDT0(:].8PR*߼T *œ"d*-"{& 5ʡoG? '~9 l8*X;}1ڟ-`zWπ34O+ Af鵤v«V*S~Ƒ[SH^^-n_a9'p?>ϺN;_}ڔlĆ AUUE$Pd6FвLG j7M* |pXҏ]uԧ!߅uBeA6Pșhe6.sȗC;>b`m]}O H<^@BqsR4@<[GkqUVa<{_Y;1JB]ƚjgNI.yA%G(Ԁ cK"9lmA~5jZf-xzꫯ(/|?a&^* UsE4bHg,Zkp3; ]76lf568q rۃ .gze+?~`}͜WhLK!1jcv|'&E[7Wr G[U N馛^1-"""`V˴HR$-I (o<džqZ f E]n݃AgU*+ZGvLKK%[|;{}qS|W5k4 sk!?˰:/O4ep%s/WhPS;GC2F;@з_N>d#YЫQynu6 pr0$E: <}ȇ7~BNC?ᬱ=l_0b7z}Z[gc[u0&q3ل:76_/M^X_:W~ Ut+ʛHn7 ȭ4:U#wMlbØ{A}^ A =#~܀u\.IX:. UMWEI:EJ^+KfA&mσXY U!@ `4׿L 7G7KuxDEH,Gd;-ꫯvk\%c'tM"@vO!$-fɣ-t,_|q/вlh0C6-Kb7+OMT Gw)[,`AƧeU|~ʽ/}suy^,~ t\qBM#FOf%_\Űf8dٶLHZdN;;Hivd\%9gt2q=V2Fo:YWѽm覛nlsX +导͐gūꦮv*e$'m g5״o>{FBQ&OGKanŐͭ"U_ #i28.;+Wo jØ5疍iWM?OcW(WV$d%%+[އ1~Dom \YY+WudT Y*cU2(kYGwF|ʆ~-r-ndo$Ć-K#:8 7Enex5 J~W۰~uVKŒ0N<4Q %Lh+S.g' ch2"MȽ$Y `NiK%6b$ z3 UC~'?ST'1)Vx@Y.ңmq"-|}, 38._+l D)6@ӑwl@rˑG9b^R*rLtΠkב,?f T0F|_v@T4w|خ߰vDVVr%Ur}Mgm묳ɲ@nw$SDD' MH+pEH4xN7K :I+/Z Xy*UUB~-)A X5j\Ԩ  0ɜZy~7YZEvpcNفF6q2'^C~+w"ǕnVu$EuYO3Oklw]׋]TX4!a|ܫ$U8jr%W]U5e3qh&a (XhHɍdD"˃o@+Brh`F/|JE3lia[F4RFtY[B^kim& ؎p".ᷢ@W|c566 7c -2{U77^YggGb6h^pY^Mr_̣rG[̭Թ2tu饗;3"46 ^M ԋ$cDgD6TLUPu0.#~2H#qj5-jTDT=geyřgiĶey!y ; m]Sō7dβj9TG/˧+,$ d=_yeN>RayQsaycL}f$z}?*6jKrF*o`ǓN:iĦPDD; MèղdI`eWgА; smAM4y(#^Bq`}Sd[X)*" * Nrg/⑂Z6`mL;ָˍ7޸{Ky_5V:is֧&9'/foqC[XΟa75^#1qbcX $yUU5 )S[UmL^",#峾 E4ݶ~chF0mF^Q'$;S&Z[enE}䯃jj:R[َ e.O-0JӘuRT>QWʋ}UIM5%'6tW\qEL(Ib,ٰ֖{ʆ @tBL+Yx4jk>*5^¼a/5;aN6 NK/l΀ҭ-aL2wyZ%,!Of,O?2^`o@2jWKWr+{_+Grk?lĆq:/Eσn_\Q( )E?o6ʰBC_u4j!m8fB lG4<n#rP/yu'p0,`NOW FbW]2#;# VtoɝP(̭[8g;îBp#6C0!Q@I0">}\3 .),ÔtjCM#8/836"aHEE4,5l'Y[ag_v[am;rE4G}S;N%y}?q:IPj۫i/w3rklxn-GrIϭʯ_;)NƑ_y?jܰwD A T ^ `Rmr EmΆ?hiQ,TL%&gV68%YAJtBCzW ]6" ~ie쥜uBHo|wkg$_ ꛝ}=[kxCJoU4@iR}YAgU-Fwʭ"8qb.F46.:Q^Ćq )K/6{{6T\l1剱|Ya1kvwc )M.B/C?3tEyeo'Zɋ |Hv LV!uO<:^UG1V 9V=w5&tc?s=6 gZ QrSUN>evLa7݄ >?(_x"5~3{o 0@:fe_$H<裏ĊAE2Eg_3o~~ʽ_UW›|xc/;餓Z[fs +^6v&}.ww GyhK6W+,Ze6nd]W[A~!6[K.]Ey/~mV#moy߈_끎;݃'?M :]/iAq_O͛U5_wONbl|yr|r $ch-Άyn5) ɀ@ȡ=C-+as$rbϿ| _Ork]ZEaL+gs;ЏgtD<8 H$X ($g>q~;y@&J3 LHg}vnycۥꄭˠP=Ny AȱyA\ ņ"lfxvn`m _6("UTX] >{Q%>>lum#;fJSNwՃA!r"/)7As\}[K[[fo[pAتLȟeΎX佇7u?m;̱r?动7b8dPQb!qu?_fUP! "W"SyŴʂ*bYTL-I-/&AشynmdYmWEl e y VM׉b^MuMOd6r&y11kP6 Ld#n#DV'?qCޱj11W,Tҙ%[72,tĆqHAbQV1UӨꪫWD[F'=,j!.u뮻Z[g\s6l3obP6dHȣf˄ҡ%\sQyNy@폈0!\ iua' EY>] #T8Yu<"28_ɷ&_:FQX~"E^y$;Yr2RۨstSL|}$o,O @5儖?p%:># ٦ H,%uM5Ȼ y~뗭tܐe*F4aR!iSL(y,#˼zh% P2H@4:D1;Cbȴ˻u]`.E( ,";pandk@ck; <ЏKzvʯOt D4ar(ڂ%)묳N&B`%8Il2f]_N(tf,n-:V1=J/Ka{HbpriLm˱'mUU!Z٠vj@#;qBhj(ȱ05q|ssݶ娣ܬ{L~+Yi5/'{ٯ~-쿿1tUsΣ![m chxj ~O8aU8jD41H*$Q5:HBew<ΞhB(p }#)6rV"9;zǺSO=oW\O~rdB!E!=Wr-EL:!HE:3J(j F//xi|//N!O|?:k1_Fl]1F#R,]R 0!i&n3iDrǷFfI;5״7=.#5ڢZe!sl62,Gv0Ĩ ~,j.R~@KgQUC7&&37Ei,]w^%l\ESհ"r-#EJUB ) ꪫZ[f$)>ڗle?я>UEzAA(#hu@+[Tߠsv=6M$͵n܉'X[#&u匯q>&w[c,9'u,^\h!7fLtoA/cp& ~ˋ_UZ*{<'ЕƈN+œBʙ0BoZ,>}3El/" |GhhpF{x>0Y^RADz͊%x*:9?ɝ~^w! )$;2( r].*eH1aHgE5W_}]ĕ'A7pC p ޚ!QD{ʢ/3nRt쬳Sأ`ws#q&Y[؊KYku﹧[Wr%y(Htw=HWkm"3//r?5_}U3r+ǖqہm~Om+xR{g?ʭ|Ua!E~ټʪʜ]:Y cM,DsO>$ <3t&SHl"|j+t/ | 2^jCFw#9,jGv sOɣp {j0?]|?+4_WB. 1&ءh0tt :סl1w"?=pL;H. >ToeUCu}u@=:n쳻S+I> ܬI73}ԟDo&ugd0 NKl8T,nkuN=^f(>|ݾ~Ķ4: Q ٖե!ʄyx82꽎iyuo6i"[ sQ a'Q ]E~ bh} @A sm69=eY˔uBjO glmGhC-8;{hVYB7Ƈz)Lr{W\瞞G;ڤI1: 4{غ `7m2nML?iX\;SqG.**z6Ll0K1V[HL嵁g2drGɣ@ת7 <*+(q2Xg0Fԍ~Dc\ }>= 5|4 '!+~R1oK$'f9=%p'7\\sF$OP2L䆄a7'$4͐4>3&4dM7[8=|;kL)Ǫqؙq^UȻ:D38tM#O4Qd~dSlI~:-O]lӏ=ڽ(b HT dUHEYIK/uO$+m=M^^ck;pRA ?( *CMWy " rIz`RXl׿IpS6l! jM1, W_p^l!X;+>q뭷\0TopҀ>nlNIGǃ0iaSCVo,!|fI0¹ג~սԹfQOZvƎiV;}}SJ}Dc$cU䪨뮻L_5&tEҸ[0V0FB [`vM#X5$afsm4@I~ UP)Lq.U⓳z׻4G x "e3<wnb wy4*@~D||ɡ2W}_ hỼѶ/Ć1D;^1h #;rdF|u53%oNpvc'F'ƌ+1T{&8L1)3 _'⌼-[6rc|4"9*6C1"ҏ]П `FᰁK/PlH1% ;O<ϊEu, qHcS6\:=%sXL4_6DA؊R6G#;a44 rǠccaH6`96l {3+i@f5&X_aza:xкM_M|Vs'zX{E[qI E|nc,O>k|]qFZ@wex ƱS+5P R͢&c,d7OAhݭ}EEBa` G3D=|ph.y&2/| ~bBs( |acs"îok~_*{rU>!5?ɧl? 8(@]vſTP ݔ  6V7àŜ}uS']]wu$yrXz"un7݌;R'*gf܊-!_L~0n~P$#"ru=ƈ2$@Bfg.b.qЇ>:ӄf1 /W}F& .i2>[nP=w!'l@lqƯ@{챇WM1#(v9`Qc9,g[FA|ːvSݸnw1?>J^AqE{/&'(ҙE hzeNy0>h Oxdi"tRۮ[{mlP͗Q':k2hzkwA7WZiQT($Q|jA(~ \̽D@>ΘW6a=b53-ѣHzU"gI: =I@n1 D&5?&@|ڥ%kS}f4,<2Ƒ+̈WQ!N*{ S'~fqO#=@\ƽu2(!aÎ lTv՟xq: A78U㮖4n4c7fij56elnWgcɓku--R4fY>e8 HC+q3 Ԡw{1$p@v&} 6huZv`%n2O<񄿼$ 3a1c i^%_ɧͷЮ"lkﲫl˒{@x*Ŧv1!ӠrVM6,lj0F_ϒxbڀ vQ&fIv -D'芚.5_~^?B d$0{k9E+ۊ$P.X\+GVRƟb ='[RRO:߿6?n$gKt\xG3H)I:eˉO5-Ǣzݺ/va)ʆrk'=WQx*S*@0N"mlul(;*˲_ [)Qj _9[zBg*g[Fj-F9AG gW`J(JP`gl#G(BXF*J,h{mecⳒ&X=d: WDe` H%|ԶC֏, *g+K T!Ւ߭]!l$>sU@!α%v*,lmBŃtlE?K/Mg}IbbIdلS8K y1&YK5#|m4!{:B03-t@ }4}A:,m+K]Yq)i Kݬɠw$'$>8!ߐp,ķHtj^m6j _L1|5Y*^o"bPKũƥ|G{y, ]'[,lm/| T,&%k~SN ߵ!N$mfdt^qޜDHyPˆ:Ew+x]eՅ*m&,UYW)Iʖ6jia)*+YOR/ жvb{fS Bl(aHl'>h?]cg!XO_@^ 5GGA9JvTj0# F9#"Tk4 KMRIږ-}䫥l`K+(;Y=p:sl ;XY )jX}ˎvYi^v6lV&059爂 `T@$ HX@ `@DPDPD̘**&`_ޭg;SuIsoU MY4 6J@ O7BGt@:(WQEj%coQh)2FJӅmϸCE 1b~z;%ttTN>r}JhI֕J!^c|W2>3GWmpXy0$"Djا-'TShHVn{0([2(^FYLUUN2£1+} Sj}cc[b$R\QRоG޵|y)*_+Hiyz^s=*ж2[>bouA>ץ}@ƋhatΧ9QǻkVc%r2ޖJa}[헱Z&9~:ߧ K4UgG9m@=1^zJBisgc:j}'hR9_i(ţ۠^0GJKV"2u=«ʻ(uJx~|~["mw w#}C>)21R|Te;2^c-9]ЩQ Z"4L"k)Uϵ3qI7~:9R9Vs=s+<ҽ"tR26ڱ5:`L 9cFR@8[Vuc%X?/&;#hxZS?WPV2@'vݙʃz ZZ*'CS-MPǥTrm6Jv<V B1u-fܵ\=vFxgc#8||-㙄JJ&JNGqmٵLAe|Bp2+ss=7Zr.eA1_9Rϵ~nyRKОo;ҳ\;BKJzlKP?;kYnct4P>93EѲs2$q:TZVL)c:LuT"M%Xe> @aˎP?aL~x8wyyI|ޖcG8Xg.Z%Tƌ>ݓmq3pryy4Mi^yx0fK1u^vzѱi=<8]xK`-G1tttt&z1=p񢖎mƎ+1ttttC;:::::: =Ho-g6zqAqrƎӎ D8][:::c_q_1qѱ;E;::::::NzqfL.Mзvtttttt-TtLzU882Ǝ4qfaL֕0vtttttt `L>0vttttttt9)S1&?sKG>?cKt7t=>8Ƀ0vttttttt"cqѷvttttttt"mtttt;zq0DttttCBkűoMO>+^>o³mo 2&Ǵ=wf,G:|t$+2DVp+,>>b&}hi{W~]ãͅ>ֿ˺iwZh3Ex߼az{~.>#>b+cty[D^Y~io6]f*ZשH7 __x|/t+-.{MC[ƾ i;Cmڪ#7t^l/v3EaY*=^SXZϔ cڇVu*d ~>=f>׼ՈQ>׃,6}kA>?|q_}_s=wԞ1?!]r||?9xxYrka,??i6GM ///~7s77r-~.s &rcߣśo!4f;j.wXF7ڗ???o '}0M#[>`c<0ۇ=a{=n_e r *_x׾v?%˵}ASO}W{.V$?>>n~/~Y m~KKy`S|__ZoƠη||ILqW//h--.sdn]g>lAʯ_O77YY!syVЯ.y}!8=iO~Ξ.}I&X矿K8v8_W|3///S/x/QMn2,lb6Ag_\lO';JwVlM6/}%e͵A1F>m/̶(OΗ}ٗ]b܆_~|ͬy!A6 sUf: M (ᄌծ6i|c>rL[;>IVe9Vf'}߽0crFog͵>c>规U}6K̻W~W΁z\'cjmsjn] pTW6ɫV{}k^ beγɾ>Dfmю_#$;8+d'r׿ 0\@f\fqqfe&*u+avG΂ex2N>0ȶVmY\w6(Y([PdƲ5cMƈ d#mHZqe7=+FVWhe.u˲]sDִOnZ"Kupt܇"c2O??:v1۲r Z_x鱅%E9UV2:VeF :V@udk tv AN8hDnڠZeMSZ Vl\+s}-0 Ym7.M߲}~oՎ/]3??Y7kG}wV+Cn'=gw@)pƁ[ '^L1c~3erc{gـ__: /sjbUzj\_ZT};VLΓu%)OyP'2K&lUkQV̭ҭ%W}K&xZdn lb}0v6Gd-Dc[%aɇn[|oōo|K+ץ-;7|ҕ' |:Ӷe(bow+;Ytv?e} S3PǏ@ԶLK{\׺ֵ.mWhL-L?e:_Yɵ@>?}nA|o>Z>)~U`7L@]R?hT~1U};J 8Ѓ{ b8*S agVQa O]J)G">}G82, P1.c (cŹ㨟 %'K&"n(d1WPHq8G#~FoG o-Anoq`&%h˸ʼnR?Ș ɞ߹&Ƒ#Gn}[/>c>f^M·>ND'|=@"N" +p'JxY5[1HpPݣ:|1"t/7 v|v =#^rcu"_"7Ʃn~erZwUn\/paζ1WhKyF^Ev"{.a09T#S]V>}st tMz}L6l| ȡYɾ&*նUsE[mZ֫uvmnGnȎD-u:Hvx%H#`.9V{ϟ y8EDGRyŷ_1 VW_лȄk߰xZ1T}4UF܎?_0B6/㨲)y._ "[|A2xNh 66?dE6_[lI-2槠Ill>V]yu?A1[XA^/A̞U-\m|]eG꣒߯\@NrSK-5A_۾FƳ:$« 2ftT׽uCIN@Ea ~OTv2JKҭ.䮎lI2;v,g|覟׻v~ *`$x,`ƛo BegԀMedk 2@&pI 1SaDd));L+v6>u+P(4JTu:JCZ:V-9 c8S;}B]4;''?+" R=F@/m1Uh0v:N::wrx֮HqWvvM;}SGƐUo~k5&6ÜsM tE+2:fsw>@#N[f P'] ]d"1O.FۀQL{H"Ǒ)ASc"?ߴ}6jN??. ]^dAgT%a`V ĽͧsȘ:/0B/#'}?[6c o]GV8vr'𦷫h?'`4ֱkGUc4.dS'׀Q[?jc͓Kjh\lb䡎S!l)$7I2/uO<,&ԧ>b%b YaUg1aA#0> #' 8$Hgmrdq}D6)Gc2c@kc2F|9c1T|F~~jM5hܘOQJvaWC+7~'jBu瀾+U/]u*KUG *K_5 "sݱ:ε;ʘ!?N(̑tk ?y/#7u>Qd@gx楴Kme"׬7pL.M[xŇ q@';xE\5w`»*Gh,6\|:-C3UMlt9-ЖdA]ыz-HL#3/`S'#^-U"wV3q6-&$1q 6g>DEMl3#BNj 6ۚVglAdLT1::;Fİ10U@)ql1* N?3^3G93׶;Yb,ٚ f|;<Wڂg {3j5ЗѲu˘"3)d&Wdqc8XɶO ;>~iL-%FB& Gx-QqTB7rn2?䢶(i?jͧv"S:*ߛ|ilg,Q츩pҔĴ1@%G}gV _腎xFщ<3_vwFئcY1QK2AQ2Btu3S9OMuRP{-&W,T.o;2!+I~S_m}6}$` *\0 E*π^Svt-/x v"m%VInXbu>?w,^dk2;Vpj{xM@{W{|#7I^;sXA&h>]ڏ}a+l3`ǿצ$$#.#¸ԡtnW^?zQ[fL'&h^l$ڹ$6 wXP3Fz#UTD6=[ gjW?SidPXc6Y8}u&ݪu$ % 1f&7k')cO&bTɌɤL*vj [CW8xs;M䆮!aXԕ*$ڝ8GW펧M/;Q1vCߘiffnjgg[SA.Z@#E8S|#C)lA7w}{_{;F瑓Ά?G?I6:NW!hucp>-}aC)vT@3}3f4_l|q{B&/gh)mUK)Tbڮ `7҂ &s4%$rl3l;3 J7[*db7Y 0xaȁqq;#c3]SCg:)`{Co[q LYÒKb=H4%?䨽iL~E^]:ób1&wܘ[yWC8zjku:9bF6>൭}/o0l>wݦ6?wΎfQa1;J|VWz[\m][Ks>5[bձ=eKXj"ؠct[}&X1෌ psOS>A)(qIQ0AcQ cU)pm&pib6I'퀌<#c ɀ] AWU*M˶[|qU,l"H5J&̶rIo :icBN"ZwSh\ݩO ]ۚΘTqk[dvݰ=nOWJ<)0f>Ռ]mMvMO v.LqM]f Zkɨ@ AoL.\A6W1nY!m0I(_s~5sKm|SڅUoM1Q]lMlcr ]#6u7j2rv]kKkձαA`c}+˶CG=\uࢩ'dpUv\&Υ}>İDA@o=G E$Tޚf&̮޶ZuP8TͰڠ, chLfsa$GwGKk_oII+`mDgU*T~s |zӞa" deA(1ެ+Vӆ7>C&qOu?h8l]n6(2G>YFL&[ow6A$7q}~ARuȘ$O|'{V r>cy'GA;uvG{~/`(Jrzϟ/mzE:HNǦNqZ9=$0lMC2&UI m-lXcŜYKU]_PIl3yaVW;l~Nӟ=lhSmV϶:=v?/0WzTDwI=-8{~+绰C A3Uh܇4JtX!v=h\[dJa?$$0>׿by5@|U[S711lve2P#Y 0({P&bjɌ*V\Sg넱)]aԔ̊Yz%<1;x ^9$ qn-BM r: EPsx,pa,t*01 ngNy`Kg>󙃳མ}>- ڐ`+ݢըK|ޅh32/si.:)V qxv]hoP1[} 0.eE~|p;O2H,-i@ۭNF>/_'f,F:Ab16O H2wMӪ"8Wg}sG}8!TFe!&%=y @ЧnMu lMZ]GtrL.͑2 oᣱÎsm]EW8lXFbU+ƂSUЩƗ-3ٴҘ|Ί=@Z^/ع̿\ؘٶeE}sq[O;QZ$V7r;@<{{sHJGLٚa&H]!FW|(gVkm[rOrlH[i Tx2w[6Tmo;d M6}cW>P@i+-x֮ L:/іR@>bl8ͺbo~)@&0"XtîA=i͊l:G]$Xeq1=QٓI@/ $}J-n1ȌT,;ӳ "dڝUsg6DRtvØyks/n9ukjTwd'r-ז}k{Xk\Co \&7V%)lՓ]mmY1_6ط~ԝjdnA'ۺ#;QٖVC{n]~mw]nS[v +V[iNov_}yZ'Y`dk e\2[ f*ꬰUd]io> i[Zgu d@2±i5L{g{}>T2㯾zS9i8 ԯs\=gM SG5Q|vNJ~kBtM A}x`H+yA~׻ ΰmuVGe

    ͓&0h*ƃݾ2Hց;ek* lM}.#J eH$9zKa?=51Į\6_1o]l>GJ{غe:h|vK>6/ηvj(:Eg ?h^~;0y߽ YV1U;6NbZz&k NH[Q  {sxr"'<&{gl(lu(.Ae3&K08Sߢ(z67û"fBHc8PF 74 TNV%  [ sސ=cGcD;lbA?؄ &/\h榘cH91i&>&'ttDZGf༾(Hم?䆳XsuIުҦqGKK'h6pj}jW!6gpf+ٝo}Hoւ:D'n;}Y ]2Rdxܜ7rʄ{lY>ֺxş}ݯ PA-/a[fWsomQR][hH֗ٿ[_a.z^|]g}!`#WVmW$qDl!VvB6\_E)kLJx*Y02$)Otc3p1Cƶ<^L%DNm J-ԫ}j`P0[\z}T0*2~cߜ\m?8ĹI7ms4Sz_z%0Ume,½ʍ~,U63lIvMLG)GKsa3~{dpHS̱b[]WZp%ƶz C1WYr_w ,~6-~ۡTQ b%|OhQm|zֵe,3kJgl`w [O.kL~<8s]m[6]a>Ŝ IvƲB ZϥKr((hP<$os1(W Iα}jm%SGP¦NBV8MczY7s>ThwSú)y۲ b }oV7hHPZs")c2k$I_>ZstmS$95#{XՖGw ȹ=|e̽u؍3?hGw2zOI5Vt!J^LHDס)}tUL8a G"ρj|Zï`]Ewdޖ [cwcLf^ɴvltݔvN7}d_畯|%ƹ?pGm7]d: QdvkL\{8%ƉLx0Ud",Gt p=BA77ƛdUcY~^;s'Lͩ`pȫ̩0`HWt`1YPەq6ɴE?qۥkRL0aNر;x3vnwkIvNSR~"*_VG''5yǞ ZM&bS^h_<gزgu>qnSv:җtaY6_bQzp+D{`G\d|Z%Cd3poV\O>9*|dbr{1m,l^\OGIdg5ոN#l1&SZ7_*,epw} 2Lȫ=~*0E&cmicsg2=x&rXBpz\yc.m7A62 ׷Gk6>?9ďn+J*Ol)]55vC [C^>$Wy߸x _x88kww&7jw.ΣK:Y6(vF"Ʀprz=h. t"8@zקN$Leި6qAhȅٝķ(lיpƋʣ:v;B?uԧ\נNwh̶Vz=!_#]6l:G]Oj"Yw[숝) gO~p Aw6ڹiB^۶dg7|$!DI'nZ/[ST2[>d_{(%~[VC/~T0^A7K) @o[}lӨe 8ps3Y&+v 3b|;IĘ!YH͜ Pָ$DOMu#'ͷݓ^n׉?{@S6ꡃP־Us}mbJu{ m"l 3尧ֲIپx_IȦ5ag%,-KdE+,~co@?x0&2LB[U?}V1L&p 7QӁ2<} 7sNM1WcYT@2i}syR\`뎤βI!rQ[Hջ '\JHݻ0y0w<~xpQ}OSau{e/{ٰu}8{h 7f)s{h :8 K)cU~%T6TfS۩6WdjV'\8L^vAߔ?Է_*ꦼ:l^z>-oy! _ivnUR,*oծvƫsMnrXm}6/-dvw~I[siqXYp.!&a?{N^$|#cȓxC4 <=\ny8TĽK>- & M):aRO2u 8ZWP d._?Eι@& 8qlO6.N0R(S4b22](}3A}G l3D/᳝ LHx5'm]y W+!|t_ f ȞEγΫ 5~ȃ>(%|qdOx&m0 m}~XT?l j["l#xA.6_cUt /GQW~l~f_}#hlh 7)h?v ecu^76lqGKO l5ڰ::hC{d|X `>V7K'MȄ׏ԭ εs;hjG3-6s\[nbס/E67}{ E#)N)ژK3}@L~8Ӈ@=xΎH#ǎЅev^oȹUhc0",aN"dS=.9uTQ1$@U2hK>#cU;":6}z!2y CbKYBC}Rh>sxT/)?AOӎQ;Ƙ~̕E؄5>;"tp ͔J+1aҦqfm7[r)fW]8# nyں`S!P_ amw*;6E>e_kL@ϦVѶ37g NØNF_m+m閺R_mܦHkױ({6vYצ˺uԺԯB~ư|m;G͓l_oz+״sGe]b۶]i?SKHGşO ҇mR1׬C}]VThM~CZ &`8Z;eѠcGGGGGGGGGGGG(z10vttttttttttttcGGGGGGGGGGGG(=i8˟ ./ttttttttttttt8묳^3FdGGGGGGGGGGGGǙS9眫+𖷼Uxg(.:,^ᬳzOIҕtSQqⲗ }k5N~ꋾ7 ;Λ^r/0 /8Uߎ3g}{?~Kp+^5^x8T1p<8u1.0Uz՟9u]8x \1o;Η8W9眫uYs0\;O>]>qqg?JWW0i.z-}:8q^x{xpj%V0w^WS/udGGGGGGGGGGGGSqݣOu,{?O?ЫO}|wG. _~\:fa\p?uxE]4ihp*N2Os9_{pj#l?:%ӟqqpw{;8v]p/~׻gCƩ N_5± vܝ=رcTug+^=8qTX,?v<|IENDB`nut-2.8.3/docs/images/hostedby.png0000644000200500020050000000764614553676503014016 00000000000000PNG  IHDRv&)osRGBbKGDeR| pHYs  tIME !tEXtCommentCreated with GIMPWIDATxy\ߝtX"(iZa&Mgf~Ƞa?f0#[c~KBhґMli9~{D^b+^31-]|V|+ms/1LٷР8bh]?O ăDQ\#103qȐ!Gj‰yWlvο !!!Lܻ{XTT{-cǎUhX] rf(gߥp>>4m҄Ƅ#mFDD0c0V n/|H$rehOU=z`<ٽ{ .E<=WGܼ5,M7H<ڷ;D]*J*@Fpprݝ7-br޳J+L2/ҫ==ۡΞ=ǍC-!7ft܉=Xv-Y٨Ym=bmeEG&Jx LRYI CY9φ][CWj=v+@կkVU*=wvy֨E 0]lmY/_U4BCC8q pq:t%Y;'Nd-Y̮]/z0&OKHq>{w-'OV(ͨtV<]L4C< ylu^d׶8â9˗-+Sʭ* >IF~Z`ݴ23cnǎiϓ'NFg*\x |5k]dgg3}C5f'n5z eo?͈Ұ}90i2lݲBYa)ܹ} j݀!#ѥiZ 0VHjFY q>rrrlX=}}FFF4k]aҭ Eܜ:]]J@n&9oVqsZ~ 33### *|v\.P*#ud7t:NN]GC}$QQDfp[1olWRL*@zŖvV0nҴD 7R>e ?0S;W7w.DG#Jէ/}#yڵE[DXh( >mK "rR;̝q큻ica ї"4 <CHLy+":e~>cEQ|ms t':EKbhIJžt톾LF?G'NcGiMm-۱{|=m~ymWʪ 0E__F{xͲ@]B"A(*5S8t( ^ۦ\.=Auk{BGZ I-=;\O;aڲk>zXESu O 4ުH{iq9t-*.@~AayuV.A`庍0y φͯ4~ !\OB9gBC@H c4mּR69M[2XV*6La<QXP-2mc&W9p7M[VZ=>|;8tСSW[,XLRm @b]z@^IwAW8r`/@_GQ6oohœm-dG-W[XXc ~$g*Gb!r{hʪ[1jdD̝ŕhM?l1{qͲ=yԫW\nn&[¥dgQyѸYsX'ng|!_A@ԂTWTLbMy[*"/*H*6<[GXING݊CO624g *UW*8isyndDWWB@H$R\L4o\Vv"N~wd (W ]nXͮII =qĴ"bV70K:G:][6Md}6 ZnCOKcG0¼ѧvlZUǎ fߋa?"i8Bvτ1|n=G#1ڶ}Ζ^Fӧcw+chu#V6=j""(.h&S~ڋ߄ܷS_.P"o'J2 :IENDB`nut-2.8.3/docs/images/cables/0000755000200500020050000000000015001555413012744 500000000000000nut-2.8.3/docs/images/cables/Lansafecable.jpg0000644000200500020050000014675214553676503015764 00000000000000JFIFddDucky<&Adobed #_       5 0!4%16@P"2#3pA$D&FE !1AQ"2aq4 B#30Rbrsҳ$CcDt@PSpÄ5!1AQa q0@Pp !HLjɈɸ@N|3jS$!$=KmM"5GH[)PW%&("G0dI|ԝ f0dl9Z'Xz%=Ĝf Fd[/$BrPT4p'% 9_|H I `ɓdlHՓ¹/ʄ&Mq=$u|^6^6FbxV\&=)K%lkKdL @Q+K6\;B3%7f:L 8m ͹7fDBٲ/T]7E3Xz< (!5 4ECTT#>nvG0V:,u )ќ<Ѳ%&:@kQT]M16 Hl͉XnҚcdm ҀsDdM!-t{~{$dFz玄:Zhxߙ ӗ Ǣ.sB XHz"#6@LPx@9Дd<×;6teRB\.dL':{<"2W&2  cnx=玄:@z".=`DS('NdzL,Dx:By=2d^lG&D[,Iΰ(u`iTvgFU5Of' ,4u&0d dɈ 0r2@9xق2`@Xj a5bnl :P#(br0d2d-=Ԁ0`FJS6ZmsBʝPTd]Fz<0 LC= ȺYЀrVsZ';Zt+ 2؛`DѾ2(u`K%C2{5p @0y=@9掔zO@4%R/c6cdl  28t`FmM0y%%<Ӛ0N(D^:C=Oɓ& 'sBΝ T`˥ӛ2c&ԕf{@X7@dd H`kxsB ihJQ.1ӑ@6[7@v\-H q*@x@9Ӣ3%'-5Дypo͙-K氼BdKfJ@^"2LDz&H9s`_5䇢bCpɝ`0t` L2R"S \l1DU.`Q/osGJ60d` 9`d@{*L1X`m:x@2ɀ ɝ`?K}[]68GHiF8GH2cim#q`m#q68G[Him#q6с68GHkm#q68EZ}CʌNtm#XZV>p>l0w?1 Sr ֝=&nm$/W}8/7hc8zUV_E_g.|d;-i,:ץ,{d=!!'fxލZ&;:" aFJҬ#HM[籾xoBM#DiMiT2^A! 》  ̈́e {qL5fLY`HKrwӜiz &'14?дԢ Ig.Q"cL8߉o̶C0")aϫ!ЊGeAqT#b'*[֕3 t!4Lb,âY;.*5G~wG~wG~n,A)|ou#ƹ_!r{2aNfffӿ26 Rqq%qRLwO2␙q.bD* e)2z13[eל!T$Pi+&~Y7k.:.3{FѾtozKJ'0[{uPZ(̐ɢMRp|d*&6lu<>=&Ym`y~ݜFl凔L˓ȏgIhBE&e)p(H; ƥLy^/}R-ܙv]TX--Cv׭e$E;c!0-7|`uŠ_upvH@bq#\d;:an;Ͻج Ӊ8pN{|XgFHdH"րJ#/b޾#`ILW#FmԂ \L3aaa@Z:!BTI3l3jveQaaaaQaa,)v(U85<̈kH5cޜ=|Xf:iL;5Hn2܆Ck.3 nsSh͸Lӓ۴5vmt;7&DݦI6M1j1j1iZZ7dv%'T{LY]͂cE6EMM INZ"V4\5VX!M F0瞘i<\r/MN9D =Osp1Z9]!j1:1j;1%75d`)VYVcUf5YVCUd5YcUd$+ԥC2D {ڨm]?7h]l͗ξ&ojӲ/sAg <{|XQ$ ȋ[f1B}ǣ.kȉ D+J^Du}nShFG3~U(@3MZ93: NFCiS,#>Dozij]u>Kx""-a@DHQ7 SIVtx# ~9IMY2G"q.<>/dVj$v؅J'drv'Vx5yR21md%jz`j)"FvE9p>= BVo .|$[rKK4)/w=\F"cwnl%"CiFWL-P's7gΧV؍2MunMB %2L6Y ϐ:_$~U%3:u= ^" )kmS&7a:lxsېU.BSȦݫ)?7&BޭS"UpYˉU hz+Ud%+,}I _>wy䜶cMKn"7/7c|ed}\EH6-|Yg8DNRib3,B ̘9u.JLUjekJ52ˡ|V|G -#4mGLhȑVu2o6|EoVx/,-|醱{5|jJkfmZE%myZ5i7V'ꛑ,Z;k*%m+%hM^/՟;sqP7?e-Լ,yNJ\}Uam'W5 )NB2Pj֦͘5*2Դ5vLdԥ$Ujetʹ[e5b`$jXwqWomJ+AGPZRfGVV(?,&dlKvҶq{"/Sc&b\m1U{Sʉ- BR\_*尸1Vj- l"롶o4)JzڳKjMrK}ۯf!`!6 Eӆj91 aW aQQB02Q"T% JI)~gYTFCEJT_tdr15l41yJRZm[zG0;$l<jwJaɷ}[fEt"a˘m:GHca70|\ĖM_\ExkT%qD1 O8Ac,{u^AW-I F-ٕƘT ql-*M~Xv*TUU^K6eLTt)UFyë~C z$kb a7o?x&0Lqڐ˔d+g;̧i=J.˕)H z`31к؋Q,Cdx*5d)(n#k᫲6m J&~%ɒV ːGjeڗ)+q ]d%8Ce. 2Y(Q0D*8UtE,tFa-ܖ!Ke,,NX,QBz/[dK)xlXc{%1>p'faW{~B.2Ee\('S}®*;e]+T)pZ](wFh7o?/-sYvw,0,pnYiٍv6'l3l#aRXxiO j.ɘw_lq;|TH\M\$F^.Y!N!5PkDʪ*BBDX7o?GӾTLq0n&37M93%k&/ 6NVHSTNTiʱCpNm>cZQ;DߧO7o? /:`KԼ)o"h7qaŀX?UpctUAA Ѝ=E}Ed48Vi\kA4IUBA1D>"xwi"`(ԉTE! [I{RR!ct[p?W+*f -9-?L;~bny4_5XUHrD9"D"C!rD9C~G\0&T4I%e*t3JhBIa,[frn)I82QoZbCBg,5􎸷숿1usXʦL7ܰZZ),;`o`o`L[MKss9۩2^YŠ8qq+] q\YŭH88Jty.Ōda'ZVңաLmk_2_pu*<[zs *̹."H|8Aԏ5:5&?0CVJ_ԘG=R9ځSnstÝPG=R9WF9T#U~WV_ԏ8G=R%Y@rK նKEjZSZ+ĕfjjDzLճ}PcUc㞨l+^T}` Ƅ4$iH4 JGi@&#55?V?V?0fmwg,rhй Q0.pífަLJ>O,%a(M!ӵd䚷Ur}M4fE5Z[C)C\Xԫ1c1c1c1c1c1c1c1c1c1c1c1c|1υk^B.uDZWR mU$(uf^X u\[mI\8\y֩R$mniW?$^~YeW(!"lrcT^x}{VshhyɄaރY{'ǴylSp7XL7t,3 p5CTo;2Ųl.9ͫ 8mfk9<;rXֺBJ0`#F0`#F0`#F0`#F0`#F9^k&vDxչ+r9L,SܔjNQlfH::DUmy$K*py-$*TmKp$Jr6i»vN NKTo. oQ%T z msQH.cŵ66h)بk(GUbB8Kڶ؝>W!_ \ B{5{6ij]`qf|˄>KƧ;z5[oѼ8zAR^mxDž8g[ IClZxEja /e`v+D݇Iwd$\xۤZmꥂR0b a5n GsGhب-jv.WuaZe~$sЮ 'idW?mM1r_eS[ cpHV^;Џ[905e<&4 f)98m)ze899[zLzg[Z|aI:ﻦ:Q}⎩{.}1.@k'pGqwmDrJ=ʛt+xK6{{& cjGL ->Xsc\lS g5d pLYm$\\mc)X7-FWiUi8F=X TH}_J܋3Wt`V!ùhʇvŻjܵbe.z7Lq!xo (=KĿwg8h c՞9"lq%. CiV.섗.ZukxYt9<9 q1sbk7mABzdF0ܺLX}mʑC&8烼>D_rrF/ e5 >So`G)=`YyHw60Ws<"J|k r3a۠nĤ2' Co8{O!r4mY^gi5ƵX*cβ]kT1=VW$6t;Lm=i=Vz6;Lk!vyEEah\1k4S$]We5݌Y.u}a>Tֺ)a!<1W÷*V: jɣvNߙشtxL^kqwxV,ݟ0Ŷ 0qq7e[*}OG mEsŵ3QiI0pNsaսPphqRx&ῘbB,S‚7mC推?Ph?Ph,:,#qȸB"ZW!P۵΋:/9V`݆t5h9qY %HK77"ri״ӄklڃRn玨?PhucPuD&ACٺmֹH ,.1     DuAD,wn)6m4aH[rꟜp7SLAs5.l#kpc_Xr MpjֶYcsWY0vmRs$^X귙#{Bv?Jߙc[cmo9B223Vx7E4)6tϊwbxOqڸָ\5s8!u@86{sze]Պ˛Öm^z`ݵYƗw- gW) %9nIgEOܔCiMT;-6{m FNf t:F&)pM,5+їS?:Q}⎧{5&,I?\ʢ171w(}km֮'9_un5jq ':"K6_YPx!8oXßsŰ:*,)Uos,CwDڊ'9c ٵa!9BY7ůh8T]~Rp?˧0e1s9b笸*Lг1IiU{ܗ}<{vi]ON1r 54ODjp,.r׳Y-]8 Ujܦ|IݫDclrÒt`KTCk~hOYyP8ȏ Sdlk!`a֙DttGy/!yG]2\ D6⸋*եz>ݿ?ŦY 7/:Z99hyaC `Re͖8T+[k}'t5vw,ːmhmLedeO/ݮ.uSL7N3PWfi/:U}\|spt2,EKpm4vs5l 7q6,^ky$cL p#@‡oy֭&r@hL}[7"H>sZ`Y}mSacwͪI8@#2AÚ.Z,ԺIxLUcQ'=,SUJˏ,2Me0v4%LK n2M{<"bߖت۝p1uشʮ"ۖͻzC%2/;%4g\T{kѷaho[(ݭTuc8N(rf,Um"[˵sn6ltDagFTLYO#fKF͎荛/X^w胿͠v.i*9_k-rAW0T 湵4WT0Z EK:#fKF͎荋- \ٱc#fKF:]6lyO6:_6ltDl~[Ķ !#hme=4YXn7lky plf k F銪YB_vw;Ox ZvC[֓ 鉾8kݞz]6t;LmXvڲVz6;LhuhQX^[݆=mdMN7ַUH d%AˢKX:\EYZ`/ūo+IMGox ^j%n0i}r+Jccϒ1,'vZ]=eCKY?ecjCՎiV:6t;LpnvNxqYߦ`gH$ܧXћ2u_9w[lՅ\vW-xEQlZIJb tYnKU.[QnyQbۙcW*ՙ,B5ÛbP$[Fy{Ovw;Ox~ږ3xka9Nhv-zMͤiI,e[LLgc:o/oC H.*;[2Gm7k$x01g;DlZ=])#bϔyN|h>S=])#=])#=]) ;[{m-| zCwi7Ms]tjYjʝNהyNהNהNה/vv|h>SG m$$W<'ѻ4/ sbl4o%Hs8u,x3:ք'/̷߽F|/>-\umL&,L5Or *,ccc~C]No On efjإ'7G R]gۨxa-p-8/;vqր*Nu㒡sp?slukG^}O:#p؎c_>X:#厭c_>XȉMMl/OwG; C4tr[4@[eK39/;?5Ssq)J$[JP58۾T~m\8٨F`~j?NH} M VI<,78T^0h*Cy> coz!{YLfF-[}ԸEB@'<l]#C8-{rDZuoW~lsjyR\FT́sEBHPrw2&Z o_ޮ;DD0v;_۶Ce74k>GhksL{7 e$ЦqYގ:ۛǹm"S/#415|`mm[pGO払`8Þկ 7k<{'RP ɷn9W0pOGe!ˀ+ R.ٰӶ*zuMqcڪrs8mW5X|sFMzA3vilkv C1E6P23 i0/:ZC˵ڬbĠ{qI߄!hRH[97FJ>{.& Ο'>x6NjI,oQAq#wp3D99 m[)]k][c+as1c ?a!Nu3:۟ S7]G/`2ɧfJ,)weɬ_K;\aw己5vL^λ\r5~jEmBԶ*CH+ ݀}/`r{q?o5@3)6s>1ڭkfNa#hAQiHMT TULcڮ^ᱠIK74q݋VE K"PQ?nb~;0?s{Q[XGè5R7|SkÙ$aF`hY]7S0^hW9Y5L$0ǂUȹ)-6⶧$^cВhZ7m^=qqpbyD+䊦7.(9',wmDElp|E5݀{-X|G*6|WK3ۭ7~0 -Jjfn[kxMFJ9"s} ˏi o%I `% ~]jc2忟Svs/:JWWgʇd(BstC As h7h"QoyվunI#}iU*MiN;L lm,ncbfc0.$9Ɛ n*kH3uúJ|fQfͼdZª勜E"lҢ-R+n9=2޹m,qn{3t-re^AYoyyai\Mr nIa{'KEANy^[l9S&Xs.5nj\fYmCɪI5 Cn6hSy2EW2PbsEˏZ¨TVeU18`RL&\) wT.rA-Ӌm9 ݐqLF1-N`nUoM (\ t񔡚&{5pB̰%Iy'8Enj oO50C$ODxp'qnK[DjX6M('{^j?=a7c>sI'N08gXDJ*8iݮNs3ql2٩Xy0ۖ5;Z\.o6Ȩ. bPs XI.PſB7Wb큼\ĵa7>1w3cxw6Ok VAꛊI%BchAoyy ^æ0;}cR˷6rn#4 Enku:rG[~uۤQ_Pڼ粋u75{bT0I|/rD$P|Ѝ`hMy2rvy.[e.ς7r3Nd3ѾoSjF:>xL1\IBk? 3X݋hk*g=UdICpIYwݿQ=ZyR-qE 7 k֘a;L*D^X9i6l|}+ͰA㼴3GwT[hHm-]E1 ) .úTZR0uh?[NHS8rԱtx'bƽiwA.HP|;"޳VA8RuC:Ll|GT>[#- dOwꇞS??䗤措K:lZ,ykw#LHbݱs"6rWmjPSU5]HSn!S&sV8$Cr= H=0.6ٛitJ,n^TС"4hI#ݻ./)>Tޱ(]Q\i􁺭ʐ9֦2IS*k^.CCƺW&<#Hfɭ("x[F7MO46-\*h| iDg*)8!Q#*ݿVhckתּM.8"sA:1> S4S)aylO#ĸemO sS:ꟸ4GS<'x%YnY<| xrlʄqRHe.A&a7Un+,x`\ʜc\`ҡ&IQ<ۓ2xT<(dNd\dILn5@XKmG'r6ˎqIv߄W׻ڷy-JTa8kǸ4ž@Z u~XqvFp׼{5tcnꗾGT⎩{uKw^R(ꗾGT,[emȂF>o58"nQtXwDo=Rc.IE@YƽZY!Cm<4[6;q(NiŋnH^Z }ˆ/%.(hԛ@US XKm<0\y0LCڝ.?^=1@_ow~ѥFULr 0p-Isc\fW:Y:Ζisc?ff[\GT>[V%¹ib|1i5 u]4JPMw~YkmuUiϒ w'r֨jlKͱ">4ΕY ꀲX6ZjJ&-s` M<Zysd&ԇ߃{J9Ҙnu *Qf<1۫ޕfWe֜ :FJ6UxW[֢#W4v H{ݭY摋u5q-"S=0ӬSZ֩*H%)%E {ڦ,霈dZ2άO.Ԓs$3yÖZ)(f!x]|bXֳxˀ䆹ͥ)nnN?^9;rlSrk2F|=IJyZ4V1կy#LukHZ4V1y#L/^b\5coA^ 0Wi=NFϿekL5NUYjKm-`\|MSkL9≶s20nZe.!?DRmʲǦ,$ SDJ(pȑ,9f|R ,&'.ikR{uђKӌ:f K7B~/F?,lDDo A6xc!ɬc]=ֱ]X!<5 U9Dq9)^t.7Mu3i'cg=ySuUő2d5qϖgdu3:Ll|GS>[#-ϖgdu3:L z8P޽J<iJ.RWgh-{2ZVկ?,ukOZVկ?,ukOZVկ?,ukOZVds%S0PW~kmI8ɺkΘG^> t@ͨ* 6KCn)u4`P1jk5',RCF77 JKZ_zg0Tgܖ.5,v5u'nGKtG^<ct!}QR ^ z ]}~tEO恉sD4G]<:7D=㌿;qJ厩99a9nT BQgJ=muWNoicCII$5=I(aHGGGGGGGGGGGGGOg< ] @&I$^&(ƞSP~yf/[{v iC3Oa ouPf\JCmUG|[waK3\!ϲiBP9cFyiyT;\ۮ\<- (Yd"vvq,`cH{rkد k\Wf|C-ݽ\u[H8$qpιuδQŀT")sXZ3o}[d.oNZxб)+ ̫VTLۖ`VR=U@5F~ٹo7?M#fDl7荛sߢ0O7?M#fDl7Kn9K5E@ÎCmk8Z\2cIk < ߐK[fCDϷm_b8WhT(fڗ#.I.H qr`e$b~Nu]M\ p t[ns ]qBv=0 i'&1~{z=#sšp*RZm VenпE*7%cdz]!h޺n~w mUqQ$\jH-t͖n~ǻZ.[ C HtrGX`t;D.e!zQZq'#Lhܑ 1.5#h_]eޒ9}2&vDz;DJfcGAG;DuCGKGotGotGCGX`t;DzCG;DzV_U#'vu"}$ pvu#h:~1!qZ4OS"5]"˝ 4q`Ǥg5%zCy}~s=ϯ{_,:>y}~:Qǜd $W.ӞIKg=Bb){_O?s=ϯ{_L>y}~R@߬{_>y}~__ss=ϯ"93s=ϯ{_DZz}~sGs=ϯ{_zIz̾G>l_-b!?\{)Q:6gm#[ *8hwlitq)U `چ.M2C!I@5?Hmw;A8n.3kWr51uuҺ g<'q5!Sw_//4e'G7e0{A 0&U޴d挏&NLo)v^<}^ɍv5wS79}{o!CKs aٯ&/|{V.6+׼no]=Tbudy,7%,} ##-s,kbt'LCh^?86WjbH5 p#8z>m]~ ?xN1ɕApԅGY#zDmf yMR⸙~/Lo86m i7slgs{^>͋1\6o "ZυoWOml#AN π0H)$ LҼ_%Ba /(^dacE?T:)A.! "atHM >>v=CYp!IHf͛5^ZlQHFx4;&^}KMsc{Z1zxr[ uK-3CL(bv'ʂ!\$0ߛ_C (rb_Ӽ1FW+vM#Pi>"߀|S895Ʊgk[kn[S Gr\q1+h\s]IitᤁDt#n5)}z"ZO_"oz_k<% ݺVrBFtٲzmUa+oݬO* bs{0 +=eDaە8x+OЛ7?_lYh?B}45EjGx{o9:f0& XV&>;;O[*\JH1US2$Mw |,>$b%x:†/7Jwo_!K.g6J_Iw93<.+W:o -j:t闬LwiFˣ[2"S)#gtKn&&ի /r7~-]қ_ ѣzlǕ0.+"ZNg{~Li?7Ym6' 4jux"cI61خwL8 =*SaZ ~>wK`Co7M$rsf,詰9s|"j%t?T=BP&هΐH_%wJ{ohyҎ܎3Tf*P$  ';96FbFA)狜nwxs_ͻ!/U!v}0m} _tNs/hvSWUb2[EGa9Q+oz؅JZC?k *Xӿ wn3N;\j\gth2ȓ+' 0*|J)+דԏjeҕ:ǐpDRéDF:]cx>6+p=*AZ~k&>r"N>?D dvFo9CYt7 ;V)x~;1c_i256R1y덙EK4bUѻ\8Y:RoWR~>ܺʞ['Ne( |~ "j9gs;bIW>#'Ħp_=2~RqO36>#XSahcRsNY3Dyq}clăJx؄Dʊoyߊl͉h# }M_Lp?J/\dS>)?w,+Z8o]n6?O&11cۓ&q1VG8EE "yd E.sIT Ӻ6A`Z-vکf+fLbcy?|T8mۇ}K _].i=qi Fw ס& (2DLn*B?o=+DFU9xZK_v2t%&pao)ay:4ֳG'ϟˇwc3-{DqğI&-|fӒ~>NŖm\*Q%O.g$v,2.wg'6u %~U>'t+FXA9JЌM>B?sx,|A[s[jiQcH)t|l;G:Fفfᬣ'6ՓcQ{pxӟ/ߙFhE m[%ق%'He>k㞱>"RH%c&dѐ1b&:QM? }cL EhؓD2T˯Mu#`\+U"Pu~'Sq>*q=g~n,]翁 >;JXA–vJ C^'SP6[~~VHw?]xŤV&/>ל#49z964/f "`˛ꩾj89o%ޫ`oBj|~2~i/_8>!)>8pY#9d<"> | |oyi|6Yz=d~@"c.SNu *je{\anK1lBT cNMAcfCQbc#[CJӣ|qs?zkz>2/jNst!hⴈ׀'٣sir)_["GJgocJqUlѯ >ELфNh2|z;ඡ:c1v`-D2cyBBY>0aIbxQRK]{ĭY` 8-eѸ=7P SErvkI/g|88>u7ٿ?\`Towo]$5:+xΙ(H{@QD=u80Q<95,|&gy/_w%F+bRG˼ !!4FmH`ۀ07o caw,7JԢۣ4D-b:$Z+|g~ T&`Cb- 1YzXSޟl  q-6TNt^fΞIRibI 1#0LA܍G&Bg z߿Y&QV8>Xxsg&3嗱s3'r4Qsp\Mk &1v>GX6KKB Pr'L{Żk _PAbhsӗn݁x0XZTDOȦsˀ WJPvgٮ]f8{>'.oO_j>LS?jK:^2Dl($xqklMפ1>*Ԅ{5<RG [﷖Rs:~&p8tо37ZzeU9c{ 9ڀ꧜r)@S*KQ jWBǚQ|&ën$}pg䭻g-`lݔ:,WUތ^!^ܐJqNZƻ|h;͞4ȡH&9(ϩS1Aǒ{6e eǼpݷch5=ePh"G&Y{!@5HyќN=sr%l~ʲ,$tLD/`.)*;A#!Ehbm]T"LMeglXXs=˨V; 6laUv*tu%-iZeUkɔ;;P+C5F [x1P[ ٭9u$k|VK*MBqtJ`!gV/6Qp hi?&e 92`H +>)Hy,!WEEީ)![dފy-ck˂mcFvچ݄S|aa`F3s|Mc,EnceL\ 4fUֈŨPA >yNeBgCoy.yۏ /يp-[V(h hs2rXW¬q4w<{OĢ%<9ѧ ߗxms&6B-> +m|Px9/$ -&l ޽WibWpW䑯^wюnpTnCa.=)hqAQ葢䤢UV0B2EҨ3Da>59b"!kMݚ{-pz:+I{n1KM#pr<͡6D%kpBGmVu8 ]@ y3D 5BbA ɭ7oס+:'ri:>.C7L!#uhnnt+V1{.S{\e7L !i\)lUzEb<)y 9  ]@4`Kh$ԯ]ʃ=稆+ɋLm6LB$ 7 MEy9*U>XIYryj6Y`Wvxg5Lؔ/4׼L pQ2IXW ō޿{B0NCP||-N&q[Po&N{V)AOm{\2n)>lߜ&AC<H p@/Aup[W<#6ET4imfˊ #ڝ 䴭Z"iu36TQx~ R4l]۶d@OUx$CnH3ծK_|S|~Br qltEfaxЧB7?aƣ`nYCNԴfޕψRý4%G4;j4̱A@&ˆS_MvK;h:s{KQ 9Y˼Cn"lkxhF|R.!D B DtE 4"Piqo²jeb9ok_x1alZM u P@#7m)=Gh0R{EE(Mti9,qEI/\ƭUyjv%]Kd1쀞p:@*0'KM<|k"a34Xc糼-0 lN3LwgP![$g-dۃ.bZ9dhxfOR P߬UJ"%7{ǂ"$1ɹ fz`b'zv X!-Li__O(!n2PǮH$\ w W9|K9kL/%f *y =D"|cj:  Pqh~:Py&Y4Ikc*t#b WdxNJYG3Tn15;29rwNƃGl[ֽ>glJ jo^~:Ŧh@Pҩ+uQxnnfXimGc7(G&48=Vߔ~QW`zskku=<6*s–cؐY#K0S;: )XU*nkEM {tdA&dV}rnJD'/T.D ,}ܠ;%"%8lѮ[ !ގ ^7^KCˍp4w|d {3קNhvurQ=,s̡i8xm}HYXD)_?X1~J5Wj_*l#OU DyœW^X Vk~1[PH/>T5: q:[1Xy9<  5g[ObM\zW5%@gEi""41dE|yś$>Nڦ/6a yo >tf j7Ch<Źw]>ywϫ}]W>ygʁߞq>{L|5Kw[:|ʉc _A@"rJN?q_qWz`opy|~)}_ھB 6`"&slߵNE#z^rƳgW-4*ڣ,~XƐSђB \pr !Gu?*x+CUi[JCںL8bhQxDaReBW&+>Yj(_])XC셼bxCޟ#Pi:kɻtCCfbro!T5<FhߏП>|G>|s6|y¬p , !@Pmq 4Q?T73cPfog(76"g MS7rf4Eg<`Gֳ`jk `>wj@w_ux< gжi`.le@F61>WcGS(>246bh >*o6!4z 4r5(;6h$:D+O87DƱ?6,LL [arw5[>1!o۶pܣYϦ?}1Lcg>YϦ?}1Lcg>YϦ?}1Lcg>YϦ?}1Lcg>YϦ?@4rR#ẻlW%r2P]x2Aֺ.ެiR?# g||_>h7>yC&ĉN+71 OdAEdalC fτ wugϟ>ӐG>{H& ׻e}qWϟ=ojX>|$,/̟>|wWiϞ0{&)U/r5&A`)ڏY#zyPxLߌj8p9@a&EB$V @)A$9QFDI*h}IA/O-j+]T !@F瞾^7n}Q 31zA8&nG'dRetRH[g =ʣ|6[,&5:c)F^'AIP'ٮHtg'Ub:3$_ᚤNwCv7:"3{-miθA.X͵oYpdh1C**QBo&9>ã!4q]Z* t+@%('$R%7 ` nkkPt4L2۝4ĩPCB%Lc `Ol@W nKcu4!j k~0Q C8AjXn Tl c?$lcwYvU+TCp~X-.UݛM `Jyz V1 %YYK`d$*2m;:Ɍ.i]mBzh9 'fV"<lYz1 ޼ pc* ;6&}<'rƷ@,637nЃ+ NFD]Ϯ{k;x$ފӯXTYux{?| kuR8rV>1xKCm Nd շ8DMMk̭@䛹I??Liʨh P~b47 C%%5yUJפ%E6zQQEDN\Ԃu V<&ÂĄa(@ PicRcBWaةI6:R~$6LxYU6-"3GaC0J"BV!QK== l<Ϭ`>YpSǛ0iJmO$vѮLށwp pN\b: td (7RyYj~AH5M>Bgvq۫m ök6$XnA0G{kӿ~ˆ7} ݟFc9+~5q@}ʦC%#@wU#ۿPټZSRn0uǡBO5uȌBsD_vzTwnZ?e7/;uKT+Tgq;pifưWEAEML!xE;wT+]̫xIQW7N5 4vM'8E&ѡ'&8..jSڨh1VFet]14CX5iD($ƍdCaXł}5;\u+)V>0Zz\HHQ 5㩅"39 :jy$$ |alhdlwԼ*z4.t.AT2ָl$)Du/|Q4pi+ ,J-<>JBn(!!HҖ?l⏶X$!zذ9PZ''E'bלES͙:>Ϋ~ @ptPLێwᜌ 9PM' ņW~}PAJQ.f ?6/,L+lF(H#|ZjjdŠE_% OW6y |w }6 ӥ "-C\יЈX]Uamb;'HKwN I<p1ump >i*5r \..\b̧]+fu6":tx=?D?ҷ5] 7b,7u,]//M Ihe6@y  > &i|Hu* sTrWBqVi8 m# fF5+7}$RVʫ)PcMZwz i|aP1ymWm,i uH@3mz@H/\n:A ƥqm(q !{o0HXQXyooӑ_X()W7,zE<: F<5"qw%E?Kâwt;Š#f Gɖ A( E^;yZP N>t[$gL^~oy'^`$kf;,yՁ#y% ȸ*v Nˀ:WLTZu!bdq qozb&%ڱo^Z'p@ZE <@?IwnaГmL`_F9ͧԼXBA}؃]eY> 1NRg߾^_͛ɧ~IriHRm:_ly4sltn8W&xϴgY`[bj ,M&|)LPvG ~K"2f}|;k홻|kQ*r3H4vt|c6RG}Ù^gԤn3M:SN~R2rI]׏h/hwǀjgi2*M] Ӫs泌 Xm2vGE\ 0~Xk B(jchN2æ k;9<Al8 '&vI%O50-+ c/C`!,A<ΎV:bukc h.ָ9\`QMf ѥx~l//<< lri;=Njһl r]j jw  hrԂ H7qvL pٔ1"xe{ (TO"7tc(`B |}uRO8(cymMm9>#G`|&jI_d‡DGlm {4yLi./" yk$|e”ai|'/:Tn(m,_!Cu0qdsYvw8NB ^,88]B/nEŅm&+d^n;ť'8"ݮ3Q n`*|5y/JDሖ)@ o}3jzdga"`UrUSї ؜k6P3%l  \q{" e!;vo2\"KF!́;cؤ5F;uU#6+v@TK\iIuI9XѴ׈9-*lTtw( :LbA(_ 7т(">B8`EBs&jX٨2QbX:l\?d!e]BAB1A(ɳTy|ψlKɾr7`-x5@$89(SxGA 0Bh1k?]H}K0|  F E?TgMBc|x)W &{Np0<oTB`hk|Hnjҁj3bglKF bN*¡82A~n`xb/-!x%¬xjCDD^]|Q LrS Ezy&(;C==qtr=.A(K}ᲱM;lɼtӀ_o6:wAtP>.2pi~#2 }os>Ejp;b HעkC ~2ry0bϔ ;&2:+;AGH/,탣)"+(`@+ϖ3ťt?E@9 BBtۄZ_u laHSv[57""`cR]H #b2-Dи3> H5P~ I*왼XHA񷿄Kv)$Xв% #2 {jsr:./l}QYhowwa!E|h,u pOྲྀ6B2&5H!XAD2]3g]zPejwx hMI>؞޸@+h7E|ۈsiZooDX m)*]Zȫ[t-Nq8 Hn6hxC䎬G'^Si?aS;ͣi |eO +m]R-ez+P(CІۅnD)xNxmNǤ~ok?| .]1C~qG 4p{1ir4r罚?ɩ"^ )D\yaX( myWx1ڢf#hKSyi8%!lZM^h Ws'OgM,9LxpcÒ5jįCAH$5kVtq6 ت@7tN4G k}$/I;"}J;/ L)[",U1Ln#O@-,TWm.Y$WpJ W -Tf;Ŷ]2= k sP FRŠP8rD6hf@u z4kĀ. J|&2p徵؞O?IJG4RbTс1tZVa:-'8I4eg8/7 rp丼՞ LetVj*vĸF_Egq"TDhh@?PG4 P }՞sZD.JROʼʱXSZ=}o2[AHaC!;q6wN gGU}>m)P9Id0o(ić'4Д$;H< xu{27gMW6ϐvPcP;&hQt"M[p̳k17?E6j)9kEGyk  CJk N8C}7YXyHw/b;sEP~M F9w㭠T!%Rg[^1N{szDB" e;oaBHA8~%ZaXVZiC)W7.2Qf9ۂ@P}CcNhvaߌ]en3Hu+3Ioܨi!Gjf,`v5ytAHcift 9(b!U0&X^HuYIJpB1l^uVC"-Ї'즞ʈ;O`[[@Xp\q';v6([q`jX`HfY C%A[;{&Keи[M'xT !r^0rj`8nxJ6U` ")l(`C:01-%Ue9 d=cӅ4@, %ɵۜ=? 0 ;x l X\F6vǑI_qDf*`xy vTrtG:9*"yS˄JIR B."c=, "qd8e@tq)ݢ:KWCS;A~M. tiJLy߳l<_mW@5{t`43~~5af8J0Z`$nkӫ@ w[(rC_F:B4qt9 )@pB`I Øt֦ۯ=mc,ʪ  W.E S gxU6BNG;}a2z2IulA಑*[5pK*1 vhSp *.ݓ4t|uE6<22۬Vt&)UǢ Hr&jL*L3ҏ01ktl  Wt:ήn!^#p@'Nn]}sTcʐBfFzRK`x" oV<@d6QD9Lt_4wd#DDTPÔ6-;9>r'qkM/G8|%,Bh0K`p)#YAk -a@Iw Guwnjk}|9l큥^ٸ^Y+Ҟ l|Sule=NSat=Ha@"g\)L}Er֜ÕxKo9%8'lȆp吓$pYBfɌpc<.8mB'<0XhR˳ЂP兆uiԈcwh'>Szۃ;Vk3ba͒[{(w-ʁ΀q`R5!wG5_x(o)-:n0yJ- %@bH g! 8uClFGLK!aM7l +-xkYkx"B L|O8#<.IZ4 ”+$BNi>P "'Ae869,. $RӼ..7PS"o'"ŴޜxgIK;ߟ+ĸ TfR;9} 9dLpG)dfnkt^z&m-N u?)U:?aF 6s v >fBQP0ߡUo_"<޿W-:N,pkYU R)5[ڭ \L.P]ݍfJ7V!ӧWmBDg }2厥T!UWox`"Gp@o?Ŋ0kVd@ f2l^ٯQ( 8OIѰV^𩾢 CǦd;JκzV* diǛ6xΦH-) O˦, K$d#Y 6*$(Y~ͦ^̦I]YD0ŐO>{.ܨ^(7A(9zASA8l܉~0J7+1@_8LdSWF4`$HeֳG|yZH %!'<_Y\EFz\V8@<|Ѕeg8܋!XUZlEGfjDÊ*t&R .4]ߐ(2'KKasc=-R ".H:Y5,0,gX B @ r0Qad=JjMm8o##O)DTS0;P qF!:K#l2(:N9gj9?1 45 I $h*̲ԂK6xSTL4 r+ H:yV{]WA[C^x`ZAxV0w$[/ 1 :T,1DֹVBy w|j6zĐ(/3*+j%"AdkC|یsfmҺK.Ab>Ѽ0/l#*G|L!xP[CEHhuTt;Dej 9t'Ǫ0Dmm: ROjå=J.Hp8\i C5sH-&Fx"6ʙ ~%8B|ޑaCvUHi啕Y 5Y΋?a_`\s82N?Ϯ<>𡫹'-qْzab5q-sosxRӌ <`TQ"RCat˖MqDžƟ=}f&@eL|̥^l eV"p L7.H^9a,cǐ+p'\)]"dh^ ZQ =yj1-$hUÀW¾eE|iJ* { <,cAd"J1Er&(z h$H;"A>mBO*RS퀏Zhѣ  =`P .C-O^ݻv۷nʓ$ g:ƈFВ:pp )'iVF)aJ |&M%]|KcToK^ї.\rL[9Bh oăowuew% "e!n I<\)Bt`ӻHJVx1Rx )K*z0/Y_GV,~]os]քa*N]un?JkìU]vpu~!" ;L0)h#f>@mcPǬf~erp |)%c{0G@O ݅qqmGOxg;=8迈J_ćy7}Hӣ APq-\K)aa|:XDx6aeh.V25 TLPЌ7ƦJ7ON8@07q"%b4\-=;;^Jg.Xw(X{+(V}TA#nrM\xQƯ_|UNéƒL_8>cgBJ/R/=笻ae$PW[!C{I`IC'Z}e׋& AT{0pt5>^٩!65Wlx൚H.-NrrDuo㭬TOPy7]8wd?X:X}υSxA@=K*K&p:uD_ hD~J4h5pv~"Z^Oywտb?(p()3uq0118beY"0)k}T` ޘ_(Z6-@cA%A7@/pMH7qKT_|t{3D.}BJxͱFf,H VniP2j@zXhg90@Ew^ ]q4o4~5:69pX |3dmF4.iL#KꕣGap_T; <ᴾZ?9v J#?f֪UVpi)SH9RY :J%̏|]9V}[gXOfzlz՟h;l篖ǭYV[g9V}$l篖ǭYfzlz՟h` >9V}[gXOfzlz՟h;l篖ǭYV[g9V}$l篖ǭYfzlz՟h` >9V}[gXOfzlz՟hzE-*S1#^u-2u6TR+&ffDD]&d(ڒB\H߼״$rwOHJ֥I,qq q62QA͟~mNb|R[N4NOy)3I$eZ%R=TSvKiP&]4DGQ:xfTe)aS`A!l]!//(gwʵV5kΜx9㑘˒jR^JrJ>;qFM6̧ZA'yk?R:هǵ_܅NjWb.:wR30_QFQJ3#J"=ڕ׶kkrIeCdl) Ղ,u%*IDJI  ^[8ȋF;<JA܅NjWb1qg76c$o` ΝԮ\tFv Y7#{޳f>n,RFO֭uw؄.iMJ̺g 1VagIKrgA܅NjWbvߠ[܇oPx8n"#QDjRYlG!pyӼ=؃ ΝԮ,'ZZ2T"q yЄJHS-{Xe$V Mvuj#3Szh ~98Դ$IȈ{kWTzT)b9Ә;%ffx3lVVYYU F:vdM1lǎԌ-f_Y#jQb=+>b=?x'=%); Lt~AjRw?-eŖ.%Y?b4c#2>_Ѥ)R*wII o8[rZ X ?8i3#X`?AOԥWomJ3tqk/:"Z[}Tə}D23#On%[d.?~SWq%j"-Ŭc>)6_9?k%_9?k'b_ ~+Q~P5 MLUoû+UbUDl}Iz#Fp4K8Bkԥ$fI""(Ρ^%iϪ?S6 n4Viő#}B+3ы׷j -ktF(^!T\,[ԢDm'JZIdijt VmBMJi_[N46IRLqe%HlD,Km*Jm.$DgjZ$""E>>-Jjn!//(u[&M 4={DituLe nֳJHgäe]qWm*ޑ j]QFDuj$F{Y8h"G%'E2$c7dx"޶,S/xd9!I4 4#ZI{ SV-uB.Q8"KP *ջޗɑ,~ O|ce3lԞDF~J4:TcxJdVpYpYi6tKبө qSM)t$/R$hIeN!9&'nUR1;pTd#&kөq&ӨҲ3ВI S߸q[U~DF.TWPiF hnRԵ8fAHqxWh^^U>]A!MqHIeF[%< &|sƭĪUdiAtLxL2օj#3I3A:*b,ơnK 2(X?˜uJEvi'"ԉr&bm%kQw[줍DdI52D>!̤lu9iT&_}F␣IOF" D2/ MMʕ2㠢;Za:'B%F{Aֲ#ЭM4Ylx%5tȎδkƪ-U͋)EtZɴ$)>#i79WCW>-oU `?\}S?i?;p}+~wg/m'X}n%wy#OMlo͏ի&~l?+c~NSFldrr?YIKdrr?YIN(YV ;kd$m:Mr4y0 KiRyG\#v4Jͷx4PK3-. &i$Q IʋYrV[HJؖM$nF2)n<rie:~hK^J(߮!e&ܴ & B ғ4NB%*FOj ǐEĹ#doH% md|oUJ?797j]R^>m:;w*;ddth%'u-$`)AIcV/?(°IcV/?(+rmd^KgJͅLK\fdoŒ`ď4 fBjLL4ޞqI IqjJ<> X6lQd͡V$ oMQeR*pDFg<{wd,iڎhKn0%dzfdy"vDf+JuM[IY Rffgf`9&bNBPnMZ ZnSQ%kJɥjҕTRC*Q8T"{-X3(*&TP&cnxmZYKݩIVFi3R})N78mbkfVŎigi֩}o4"JML(dj%hQjedô&2 '&Zҵ6fIIb֋i[TJ̪l7#MmKRKIx%jɑ Jq@fp9)dfҜ` mIQq.8>%FdX;6\ jM@`$'VV%+JRM*JT##"22dE+fZ$ƌreqazFdFDdDg>BڦS6c4jQSRZ֥KZ)JQ»I)T7m)+miZ$IRVFFFDd ذvmtY8A~:Զ\ii[.$R*AI#Jˎ257,kJKv٭fӨ}Z#pВIY#҇S):b)Td8SqJ[S-JQ-JQl)uSNȂ2JZM Q'8դԝXDdJVB.vvQ:RLhOjqqX/"v$ &vȶKgHqbr[j3bJLb"I.fі0,Y"fG1|Kl:O>MJ4ĥJE"QiT-5m&j6e$ԣRR3N(YVW*fQ@=oۍb`d()7mOL 6H yelmi4 ,D| h=2G{oxڞ#@6[TDo-*_7 Fh=2G{oxڞ#@6[TDo-*_7 Fh=2G{oxڞ#@6[TDo-*_7 Fh=2G{oxڞ#@6[TDo-*_7 Fh=2G{oxڞ#@6[TDo-*_7 Fh=2G{oxڞ#@6[TDo"ƆcĎvS-JK'37mOL 6H ݣ{ ѽjzd{X06Hשwz4XEEJ\fC^%4H"32oOǐ`'J[E2>|Oی89 Y)Z[u+-:]%ڭ,<ԉ5%! V񥨌m' <: (5j$I1 d;qRIKdA'1gi_4ۑcpKh1fIiNfLia~Q)K%!I3J#?'>R#YD}#e?3L5.ZMBT(jeMT-j:BMh5-J<"""Qk;CBFLQN^%HDUS)FD!Ca5⣯xíeFF48%$̌e3#c\v=r((CNhui$"%`ܞxEIgX XƋ.ZiD'Y|CKJT^ \I VN ONf$V^]Q%)˦Et edL`:R-}zuUJdzK?iVι|^30IJI䌲F5W bM((Zը?b=t3y u/7gu/7g )}KC}KCAWvtD0x$-hi Gimn+ Cg6Lȏ6-.TfƱnwyNpԕ$2#.9!iHҭUE79l#/*y1e r5K6Rf˦ Hq d}KC}KCJw_Rv|P@w_Rv|P@Լݟ>Լݟ>*u/7gu/7g )}KC}KCJw_Rv|P@w_Rv|P@Լݟ>Լݟ>*XK;m*K$; kV>g)IiIeJIA%hn!E|Jvk0nBa.[ÈO>6Bij‡LmD;3QCQU}y>(};y>(}U N^oϊh^oϊh`b%P~S,.ƹťCdgJx.) ȋ'B%w9"ۧo;SՊW)n/BIKkIIԭ)=֣l4S (2)Hɏ(^x)2(JL%*J"4X%i7e)NlP]M[Cin)iFVY=F^ FHD2ut\DGefۮdF|13&qQ4\sIݐwj3wJ4ե\KdJJT򖅦J:r4ƭdu$DDNDDKVCk@5YĆjCzlQ%i(/(Q#+QXIPMF$`&=@x@Bu'3tʳӟ埔ga$.^q%5]M/m&WH2w6C.F_۫MIeF"3 mmJ[6i3]Kxdr4g-vT*K^-Jz?@+OGņq1,FI]>?3 \v)- fe&O_zQ$!\ƝN/ɭIgRcOAQ^|K%ԧ>{mK|ktMFim!Y=FX'jUȵ}pfm&&^%FIYs]NR#Ɉe/1gYwͬ["MMn)Z錙-jQd1*6Ea&Ϸ3MմTth-8DLq}rgh;X]HTDz.[^cq}rgh;X]HTDz.[^cq}rgh;X]HTDz.[^cq}rgh;X]HTDz.[^cq}rgh;X]HTDz.[^cq}rgh;X]HTDz.[^cq}rgh;X]HTDz.[^c!3j}UN1%M[~QgvKm'$O31dTUiԤYK}ŮɩJ[)Qbm" ~mԚD:y4?(A埔!}au"Swmzd?(A埔!}au"Swmzd2)DdD=kɋ%1yY8ӍJ<9##FBdH%ÓUi6\#K-vVd֭)%l#ʛ*RՆÒM/(pI!j24դ#J`r'5ʤ{Vq^=Rx!$hk uXV*ƬL}f%{jQ*2HAxXgnmF*j 3O]vg+ njLkRQnҕJGS #0:ߦ>FN[7t%8LfEdG5KWKDjXE]q8RRÍ5/[{%p4:xܹTJmIk56DZ]#BMNK;~7 1w3|Gl+=VUɈ('[}AN#EAiO;jtE~f.'bһ Z}ݥ]rmĭL;HtiQ"U=&Gǁ`4nZl[- Jf3&cgeI:mi5nеtEFCҒqҤ5&ZԖPKRdIA*'jK es-T1O4u2)n4Jr{;nq:vNI.0IVXQmyqj˃ 2^SɺNKZI)l:FfdDiri#j}>4P]B^iM8IQdHQ|xȌ T5>UP:KY)mǕ"[ZA/Q JqRA)ԅYҚ2+5m̘)KgtVDZHʴOĈǁVc|F:u=O#, +2Ԧi h)4fdA:*L4o312w4X5a9J8{K`lDmU\4PrMB4)QQ$넂5'O(7&iIJ*lsR%jr:tY <nK6{9hMq9VMu6dt'SNv@; XtћS.6|goՏ"$7>gd6c1-J@rjZ :0fLzLˤxHTjP$8iR9E;R\`0a@Is:o|s:m'; \N8ΛDm:m'; s:o|s%ΛDmN8+@Is:o|s:m'; \N8ΛDm:m'; s:o|sOB~V~g`صJF,C(OMuh(ңIF=&eOS F=n*ԡE^pҤv7#$:cl:m'; s:o|s%ΛDmN8+@Kĩ_%Zt&cē7^qjB3'O,HT }8.nirsF3^}əg99"ˈZDU)I' ZJBI%ߓ-%M ZR8I-JJL̈DjV ?(MiӍ֬.#UIs;sL}quy[mZI 3JfDyxZ*ի;=sgy8`cFS. )I)%$\O|c,c'DSdg"^u}BK&g)sTjPK%tȖJJ(XP[e6Kvփ(R_ڋjEA}vpXpN]:wxϹywKH&.Q'AwjΓ2suH\t7 uvlE$!f>h %ݦ]54&>!-_?]B{֌}!wPHwu Z1?]B{֌}"Js'hwu Z1)wPHs'h*?]B{֌}!wPHwu Z1?]B{֌}"Js'hwu Z1vcq]N[r)גYHdsxpT[a^+)8v)*gY T0%ZxlbIkWf)#υ!|$-g{KE+Q ӟ=F>뻨OzяU N~C=F>V&bVe2K4+tL+BLy<&Ԓc\Qi~\_*$$łNв3R$,(Z z!U23,u 6 fzGBaQj/^|{8148S.zۑ Vc4<.󍉱dgh )םYK>V. jK)|"S)N#D^ojM-^%G231@ɡ*ݷNvRe>RHu-ЧHrCfJ5Idǧ+Fo8wG xdzJի;?p`%lG)MHLÊ*)0Z7UTnёn#LjFp0ÿ+컚%U|PN~I2qOFR\DR^3qDfE4͍QxPeKr8%*$@}=dzw{1g7}=dzw{1g7}=dzw{1g7}=dzw{1g7}=dzw{1g7}=dzw{1g7}=dzw{1g7hIR&ʉW_iȭOƨ.M6rF2}Fzxg9x:N9hUjLݭ!9I[o2SߡR+^p7Ӟj]:jUNk1i$n7"zwJJp@<۾ ;9̒ 1MFV(#>'$J rkQ\xQKeɉzesɆSH""s}gS)M6i$tH Y砇^YvlR-Ɗo,ɓ K4?J5Dɗf%A@=;O'V8;qxdy&UVw{,Gڠߗ3ˊKyEqMm);,(̲G]zvnu:k35$zſliRZ}m4Q-j3%$JəLXQ)1## `*ZsI2M=ʒZGQ57:qn'x.meĆT+F]YhKiJJ)jQՅg:bک[<'7sS[{/Vd'MN+\}rS#j[A)ŤF|REi"NƉT@.uITV9jO,&DU6Y%I)Hx4\SxԨe)u PY3sP%)ն|"A͝[{2M cDE=堒+qLo7$NOA}iWdJU*[m"kTI8$'%$ZIk'JJ"QO/c[QWN ݳʤ⿒FY?J~D̳ &N8Rfg<|\@dxw ӌoNgvGknКSܫ2nL'ySyE$e/(ʇʵjΜ,Gsa-C+˄Z\^?".X!P_tt}iZ"LF^8 zlU(-NL2#ũN6)&d|l4J-LCē7 $> *I)&JIH%>uE*J )Ǟ$MiZ(##!Z5\E uzj#Z 'y&gx"/T˓lr}ww3ItdS5m]tAKN njĭVF~VLir\2F,;bw?9qo{otgNu=5hsȠeލʥ1gF"bᴸ{ρ)+ਏeHFiօRwLl>p&(RJ V*XQdEVm+󴮺|$F[%—Z)6M)RtDjh Jeh<]%* (esZ҉MfgAFU)jkdKa)>N+)##I$+=ڛlҥj3Zgf]&~#L7^YCa봺-SJLW">iZ $dfFٛSdԪ*mg498mT[*RJ^[afO)EKfGM/f V~{Ւ Pe8HRKTjQ$) Qx2R73wMsU[n[ۻ/^FFkQzV|s5tGJSfTNOo#lrDZ5!dZ tPʯVSe=6NdeQ]yTGe̒ry."9e&hBFD}Tr WXODv;차$m$"ɬϧܑa/?TiQ[n!M% gx٥ySFZDrg.4QUz{Q[IwdA$$dFGmqRy:XN)p{,c%FsԣɞcSr4u6j7p/tX"tTR~6sֶ_LۇY`G+I͝zϦHT䦕Xȋ-ӌpJ̗M#5%d$uĮjjJvU>\Jif- 8림/XR֔yuۗ^"u!dMe)=IÙ##e'9sZ7ٕ)0TSH$TRnQH%|tyZ^ h3L]JfB]$/[qQ8]A3ɧx?׀#uY[Bj*쳟N+N$OJ6RS2FjQujQm@mUF:E>-ɗMPʛ7< [.)5k֓ ?nut-2.8.3/docs/images/cables/mge-66049.png0000644000200500020050000001512314553676503014651 00000000000000PNG  IHDRV sRGBbKGD pHYs  d_tIME / jtEXtCommentCreated with GIMPWIDATx-tO924Re\0a6Yf4Y %lb悭TőlG3wnh~|wFR!t:a     b!^Ͽwd߯^!:NhGMIzWt]<ˁoO]l̏kLq, m=PHl;i؅ 4w5nfY?M֝uuo79(0SvWWs^Wu06eu J4]^3ԉ,2˺wo46M.ufT 6ށjPg[oq(=u/Few|PoH<4ߴyPK6y{|alnud[nެԳ<۝V;\χ)n! aH}-޳4 Z9L}> h'V'Lq44AS{S&{аe8?W@t8 ramimAۆP\ j?BZ8 /T{YG6hh^/N'P%BKjQvh?:2r4T?y< B~(H~(6Y- +MFA΍ӆ}4 zMi?i?(TROq?zBRȃdڴS= ~e/ ӧO?(""FDaFYsDh48==I܃VX~~ɣy͛vqwwbʀnB)@m~q~~4A{nq=cw8F꾳4:H+QP1s'ɀ6z`Wyprr$ALӭ׳d4ozME;u^y0l1 b:0rr=M>f_]owrG`m:Ooquuwwwv @y0>nDDOx?~pSd2O>Uv7(3.;*6^'''vǏwF3.8 k| ͣt:ЀN ! ( '-;h?q=#襋{cݝy0N_9?ggg| t:^d̗IHJVTٖ3Ij'.Gw&/ =777*NOO3_#7NSڴ< q~~n.~%}lhE-Cx˗q~~(" qttkxH jEEf_~L&_'(:fY\__x<`^ec8zݽON[TZ~uw+z⻟Ėd2ttߵ6SolUM_+ΐ%sU~D= VN_߆5I899Y|/R<~7֫lwww U'@HɃl'c2&&I|)ILq9lb#nh777$nc7n7at桅Ift]qrǹ6+\(=h?삀 h~3hrIdxSj} ha@By۬*j(EԦ4ꃵnSA2_7)H)^8KoRʃ.)iO]0Uې u hZ;E@WڛKa[V 4 @@6z4[I}*%޽{~ZQ|5^|r|tEWT^;==xuc<ڿyjCydm/Og/ qqqUHܤЏȚ^@M,O'ЫzpBἋ<8::j_70Uw:{6utӪU[L&l6v?nĉ)c}jsqzz]p4/8׽޲dypqq{W9<<}v=SI{F<7c2h4^~?˗/1 7Nc2,q??=}}}_|YgYfOȓ=:M97ŽVM.c|ɦy],BqNӘf^|xB{%uux͓Opw:Zaڌc*qR?N|F@4h@@۬~KdRɃ) slSyn<[9Z>ElӺ4x4*]lgcVTZYFMZ:V-gt?6&˹.y<\l_l`ThZ8ϯ25S)*GY`VAQ˾(l`VЮk<L_\l_lule+OsSVs+y*Euȳ*j.&(v;\l_l/˓e62}mmh]v0Jj|QATIYۼ}*5w.jxQƤV Oy6?Msω;|&@ֿe΢ )zy֛u"óc>َZ<ŽbTU[v~QLJ-E'o7<}@e\wxU[nGЦ:QYޛ.{qiM+vlm@u:x>}$Ԑ h T)'d([E-"Z2ԢLq@ h e/$o6|5~?7^ϟo?~غ0rmۅ|{0)jE&ZOZtA/V󸾾ߏOܯ? b8fZn6ś7o>֯~~^H/HTԈ2 "+Kor-Jj]ƶdFDz*noosmmo< Fis-Jm=XOCkQR#"O@׋߿}tݭu۞b׋8883.//ssQQHk{YOME{._F[Mq!Fxut̯}||߿{@ڝ-bԚgeto/)nSFڃvsiEnr@*4P˘x@AbU@l):_3Ś5wnŰM#ŲNvYѠ9;YޖkrTV}].+k܀zSy5Zn/PyUH=5bl4uQnv.M?Լ./vب/// z^LӭÇߏl{iz*:NǶk6廆iw*AguߠQAFۍ~-l?Vkd2ɼ`08<<]vb&Vwyױ6ܞ"˨E|6W}DD|-}z>~Aq|9޾}uѨ=Vh*umcYf6)u گ]:բGл|F3,~zuf8>>[/_ׯsw=z~n9#h!Yf{,mHEkAK-*)TqǷoSy}}e}_j7oDۍX/.//?G_mv۷1rmP}-K=nY=:)Oq4}CJdZ4`>GlNSY&ګQV6{i1e8_)xZ~"kQQNEǮvȞdٷ-[p:ЄZ4KRַ&bU˙UA@o0\t7ٷ-"z;!݄sldz:(stqyxRpNоP{i"za)˶meiMZ6M;?vu\E <_X ^[v/pW5/ Է5䩝m3b.cԺeZ /ڨn{A-R4A빢 j:$ j:$ j:$ j:Ծ:$@@ ԒpH-_h{0 gPP|  ca8j:$5 q4 @@VSTԁZ^-@E7h@@4h@@4 @@R_g`Rr<}aWr\GG%4tjw԰j&bmkKC;]?ZT\[WImL6l;b%yݗw<6h_f}MAG_IQ OY= $!kK`r/6kE==tt쉂WS`5xsqIEy:5Uhw WUfG.z:Zyc~֐yYUMqgq௮}|OOˡ-TSYMK =Xhp9-xq3.\?AO<>Ϝb%C|Mbh*cuDx>Pt{>pS vג heѺV_$۠k̒Kp}<^Ϝ󂇰iNj 7VXR T0;ܰK`8iðr4.󓥋_:z:EZ`# ^%l)yÚY<:3Lcn<7PUg+,gf>)pׇMl_QVvh6*ZlVئ_ n%4Ɉ?>8ቱD1hAj:vHht168 V@y7*Xv4ܾʎ hgx%htrFB?]/b Hھ r}x5_נDD|{JjI IZFA#k5B~}2ؗC~кyr+A Kh]<[ؗC~кyr+A Kh]<[ؗC~кyr+A:^ɥ-[4fZ3s~7={NY[DDA ?Z_\7Ci0W A" """ """ od=:=J77i_5.GU:M }C.T`{-A3`Hc/s~5wq.GAnVzxu BM61F {$9!#٪ZrJHvEy_04>'A\9mI}1 VJ-bW_TAPC\7~ݭ'h. .imE4s40=nMwtw%Tз<'g}ɣtݍ 4 RթTՆp:Z4Ps7z 6EQpԚa}K{X 1&n@%0v0 ˇ P@ڛ}voԽT'IP#xFΑo1O]ng*!eEMQ2xk*zm sH#-vr9pu\jW9iWok04Ƣ r`{pZmk7489IV\,oXj5m[Dhg5kjit۵{$G@ `gt|VM[|]f:΄#v`oJ *ʛufҲG3ǐP:Su,L`a%yh?oT7FӺTڹt't.k0w03Epؼ=dzbSkt);osxRCTt}ϑGjQcIwjldrEX^nkq`ZnM疚 C`m@26Lq=4kƃۗбvwSU m$|Gk&,%vZ4<լ~n_B"" """ ""}x5_ת#jj6A\'ދ,|I4M.4:Z$gi ӖrĖxޣ"mAg|6iVVzxWX=nL@ I[q]^أk k-T6v<9x_@w쌵U}^e_]gS~4\} H9;OVV[+RTiMLeRmhs{FZyWW:Oy/ڃobOJ+oL:nH#lk#0NjZ0s,^,Dr ~ojb[G*~DA{ heH;[FY-/m`ԡK4~+ RKZ~2KYOd=: ,h+@Z]meJ]l}1um+`9;aߑn/jMkӊj١[N?*XK&E@4\QilR㓢-l䙊Jj=c-lm;tԗ8mEL/6DC M# ]5VvmIjյڇKkm}>"4r5u\{ZA!w-GhmƉjz9ao# )a[*sq41Dfxlm$Ʊ` JdՎvSR:;j]tP;s`}q.&Ei^>`u0 8t>t d`no|#p{CΟHk$[GNd5pP-DvV18Z}"㧈b8Np0-O.)dL/Gc:9\Ok1/ZZъSʐї5I2q7qQZoԺ6*tʺiT:dlnp{-iZUS[ڞEIMKAS%CtfGfֆ904]@ SzTWKmWS$tTF&H1svI<'s.wy⨴C+dib~] kd/zA r .4P89k֎#}$?JGWnIkqឞrO[U8xZ|nSVRIf?FbLdZ꣌Z3ՏPDG=7ܾ{UĽLt޸QiשrD nΥOI4ִĊ*"&U{vks/󨸻]lQi״8!i+hӴZMIKj˦/s"iv+@ o_6gՇ qM-4Q[Lk4B<w;-x:@]􎶾TWd)O_0=o ϏiWaRv,\QƨM4%q oX" n?:zwqտ>r 6~}'q[=]W" n?:zwqտ>r 6~}'q[=]W" n?:zwqտ>r 6~}'q[=]W" n?:zwqտ>r 6~}'q[=]W" n?:zwqտ>r 6~}'q[=]W" n?:zwqտ>r 6~}'l~E6: Ҵ5N.j 8vyak4NX)r,$:- ZF-[ Ƃ:T2WޑE#\Nuc{CO-=0MW=d5 $#ַ'|d KJam3  \[1hq`v T}Iii9&Yi'Z6јEC cs֒pIw@sډښ6ѺhS86XsIduiu6ě6cm Dm%Q 3!XZj[4V¯_^[VdT1\mҽX#uLFopBCCH iK;4.ݍ3館51Nx2{#rRj}*4^j8#?A#$!ѷWC]k箯{f-cOB &{+yn}U 2RHX'FOػi##$| ju#7vY7HΡRL%azI^czʃ\r c<7Pd""" """ """ ""-]Jc:_gGN9i{Zo|.~۴s!DSj;~h; q @[Aa$Pz/*g,յAS؅5K˝4c{%KZ\LiW|l\VI51;tuw4c9(=Ch56E-} 5/cZZ81y" """ """ """ ""8_1H\ޠ.JsȈVG}u[nP @z<9-^Wa -=QgݠUY<c$[nh;;iCC\᫗YK[IK5H=7ER%cs;$&cݬ,i?D~Sg>1oR(sj 1-S=Fy;8xʸ䊱itk34H6`n s / Qi-PCQ1ĵCGs.;_z,Fw%4Փ-U-ެ2;_zˮ}+#ImC P[p$2 lWh;Fe^y-vU=)=kG5~4?'](_ƅWN_ƅWAf3=W}ӹ=W}o-PZ$'I|2II9k\ȵvlAwMo. [sq=k OVˊW %+ uRpOBڧ[etƢaC0YM k4jʧՉ7*I -òٜWVg^A][{uAI`lVT진= cC[y9{տ׿'PzWVg^AY&Tor:@;7&PzLn㯉m>s̻ܶ6РGF-3.M)̻ܶ6Р ;śRZm5J(]h1>]%ۭ"\)YiLZ{DПs&Y˿ {2eE-qλy./t?/j $Qj(w12~Lh,QGw12~LiƯʹ2ѠVMڮ6}5,0XqѵG^}DžnPpⰤ[fCGK f1n8}ՓVٝO#isasZr$ &BT7)-zz"KG:fm%7rOܸ4 ]WtW*G=$7H+7#-W ۦ ^ȧ I,P:9`͍sF^OֽpT{^+ᦐ[҃RȵIq L+|в+ko39+.qN6+%m%z"" """ """ """ """ h Dm }7VBǦOQ׎uPd""" ""g oDjGX|We-`e-Cm}T2w"#i ޕ;ݽkF VSEt޲xG)Tj_#cs#*Pں*;٢l8h;D񡆷CNŽ(f8hc&w*-?'I$. ^MA:ė<#~! $hZ{Z::}UQHxDH8+WUzg>(;p ksԹD@DDD@DDD@DDD@DDD@DD^_E*COke cQz_ZΉ|&}Ks2D]Im6u|5A!1eLJo;{ޜ|!" "" E[vꦏJr/J3SwF?B8nH-!je9Κ'qJ|yP4EGpBC' $@cH"u3]teҳ x5Ƙ_Qa~,ng6`,:f骠Ī \( w Ya#ǹZ }Lu4@$Z/qX).5TvntLd3@< lƢL}7,9{|xȬұө*\5nP$MDܵy*DA7;ڦ%qlLcpl[3߻$C8 mw_+K;9|+fqʡ*Hӗq$wí7Ğwí7ĞQWj8M'.g9k6>+dAn)=jZ8K/dAڞ(9kMڞ(9kMEv?tzv?tzDqOu֕wJ\zD=⟃\i?5gW>i/5gl"{UOKYy;UOKYy["ڸ7%LO576j+hgf8.A dyHחޟig>̭pZā50RAoӓ61X6}eھ(4>kTz炭{|^=\_6VRAھ(4>kTzv? 4gjHQl◃Zi5=}Z" t棺kŚo@m)6c;o]qc<d5xiuϭ\hYl#Fry9K^lQ[inͩ21r/DŽ3D|  tQAt+J[m{`=<syxɨ֋}Pܭ+'r%k-8m#< z .$XY\Hvn{ր" """ """ """ """ ""^Q_}c(v)n^"|l·a1 /o#竒t4jg\먥I,Ѳ#8s㕄LHs!jd-AEHvwsm*RK(і-W"~^"~؋CKAza:?o̰=?_u1 yuAyd Ξp{qNZd=Jm>u3T\1⺏F9A~ԏ x_+%M{QT{;نO}I֊ ؋CKOb-9.>(/b-9.>=?_t?_t"~^"~؋CKAz ؋CKOb-9.>(/b-9.>=?_t?_t"~^"~؋CKAx\AMnn~f?֬J;75]+tTٍA^Fr6]WTO~l8H6w*6nROym{O3ITZ/r\}: P^Z/r\}:{hxyq/QA{hxyqE%Ӡ\;OHYth*vtr4V39ۄ:gXOu5V [(jaնY"a~։C˲3ϒM-km=EPsbc\ָ_!JKnmh_ILgcם2;`>$ou4&$\p9|.*a]IM4࣮|t0$U{X2\29O/w^lV\mtM8=i$k{"U$->{H%VJ ӴTtuZSɷm 7E;7np8݁DDD@DDD@DDD@DDD@DDD@E)xŀO(*]]&t}y, t4:Jl{hk77 `/=.;"J:?h޵?tZ΂kS'GAW)-u^9H`$Ů8w86z>:>ƒ)vuz]l3U[bJ0!`d-haXhe⎒g!mw29u0Wʺ?Ǩ|ٸ=tPq 쫣z͛An)~#R}ӂ@?ٛRM>Օ-}!?_pb{އpF<ؼ #5ztv=)#JQTyWure ;a8<̊#WFۇOe]7n(e]׿7n|,h E(f_E;>킼<+SE~ۻyРE쩢mݼ]SSE~ۻyРE쩢mݼ]W, ?z衽t?말 oKE}kԂOap=gOeMzDOap=gOeMjDJc.U^AZ"=rGEU9ƅg]D3X]NWpˉZ6NT=ʥu Rճ~"< SD}]WAl'SD}]WOeMҫu^(Mҫu^p+V:R>ѠEڶũGh$m6ibۻ8F>go\p܄xULi[YqݤYnJ9+`8|&JїdxBj+htu"mGkij"{v8(7[ҢEAbki-F]TG&_smXðrZUutZ҂{ͲFY (jV@2cZd;KSW'U. ‰XiDQw7uĂDKJ[i2hAJaZvH2nc۩kYCe0VÚ9[UKJ:?h޴FKuմڒ;U<i4'q.0p!Þ<4`ar Ej9}??ѨJH5h<2Pji71g,\?;Dښ|cu-̂n8⾰EmE@YaFgheBC.4Y9鮷)~utz Dg|֭rDA%t^Fj+[,zx[,2ђ@eTU^)S]UIec`eQ;^Zkj*i.u֧ڻW31.;pvܵr70@#?GKv}t6S%5+s@R45!?8`٠DD@DDD@DDD@DDD@DDD@DD4Q55dVJeu> t́ ,n45cYxOquƝ)(j/\64ɖi+uߪⲊφo8H3nv]\/Oڹ U\u6EZ5[w,Ü}t뎞\/UyHI ۵txs\XS}5Gx|)&GU[ktq1g:G4dq d4XB7KTH2j kª |*8#xnK8k[<֜y v']"UOLhtRG =G1j9kM<˧$?h,ǽ%{柸&KxNy/)-IAx_.>z.krȥ `~hY_SzZvnZiţ|{i6&hYįZc͙u;YĿZc͙u(q/ᖘfo]Nq/ᖘfo]A`?Ke<ٛW˭|M-iXPY"'ZiS뵼Lc|؟אX"o>_6'o>_6'[φ:W͉yq&|1Ҿl:)\aUHz*0VsXђ|Axuthj}3uzaTR'v0s-EGޮu:K>*K}D ӳ278aˀpঋ{JI_^V}b=@u6Kj8kbk@.$c>!Էo%GE&,^nTzv 4i?$v/} [Ahq5D=?t+Eq;zoo^w^ynqfQj˕u4Q!m+Ȯ"Z6G3s6'._)tk79{Xm.@=dd7^+U9eBF=Šovcg&dgJ3vl7C;jMc/tIޏowu$ ^l6UO[d;gq0C(1sS׷G{"U'SMWv=@|/pcZrw ߨQ[MeEM$ES;0O!hvuueM<!$5L\?a> ԕw;uEo[ OO?-ic X U=j+7JEr1 ֞ Dq5rrB" """ """ """ """ ""ǦdT{&AW[pTo T(el;\?* mV~cqӡ)MQ-chZn7:(ZCoʗwJ,lq6 54 DDD@DDD@DDD@DDDAc踗+}u|KK۝-W OLxaHIW!kTN,-OI]Ww@0ud['tmkZ0@DDD@DD;h^~>ȠDDD@DDD@DDD@DDD@DDD@DDD@XS~:K!ccQp޴xl;ffS gTK9Atv~.4wLgcs-?)^; mDnM{wSCE $6y5HpF}G.Kc~ٿy.\GAˋ?G[|k^iccDy-k@w3mW,۠U柳;c0] E%*7oC1 OQ dk%Ca<`G﮶i꺭7c7%)8Gyh<| Oiih/tu6Pӽ6&Aok ';Ճ-l-3 >== Bɣit %cAz:˷b͎q4N1Hˣ [ҶH4zi$c CD],4>E@DDD@DDD@DDD@DDD@DDD@Xߪ*zuk!c㧩Ǿ!/.vUEW]+h)##.vx9)Och{{~r2?Pժ `D>F?C{]E>ޘԲ]'p#cNZ>\ڔ=. 2y릢K2Sچ,{4kcpi ]G u5TG3WNdoDC'2NTB rJږJLb- ZBo4KܯΦix\y$xxg]"ZL%ez'Fސ61?LkQ{gi1ej iQPM=Pp4䖱p%`z%[Jڈj4m =OBi@G#; \Pb4o'_+CYY?y#05۰㑄f_SҘ/AIKD-wS0rqyWR _k*.VZjPTJNY.Ò9=:D@DDD@DDD@DDD@DDD@DDM=dt,M^:փ%gLUk(jzzSi;cqxr}^@j i=z;/C"Zmϵ7usW/k[nWv2Z:V vI!2yU:b_.  .t? rwQ%Bu{~ȠzI|QOu:CI&9st-f]4 EXmEXeLzzݷ=,Yn\ AkwØ$4A~ /ҺVD$.,k$t c@k kG&nP>mCKooj=MXgJ~aR.$fd<9IÛ_AL`^edQ5$\}4EM5=ʮn%S p8cFN s' \5n~چQV5O c#KInጞBjjW>: X)i੠l #<ã{;8 S讐i#t&)֑?uM-W %Mָчob fܱ^> ()3P,VKX43U2I7F6%u1+ UaZ*UI "Vto98psi4-7nr2[?dIPggFf.kNv2yd_yaz :I]se-|F3ilq20nk:}aauTɢYFƾWmwGLFᒴBT7{p,tmJb֓K#I ڻkM&u6ۯk%HVxK>+v!ż179:=Ke-4ݭqh/&wVϫ7[j*_WwKJKm<׆T[d_f!G{E/ϯд mlizGr6qDDD@DDD@DDD@DDD@DDD@DDD@DD@=*[{.nkðiZb̻٘Wom_o_AW=44 qdM.fZ콥Y8 4}ު؆(jZqSGRǖ",\ ķڻv[9`z^}s- s sK!itU*W X/!c9^K094{:1h`Q6Y>8#\ yuǬ.&ӽZ:WDdAּc'w"J44ܪ: ]PGo_5KO#j45Ivj*n6ns(pFA$AT{]ghnN{iyLTr$C<6ϖ<~a:63W6g#iadNh[QN?vTMSE,T>I+i'h1w۳ Skn¡kaжWNq$`툐X9p;7;{oZnd2GPm p;9 'HVܧ{aJ*\aR?fMw "B;yj5L3RMSPl28s&s#n3kN p=7 m?ռZ|7b #X+][a78;f ]E#*"xcö7r-;ppZ᜴P$鮌NꚇC+4pTU+Ȑغ@X"p-p,NU=MDSIud-吙fc6DZZW EqIڒYEE?KN:~Dmh`ݖ2FAX뢜CMIOS%]S=k1pqk4er`ֹ@DDD@DDD@DDD@DDAHrdv@D|CO DDD@DDD@DDD@DDDAnut-2.8.3/docs/images/cables/mac-940-0024C.png0000644000200500020050000003034414553676503015155 00000000000000PNG  IHDRiPLTE!!!)))111999BBBJJJRRRZZZccckkksss{{{}Z{tEXtSoftwaregif2png 2.4.2^G IDATx] ?$ݝs&V"P Uڃ!8sAtY:q,8hK2gT4\SyQXe5iZ-U%~uE 4)vj8eNh$(MlJL0H֔[^c'1r]fp2c 4 'X'aU''/rjI3YŁ߄si'8rpAdo;/wx@.pksLaSp+ ?'w:T = ҫj&pD ,b BX, ʄ[ݦ+-i^=/+#) d*whjt? uKD )-DѕNՄYm|z‰H6 SMҢ=>w fR>bOIJ#ZkfMA,_O R L7c ;2Eظ۴WT@(p)cLNP S~rI [H}z>oxiWaMxK޸7|xY'v*mAv;LNPƩJ?S L!& W-`[fTZEzXɮH`0,K)aC2|*M T :@ExWѦ"z. ִl[ǽ)|SSNaRhL&ĘT%8 Z [oUiUaԹn&8z^?&%`#dII-3x`%R 9ͥgnirB~N813Hp)r\〈meޫ₅$\YFe):$f-w/8 );IGud`xK; '`i~f>ʼ#h&Mpcr(g݈Si ;3/s|eb:G$kmʭ7z`a؃Wc5y{?I(3GYиRzKَw9xԀ ;e(;.PcpЊ g|"` N+r$jO)0cc?0᠐9 z}ەZ6{pHuYuQ[u_xIu݈_ؒV\\z锿.xVVo’a»)CaȂJTm&3=!L7䄠?=.1z{MeH1?LicIobrM6B^zDUY{mg_e4!h8T0x@|3TK.P*k|Jll ȩry:a\&]pbyl lG{Z`>Ydn%;TnS̃ Ϟz Aq/}+:$Ty'hIⵗaiP8Ǭ{.°qQ[ hK_ zgs%5WsxJO)0`Ee {Ue`=fk& 9>X+pɺ ]$+BB*qyU{{TfݪBe[&L!NJ<&;Q=''t¬ʢPv@w)F;=FbYG{^w(3 ܰoAQSWd rN[Iŏ*E,{{+d/K6x0t0Þm"!= s 1p0 3{ݷĄ! ~Et̊>gɡ&e^A*>zH+P#fΏRք 5\4%6 ':q݅^1 ⊀*+$oGQt "}oU嚞>CDmw4I&n>lj4Naf~^Z&>3ɦݦ;C5Ո Ι销K{Y#aFE]lU~?' Ax^3>|h*:&&JG%vG~NRL |\~J"c]?"Vc5L9Q]H_Tej5ᱹ߾fI|o(3c8^]!Lnfa2th WUO! PerR>h#-bsC+b%9`IÊE X즫)R` s[*'&A.cFh2&F"OO{)SHJ$B:3KJ>B9cEDj4Ivin16K3]iec8Jx"o@-ce!6wI ,ʠ5\?NJp̔5dn+Iڤ;J:Tz,ǨGpjBy 1>|P ib_Irbv #PJ_G w#.WH亾U @ZME*#ER* m͢%(xF KO[&wHog I\CL=4~.ͦC*I<Ĝ|'鏣G NT_c}PĜCR/> pZgC(o[֥mP1C()\.jl?ʏTdIf!$Evy)2$L?Y0صMUPD\Cz!Ϛt8%HTqf:ce?(YB!GѸtmn![!'uOf;JCuƯciZpvg?sP[Hxfty]pwOx~a:lƉ# xr]RK,=xv |Q?XbЦ]2Zxr2jQj,mhrbYKX}lx $dަ鏣\XwKdS,hA?a*l`P󢩳,nѴAuG<~h\Z^R, ~^JnXlQˌ!$Eyp^,S1J'<"-WHS#{QK"3eLMp,ߛUu! X 76hrNڕ|1򄢞Q1$)fXXM=8XPa^}fp qg4F"?UJʦXǁJOq%+1wSmrл YvtNz|@ͯ0g!$>m%L:NA3wlf?G[B؁v3d _=a*eW>Of} O\ӛ,EncpHQ'I3zh.RIRxu@An" VNģ=Vjzb$˰eFj*rF=tNGyϏG$f <+SN5_Y tH%I-cvkց] 0@?Q£ ZIv[gқu⻮6CϘ'W4ttH%I{{0Oơs8JxN Qek)ygkvDO9LjHxwɚϘ\G ꒚ׄ&9'>US` @R2\Z?1n"/]OG,0idzpbE:~pgj E7_EXν \{4_U"I Vnp<+˒GuB~7Pm!yiryV("K]t~zr6}h;1=ҍ>8~ Ò*8^ =?>񻈛gOo\ ^2b"3lv9Xn{bEC{:(g(vL*q'Y=TzYZxgꩩQZKŊH0LQK` i]ªzhOSpot4:~gS=u,7^_x6RC#=Ӡc ,;n4nzp{q!jdSeYMDE+bE@A@o#иOFyplk_0fFyOw=8`di-ea٤#zhX[ά^YNGvݡRS1&Xr:fRu24LqfYGSzٛRi@}lR,Cn4_K#)2Dkn@Ǧx%,tU͡dg?Z|28am`!nͯ]sT xl,5[b [ǎ-wOj"dLt 9񅔎1[tCgfYNjjΑOtPq)ʬPk=6,hLrRSV8s(H v|}\tlNJtXUJƭ_!#H9[774zT E[V9ѡEUOk"PG?At s&F:th~熃Ӱ{h_h4>!?[2tB$߳o58Z<{GGWrFp]V̾2C9$,ӡDz(+\kH-mNGgA+G`'kÉFpUGg̀eKe:p S}eso`(K݊gg_=rr~,ShJ|)X'ި!@7dJnw./1A)w[+#n8g4?t~]'Ak};8C7+U*4p:fvi,G”ql|l]<9eYhädȼF6e_;VaWm/C rz߷!QR99>gȃ55љst >}.eWdDί67ѸП%VDi5y[G΍aMB(JGO-ci$hTGzkƎ &;1Af!n`mE=ZǜOg$ss_Qa,w<R t(R;9)VFnږT 2C7d;1~wO~:{i^+B9!ro#UeqRfbq88iauæ/Qܺ _1t\f h W&g7^L)Ab$v 8 儔0ķƪ~t%1wlJqMZxX2 [8((r/Vzj ȸwcB5d H0[M<`gHI?(NG}Ex89jK;K:}r3w&5kKZ+SX1]|w8W#{Z" 8x=w$50:pLnt=8;H{,m#[6vK)77-?^pLn5FmtMyE4;hZߪ~ i]3a =SXWf?VT#t"28N;'ޖ'ugeڝzo닁1O% ,r:M!NӀ);+(ԙ5U-8:p|)h)7e& p|U1~pߴߔmԗ|/y&lWj +,87bK됎in:f&ޞMBE?nʶ5>LٝԴoĢs m !Y3e97_ԴDߝԤ x6bCBl(9.sk즍B-uklN2i`'?f9ڈٔ #Ah[u[Ǫ80eFSph`ПoS_C;7F(̚鐇).Z+:lvIf7!L˦lS9>vZ: ְŠQD pnY:.p7{qX36 ɜB*le[[>9 pp|=:6v+ )PoBʖ#TB`ܰ.{Ԙ;}ֲ9YPl򈒏Sj:SEUʁ$No4ƴ&Rc#0^} IJ 2n\re$t!9JC76 R6r{Ag,ZBdd$V1u\]chsfO >i: 9؞[ Mߐ+~m1]/vRٯTښq5"ɭC ўDiWO+k/1*V_E? L!ޢryuhk!/{%yدlIq5i-`Qxɔ[9p|1eGy)i-+@+jbBs~C|9%تޤr#'K>212TolV<8v,~Y:!M*(E1s1` PpdzxlPIXvSU>?LUhyoZNB7.57 ' {&2ӻ+J)՗q:8:Ǻ\)>Y>ɼn͖!ٷ`la_Rƫ[,R&&%uD+Baj{ni a@fRm[:;;:v}Nu_eXU=vpLIڸs`K4j]ݔL?x`2|}F)Qǣ8[:Kvʓ=GePdozc/5w<L왁lB[|#BO9CB;J}gfQx=DdrBą597h3oca rc}k0z=# 9Ys 4[9dCġ.R:?uF ؞[02 i뜇tlJfR<\|EzIt 4#%E 0+1 3}-]S$'8d\(׮+uYeOxys7xYp|.]GE,/)E YU%1YmCţD4%۱Y҉klH7e`V7gCkZy*j0!)5@H*/]DfJ'ZZtBo3,!LZ/R0Ō7w 3"|l@_DyyȸB,7TR6Dc)66}mi&R?l|)I @nvwQΑeS<*]ꐅg䥁.tMq ۔,UѠ̭x7vڵ1dqlo}h :heK+2 dj3b](j!;fSW8~-oA7m*4uv#8*ZϪTĘ5E,n%l_I,W٫a 3[H=)AwX<)4ʖ/~|ݟ༪.3Yt^5BdW%(A~bƴTqq)06<&DT +ǭۄ6Ř,Qff0FBȨ#;̝ lR[-`03U(!`붹ۙbk[SGc/!HC^Ásࢪ!,R ʚ`>mC9;Hl$]ìhfUly_wZ;t$r[TV1TU0ٓYL,Y=\L[XN$=rO#6Nn<~܃~!kID=9thf"=-'x}7v,?OcŞ]MfNm8]IsY!̡Ar [ .pLy:vwq[_pQUw=]ێEփ/e*!h&0;p 'M[)s+8L~ ?'~]3t2v*6l&3ݓ jfATI{iMlXM.T=F^biK*o*H!{%C'wL<LSq8(ʎ;Km%J/w,oW<8ܠJH0t)9iCJ`(nn5G"FCfsbG)y\- DЏ Дf+\|N={*OT/ecESf00xF@qLe@WR>7 N! `_o&\ࠦ8aRUn5^]IYq![Ѹ`7F0caBKWv>Ԃȇw* 9DU pe4{ӿj+=)5O69팅\N(ήer?Gu#B\׽T*aκ__dw]K[=}%Ą6x6qs=`3u#,xEs}Zw=`o(#ߵ(:2 QcWmH(!&H]d3vwǣ FW'/&w·')=+Gwga4*[f'5MiW&wҪ;*}MoPĈ1^<}UzWk)ןoO?wV:q,8hp4K0x2^IENDB`nut-2.8.3/docs/images/cables/SOLA-330.png0000644000200500020050000001256114553676503014457 00000000000000PNG  IHDRsRGB pHYs  tIME ,L IDATx{L4n1ݚ&@ ` i;vը9/x q˦hnL4W6.k6k5U7qi]-Zf *z'?\ΡD>߯=|L!@ D@ D"@ D" D""B UtB2HxxuO~ߵWxx 8=c*((Е+W#>>^sUUUUollԂ $mܸ5D wyǫ7yWO?եKTZZM6EǏNڷDC{>\.Ws޼yl2khh:.L?&,,̮^*m=w`ڸqx 9sFvɓ'?P͒~uy=^eۓ˗/tmqiΝoW_}}}y*%%ETfff%|~|k=2C33Bs8e˖.Xqqnkkk3Ga_^_=w ~WlL lMW*ޅ5[,YJ-^---߿ﯪ*v{YfiʕRVV_qu}Zf^yX}TTTb UWWEo6mڤoLzFej;v6[[[m͖fƎk>-66ƍgVѻ |m3f̰ӧO3~Ef"nO|!@ D@ D"@ D" D""B!B@p'PN/"BI|駄BZ.g"A`8ɮ(/~ff,"r@ߘt@].\ D""H0illԂ $mܸJAoժU0`N<UUUi߾}T ?UIC￯OР9s_`&[W9rӵn:566Q֭Sss3CP?\h߾2_Dzm޽:~lBerƷ+VZ---zi&P1?ψ#Ov+55U;wTtt4C\ D"@ D"9zO!C(11QK.U}}=c BdZpN>8p-ZDB1X~tzBR0\9v옜N'= !+@G}<$`"}v 2P|D~i׮]6loG9:b&}vڷobccM9<b&qzQyyoD>@ D"@ D"zg=:<C… 5bTÇWVVC|bUҐ!Cro|Ct %$$O>`&۸quV555vk˖-zGDSSSɓ'ҥKAiwKA6c 9N-X@TTTRݻW7eOQQQ:w5q\\7D3tPvvk͊bh0OEE~_Tt:~zEGGCh"@ D@ D"(!rM6MQQQJLLTVVjjjh`"۶m/~ :uJ'NP||ϟOB1XmiiQBBC 1pOPssvܩѣGӓm Tܺz7o믿}{TX_W5DSDzM= !)X@ȺurJߟބc BرczLBOBH 17%Zv֯_~uP|@Jw`y+p!*27< D""H9s222ݻJA={~ӟLпo*Īŋk̘11c=3׿Z >\111Z`^*=zT'OԀj**3Ӊ't}IrI4j">M:U/W'z衇t9z.g|{gn:566Qyyy7nCό3_GTss \`&@!@ D /{HM`ʉu:7B$11Q֘1cTXXVZ!%X@@Lkk˵zj%&&*//c V<Ξ=+P|B5zh\.ޚi ĚȢErxTYY=$`+ &hɒ%įvt:|^_˙ fb {g˓Яnݺsu vM:>n}=ATxlРA]>hͳ^Xff%&&ڨQСCGu]w,{mʔ)&q;gOo<^#!Dm?/Z5%K숷fUUU^啕^D"##54裏:>}z/ x{ #FtHJJ6s=;g".\.kdM$@=S:pڪ>Lr:,[LEEEڳgԤ={H999>XÇWDDWаaô ***xT[[ 6xO?6lؠ˗/ڰaO͚5K˗/Wii>s}|reffzݢET^^.#3:+WRG.KYYY~OKKJ~ߧ~ZoT]]-ۭ^7//OW\ѕ+WfM:ۺ25mܹot:mٲegΜ3gZLLXFFFw.W71 &t{~G}%''[vv꿯mmmsY\\Y~~8 رc;"##-22Ǝkvկ&׎x 3f9KOOGzl޼pرc[oeFKMM;v=y^,>>޶oޫvLvv̳㾾^c(gç/|b!B!@!@ D"@ D" D""B_1Z%<0IENDB`nut-2.8.3/docs/images/cables/belkin-f6cx-rkm-xu-cable.jpg0000644000200500020050000004165714553676503020017 00000000000000JFIFHH ExifMM*, JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222O" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?~(r@ G*y:YL\ H<&2*UTqzsyc}1Y:JdTF2p9 hCsp4@'!?(\U[$|3[Qݔtd$lNʨSMuE#ye]]{y7n^=U[?,E)M[JW<]5 XMħz3+ʼn?wdӵlW97{YK %!v瀧?'g\A @̑7L>|9(jZ/s$eÑA{|mSzTύaX'#XN(Saqm{tVxZ58g w;jA!^^m%,.mGm"Fn#8((9S.4g*-:w2ޣ tU=3PMRF',kBHɜW({VB#1@}EMETѷiA,2o&\P( ( *C~Jpj3[~(\4M+mn Q@AƔoh}3%W8\ӡz( _hs#fR3ŋ4Τu}%g8` F+f Nwg2͓ߧţXg=󊬌97<Т0<7٤:e͖?7-'iOGpv>{ςI=MmQ@{\<)pc.s p'#@R/FTEfes ͻvs9qע0z gU(#* UJAhid(`nd\n9Q1EAigm-G@YԚqs$WC>c@ T€,}ڭOzAXwy>|@׌ d"秵Z5 oc:<$lP r0O4l与#`%FI*ƱҵI]BKyV_!b1 <~d_]]'f.=>Wz$*8Q?zȷ>K}6#GxtfG dn_,}>:~xbM>ile3Ii6# ԟk?]PۥByYn?.=lnS?o?V8W^ԙeV"!(Upv峆{v_ƨ:6xDyb_<`ciEQEQEQEQEOs=4WQ G=)0Bvw"B2l k!_&Wd18Ym;K:oA1|qJLzT''G~bf%Cu G .WO,Nr }ڮA{>j̾q~S?XmiODjXЬ˨JJAjG##PB?7@V"bZW* qs~0wunZ 2-q G[i_o*׳Lr˂/Ppz35od%/"/ rۏ vx˨le(KIB"q'q1D4{ڼqܱ&-`9r OQ@vMc38|봒@ N5ig|7HٍR=$rR.@##;s^~SMc~1J?_q=cghq=cgj`۹5Gnhۏ?U,u}@:<0h#=:?H \Jn0뚫F!\$9AkEQEQEQEQEQEQQEQEQEe_M~vqn?#A g}{%Ϋ%岷4m,%2s7nՌv/tۋR;8գ "дi0Q msMhX:}!R. vX(+6{uXVC2`zlVgAO5ɒ Q'f3:hQECreated by Daniel HarbottleC  !"$"$C"Y  !1"AQWa#2BUVq$3RSu57s&'6FT48bf ?ݱ[2R,< RT)aU#@xw5곸U( 67!ث7$w҂R57ko3ǜF\ IvoP~#$;W LX2\9I屮=ԣV]Dm?ŵJ{ˋJ:߳ʾ m-u.28qhdoHB%>@ξd9W!0Ie6L%#$ZC]9.7O{;\ 婷G666GhCVX[CWu}/AHq lxmot>{L7ٗ z!̱uKmh E#׸5_:Gz m\|L0UZxlUᤝ]yq>?OX]q1.692U] WQէz.#qɗUM>Cj!n|)A)v/cM#_2/[h)6'iO1X'`;_tORx-;8-BNrD64vHګy>Ic˺ytFZô`up6[Ѩ N!u:UZL)fD[܄v֥7>a*#U!jŤ4-# cC*ޝZwP$RIo17ԌA>+y\'זeK8ڊrAh (((((((((((((((((:Gq.PB$)E'w(((((((((((b9t7rEwDe< =tZRH'[>zj)J)J)J)J+ζeǜChOt R R Rcˋ!bK.a SJ (%@yt}P{RRRRRo lKo0ZǸ"ޔIw3=LmkH l/~xi."% ~(<‹D(΂Vu=ۉg#@"|˕б :6Z[WD G1H}nLoeĸW+%#%"jV! 9ܤhwSI%\ǘ\!4 y˞"*b=+l1x9-ԇQK~+$#ziwATb r^0wD"J)m(ƕW+^s77+CjL"̽"|%)? qC\}TkUe}Eɲz bԩwpŠ;ڏ*κŃ l1#ܘIڣ),+eVJPNu1mpz-1U3TS%-i\UǕ10{6$Ɠ<7<$qޛ$v޽^ݜ6[79e˨KܥMo" CG~J:bxf})x4vAft%,^))I4 .*b-}ˢovj m#eMA]=g}FcoRK*pDGEFe Uπj <Yɉ^z}1M"c %kJ{ﷷQ10+<&&(2 w DUa#BaP5"˭d:뭩Zi% hywV5d>qHD;ݟmet!D+-{IՌ2N;!6GoPc21$|V;s//7]?nj۶dÕ m.)!hX4It7wuSTn6Xov;4˨Cۥ%-зo;#w ve:IY`.0ݗkhL 7:Wrv7^_?/R?Qx/i&Gmx)>ےVJR@ڎN7cr +oAR } Arkv6"\_#b<4N-\}u$h% $G 4~,.9g"}[*fn1Y5r~CQ(KRN=Ab/,_J-0}3/Y!6ajuqI{W,*sZ&=ά8R~ݵsm@Ex'w+r%JD]=Nܖy+arI"ga"JRJRJRJRJRvgaaV!(uE◓։=o?3k/bNfis-*)BJ@W^\tD{o?!kNk8|KMҲXʭY1Z)IBy'lcz}U[WmC;Hc +JKN<އz ͠[r}3?pRਘQfM k*Ļ kCŞ*7ÆG?ԥ((((((((((( nYVřu@6RzRRRRRRRUO38?jT3Drؕ|zpqע"Sl(qkaNq=AqitݕfVEC2mƃ79% ^jNy%9wH_}v[/{WywP+=CןУ%=b=#t=gN-%%;Nka@cFт K3|a&Rn,Nd!l`*9V~YCR/$}}=ҳQ|͊vpF}ܿȯY,q_X9W|讲0vAZ A7lk3[dY%RT6-RVғub^Ok/=7[Ȯ5q.eZaW+aamm,IH u\Vv+dѹFozyhs[KÅ"Wz{x^ #UՋJ[8o~Pj9Q+-/pyW_smd|pуZ$-J7Dk?fH]Og ݿIg}2O F^S_mɓ}RYRn!ŏ2ꃭn"UתMǬ ;Z2 ϓpuoJaGz;m)aD(ٳ?\yEӑ1 N0xriuD6IIYXb۶; xkSeϵie:˪ߌ)S %=6Lw3^.)jq^3)@ @'! N΂Grvh,((((((S2Nա#F/8r?n,Ty|TQjr2cx^ryŐ5u>۠)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)@)ASwVʣM+%ؖm*=JXuȋᯐO455RG[H,s?M˸u݊xc*qW;S~Dd\]+7pƳ#EceNJmuܑ Emm ҐJ!CʏTx?2gmܻ&حKԥN=) [,:MIMZs&y 0s\{θIS(a+Z$ueo#.ɓ[md&Ӥ̗4aa]qy=Me<͹lrLwyp!ƐvL#@zkJx'(6)J)J)J)J)J)J)J)J)J)J)J)J)J)J)J)J)J)J)J o_UN7 u[(+Y>gnm-ק:ۜy/)#\pg :BV87PU]ȌUJJf$瓨f2c -R]ynB>R'4꧉< ך1s+RfL~'J Q :#Nh&QqA۶Ig*9('h6BO2#k ѱi_:oehLm x-wJB I:l;mw\g꽂 ZLw^e5PCJsA6a%\Y&^_^Y@WBqRfceM\DDI囬 !E<JA@'wxl7$p ud4 6ʊ[IP椯)Ǥܭ]\d&Tu!iwJҒvN?PW;ev~$1)_ӜV[>ފJAϘGSEzRƴEG?;quw89lܔ^y%A:;rbmrmBMR$~J un Rq+F|hn}'V<҆{͐v >ߞ(RV()*+ lle(*)_>)_>~no|~noR'˦߶A=O]$bP n^^.0P5ƮmEB8^aJƴ;nǔ:JW,8 . IgGϷ҂_F")FRHC<߿f~5ǾAq#BGLIH|?ɣy%[{7|M)~8 +YSIܓ2ީ*pujd"n2-K㋥D $)XA*һOl+r[}ǐR$AP*.PTA'Gf{MVz)*J[IrDWCQj$ނJRU>͸ۺ{skGQd`Y-vlOZlׇ̖omV2Z"\JPpRpJUsG-&v/\.0gZÍ6S$r -AGsOa#XXy֋{ ?yrw.gpcH_U$w}dջՏ>աRg[qV*ZR6pI*ڶuc CBwpqBīCzf2kŲ貕z]!0G[m*Cp)Z˒7[C gq'ȹl7;)!*\jCK(Rk1B3yej -*Gj!G%r ٠ҔRRRRRRRRRRRR^:2ޞ٦ uɥF,$PoH'@ꥭ7.$?RQ)ԡM6+d)V{T]V72{ '][c)6 2TT9^ZmIE HSͲq1 H$HvG;6{&PaֻVRz$G3o}6}vϬc9k.%$V))!;N!lԫM)Y/w._S D xӥ59YvZ$7sS&cQRpe%d H \e/89)E>#&lOg6rGNj1wN $?H$(uăt3:O٦ݢę Ԕ;nx|T=+k*铮)H*/,%$@CQ4%>ֻ,"p(Lp$O ceMwIHHح'ཋc$J'ɼJCN:Ð^\'GrTR\>ݝAIfrR}?;:wݽUGNml7ȺJ\(~g}j"-3#eO1) -_}[)AS=4~?_OsKW#lO}v62^?U(*翆Gm9φVHE@{^bsb1Ԭ!֢:@)y+߶뫊(mKRA@IQ&WyɘI5+i}t) eSاRY{l3 %π$*VwqvXorL21BBHBh5CV);GysP弛*e%n i-AIRV?y>E.=qn"47׹z:^HJR;I>Z"uzYq eyEO .X -.>%aG\A׭?sۼcwdxTVJքrWP,)B\h1ziX joU!jX9 L(68loY7r.Qy [+;>++;D{l!%'GCjKE[ ?U3)2-]Ab˻Ir:e1[7v|8M9GRWuF͊] cTQ-Ch%(sGg]P^JP)JP)JP)JP)JP)JP)JP)JP)JP)JP)JP)JP)JP)JP)JP)JP)JP+Z:}1n{P$6ѳCRI'\~zJ +XrzuQ ?=A:;ɋiJ+IY(-#I탳߷⫍(*%/K/|[ve(*%/K/|[ve(*%/K/|[ve(*%/K`DiwIWGO)2VҔY(@?k5*"7[ŲGQ $<Ҝ^ɪMM ꫶A`3-ζ݌Q[m,s QGۏ"uj_P9%V }˛5Hv2$xngE+INvCe27뜋K-;qq*3[ #kR)G`$'gg aU{.6[eS!\RR7ȃ ^WJeM?'2( d+7V:Pl =lyVM}^Ua7)mʋ:$G Jc%+e'a>.]n׌C'ץ:j:!Nڏ +`tChTȼ +q)J;-IO}k7!m2Y#boz/^:'J`\f$ZIa= 9dlE=>c~?Ҳ^q҂bq(yox}VBqjw\{H?Խ("[R4q'A;}>N[yq޵ΥAz -kUp|R=mu㖷/Ӕ )&{Rc+dڭԢ5y*CrI6kwπVZo]:NJި9RYYvY&ȃo{nJ) -spmR;rGv3nqRASK)%JI(((((()=RmN ,y{BI-jWNuAzU=Xng;ir\7^D>-\TTy8fo/9j^`ˋ.iG()Pruӌt^'YgG/ݡ5oiIU7ŕlA{Pn߬u-ix>3 YP:z_PYSwmy|ܧJ(,1-$qH>z>fzdԐ1%B m~JK.%aC{IF/tE]>iEZ!%+'A^鵊v3,7;20r@ ]<}ޮ#+u<r4"-fYS4fxЀ~R R׀xz`j+ }>O5FXԀ>H%),33VTsP=(1 DQiO( EYг$z4f|Ѐ~PFd&(g 4 ^Xe9Y$3ЀE>Y>h p 'ɢ)Y8 `LtN* m@|FLp8߀ZcJehWF@hR#W,<q6+Ky` `*rط(nɈlLɖ8D?,M)4Ȝ%0gAPv:D%w!,D%pD%2 23@0"5P$%4!1`pܺ,ZJ&IoXO؟Pȫ8g!iqZo Q+T-]>$dCdTzAToo+[5"MH'[ouI'[oUIV%[oUH#[o5HӺϭϭϭn:Hd]tu6|QslQ͡fC]Jt=Lj]R!<ؽDB}wD.s>9ۼ҅: 7݌0rqLIf`I,%6BJ-0ßXs: ە1sbbA>4iuZNUm"Z$Tb+!S1 LTGƝ$+!X HV2BiX:5+4)pœf9ooz.s>,-#6Z#lǚӄ8Dq3>-D O\O\ODkP~XL72p$kD~''''D 2O\O\O\O\OBٌO=.;0[H}R:jֲm_5 m{6O鲭WM;A~Iwg۲:y;:~ ޺vkmmu iC VզX%Fs}aϬ9jbDF XDiLL 275f1Tb+!X 95O2Bdc$(VeP2wvjQ"GexCoTw;oTu -XNV*x0ַR+Z[@6Xwd嶇AMHlҤ u5,{I6LhXG$Uo3+::\h|3G^2DxpqFE`ݏ|w&EdȬ"D"dSːs {!w$BO 1"dVLɑSo3&ECɾȬ"dVLa>9?; G{O>BKaw w\7.Tt:W \'}|̖. %ǸNxȲ+֕!5G5Z9F|#Up>8cj5Xƫa1LjKimNe*V j˦5YVytƫ-gC)! DY.TփMQ/EZh/km9bm" *C,~Kl^ǹBjkJL UA@H'F'5"F5]O-tc]?ȵф_ [~k1L MFwoAky]Fwo C.(_D4 7KEJW D0^u.^]-O〔@Goh >G^ Tn dSLPʩ 4;B~ѿ|nl&Z]FZ 1H4._ĥ  yiԫ$Z)ªN x]riui]KX ]˫p-:hwGyw:1tc;ݥˇ9⇒j8wGyw:1tb.Qv\)[~)MJҒ\mT-Z85=ƼPؼq).ܭA5mj"AJ}mDFU\Wd-Bni&YKXdVC3OI<ׂV)B-4R,XQ墵YUh4 g(8Si'IPdmsΜ=;tc;twю7s6VH'97sEVݲv8䉗'/rfvHh͡aUMSju(K}BOۉZT{V/UM0et4 zPLkI5$Wsc}912)2qNf]@єS2}ԟ afGeU~=?h߾7*yV[O|oV-)DŽC "Fae+;[+CN6(ID)j!)H'z}[iԅ\ [hIk':捕:"h-!c`7lZ)vr]4aCi <Ԇ]YJZCKPB*4x }!z,: 8CԗVu)Jp5e+~?[ά6)ZA C8j-)SVI 1W@Ocm4`V zE $Xmiqͩ#xU=u j[{U ]<8mY{*T\R0%UN9 &!&[e9+XJIgIB4`!HNNy#B3=djY5LYsgѓDP否iՉ$4s(ҦwcTzg=fz3=d93[tL@ߡУf.2K >d*%XuNÕ$A^rUx8JR(;B~ѿ|nyi%ݭB8)(C9Ej%Hĝ'i(z#[Yko(z[Frk]\k]\k]\k=\ḳ=\ḳ=\ḳ=\kc}} uQ6[󓋨U- R1v~ ?h߾7B<~͓%Чڔ&UxhNnnv &yRT7Pfl}nlcyuu[Ugz<Ժ2쭶A60Y{Vn[@+E$h܋,DN=VC"Ҷ@"a.Q--P;Lwa+/YFp@RBҼe(S/Ҁ%x؛RٶnlХcSMCU3'.e-54SUYmWmx^%+RR(8+Z$'>{eم eKOpCMLKYm]hƇlE篝J qF~9:i*ЗfU-fI$0hk7s|"DM.} ^+ע|0i*7!@q]o[wiHJM04f&!$XBbkx@y. dl"\P qR8|z!eݐVEm+u6uРU4n3 (Ц EݫSÆ-I%WCU7?Tyio1„.*Ҹ9-vu>QOnGoiF~ѿ|n0C,!1AQ @aq0P`p?!Y*Qнk,PrFqniEuB'/ ean]O4ؽ[ f) ?LRUEBD}hȫ;I}8 N(\5s /iCSQ  YP)`*CĀyv^T2Md@, RG (d[Їuf3qjEaZrđ eL1b9YՋtN:DdC "߹#ĕ*Tw}$8p÷! ɀwvwUUUUp2ۖWiΕJS[FJWaPq`!"EI˳eлXf0x;PQ-EƺCWv0{GVXz$F;_-: &_z0 V֏oHnl&7= 1}Z&[i{q|na{X;@Al(}kHzSEF;_/-$p;3Ԉφ6SvX$ A| -giZE4}} $˞CP2M]~%/v^c6yE1'.D~ [{z+`a TedCtJYpV[I%T> `/Qӡa|lޡgƙXk,]M/!ؓa?^6/:T$D?fPLa NRUdc[p&x JI MEb.>e/Vh@86d-2a k ZG;;{4Cq(p%2]C2'`C dCNR$&ZWtI.A8o)1(iCBv&J1'x-LInRte"6?zGrH躺֗ /RY$16_ D!4&*a,_}I Y^U2}a|vip I$I$I$I$I$I$I$HI$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$ $I$I$I$I$I$I$ I$I$I$I$A II$@$I$I I$ $I$H$II$I$I$HI$I I$I$I$I$I$I$I$ $I$I$I$I$I$$II$I$I$A   I$I$I$I$I$I$I$A$I$I$I$  I$I$I$II @$ $I$A$I$I I$ $ $$II$I$I$I @ $ $I$I$I$I$I$ $I$I$I$$$$A$H$I$I$@ I $I$I$I$I$I$ $I$I$I$I$A$I$I I$I$I$I$I$I$I$I$I$I$I$I$I $I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$II$I$ I$I$I$I $I$I$I$I$I$ I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$H$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$?s?s,!1AQa @q0P`p?lL@F\H#cԡd%jl1*\N9h~J{ QBt@>hvS&PL ܣG%#š|" 9]uP`T"#S'@L<D2LӬ$!R3Aee jz#$U% .nG@C:*{*=O;|<]^ˡk+C=@bB8.PP 2d!3T-X7lgdH"ZlRبɾ^FB  @7=A;Yf͘ c]g]g]g]g[\ʇh"B;_} < mgc;X#UW3:-]$HH"Ԇ,2ނr$a:m39eB] xߪ  UVU2ƙ6 kOTz~Y6)" "Jgl x e0wU3N~ϟ/3@ 6jpTr~F0 ݮSoS*=,i/j:U{f$p_Xh |M;0z*xGݢfAzMrZe2Qi3N~ϝ3-H% 4%.)dɿO jy/簦)CNq"nVȏ79)H+zXLH@t jDt'NFiv~xH ^ 9jAhlބMفH@k=¨QIT*Sj5,r 0M젱rqTX;;YD*cNK S4*ԁbň&:f@@?A"!J*@ gNƨpFILnMsEL9aqjCTA5#" kv2EK`I/"@e1pEJ$yr0" } SDP gN:tZhJf \A f-KJ[ϭl}S v4g^7s8wIn52Tz~Y٧@+":$ɓ =) CϊT/a^2dɛb9[:AdX+g-#dOe8F&`Uf/b'PSe65:Ǚ`Mkm?bLs:DjF<)DTgԤ\9#6&/Q,91sײ.{o}.za,j` x)ju3t1i ٪\4Do'NtSq`J|2`^hG噪T7"4rx,DA#y\~H]@=v˅R@M!GLfD5G1:&K SjNP"EEW*Bc߂HZBa6j!"l[5*Uk&hIfGCjK9\dYR79mn}]QDXۚE{, jHuίQGcL! 8|F4ސf99]mYFQ"#5"N,*YVj곴~ۺwnڗp]EFUqD\3Oو@Ɗt)HȮBf㈀p gq15njT(zczr@ݎI{o;xLU>,(Fq )WKB^ƭZ!hPƚm(e:mq,C› jN&}k7BŎr84$*r#Yz9'‹SDI\%(ZݖDZPlu, pP2!你@ (+ ƃ J&Ɍk"Wcmq -"DALӬy~Ҥ19 a jsC ?A9H;5:Ǚ,12Bd TFzc]@ 6ߝ_)5>׫@W`8E&+}SA3sSy?ᩕ9H;5 81gtaTe1iӀ44l8aLfÉPE>y:|;ix NcQbVgO3sS>yT>35ߡ`^7:nut-2.8.3/docs/images/cables/73-0724.png0000644000200500020050000000364214553676503014241 00000000000000PNG  IHDR X tEXtSoftwaregif2png 1.1.1,!qFIDATxole ӒhL1p&E0!A,DSmǟ8}fjLt tfFH(F&Usl!b2+zO_: M"+r`Mr+9pܕ1 49착J12uإMmj,c?3gˆȐ,R (3m  @) D"A &S+B Lq^ }Sx jɾD4!OV#^ETb,ut~pc\#6 DxD k+?Rx0^͝dXB18K3ކ?Ⱥ?"[A67F( +Hۯ]ٲdɠJNa1Hln4@ o]|o)' l :{vMDFlmZft}n)E ѵ|:°p[ᘎD " C|ԇ:!?l2 @ @ @H*^+Iue("qXUK\E{a@ !x :~6{ qPhseeG@DV+,,xK1pnY1a/>*HKVorηƓ(PD洲W"'zU}Z QܰFJ@HS'!5pFH@X!E-Iq"+ڽ*bK,3P/y$N#W}(YuAýA_W(]QEӌuc4#=y&"K+Ly i5b{l?h{:a`c v~y8p?P5݌Vfi- 230@#$%1P`^y0 $k!K/x6 z׵={S׵={זHQjkS\ښ65ͩ 'KF*yH@#k=UzJX~V(: =wsM8ɦxϮ+6]mMJh' xb n$YekᵬrNc|g3;*gjdUlghS->SX/kퟱ5ZNieUΦMSV64o7Q3{d{d0aK\QLk<,X׫Ef9ıcwk 1fRY66ɧ%]X9枬W&}RpSjxƃ̉dzi+ҹ5 u<=[! Ɉe}4 ˁQkszep3MSøm23r?v}u}k_.>]||Ă]*x^[75pL{ 9+ Z.@°+ݞғ,u>Jl)m<"ۚ&3g5﵄9:1b<,Ȑ{dFn$"Aꯓ%p>Eqcr5SXk0 m3Bיۇe1=߸s Fp7>^?v~zqQh3kc6uDl-Ǭjg9ҧqG\&&-I"_#5:MchsSk6}O(!iN>AM`ާŶ%@n]UyشCfRL9}_U~ߌz8zuS۔\nb1ţIh.;?*b&C- 8\m+fPx&TgV-OY;B0DSFo7Cf ?vieidIm2eZ6a5juǛgPi!VNIEj .2`+rR:kUzڋ՚{7[銳w8p*U}?uSønL6owaZ%yz-|^_9@/td$.ri,o6U=! m~VAF8eH-SP"1ͼ&3p̈.2=߸x*Y!ɽD *\gę> ͹*dXl\ c7q[~߇W dwV8 l Ul Hc(r"A<2g`,m]B4ŒKˡO 12, &bjم vɢ$91 W4c!^Q5WC QDDha\:9gX!L @Bާ b~26 B"{$͚[U3<Yiu1d1`(aPL<3,S\GסdNBRףc^k)N'Zd!s*V×d-?B[g %O D\Ĺ2*., a\ ɻcF,_VEq5  `ho!`9_XDEQ5p"0Ӗ _0!1@AQ"#2a `q?$x^HؒHEA/ ]!ژZ+wroJDcu-]fSfQJz85IkHÏI\i^bնYMP[7aC*kYs1kOBY5.LKJ AId簔Z]V$jP Xȉ!'!"1@Q A2`?:&h7ToXaI1†!L 0]Ґ b NbVa#1tZ?@qYb2678p~}"2VH2=h.^k(Uf0oqF?lK8b[z(/H0Ki?G !1 "2AQaq#0345BRr@bᔢCSP`ds?3W5u GKr, T׹lB;|qו}ok_?Z@dw-k]皾y皭&a2)ˁPdw ̑vMe,3<]ᗎ&%Jn|7x0)vB ( <ɽ,Mjv*aJ̹XGea¸|4[V!1N%0[[6Ř̹L}W ~0|< uS>)nXB;]C.O`!sgb;7n:if k +9I3up93]C7.^}]9-ytbb,a %ǎ˚7\*oCba>l pr7aJ$H>ʋlT>]vn*:ބq" Tސ:~M!dѝ{\,# Q~>AX|NhQ$쯮3+W^Lצjׯ}-zׯ}+zs_Ԩu0KQMTZ@ 9F,T!:2›LWZyIA]k"#WkQ ]hX]`.Sޢݷy,+pҌ6쐘galTE)HVvLqr(+qu{ !'2u r&(4 p4c=sN^師12Y#˕n*/DzIc3h~P 7Etn*HQ×EX؎;=4y[ʋh]XXH"]N4 pK ia'TJ"n[S;'hVr|o|pWcRo2#ȝQxFE>"l: SV`HQ _I}>r+l>?w`䓠t`O*H}PTۮ|oFBυN|2 z+>#G:Bٓ%PY-f ^wqŻ^>?+&0#LʺEbiTw\[#.nl>?&KUt6`T_OOh4D DÚWٿƾz~S_OOk}a }a }a  !{0֓/nx(!>A$gG2,Pճ#rK_U:ZA ]EyY&U*-)!fF`:}4|{v_JDd=G'AZ NFGY#\^hF|_QxS"红{%L:Ēm [O~m˔ '4&{(܉93/$x"xl9s:S>@tiz0Cnʛ&Nn4NyԘir /J3Ǵv~E6{sz RqM!MXt2;'$ML8HQ22/|4K(:*}Ƣ<_/ (EʋT_bD[ldL%L*K0-?^18xfxEpE H'\3pT2YV9 ݬG`&3IGJu9e ;Ǯb4mX7ߨNjx 1/I;lIȘFs˺*HpXp~ݒeFȣa{<,XCs NFGY#\Xy7*͛\I͚ٺYoͿ}QxJ<lY%߆]XX_r<ȿS!"˩Lxlʧa\VY0:knp1x~_}W?Y&ʢV>xOy i 2F9^t\{ 3͙!`:lུ9{s 4Hx- TCkl5ϰ6Ŭ}hEP@͙TTGveI{gЋ|jKŸFŧ[ 4Ӎϟ/Ί܋"4U<Щfn͸W/liY)aj2Moa7΃HN*' / n| EykmVfIn;/ba7 |`YL΂P>ԛXj÷!sKnht: [ͭ3s툃 i4w> Ánٟ >?tm"|KmcO ﳠZ ֤勋D.H4 "XF Z(|!Q]*lHpY=]H㥯AY =TV2STh`۫N1אַr{. p0qӸ,2t!VGZ1!p_,y eaSe#w"6!|H:C \ΫczڧC +74tY#+{)ҞFȌjy "2CŪY6Q/ED|8ɘ4N}j,B%@QOXero^zOWi`YpgxVJWHT)C]n=tƤb|XTwgU$6B7 ѵ/OG oO#pmEg*f^ldʹe!h:͊&E˩#q= O,2gKfb@:XP|Ր5]O³&?#MaeDf %:)HoY}z@C9t9؂gڬZEAF`?VIV$eB/̰\Fg$2]d דYRg U$^'ٖ9({;XYTX >;&oKAӴL{5:Tb 8] q:D͝,)`TiE(/ eq,ndF/¤Ko"*G<|ɰFGlֹ ntDs#e= CQc};K%I#U*t6:FPﮂ렾BEҎQJ:Նf CoFc<[iã^Al02e=潲O3F5R[*ԬD+.WвQV 㰓O{zHDVTN6L8Ie ǿ&d,{M"gSU[ G̮B;(42.Fd\Fg$2]d ֱM<;f/{vG >2x%ia{&N=+V5GcbP@sT}\9 RHxbf$̳dx/@8|j? +™G8Sb𸹕0's:CPtD,X;.=ٽ4L NdjWR;!\`$7 6|cfSn]zJT#E7cՍ{͉`P#W/4rM1̀0r9Sj\3aT 3n d.wL4,kvzeXY%q65Y(:pfH0у0vzC>'eYUF쎍ҵ,QaH~֫[Χh!@"&:dEM"Ydjر;0x8HWk{&6u!\f/3֬9^7eA@аh7ZkYbq_mNAo44AĠ"&۴5}h~8,LN,ʁP _I?Q l+͐>o>dYb-,J ^92%/z),asԌ_h!Ào(SP%MhQx4fjƪ()NKџ, {Tv6ӄ8幫hcI17ېc {=J5xs@`$$j5+wWՏei.&qW Xwo߯ g{IX# ݃zs`6ک%2#guO18ocWHoGGe9,yw{-z47Rp-b5q:bFR 5i|+FrPH:trmޑ֜)p PP ,k5He]#ne ^Kوn1&yw{U`IۻG)ʕŌWm4^tu#`1}p|߿  ܂kU@sWrē#0S8htc#_I85*ʸHċ6_iCU[Y"S)]׊WsƎ7LngA@.DAu_I >,AM9uh$1KjT6u>o;իpn}>WmH_~w l(_y"4ۚp_{j*fkWa^C&]k_(] "z)꽩W ;M# '>oF(Ε&Đ}_mWU??UW_?@IDALWH<;j/7+6NK(n+m^arO4wQwCӧv9d$`8 '=7|ï&u:ǑN%A꾓neBi2 ౔!>o\ OߑV bN@&;qWr,u ^׭Ԗ /zkIRigi:D޺p CT- Yuq^e`~fbpO-f^s<<;4l ܙ8o"a*~䫷Ṗ`&ט3'e.RF1_I$ ǰ8(6pGI*4js*6n#ZuxF?Cөo@(5nunP&YEgAKe"R`qFϚP#[R2a^b˔W*%]"GtQ1$36{XO|aѦVSiYډbG@*,a,uIq Ns+Cb6oFpILnj+\ Й28w]Jn^Q7/ik\ׄ)rE>h0-Ђ3(F2͹Hgw6} Aگ0`C&&'SxI& M$&Bඝ @C  ZHYo!#@ ’Ҹp9폏$P9buP˂Q]BUo{ަI\r(`2\P3ߐG$3/ lR6Ӄ* ŐMRjM$W#H,7.*%7JBӭ,Y@EY'C۽*UXFɍ)͙E.Juv@$ڻw Zq) 'GNL2`}~Uk6lzR. ['PD %oQ梖Wo*PmSx&$ es `X sbla1 Ḩ,K"jj0P/"[O|KtȔYnAwtj 2d l0FPqƵ !%lVYȷ<֫Hp v963eLqQɅRЭ=C`PBcOSQd5ַ$0kJ'*t"I?8;Eho< ?Lr'°[{~TqP3A\jMec 7 ERfcfY,͂4Xf[8YG"tIDl"'⤋ vWKۍ?c8[e-[~(ȭJ abF0tZ`u l LX"Ḧ1r:mP-H@8PY$8[^ʵT|Wa9 <0 0<*E0!nϽ_ }?NJe cJB(وn4~f'g 6_D6SCpe=ek,c&!1AQa@ `q?.,1;2F8֢"oTڨb'o sK%Z !㎵ iQq~l\$@5k ;۬y=Fv:2=aJU~w34Ⱦ(vVk߯+ы E;䆟jt1x,&@3tu0K 7~Lc'0ɾ*!1Q Aaq0@P`?d'5!|8t}N KO  aX*00wZwB摆owߥ7ǚky6v.OƢ$813F/:@1 (XwΝ:tӲ$:N%N7r)D2u [O:0]!8t%=DxtsYo z_:rH@MBv6T@L EbLN Uk,mc4fX^c2DHD/̯ntv[- cdhf\VBW#_yi!6廧^-P\~=D- YO[ˣe9LƪBOBs4O`nt;Zo"XwCM$) _ ?9<)ZY]3|ƅv3܎.3n4"-T70Z bc?> Vw4Щ ɓy! 8 !xs 7 [[ L.[bayhe@JHn d({Ya1NWO[ˢCަHT5 +*)a9'7Xjcq抬v;kjMF8h)N)+(QpmDŦߵ<7ȒE0@B@#6%"kZj+Mh"T6ж褦 .:'6)e4io9fPvVBW#_yh­h !I!PS`K#>tuT.Vc.Ы! t>6,gc"rP̈́ cS[1_'A6\3P7S2E2t'J8|7S۰}7NaGhb`-:zrvY-wPa2忹6&[޷b" R57:#Sa58{=o/u+!v1\Ĭ !:QqѥCwB&zzZW%!J k3 ^&@%Luz&k$&DsZ &c+Ý)ѷ|iLTreia&AMz_6^% fpRwU1NxgV/_"-rzZn`rA2!6p؅UBx9qp]!@t6ZT[!qɥ +KFC†1[|ϥ4_Y% 4 d3&KC8`o/Zi\ IT`*МL G \9kpz_p'̦ maMRn8rz@y>%e^e_$el+ z_$c,~S&h"r:ե# ۻH{{6dy~2i@Θ޳P RW3 \Ug妭7 WզJބm|Dca%Lx)1toO[ˣfA\u^M+>@"U;:hAу(dɺ#F!MιyA GB3O%of1P89YW.\= СWzz]4U6APYagd8PA`MqTD2@콡RL9)Q$La h'c3wM~ǎ ];sЎDm#8QL1RgM] $`$ceD-9H}XYauF r|gV^[N @*vL-/w3܂ JlߧSDVA"O[."r6wya+pV'>{o/+XJaㇳHXxJSRyO$"yq;jH%@]gL`U_*U_IEvXrڀ oZ%1* W>z4Z>S:(Tt I 3xi-3_/pumCr+eo:),)\F&50\>b6[GsB0ׂ60Hn)=}o-qCB,&hcAM2@0>{P3RY=e-2}eyh d|ykVY~9m\,SAA,3ŽpČOSlxI6SAD2.S%|z_ \o6_'=ㇳ(X3y80`TH*<䘦s`* |cHa V񭅓Tbd,nln*ȔNDd%`V˝'fsTlWv":!(: 1B]ILr~.QEڇbR \3Ъ(O(LUЅ ς wpU>5_AI ._eh!7]Q 4[x "g`,N3ȈD2Tv'`Ʈ$A X,.:/2HVu`JttPJȅ&hDK!ttaYg&üB2#G@K(ySL"B`l8bEpd|H-4H D QBkHԛhF;QyBeJِ"(( $$1&E[Q$qlQA цӦS η9擀6 BB{8)=`a*nh <|3_hDM:dsuB/+nut-2.8.3/docs/images/nut_layering.png0000644000200500020050000070316214553676503014671 00000000000000PNG  IHDRljnsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxuGǿU㶮b[B8qwHH J htwvwgvfwVyުz c p8u@[Zp8Sw9p8Vw9p8Vw9p8Vw9p8Vw9p8Vw9p8Vw9p8Vw9p8Vw9p8V)Ap8ᜥd3Ɗ&@lDr8p8gkpd9p)p8U(Gs9p8Vw9p8Vw9p8Vw9p8Vw9p8Vw9p8Vw9p8Vw9p8Vw9p8VD$!SPa @@PY p8g7DahWM5ՊfZv*%{LqKk Ao$Ħ5u%MUS p8VS*i9ǞtT$g3EjizfXQ[ցNkKp8éB]FQ_]u7؎(d:;Z]0a-_ AASe0Frp8,QQS*j*Ruv[K;ki:c~ZCAEhi}8p8 vtΜ5^aɖԇ;`d;EҺp8pAǘM֛%cuK@F,jyZZp8N!h*RlI/(Ys]A[O4)- p8!ef//]_Y}stXs)Jօp8r0jde ey0F(;ht%kܮօp8:ꊺY㷲Ҽ4GyA?:kܶ  - p8u.+/컣:BdS2O^dO 1 "s"@ :RDjP1*Vh::DMGW=i(rH-'D10BM2O-Bb'K {eJnStPVWzpaJZG\+NdWVQ k5LK(T(5R=gN#jYUݧ&]N`9!P_c𼆰ڲ#gZ}rg[2vQTΝ;df#N&"éTrP0T,ELN(h8DMSvr bwN 9k]zE:U2)e˩T@J Ūؒ=Enr?m(zէS};J}dE@@^ԤP*XektTA0E$wmA%-'4 zGfӾ$4hV ajS%&E9g5t6.[?2}&NDeh |#jt WӐPFAS#y߰0RS*ىbgX 'LNV N׫ZЏGT Bry@6N+}:R!ݙ HL.Bϛl3U7Dfk~e֥P߀SϛvLAMp%^= d~y=鑯NL@IKtEZAc%=a'UZ}jw@*:֘J lk mAOzUTpTo48[LN.FO8$6?κ-Xc27\_LQg('sZ[4(CX`C;2ɁUņ#U 9%&Q*Z]/@#-j%JriD_tNNƑqрqM Byk;8C`z3Z*BGXaQ(P\ȵN0f~e ZØ eF &qg=%2Ҳ۬і ZZTW4;LFK ĥѤ0)4E:J&%&$E닰7EZ )Lh_sG C_kZAdⱪ Km cZ}*ad8? Ԣ(崺7Ku2F[$h t(4?7@u_8i"I$d'COEt4F10T$kݙ1թ1,Un(k̞aEVFZruЭѻJsW/r 5z*9(5x "Ahht'<7M?%30<4NgoJf*ӕ C{?Y5-yʚL p3^i@qCȌN `t?#P6۵[j%/(7?H(:mhi''MJ>|a2R+9 rUUls:LQJBc(2i 4536}#Miw;R[:J1XU]Vab~;LkR3_TFt{Ur~$IUT®-ُUdP4[ϓcns \y7ʍGG2؃ѤCnkD2l5vftD*:3A1g$]t?7]82a9 6)?U67XvF4q޿#939q e4}D0ܲB!K_jj0ؖ@\,*+hreVi犘rVѲ$I5"%.&![4x۶(useG gݼiRsT(Dݨv ̤Jv]eD%Jg`><mh_{UH m|#ЌBCQ*iUůߢ`6U68k^ lD3. Tt)".u(2n}p"]^EWC EB6hdWEO3|F ;_9CMʊ+MowrcxZW vnri7DJ\R۲?Nˮ*ۛPNrXuxnK(k:Iȍ[&ث\&:l_j3Ie‚~aNvs&8+_dNz&AQ`V-5<F[FL"M:z}~'G$R^UTeůQZ]7%:vIo[ r^"5/)DSE30{=QXSf&˪SJ0yPRZTK= rpgU(߾Di $5xow!Jä$em/%W .sZ]wG8%$)G,-z')OIfPָY]Ş=cHǎ6r8|W|9DI`OپISWV'{F Egʹ&O=HҺ#毂ANScة=c#e f&ÕڕjLSJM֫J@7Bd|]eyVԔFEjs:shpƧlr^e>t^]֗&wm>β2 ٹSӷ](;.Lx0hE,ns+ +w_\4j2ac+ƀ1;O?[HΖ{zi*XHW Xrz Z7!C;i|r|r|}w_yqW^5a7 E&v(aŽhDQc=th_S+;}4yɴ4*~:ebjZ,yЈ.duiD\9E)7(mQFG׏$BZ۟~2ewGhO%y%^QeΦ$IiI Wne>RYV~uԛf_?X]`6^Y-e>@V ϣh+&3V޷/v,YUCmN΀KWXyzÐ'۟ň}E)u'-MFQ~K\9L)k4CUjz| $gyYV04.vK߬z3/ܫH.~ZcV)׏Fzo_(kΊ@AO̢o!?Xޑ:g=,˒(P\ñOvo6$Rr"($>[plj[n|Gӽr|Ow0rt;Z#c\%?rk{۵4۵4+ȯ@ \y31 шO xhI@r _XDz ۯ|J=mXTFu ]8ϕ}Wޚ!Nҍιy8ﵶjՓ'_&ju"+iC75o|vx́tɢʖuG*z cΓ\n{&%greyUE)fy*کWGl )JC:\co 3s"W>fLQ@ S; Nt{c׽/l!۸75בpxӟkOk2`ަ"袦-}dդX8i:mC NM}Rq]]ذn^v ۶42\wdˡ߅lc c=4O͟?;!m -9ul:z-M^Lֹ9{umfk->O+wd#[$)ؐwޠ]qy 2\v(>|Yٰ@Xud=\Y=cC*ඡcḏ$d.>zcEr՝VחJ~VΜ@V_G3k?60*PbH bjVDZz&PIk mA׈0+E 9w7TMAEE>m֦ PhKkٌ*YƟE'}AeZ$lQHٸIw HN6A0Ҭ2˘"WXxJot?5XVQ]39Кe:.gjvAи E 3MGQwb&1p2;Z((:?]ҿ(5Fd]$8) wCGAq籖%J mAsFKېGCENF 񾫹@+;91#zhZ,ueeUOˆhlbYk~,GICe5oF`l+TT0*i*JJNz̷%BGҳ+Xaa55YMoe=)ٝ'9q$BWٹ${oumhm}h@R;ȣ:/^uVPl Z-z\{ IDATzbbQaZ1;gmjAMV^DK f77KPI 2P$Sz>FμOBJa, Pڅyo jeԴo]ٰl7>/u$zCW1 6l\=r?泇\G7D!gڗEAJ X)/*)մmP[AIrٷṣڷZapEE[+˷Ra)R75 @*+J <~|l!rh_.uWQo%g(BrN>ʔ}7[7P6:&fȑ}zbb}ړN?yuv5ڌ߷i?۵n77/GO}N!8yoQCav.@vo yF}EmA' olZC_Eˆ5 V 4?U 37X4=Oy Vv{{Ld>YN̯k}J=ȶ]jtH29B>jW! |Id:GVC/`v&(w$~ݶ5Gٳ;@K'̵N*FMAgW$.ڧ_sBMﯯٙ쭗z_%Z_ٻ#W")ņ]ɨs_lU>qO0W+#\zytd,7 ?qT9]=Gʋ<'Ll>0n\yl38n1Zeݮo_ çOBZn$cA0I_-bǶ7bUKWl3{u{I9XpfNl!rKEJ߬ؓ}Bat$IƎM'Cz  \ޕn;MvMR^Z>XD1X|y:v9dݳe5ȂSM $ua'6hjn4biQZE#c|]ۀ6`@D5Vq1/ji=Z;U[ E?ƶx8NJݗ==9_y1juTS6cz+}ɣ0M" [Sl:z'rF=<}̻UKs[/xSG3m{%L>usUۊc>CW>ze%%I.jӣ 3{u~\7ݧ 蘞Ll1&"i&I&{q=. C"'2f磬ħW{=cB(#TyJLřHC|,.gGEVsY֗dd7JW0vJѦ"g?kcTU2޹ӀDgd/IN~rM,"8G7n8Dߏ m57md>tpJ,h9NA$GX(k)/wb μTg߃Uߕj4eYAv1oY!dzqxMKs5A$k)9R}RG&)IM9Q>N`Σ:yNX]CiдӘ|c*Wo֡@uFVدZZ,Q*~Y?/H 7gpkc~ZMMH9]H:1hB)u536?m߰>U,% ƹ"o#e[QoLj갇DU$O.x4.)WnXCot[jc=l\FwHd-Ψ|~-lZɧ7qR;yw_)}孥VI` JL ZF1R po<rZ.i#֖%剂&4G"Nz8H8rZ+5^\E[^Mwę9fy j՗SCYw84;n7i$^U!:P!;De_("D2[x%̒NH?T(xV@vf&o¤` i,>^]P0\3]ӣt h!:D(Lgcƒ^ý}EmvfrӍ= .ܺt"W_Cɩd~~|ӄϽ:EK&zߕSD@ vZlp$  } sJ>A77E:z3z|p˃l?r1*Dɭ]FƘKH7;CcC)@^շO_{ ʌAz=׮,g+b=cpp+7+ SNfIqq];5. 6E {o|{jXU{=%&j؞6l89Gۙ/b~9l`W7 ;M:̾ntXȐ9_Rpptkk;w۵ɾ,9pMCz4 Z1ZrHzx礇w8'7t*>ٸо5uI>հĭ ɉ$1N>m !{B*/w*11z!:FVS;)u?7dʫ(w)oo5k4p><)+ GT hhtð1O}1 W.pmݘYBnH? 37qӆ|WYd{3pkLh:J$ + ;:1=2wdOu6RJW QCg_T3eͪSvSsxw &@֩r54ɒ(DUe˨z^&?nl `z1[bȬY· )SS-̉r( Gб;`+J9^#[|tf$" (d% /.%O܅vC}}).DmsJǒV)+1 qD-d)Vҧ26/ϫ?Sƻϡ?8^R;c(#LL w)eš8Gx {zA5ʒ6Zc9G Y.ﰮiC w$x6 4s$)-ȃ@*Q_}}@g =pENӫ{_Zc,WqD.5;pN_>Jx7#iW}:=b&~璸8kZ9\U*K+y$= 8 bMƌ#!}`pN70 dVmي@1"o̹t>yɌRsқ,O09o*xd ?qSe6U_J\.b-ؒHֱ9葸sܾ5ǹj;bb  yp)gZY_ݣv ̆uYs[ѳ g0vRj9zeĈD v[Q^VO{@EGe~+2 jolZƈgt?4Bxe~w7L00ޙg)?0oM&MzrۓNo^*s\vs&aSl6wj pUJb#A&{C_ QhT-~ڹg{r璅/U`㡹Sk߽3 EшKǑE;Ym/O:D9^EV^잞CN;J͌(zR9uj[gayÉo£8|ǷbHoؤcKY9d-LëZ:[j$'N UF?o97]|_eIG=>6HMlB㔃)mGg۰%< A ν.)zQ+m|%>TcOg| 3fw3@Um|ZuրYiutT+b ɮ\nQN(rh?Vb6(Æ%k)~ny޼6!KKc+!C5ft<[T\\zEoA cP:t]ylpI3PJe siډ%?쪉7x_jچx4YĞ"+:th×P~z=g]zg%_6U^DQYxkm/+ŗ/bO4> -֊^F#$:Ӵɤ%KX G%_r/򐟕W[vi `߆= Sg\P[y3=Ep/ekKXr}%.(ӈʲҥ]BW;'_4?Cٵ6gtd:}5)fۥl3SI`"<:J-w f^ֻnRN-}Tҵ{&W1ňsLz M:-N?9;[vcSQpڎQ߉$cr#$x5okSy~ $qTڳ3pȪ$_~8\eI$M@RԬ/'QsDx- .O?\YTϯ HL24ۗ˫DJiȡF> D~I%;qpyRK(ukץ]jGDBddR ځ3YCAn93E^6ګxOJ㞌e;ش9cIU)[O}d0OgDWVxW+ح\G Ud&]1veT;m>^dЄ!صz+S=|,*lPB٫KJQnui#օ8:gTɔTRGf\ҕnޜ9 t%chzhqEE:s'v=L M"FӁXm:}'RɥԆrgm%EB ʅS'XLgLM_{v^9)F^*SzÆB/5GeɬëO,D32;ٵ8/PWA[Ͻwm9TۑUEAa]ɰq#W!fV'bhjO:tMsi 3GS^mޥOG;ӄ88NdF~I1``kȤa}4X7<{;vhߣ#t+Y*  Y۰'<`"qY]YI@O'KW[WV_ւN EFU~jIzT <5YCu܍زeʤIi[ 4߱sႩ]([5Aof#y>peEՈQ8zMut!ؑtevW"6ބu-^[`F_KnaeGٟ+eU~rK]OM1W^=FŘ`!I2@%!4 %-޷(TU̷@i;mtL$p˴YI~j9z޿+w IDAT.78p;VogWmcGP5 Ws.O祿XZ ;WocU*e.2j0@hDuy?B\tbOE%:%]ZV\h"2oUu:uZS{{e'kUQpm)<aÊ$8^ U|%њ3@ ]Ǒ>ؤ;wpH `2y?<3Yؼ8̨[@'NGS.*ʫ02yz?K Z]`hїg soM,0q% 6(uM=n FN_J*pG'^6}Se팜_}SZQs qXj(.P \ed{K=nV]Q'=@~|[oeh"ny>2rx29; F6ٕ mŞDa}߂oalQ9GHeRxYŢ Fs, 7[5F\|4i]?N)/yqf1uf3|Hsӽ)zmE:˯!9\ޠ/*Z7`Lԧ.ppACSN'{a#Q~Rk{K@&-(ȫP{F.XX=\~:r|:mW^<ʥBzTq$2 aJ*BRXtӎyk:gY"P{fg䲔NIǠ8_8}"(<]?-UXtԝl]OAG~[6s~.b2`]u> S4F 4L=Mw/Sdvi5Y'}>Ujy@YV]t%;N>x>U$],n8y8Dfe>ɪ3sUQ^Tv0Y-zS)'avHIMMqЍ+34fХ:&QPVPQ/*7ntb` ;}~Y<3}7mw ,V_C捙J\w;KŪW##JIq5L!CFv71/ﮍ$ G|| N.qW+ְ>:ct(pY) gpx4ɔ.7\[NfX֠7\o F%,̔fF/]֑38>0}'OS3 r?*>X~@q(Ǥ[x-::MZZ 7q OC#VƮwkF;^{^Xdpvͽ7z|#?ڻż;OjHTŬOrS^%oY,ŝA֬iAs*rϊ.lRXt2h]m7Q4zO}#E[f)SskDUG:whsZIh9^x_/z'W .z]ttgj L?x{wGk;YFL>aY֬6:=i76[w&M/&7߻Vv:>m=V6[t&;}/ןY)T4 L2vJ1θDV_׳cؐ+' [fA6aXۿ󻬾PLrjI3c'X֊4w?}'`PU:(WL9b>s.觗/ƪvd-MHJØy7_L`˪ aw̿tJFz~_^Ɉ5yqX2pw'鍾wl/**K<|X- 7{w%CMֻ]4gP/lx2jk:7,*oa r$|UH `N~ثE2~s40|S/P+p c"&Yw8*}VA.0C3>l y:>xH9aK-%r2߀P-nh`Jsnin{fi F?Gk}ydq 1=lr±ν'Ë_-~ I+g/l9ܝX~wqpiKbn"2w^a><YoUdYU_`oxaDI:EQ+O?͗”p[8S֢Y TM#tRzΕɃ.Jlw3$_[Ώn?@-M~ٛ_絰qqғɌ#p#I{\^aE]׽n/x%pW_{s;8)-FɴIܼUՃV|^lmcT3[}C\x8뚎uXrȥ9 /u  F .}l2f|6qv{-l#B\4 qRTN3p|hd~ULUB\N׆z`eχ >n-񝗾 #H\PF;>Ѐā>,{Ro%ŲE!Tw qԑdb"M5ͬrwj*jYow?|M6a{k{.D|~4V6g"/--˃fX5jEB͚D.ׇn@Sȵ%; :~RKÕG"einr2lb6Y0 }2ժ;jzZrVW ɥ6TȺ0ư{Cy̷UXUV+C<#RJ 0b\ ,6|Pa|ÎrATl؎>!4m az^})V?G+`L^Q6k(buG;r!/tlO4*y3<5ߙs89dÀC>B9\xdt[>lc797gHho o<~zk/zF92vg챇V|wty &y֬ޟN\z|z]Kw-ΆGoYh*)(Ɏm/|ʖ^s:O{gN'μtr3wO6ThsnaRN[sl۹%zQ"A$fKpBJ Yk.H$̓,:qDuvƺAn)}`;k<˽S_M+v7w.\!hnrYuCŤ_dRD7+ӈ՛n˲s̈́R/<^x-\9,$<-!r@ /o;<ee#ruȣJ3 `(\oXM85E,Vimflۦj 3r0+ۄL#9||+]w/_xB_'I lfge.ZD EGc;YGKG #Jl`cA YB Ps9:&K^8篞%0jH_VTfF[gԔ10tЎ }XLc`0IՎpl 6t6lLit71,ϒ)7Z]Φް9nwwXs{%({n~5~+_2ֻ+Rг-K 3V'Kϴ$_"}Diu|mjs7q\iEiHhi%]"OeLAs$vr({nI>\\dq:}#vw{4ճ<\Bݵ޾\c--ƐرNI2ȯ&N/ Vuk>AVh_LIM_/86\=zscKWt#8;*Z^;<3NFz%JI\?l QA3|gܳޠ%?<^})4Vt Ibe; ZZ>|&|4NJI0SS#O>ڑ*yGi48<fZKmyh.^ܢ0qif(ēs0DT:~d&|1JnmPKcfUxBRk.UǕ%LfnBzRۇ !p9}o>!B(w÷m/TWIe_v : z`1 X c;f{Q=&f4NeF4fЏ ۊFÕXmF$1Ld-q)Ru0y%#w*=.{A!9'g{ {3S!ig93LӼ5؜̬kDUAT+'Gp+vo 3N,!9yVbq!VWӎOCli쌘$dS0"-rvŤp f57ĩ8y{ 3ky&ԽrX)>n*&7XyY˸vy:a3fTgDXX@ IDAT"ECωjwr;3U_7f&Oia>p `YO[ f] j4yr(L~k?/gk? >VSiEg`rwa{ws:0ǝm~܍13$aZkS=T[Tq9yf1Wm~cB,~~Duۗk4lf01iL)`=8!hVF=D}Td^"$h>棂# Q~$:ى8CK+CAj%(1J"Gl"q:#z:zz=9(-g 9 ) qhڎ25,98jdr{ݟ?L*t>C_{3y4" ?l4$\^Q^èqIe0B ߠuHLBuۢ=&nivMsQE,`ӤqzC&.'NC(|Y"o/6 mO;kt[6iI[\:w@ %^ :tE#2nw|(Y 4ty !0i83LD߱ǒE`9ih=n. #+j<{:`"2c:r\ZГ&5jI\.Z^7hINA.X[Z\5[Y֓0&1t\Nxz;zej4XFt4ͱu'~P}_X9445BۇvUgFZrl̍ |P6xr8£MJI* OUd1lƾsCiuWjkxde]49bEIi}'?U ؉o0< \se18Փg)Sl"i*r2weLz09N<8rzeka5agvWvЉEi?ptnx, ۊ]tmٴb>D:TrcQ]qiwn8LEyaf71COy+zqt+\+O"G{I`21F=Ykjh=A{VSȂdO*KvƅDaHOq-Fe"v@fievUvRJvOn˾EߒaoXHЊ.!/^j9-=n64uo=$JcIi\am?je$浐rKrHDW6(tOyRK92͚it뀱nt33g?ԹH }ir,ݡ$rkv:7V$Kv4I\cC)^lLfvƾR bI\m1wJNw|7ttz 㑋*kqy,`?sLv&XlТя .`b(@CNϰ&-kP|9#kwy6ыT NZ<`μ{3Ɣ| :|.;"FxA̱EP k@ƌRn[͙YאD&Wdi 8?n[cq:7uX)R>}|VQ &hPx`m]V'k뼝m2)7fG3s#&Ĭ=) Ы/˛K?d m_pT΍Fj32R. /z_R]HuVt;݁6n&`쬫X,]GRc3M,<='vI=NϰҦ/LAC[}va][PAΊ]r+u*&G_~O,Pѳخ;Z׾z.u[$?'N[Ɖ'JVl(5Lw\6^s]KkhVaxn..H$ 5SoZҌlZ1ʟۚbSm{?_b(,ͦ'F J Ne%?|#Y1/w,J|a),}Ԡǹ>lYnuaQ6%w &.q}tXA-АX<.=1d_Hosu-_k\ž݆rM \Y.-$\vw[րJr}+5 3@>7=uKR^jg|[-(ɢYbeo`{qZÿ́%Eg0s,wDK.?8iq5'Uڧ1MHac!v&?}hsU"U7ʎŲrm.!Yn+s&sFy>.+~[*x$;8B0h68&u3eg5OE[bjRQ,W7c>G&㎓#g74Mʽ+;Uym9'3CNP%ImJ*>\ExHuV*ԯTL8/ҏZ߷L˻[CCퟓR]aX)C?P*6ԴYk$8ʉ]H{ZDqrfѴ`Mt臺3'uPo%%+ #!Xm?5+E< N[)k@Xd<)RtwRǥ_W<6L*Ms@Z JMm D,˅ҰXĪD('ܚ-+4O[]Z%mkqEI9?J壤MmPcL[ﮀ P+iGX:q<<~-yl}(20hRȧ#9)-`&[_nT]_u?Jѩ(߂ :m\K'u iKgiNWֿek%N;vu|;մ'R=扽k$ ?<{6286 ~rPDzÎͻ[=;ArphyCN?fF?IxزlI6W,Pk=6: -SbC]j rv?pWr+i%m#玒X MX%͞l@xVu?cdHx_Uu"13(WK9WNbciHV0G*~73s~@[F8}J8Y^QDnDh1K )ቸ0,H#t6Ȼȑ"D'5 3]gϺ|^~[ 2w ,6T8<$ Y[jBX/=cM(ib'+~d KB|Rf$mh_ ;:+Qǣ\Hj_V6'@&/Pox=-m"hnxRtɥ %vIm?ި'c)x<v /RظqԤelrF_&˓VtD'X*64]|E].qSѿކ!ww&7M|2$ zkR?TK<3`vN}1ȓV7AӎP$(wk[d>hI%AX]ѳ *~}z 8 IDAT8RQĂt9Adz {HtXY/}V迻jkҾ*7ΫAH>1'Zۊ>\]u|(48>1YF6[`ABAօB@-'-JNWwkE#Fr#e$B& n >Ϳ8ʅqEH~ȹ9įe(;d8ZuŊ\@ /]tfBF!h}Bco)B=[J]LJayαSWb=!z9TQX,6V7^u&)%^Cqkkl'I^Ttpu,dl8Z ::%jpZ]iJE+kyYrst~~xBxܜ:(9-(<\KkXǣÎv#hpzCq3I52`d?{.?JNySZ <^̒p}a(&4sϋ$}EԿt $vJ3ћXǔ*qã=~w*kr]uZJT2\\zWi5ڧ(Q,2G|/^rq0"ri#X_[k<c]J^8QPCang\Kq*BΈl08::V%kVEHDwKڎA?F8bp9(Kl%a+]8, <`OltT6imf͍]aᓦJEZ f H]U+lba"OÔ9cI^Q&-;؎=Yw{gXk%{8R~?cň1EdͬP rxPW^_N- ff\gՅ*sRצ1J07ųb+Cǔ=ˏΕ#S;NcQt* ?g9%]:v…LBy󏒂q=+=.Y*_{1mX?; ƙ:EH H6VI9QѤv֒dQ>YyHC2}TkƟZl#-MgX#6vI%Enw=x:u:}/>ǖ~rr;Ґxxz3{ɸɿoW?n033mJg4bKs6 z*f :%wuMM *)PVA>hIwr<!(?J $nlbO H(ǁ%o,xCDAd,?FX(4ڞiPvcjh9h<8Jeҟk?|i<Ҋ,i&L1;a4x??.V UȢ+{)hnGJtّK1f,TЗܺ #B9.]Fdh8L^x >n8DP쯡MүGD ]?xٰm\{1Qyc)gN&7ܽgoa D6}Sƚfg_gQןoh~Z3m,y-fFibU;+uy70v$?-;}9? :cO8~l= DR>3"8/ 7@:>lہ2B<*+Z¶l([4uNLO,ÞGph_=cb'Gob)HAQҳ,pv`oFjvPd t\!J۱=-,nzn: qp/E fXI;Jo&#f9y# *Fr﫯0reȎ]ٶ^-t<{Ht9{ot1f^]z{Pɧ$#G7>A ?X4?6.y0[ud9Iݍ#dfI Uexr%4i#{p\SQ2Cˑ< '3䄔kG LA6巟[pI</?ܳ)|X8KIM\uq'鳋*omeRqϾd:9m$w[ {_Yn8￾6V~r:}jB?,b2~Vrrao|=y矆&Ee#Du3l[q8QvlR8~4t&jPV="k$@6,fΚp~.|c#'8|%Xϝ ٖ+O?|YOثO`=o~=7?r=_ t Wy}G bgMDgKGX>cgM?Bݠi9d駠=s@)Ww`|HsI䥧_y w}}=.yeꪚ,<6_􇽮Qb7b/(Z_|?;poʨش3HOlL@Á*f^waLAQik 0iz=p*U[?,Z2xQ/]]G''7d?b.: WJwïNzo%хYOƍOMmN;x1 qA~ϤE'[ |0:i VBrrMXéJ\Znfg0^\M˦?<᫊s `1e>.͜٫c݊OGbAw2.Eݸ +=L )(҇hMf}-Gx \XƖG6қzfYG"'dtY>`_*6w4}p"3׆gN%3NOuХ{|eXŀL"^[*әFL?0rH<Ĝf Aﺒ╇cW=t#Ytt+FN;?{g[ouf?L-8; cGaʢS7cGwʼE?"B>,99([#O</_}5Yba9 ^BB*M "- !}[+0bnoɻ&>)#1Ydg%e%ۋ$Jc v#T(yBAņx?0o)(ص+wGPfՋrDǎ\ n3tgb_\Ö\2ò uFi=o\Q 6 Oj`!R '"__c~2vU{'ٱ >;:J}D ץ3U#!",lr.j&mkq?/:Q69{LrƑἿzݿJgaQͪCo '? sL"S0L;}3h6ZpA|Y4ddIj-eڰRF)" < F&ICF8]l¼EKpU_3&6Lqxvmx˓X5a8(CVT}=gUlᢑ[foҫYVgԳ\0sC\!Y!bA GGO~z> R Π㕍s{w{k\I !x͉b@H)iw|X1޻="uo*eFYyljqvymwšnu^@^[jWQ׽Vd{qk)<Fny3Dn;1'dDRm'`ܼ^o-)A~')G͑Q"d]E??wOzIx;;Ei?}/E87)SZ|@LtӔ*[8= hU޿߿]y*""v1j!a}׿@> _gpg~7tԤ =ڰ_}~UVuvw=xiXѠ~||isyw4_?I|"+(/){01O/;ڽbm5W_W߆{> ¹wߊoR^}ካik ]y3>Q\a) -;6!9eKqJ^s2~ Pb^wUû+q܉P4(Α=G~ ?{~&JdѸ9Gfvo܋5Qqy8k<z^Eo~)1l\^t*܂C;b܌v0[(A O; s2R݀p:~Ob'_u1.v| 6u2fG} kmD`.T* v nځ]+B{_#~?~Gvlxv=F<Ճ4/ 9T4rb,DP0)1RSm d&ox/Y (6S`Ϭ~][YNQY2@{c -ݷdK *uZN8j@sC'S;zb=7Ѿ")7yWkͿtƙ8Q:!H8V;Vlu< ?߱,X;1>qj0)asqhfG`c@@|ɔq}$_o{m~k r 2P207̻HLvQ9='V1W|j^hTZZޘH `[ // eAVlΖVl[\;cI撖suUyc ̸ VwTĩ8Rsѕ]ipuuUM+wS2<}\Fv?A_;.|Dx\xld3qWr4tϏx]'U^s%2dfٓpٷ7ot[h(5杨>=DVAzӿo O MxkMw{Gξ_2\;eӘoj<2L?7>(a2{dX"Kᮈ~e[Q1.~ww=e1}yrm\Ƹ=j5@N~rX^pSϣ)Y? W׻_K6~w)Lݾl#YΞ`K;Onè֬^=c6wxp̂XMsxWli煷W?z#{{ك_ΟͫMK IDATtH_o&#Ǣ@g5>'\DNq̖P!YKJ㝼BQzwL3kӇ]2ΖIiX,@)2ƲEACO&uG^\fhu";? :qdV>v/ۍX2l8s|>5V5{],~}!XgJx?tbQ2b$OǮ"0zJү c!@CVVR9썿/un%17s OWW{E7|ytMr; w* ј_]zkMrjڷ7h,MgCbڡdM c>GZvddɟy*a 4Ȇ7TW>7nv9'BZs]x<4 l;2 O-mp-4 mlmC f̖ jWﯠ?\wbºo\pÁc>/+ƨwm "^fNQeڶy0ew Opv #=u+lG^a&νDv߯a{\{>y@x, 44`Qo8dG^lj Q)IL ~8.~f7^ya`6sΙG-iuuMlW+ #"l[4oT :0F`A0Wm<;L;PXp$щFH^b2Ro<8*erHlF4炙sB;!Ep)X$,d6aU#/+*Ӆ_h:ZIy$+ێ>8ΖVT&X8 螤U z1hHn܊1,뽤,7\7&tcŒmХ^zc q3Fӯ_KP:$x:"ϫ5z5q`, 0~1Ş0w9xc7K\[[\yў{q:9]V$, DOFg>_@D 㭾6',ڞ(q-=H]ˋ(8$'cx_"ykÕ,l z:zC+2إ_h{ޗR~J UA=JgEb*ab1A6a^U+p=ؽq=/YFv:NȓyH57)Rv|p&: YI)"7JJJ0NᄐSg ǬSǰ_>|Jrv1j|掳n--֛"_߿{{(;ǁY'o-AcM gE]̾y+lYށqC1f8L?~2Q>~evީ,0|RYܒ" 0 ~|!1ٲ-.!<":bt򿷷nr[ Ta؈|v3Ӈ]jiԸ[v|/I78 0ep}Q+VӁL<`=[hUGsm ʇc䡘qf닃L7МKa׊Uv}5kӓG rJ: a&oxX,fIvl<:$wޅPW"!o e7()/ܸ:: jI!W?n1hL|mIL=1DD^UٵQv2fNV&jE(*ŏ+,N+J'^J}jĵU"/V~i~"^!~a7ҮmpGʟ&2ۃF"0me`c\K4lPnȘAjC`ꝂX7s;[8s,kԕ& g%^pl~TH209vg`Fĕe0u(/zΙ8.Xk"K̗ k?YB'?6 '-;Dq&N Υ+juS`s ^p10ݯiq-z'}삟`dF8#pO ^Maz^WᏯmn{?WxNa~p$|ϞW#?ylԌqwt[qD`$p |0kvxsϮ7ύBTdRڽWz*;w_{#^=.[:Q:pŇ~7_R}׎ž1gk;myZ3/>{j]="ҽ@1L) shykӹ?z NI4V˿b0pócygaջaH1ù t 0#7]:)K,BxŸ2{@5uớ(*ș nY=`p`!I(Ƨ6ڂu6TlۍBL9tKoY3g&fi`bfJƶKŜ @=z3:!Eҟ K ,~klL+>]Hl;䈻'On,rW~\ l6yc٭\N/6~^} OwGغf =3 矲!x_F=}pMC4PTk~cئHEK ] çNϟ{ri|Fn. X翧 L6אIu|Қvcܑ(R5і5ͧo?v *+6Ǐ 's=y(+)/āyVZpE䝯px?s<r saO ETct1tXV:r(2rV߀8e{#pVEEٺՕt9 aÆ籶6m\s;֐ ǟ_V ċO-?XG' dG@Fl['תtꯄ%5q/FVN:ZPـ K7ubOO^Wb57Kn'wGH~ua PM$%k>l&+f5xуlvYdLI%us gӆcطӇ_V)3޹}F ~I_5gQSقy ~ [f:51ct7y}ޠ4{appa8%兘q _*¼RM1| It31lTZ=F͙wY .4HW1-ޖB'`wF|u-]zdL;q?//j*u/JX:-OU7#2r~:r ypqyɋQI5!lꏿ$SϼBN|5\s͊K6|}t ͜ 0< !8 W0-6z*a͗k z[ǜ0ʴ)56h2YHyKi-Aȶ4S4s&kpq# 2Kh}.s9p`_ `VRۏG_H-NYTPXlݎ@)kjmB8H_Jv?dϜ>_jNx1.ZL9{.&95 ~ڱ6lŗ/θ/`Ϫpb[ZѣO&rnrֱDʗDx+\@́ (G͊CSVb緻vc{f˩ 0 LT lӚ8^7(\}llȈ8;سgkؘ?}&Lc96~0^@cu6.ۆ/NjDܝ.X]usM#vنʝ T:͂#54_.t9={*@24Bϣ~Au <ҥlh[Z|{i <̌(n!cj-^I3!Kj~ʲHYNl -{i hI[K^n2͇ڡ N\wœ+؈uUi]%:=8t 6Nl֯<@~&LO.MغIr'⢿ Y0" UMغvU ]e*+u}o0#s`I6~^obdaOf%챔qp{7{tfNў/1F ~?E3 ] -{ C/ɱ(Qddtxqڡ܊=$/i.,)$81-͇/Ҥ i%g8ML|}Vw>@L/#zX>Rņ˙GQ?@,566bq1e/e+K_])->&-e,ll.&!<9Ɣ!ǑcEϊ)WWD/+C='9nĴJ=Q9%v2 YssSX?,z< ,r)1D>Ƨ6YdZ/!\:Y5rYl^tL߮΂e 4iE5}煰qG& .ғVVJ9>wI Adb^2BLOQAPI)Eyky BhI\aRZ, ~#IGׇ,[!|{솲+_*Akkuȡ(niGʳ rQ"\cE!rf<] W%:ijt7zO:1*>ۃ4: \mq\㣽v_2&df0hojO 9u[Hߡolk`mptPpc;6FQZi@Nrx_As\>ڣ"t[X`݊V!W߂'Xx%]!=)=h$ai*/j-Cw\!V4^Lhi o4j&K"RHS?&gr8 9F@,8(6QrdAxe:.*G^ړ 2(A*#eJe:mq!!/I˵u٦𞤹5뉫tͽpNxRM|*x^/tol=vKc2|bgT_ w$B<<Z=8 IDATW =D,w3^ :x<(ے.(Ջ,Y:c},/FRx.z^`Gm9 ˹E$2.g|ӈ{cӑN+cM~V_yV.xP8b,eg>[&lㅖxV ø?kG7n[۾s\0_Ct_N{D}y:}LaykM+1F?(ӒzvЌ(bˍrcy[ߙZvZFڵ['v(^z d#+ ?ЬFf^/9@~eGfڮ#; Z#}{v^&#t -yvT//|^ZA =cfZOƟkgI/uju"ך%!*yԵ]L}%>}bq&S=Ki%CGb\)yvy5{}DD+w@(u Pl fjENzV~oAJ!Kb+~Qu:YOz"qק1&fW߉JBn"qtZ~ӗET ^t}S=Nꭣ_јqT^A7rk~'xRG?{2m3͌ͻzO.a\D<~@,z9C-_2Bs+%d ɎQ݆42{_K`䝞Kt@aTTMd2ASDjtvB4HBQE{ObT\^)imuI6u`1e ylJݥK2KzW[ܯmɄ\v3wۚh+[ U*8pd#+7 86o)#'3\.z:]ۨ[#6kQ9CVw(Jya ˢ%G4:PӇg ,kYnʰzdd{y3R~I'lC9r^X۱dϿ0*MA_y@WSJDW7v1D$h Wœ95JJ^oɏ+X)hgJyO`2uDOܵn;_7mXW7ǚH} EhY^#Bo܍~O?K w-4$_* Ga۬#K ټkӥzzǽGvJ7e5`Zh҆w7},A '-49hM6fvx+ڜ9JsdZ҉/wh4v}L(X  h% 4[:Y *:\v #XNi&{'jKpе~Jor%Or /{g]B2$reYh|V&]E{PSڟ%EK̋oo(޽TcIK+ ]ujJ_S󂰮3ύ#">x %bܽ Q"{2]omBFV9RR>zV@OP+{0$YltRY@WFYQrKOiUqڽ.^"K}򌊀pBNQÇvVb]ǭ)y]ҕI9  Gm'l2Ӗ5) kl4.YpB!ޙұAj^0gqTzwHV7{7ҕ[yY5_ue[(Y+nsxmTo#vһ 1'U6\>ޣ~?ޯo{9L^hl]B/DIr(ٖ JFxRc|{<;3c|f^ut:)60;h2itzoM{ý/"]X5^=yJՃj5҉S9tJ> M/3jù%.(ﱕz"RREMW[YV3gIˌ _[GW<^.\R]vm:d :>obqyJr5c-/-e&/zR_ TuSrCBsb9^`Pˌȭ(J}DgyKx+-=} `\0&"w)Ru @0EܹY~bO. :#=9$wˍNaNto%RUNȭ;WJpTE-(v Z3dNk|E)Qz ]%҇7--4LޓZC;<}~="Ug8qAfoٹدǰ s&\ ΌS FEkQ4@ 6j39#w!m|—nk=eNZItՅqQiL%=+WE7kcJNbEK=DgLY93^ɁyK),i6i^`r!7}$YM(JmKx m=q=]Nv<$LY3)c̼ :ڗ͹Y3Nd65 O*=~7ޟi }(ŷeKz1bE*HB#KyBwЖ)|_dfaǩ$$;1RAw:uf;_drEBgOUu[, #)3JO齏&g[j5Ĝb{:9a'ƈrб( ~vy_rG#Z9VS Fŏ/}5~ZzC:t~4|rL(L//6M=QMwvl0lNȲûr'TyG%_<^ll@#2fkqE#|L֛DZqdq$9ϫ<]$ yw_e <*=>2cqE}Y]["XGˮ[ U{4:Z:VQĜilRh2Ё}hR~tf)쐫kqZ^}pD- Y J|ze1PMV 4Mvʰ 󋢌 3aBVY`|󈩶e'W3 ~%Vꆡt_O<*# @212apP>ǒѫe4,^r*[v<1 1prUӡrT*-5$b,Ll:`Rc={ԜAo;ffHi]zS$5jϓNwi#öfTz\4.kOT14H/u֙v7jr T=:`42 i.?/Y/" \@}STAF;p> KRN m1&_cS]@23&n)!%mʙl{H6+^W`rz{ b~xF1 f`g=v.Z &S6,XLd1ejJGA!ݷ΢&,} +LJ$ ińAD'/BL$+r}vQO-DSH<@g p)\~iя֑$1_GOY}Zy=Z3_q}kqZy/ueLm_LdW"gLsetb@Yke8 h -~'s:ofN_Nx?s>䜊M)(''1^131i&+9LVrlfJC-)",}~+=Y 0`q^(05ss-zGKQzSx 0`G%= b0` 8a"/N0` 0:{0 0`R@O݀ 0`@R 0` a+:/݀ 0`@Ad W2; 0` } TWzoxA7` 0j̎TWxL{[ 0`BN{x+y ݀ 0`@ z i\sQoagAܼN\NG flz ":xaC/z62}/w߫#Z7Rga&8J7Y0Es- g'\-Gg6nZ.f1b"9Lyd9(48c$8ڠ.#7x<Ѽ)LN '& ">|XLD$ѕt:eri2 Dغ&/yȥ)O#aqt%'WOI*-w}䯋.F)DRY'_O!nbӍeФ+ :eu'+~b^/b""' Q@'3@'d!\pR5oN 3.Uy'-~; pL̼ ( bMESG@W t=tRcUPDJȠN J_=*4>͋$xIIyi˷rS7/ $OP7I7d:H$?' K S4&Ioɟ:ܽ|kѩR?@W6#yǣk ^g|9°<*ez+PPS99Uspޖ@ayK=WTR<sE5ޞGrôM4\+MwOEK]qzȘlRT멲kum`JvN΅GV7L4#oP`uJC-N7j{}ޖ@jm\~TQ45R@5L~_JA<~+a kn&(-'*-ٴۛ y>=+`(Y}zz“- iQ:qJT@TJΏ)'N\@[ ;g،,w'[ҰߔgMeBf(`Gy[Sɯy2:@?ʱ[d͡c%UZX"H%DzW*ǩGӫMR㧗g2Z{ksF4;//wPtlg6 u3sރϭ?ՐJ@'>pޖŀ~DXTl_Kg|{9jQ.R?O4l{&nRCm^b5]MO_D6?FDbN,VVAR3| 3 ،,JҖ&=⡂3h5[R͓K5ã ;;*h\2F%7s1hy8Py7M5jZW/\lȡ*FoZCZy'*CO K=Yϴ'ʻїB_N+t^.Sz{o_w.meL36߳fxSSqob@|nI} {dL uR/dhJ9LKJ+W[-oyhGn}2iӳ9Z9zKSɐ"xiHJ%TxSuRidh3Ǘ0ҕ0>#  f CYz;;](oOam {{e\ڮ&}T_]G'(k@O!=)iF&QĖuOɠ'x|Rwl:='&TCwvs(LR?.)Ūjnj6߽V{)iG5`CO6 a\} <>J 4[r K-š'm5DxiUo~&])'ח9CJJ)A-'OxrDHzeHCKzZ»Cw[C*u*]O}5yzf3-,cڲ'=!vhZzӛB IDATr~?akXT>dNP'hD<-JuϞKy9DP+=MqBrRbyiBI38t.>ߧL0лeVqX+x+ZYI?K2"Dxţ՝Vze#V$"{O#Q:,T!e]u'`op4} ssp^׏K 狆?ݡ0toqu.-Kf1 fS%Hp<:]4+Fw,3qr_KZӔ歼XѼzt_-j墅{wD\騧^OxO_JKWCьMI6Vu ă_pt~n`OilqAl»/.X2}k+>8ΦTAbeM6N,ްx<EWibMTf|ߨޱy%M-<@׈CMkc7'>yfuqK(@;K;!`2}D_jZTP-0^R-u'UKy;43RfI|ۆ։N|EےAI\1S}+!bA׃[*:v ko7=-{[0uc=_H`\clFg[ a=Ibˉ ǘ'Z'v#] I'd1N6}ǩ5zJ9I}Y02݁=NVb{ v!0 q={g(f\tҩYew0`l-@bH$K/oI$  C(Nb)U.eu]ݝqw'Klz޳xף؏2fFZQ`4EK8 !Hrsx@;c^ t8N/PﹿIǑMW#ݿ3׭)/Gpٷåd`&;]Wm z3G(p#".6sy;.BA7#6߶۶t,yPi=>OZ+-][yދs}Bkx&˫Nsd9Nf]:;Yt\r5S$uMOXZ}Xϵ} e:C|ISluHVXJ;S#z/a=v~k{|KYV?˖},y>٭$&{uH|ߩ;nU8[,ӭ(n|غe9{ϒr-FјdNEQ.::::e2R0~9uOS>~/z_~P#@O( |?<6H^<=y@_`3)v)U?H5"˖YVu7@g;@O~]t͒ս8 詾빏;c˾,پNئz)7O]>jĺ>Al/zx窽#,O^cz>>n-=ύ L> INK]ۥڐیw,k8dɐi2LsiiB!d*JӆoԂN-iL= 9R3qxZ/ݦ˿gŇѶ$!D 8@0G:&q%Z1qsK*'>;u 5ƃ~lI.j`rrMSXU[jn;h>'Ƿ7{/+Z_/k n"brg؋&d-F _;~q>zwoׄK֘PTe8XAqrSs.G2蜃#"N(@'977@$fl iulFqq850##Oh{}ծH*7[W_yuvʜuo``? 鉫+.xԯԏ|ݼ{y[KX[̝*V( cBf(@'9ǗxU۟> jW2nƁe <+3S6OVv*DKS\:+_8#_7ޫV4Y{XWyk'W&LU3ݬM/17kvVMtl꫚EcmsҼ.V2@)Q8=V*|jJ?m~_@Q9/0eS]sf8U)Zdg23fUBȡPN!t5sPSf=~Maxo J;# ^? U;arvIf\q{>: wb϶j>,kH+*շ+95 mAqEhknhWl|gg3}Ýtc/v]i=ve uVKoU-^/Oݹ6wힼsI:GєqIe4/f@ZK<Bg(V3lGojdzrⲹZ$/?V9`}&ҜFm.k߶r+ >uDeީTƒ͋I!tBsԫ*Zp_># ΣkCl'׼{ךog[t;La]j*ۯE|]ͣ7|#|K!kVoQ3;?ZBiϼt;TMʇތ uO\}}/ f%qBStx7Byy&jOyfW}tȚbHED±>+rq?_;(*oO?]'|;>k/9k)BUj༧&)gV'C-26:8# f7HPTxִYKmTJ\|s?3~’IzaI.-=wm3l,_cڜxyksH֤c-S(5`Ҍ|f?}vMEQ8:[ n{<ћ[fYygCY77>7_]tmy3l^'_pDLS7>Sf@JVFevE#5),|wwM1Nim ݛ$KQP_ŕ%tdrp7=>ykQ*Y|Wد֥k[>i~F`eB !dj:#%;o_+`,SGXY#x3^6{xKL6|xԖPgs_@v^zgʏqS}aW<(3䷄d}usrr$*ǟ>SK^EUtY=2- E%,Ӽn37p9vog=rS=(P' * !dl1,K@Q8=d`)d4bOU/LvMwg%`P uY~[e΢I9oW 4Զ$ "S~~+9J5$x'"GL<v$eLSOT~]w\`j !:Btmeκ`8cPZяocZ3h.o CxN{MED@.ޑZ2PW{S^ O^{kywJkOa`!Go>a{9FԀfpug%pK!tB8so:SYz[ZGäyjGpoW]gNh1Y.Itt#tKeg5fG |ōKɶ폦zryO~SPzx֦4ĞMe'on2 7l>WB@:! ug1KMyiI[3}.?_.Q<_^tnKz^'΋`oe sÇbpwvvt/\'lჽ67{/Tœ^uJKc@[̜4~_L߹M£{1 ]vyS'H鬯30yNqno\fIf4]5BTN!Oww4vsӟXuozlwY]jgSfd%S|+LJXMhS25[x];7UUMVME>uizG|oV[Eh߮ݻKZ\_K_ȁ=I9/x,jOk?ҋ*zFnplk|Igo>w-uM}v& 䏯?nr\X[PK,;}x\3;D>;:%X')&z׾J}mzyk_%xgu$`-` cHD ~u[?7k`|:`>gȦ) ;c|hC}LcPHf oY\2zZN9u,8ԉ7>9i~tՁ&CFWknHv\1iz.k9o[Ngv ޵'%o\~c 'KΛ/9oN:6e4,4) Rv-/%WTx{,/-o`Oz~vÑ @7=v/||mڂ3ZқZmUR?qOESiKiKywwV&SgN{Y]V' cjUn@_Ie2ːлw8ɄRoǾ'fz19B:e,uo)Q'PMЦ59Yne3kYzI% S,O\Q/KN|!az.qq#t9M5 0u0LcOc9.TU-t{l%]W0{AF,/fH  -p9llu#3ayڏr)? UU0c86qZ7ދڊfY+wm{n ee3Q2564ԵaZi~)-Z0kxT)#a?   Ű{K쾎'ÉIƱI9,|&ma4oG,\.IxN Ԗ7ȆfiÌXd3ESP_(+bˇRJ"},\}W̮J';^VɿOx:Sz$W#KG=:. !AdHpjt2 /@(3u%)/ $BQY(p\0Mp*:ԕzN҄BȘqQqc`1`(Dv'u%Ʈ"K%XEekB!b&pad2 NzABjRRGsB!Hצ(0o L$ߒ)jE'B`kN XBCY ==1<Ƃ Bo4EETq2ih л?ԕ Ҥ0J! ܛM!Pe xˠˤEƔH/B! @Hn xrϏ Ћ.SoMFxC*!5h"*Vt9C(@dوOJ]JHS܌mBC2.$bUg u}Ƙ| RgQ x|XR<lKtB!IMOTu_#A @`DN|CVb7%BFXuh3 qM$2t%F ;ԕ qBL55Ks,cLEbB&!:`>(Z"PW D%7T"8"B%%^oho7eQaAh=}Ǭ$NJ.|]Zw <@BƎ8(/DG5& (+2Iy_O#mHkݗh hRBFpl7kbDd9_A}R>$=m۽aJ}KdRN!dċ p3bE#pJlER:ؒt GɦKsj}nstIRw,VL:!o ! g qC8;2u#D iGf)lj8+?'P1 ϒ\ɒ\BQ3'Gk9KK^{.{AѥD.u~}貒^KN}y&J}Z?~f}#xK]?dY>drדPTqϵ?RB,HxL~髮{۱dߟeB՟zzʾLH ^?>Utuq$+ )dߔX2]!K^Qkrı%dnBUR(U PU XX2=X;nÌ7n8c~8ed[~_ޏ Wr XE&0΢t2FptN/ DCfTB!B!B0B ` PU@F9B!2P~<Ӵ>] !BEJOj5>"B!G#t s)~B!P~veϚ% !B(@?B L3ϴ M{D!B>~{olY;fqeD!DN5J< -<]oiZ+O[g Lv̛+&%8/C`t<>Z1/Ƿ\C">/ZQl/$LkxD{Y=>y豯#*4l"bd.#B~)"҃}l΍k?Pw-y,]wZ{Op!3m2?MN۩s& x`V* [nA: )%::){݂`֒4s=@!%,&:k_#"[ ߾Rv}Ht]TCt{ۊ#z!]5uL.i5D3  g|0-ŋ-/ [2˲@Z^o7:B!i:N1;sͥ]-ؒ-6Ҵ hA} Pdc4ݪP!pN XɄsM+*jQѡ+S;B!dl9/:O|S: [) 8,ޢlTO7P`Vb5QN!M1va3M|ԓcU:RGeS 6#>]y!18L XYGv&ؘ9!r|LA#?:7O>Uh+U͡ӱ@ (/PׁBKfOcJ^l֖)QݰI:!BFqr-fִ:*BF\{ 7N[LtB!#V9^zQ4{eWxoU u]jA?JtllK$wvzB!#ՙ^vt8j>1&1Sq&70nԍG ;\N:ɲl]G_yE -_Ϸt!/=V:!2V' 01'&j5C<3:R>HN?Ϙns .(y[ B!#̏;O٧s ɞ*ݐ*j™&HA9yY7^yE Svyi-\z<u%BF)۴-.ۮ(f!)MO+ײmfF#:M7˖b;Λ^QJ4v0+!X̢BFQh>1H6+}nWb"Ao 1ye΃?Tx {z4!st\/ 6S9*FM(Ԣ"_ܙ:%}XgTa5f!#Qާ^3iC]2loP~&NWEJvCY*#8 |6m9.t@K v ,BmM=%7.R#ƍJtBv商硇/_yf:#BB==Xe(Ȋ]gw7b(p}-wT?;l64W$$8.ŏ {Je(9bgQR_+Jk,J<-dUJ9m6~FyшCe\>(ͱ^ߣ4,=Ϛ6ϴ+)F=R[Fn(8K?414#{޲};Bۦo&xJ59L3p_حp0|{IF'S6ExzfPYnI=QLO/ =C6($ʺBZm&?3̌Im.]r߿mUpC~H=_4ZMWmez~"]S-Cm;Z?^y~uS&O̺0:=pk.z@YWҾm=M͵g^r1rlJUgzArMF]/6]`e[+', 'X =W?9B!g:%hxN,]sH LG~})md[SW\;U]1;26/N(65m% %f&Ŋ[IV|%r ^Rf'=Th 0yquPR*Su]WMo 1[Y=nmeaCqrNeivH 4կc&x+WLM'].lQVLaB=ON`t{Yd:'Xݿq8'YMh&!`Jۑm`VjA;U߈1Pbj}=|1-xi-ԩB4&&ʸ{J7Ո5"-BR޶íio'ON}IȘ]3ϿWkrBۈ:E{ a#Nv/ Nc^h|d#$g HYP.r@ɞk(E!-4ņwѡ4!?(F$-- \g S !c3Ϲ֮Up9*1(J~ޒfA7e!:o1}i49L8 >1ޕ#MM)3,yoũLPޓon~#ssT}}#{ /xES2w{OwL\*9AG4U-6}6yi_^-KIXf,!nKyQq;̼R RttDپ}RCJٹwdRi_A;] ėKQYC`9ٝe GP|Gf؜ (RJdQO)Ѿ;Ug&$G|zW3=XJ󳗝>}egXu8X6)7#oJ)7ZZI8 bZB H7˗9s'hO<Ѳy'2_{M =|5L2\zՋ/V Fx VzW,k\tF2zs:eCWmwJ-;ފ\RIHtr4!=KvI;&z DP$S#GػޜKNpO$"C񋔞eƉL[ac&QٞZ^uݵ_&[r eP2j-rUzku5r.tXٽ;PGY#z#BFk}Z]r * 2-FvP#!dHЯQc7~#[ˌK/u=[|>tGߥvko[\c cKcWg;I9sH f{ʛo׿zB1}{,q>26(Ln^+c}]B- Їde3G0 ;AsC\1 4M8c*mB[(Y]\,{(D2?,;:=@h3ͥ@ !GQfW^i/7] &NZA^B ZR !Cge=W-F7I]j7ҁ?7um!cL.t\u: ӡ뉃s~}i5ZZ .22n?WUDD\d\)(@1%B: ɩZ6\_leB[E7}V >ؽf%d٥g$:& $A~ xqkC(@ʛ??1gb*5Zw:aI=4s@9dcwIYԊN9(@yy]>- x5Sjp8t"/B0cg_ZIj_xQ2ZhiaVU(ա kFPT69ѓ!geu^QfI;4mx_O>2| )@bQ– /};voTWsHu96Mmk業Mxr⋣k _l|MGtFcA g=WNHu|GMg+T)l~LR0};w޴= gCxP-% %n.M`<!?`0u&Ṉ&4޼[Q]۸5 p.!NzKLoiúqh@(Q]u]~{F-+0.*e+%>>I˒д !ys'Pkm۪UV}sW\qNpXqϿb(Ţ,*--Mʾ};]}`WUq_5ڀY8luƖ||!4u!8ٚq/Ma eyBљ” 9$$"Vg« )`I)`Iq:_6 -ߎm1r q BhqM4d4?ځuʦM5!뮻3oyvvt 6Kbkjja͛?e3n+CJ֠J}NU>Q IDATnҏ;mKez. KyOOm8/Mew[#d9^1]y )rzuCSr0  Zo.m{KǟRڵZE[Bٶ\mi?P ?pkY`Q4C%MثT(oԬE!%s[s3Nf[tsLNϻ>anNr%b1&sS͓r*98(@?Bhuti)2lS͋{bΜ\ !%ҥyƍ-[vk{'N0`ݺX,\.G!iYY㬹sGP`VL<+-KA,۶=|?Y-^e16o(m˪`USŏC]pU;=`$@3MppH j _[ O]ro%Į*RŇ iGop=R|XAIkjexW6M@uhݢT8[l{~y_`|CS5̴zQ쌥hV M4>gy;g,t1]O5JyS6#q?gS흯N2Gwyyg#dĩV&O;.ƍ5U:ZƏ/2].+2pF$㭷~d[>^Mcn,9`?i_mqnX'&xҥ'3N1˼2MN6t#ޕFVO䊯M TRJX|Rynzz |}]6&!$ %&\չMJ/#mUJlLjgKoީ-W )j W,6搗/iʞVb bws=a{8أkjS /pXs;UiN,Lzjm@biΗBZnKIFXCtZN#$%ú.p͛g BHN^5/o47=gpnn ʶm۴j"I.q6zx@ЅEE_OYel[AWo@k] No[Ȳ}|H׾fox=9@U+ռ[n{gBnnW x-[vB<̳3gΎM4+TupGrpu$~ao ܪ BJ6ߊUʶzbNYsV!4N=dH K<=i)ҶRŊ쭱V :%!wfe_D-1<<3ahↈ2xtWz~.ZS,k~Sŋ-U5k( nVW3:D׉`kر1!K=@ss]K{Տmy̙:|. Z#Vvڵk슢p1i,cΜێ8X44X?Ls-FvXI8Ό Wų-GNlϘJʓiV-a /Lm:UP Oım}h*dzhL5Er}]G/ 9A: 7\T:Եzpv^ҳxe_زݻpzkG鋔&SGؙH<ǶS;]t]r95\uGg&Nd~F}jUU*eY8p`v^mlM07wfiNA7@0\F%yEֺj\GhbJ星Ϟ =jԊ9D; h&C!6^[\0MFE87ʙ;AHɑ&?Krq$˹Mjk/*Ay1qL6<nOfi-,YrDLV]]Qwت75+-- /}uwz"D8iaB"A]F<ǷS%d w촙esKH;E,K*fn!4WOE-i-zejռ1wMm-\&(ABa 9&\OK;#$@h>&O|Unh%>b`|Qf /^yDgjN{r`kHUN+Ѩ`v{X6ge=y1!p19G|lCKu9~<唳oʹ~{(׿m?餋{p^d`g 9te~~:-=]=nH[ž)ۡ\oIy.y Ќ UJNA}P-g>cmE-/lͱ[= )X4t)_wccuIҘu+$\{5%mmBC x{Y{s&cq5~ C"WQeb"K\Kb?s0 O?u70ϟ- onし.;fUp^BHXVUS 1@ #,==upgYQ84+(?һsyš;7PWQƝK3iwP>ʴb_ee2%nyԹHi(ҳgKfP̟l}P<RV5CwJq"g[+mWMN',!(^l-Ι;԰Y37moh#{])e}J-&z 19GF+ߪ޷<.5M6TIJ¯T?TXs?^տul%V^`I)7ycb+r`P>xIޑ2@ߚI*ڗ6Ӂ;=sJM"vx::+VSf'g\+/6/sL[HOPGþh;>㿙E7B z31۸`\q'c%=ƽƀDPAw: $$tB7ζ<3?#24㾌ᾭetge)tIfMe h0k<3:A+B[ef5dz,Gp9m1 {<{U*s}y Dž9'y  ^{sRQOsrMV}v*L&[2{6Q{e/ 7,ʤ{7E$DIɦ2Wfu7W##}[+V"!z!X3'z5@xO@!*}V P|vYJ`^`8hlpN7doAp>!$Df5 iӢ:+W`YHz'\eTU ͑$*>( 1\Fcr"Ǡ~DlABtA  3 J(@̖$DS F$ (ƌ3e%33jwFdoc]vY.(TAcgF Qz=0:xgThI1Tz^uAbtNԝv I@%sԲu?Ni>=}^۱kp:X);ۿ*XXɊ}{bEիU۷+% {Iv5{oaժߴvo$?7.11$=;ߨ駻EAAaî @ӳszJ z9#mԕ+^%'7ЧqZtEOgu߯<Ҿ<&"D'O4fdbp0zF֯\:V=)IVt v=d;$235 p!~Y ѣ6+!CrXȡC5tU3'Gmtuu6i)((T$FjjjÙj]W:3tXOG^_4S*1qRzqq\S>< 鯔8 6Y0SJwe&cJ%.`Hc*j߇)͵T?1K<!}*r32d/BƎ4m %K<n`XC#\s8Q={(dYI;hPJK|<վ}U¾}Ue@1~wJ zR؎$BNN*''sCձɮ quVWyvNB),,ݓ4izbjo20p:XKv%H[J47bV_ }A([koe>'ZۏOΟg,iC!ZY L U*JǾu;}m5K Jxs :`sB: `.໳D`OOg6/s>)>ɲ]M|>yw-_3[ߩwN=f?k*+jg }AXF(jwnZZԼ^׷mZ匌`Yэ) ="tV5$ITZX=x UD}4+k&+-I5Pu3;੧Az2#ϚƇC:}l$ƌ4鲨R>s\˗ l[dy870+p8ӊCoe![+0myr kdL9ڻ6GgdL6n\>,O%R &F30;{PqrIN\YR9D Ax]>0ET`w,  xj'AVCQ@\|Q YڲtW٤g˄{9a쐊rr8ӉI.NlM}>shx8kʦ?k1Ypwmڔݷ/SLOQ+8}|2ٸl> Z B4fB, \0aJ_[U\扳.ҎUV>C**ެvSjdyȘ w_Qfy]1B[" ~9zh[.WC,:;{(ɧe3c}mMW),M:-M3R) @v6σ-hՐF_}8ն޵|EEn#GAU?,{ +v2s㌬\macB= ן/9Z_A->G3s:}ZZVq#up]+v5GGW6TZfQ,S}@X$Zvkr1#,V04疊4Gmաxi^Q*3PY󛸶=oµu&U{o ì \#hKvB j$vF]\L\Jḋ| %*$۷ 1ݗҽC}2%N[(=@Xr3t+pcWuCx_ŎgxCwh+6m\iwBx<`۷ VN`( dboѳݻy SM'lM76Jl62] eܘ:;ȤxMj-4qOE(5Ġĉ^U:8y\H5wD,ij=#4(\O>RQGUngVвz"#u1i8R:32*Ƙ3=h#IH%{WP̋aR7{,gyYf%öOƄyG-rrT'4-עM@7-(NTؼGOCNyJ zKre.`Ҟx`￯.@B eT)/'ұcTr:y8 ).Tp'.4@:Z]}[$b챺gR挖b_1VQtIݽptjv~' ,9]$`:ẍj F-+TS 9 IlH6GK(ܩr7 m`m*j!! b,9JhkZS}"YK; $e 'aQR8KB[tC+u>% >:LnP,g{լД:Վɦ~Lh9R7[ܥ.vPGh'49&sl?h x_︆Zeȵ'q%-qi$# IDATGRѣ}m 99|{zh^]Oi>Eci%?s0)dum*P:ˮ/G}6pCr7Dxd/TD?Ҷv0@Pvѫ L+h[vNl[0ܒɎjO,U%}UTf>6]MSJY4[ )\;>v{BR } $=zԬ.޽& 6ۧau:c;yfM9Cҳ"| )91oWjb& a D A,jKmNIÿi1lVCJPfsZU;,իB"V)UR"eۖiDyƖ{eu Ok z FduHN|PA`Tmιs<{v }Qba/ se$Mw2[)>s]9}I;&eAZ:HJiBVI(S#`1(HBfϹ['%g @ Y:"/_r,Y&p8 c]>}ʕ^u8 _\ee/},[ѿN(TvaV 9׋ Ī=䘽&w8/rQLA}*0#e`\ڥr^!:ݸFY*ú}K\An..+*+*oЛoWpD`63p׸v#*-MIpt"福2[%Z n7sO cnⷍϫUJ.cK0*B"8X9ZLҜ墽!޼-r*;e#uIR6QV+Zd#;pz;C'1I~CL6RT@8[)iz{OwfiEQ .;]䐧't mƢ;`:]hdY;ɓ Žc5]Dr=Rr=\ >4h4.,X cp5jS,;U.EBMV~Fc}|뀰~H,/>;kCLԱMiO>)lo_QaQNkCdP鮡ٶ|^D<>V轌$/s~}yㆲOt]뭣$zD$ix8}@`clW'X2ֻۧ8Ȗ8Ol@S7Q\Qdk7fM i ѧJ%'U*QM+iàJ `P0Rf;u30wEc1P4 XCch 601Ҫ.XR&5L6jch||s]_p8'ɪ}~qq&Uj>ث1In?VlIMVe' Fue(DXi2wO3=ٳ}V?mbJJ$E88) 7ExKn+Gs?p8N %d>\=Z\L x`s8pN'P7>Xx]W E@yоp8X`RSuˀ`t`}@c#H9p8G?$;w?l_=xj > \s8p(~GS&e:΢*x`pODgp8t~ з[gjt`vٕ+Qr!_r9p815@o"9`mBqK7z; k_Ӂ][ce@np j-E$@RL'_qUvi:ssԷwۡm',z϶?MrߝZ=%|la ԻCNZ[@d>X=9\cpyQe?p t"ׅWvGL6,ؠ!L U3* c2*{ {@Ö7`2kr߭e}mii:ڟQݝ,G/Lu5{p7վڙ4mb[uPW~loD>ۊ b㿭ZWkIOw~l=n-~'mσVuw<ݖo9 CGM[[m2tܦ9GZ!j]b6˴2kkCry۪k(e2>`ۏ:e9^ȋ sNZ[@w T%$%8 @"Dɂ. ` }0%5d~2SinFg7sp5EXb'\z~]j ^k9rW4J}MۏvЎBZ=!]^'{R qOԔ"`F-uct=]kN K p['sj_W-dAATRZYfЙIZM~=p8H7P V'=F>>1#sb|ʠ2PrNEBΓhp8@&ZdYGWk9`薗C|_7@bNW (}:U9pZ*`VʦDx=N/pD&'Pk8' ? Wsqp8ON-Ԭ&L OڞN7N t6s"!DzSؿ|Z8p8Uu14ZE$ CygQZ. !.P`_~ppqgA;@d7:T4:b͇p8FDJqE~SN3^kP54&=ct& xIl(@XE+Ey p8NE+݌]k=TOa@zi?!_&ickSQFʨA$e B(qN\izzOYk{N=UYx}2u ǔRLY< ` ~x&Q*8I#v{pz=jB 1#D7ɼ (|4Wruz _"hvo-oW%SYE`JyrfMLJosZ`MDψÇo<&0t?;iֱ#ɨ11O?̔K_m$s/Li~n/gՕy cm)z3.KS"Lz56TО:JzߧP[ZW?_X5#=NK4hL8 yGkز_o찟ǜ` {Σ`L%ܒ ?p) #E쵻_p?5+_ڞӘ*=Ya_F):@q\L0` 4 tI> 0ҌӔHT71^KG.Dybs[\Sgv'tCrM7c&Q&ęI +KNk%dѪPVXsJ;zj*K)E祛رRfs"4B"C1ip:2yb,IiplݫqD`IpF5 w0mŹ܁jٷ@ 2xd*O=`#@]n!5Hg}Ӕ,V7ޚ&|IT_?9J#>>QZ y%3ώ%ϭ핏dJK=:8D[ 0FŚ /}9z+69շBJ(졫+y\78˿xWzhk'@_v7c Ѓ \`7*ߓ[ wMA>`A2X>`O!%Z;Q!zK,7ܚvPRWl`$z]XD|ay^QhUN<$⡧fw_Mf F!iD%:BMM 1f q$}t {f-EAC#FwpHP &&aQna0J6WǝcY%(?I9e =Z$cJ|cNAHGg &%#"5(/]N/!T,U|ٳ'`moT'KuYBCȊ$"5X : @{BЕX`v2e_R4f2{%\um{rgv֮*2Kd& ;ȵ.),ƞzkg峕?dɳ%# dv:qZ<3k%̽%왇VJyY֙<#ԫuSeBɇYRit*v^qm Ւ:I`a zV,e ۃ$gCk:{os;biM.s:>:"Ռ֣@- P%m]~D]`ח/P "^*մsRiVf[! T=8^xg¢[ΠD%l쇥;mk)InEԋ jQ@ԁMvpyC/^&ٺ۹>9lnD|!vPXc*w+&"./|w0IDdnf1YEK'?ZB5%WoQ *_U_l`ێ0*PL`" xGуIξ\Z+YH~~KJa[eXٱr$%MnjI' Ӎ=YlʣY7.9Bl^m7q/%iPQDMH9{OmRz^N'Q]K>3Auo l=zmR3/5K;C E,X^ %#[䡡SBe헟{l$d`-ym*cl4o3md[}l0f7y=?J|ٴ_/Az0aZyU ]R0P!?}=tOv^o N^ryIHC_,Dn}zxS^Z%d&)GXn"bUw̤k vzeU&4+ HX]lرzΧQ񡨫[ޔe}ւ Ѵq7$S:,F\0Hn00S#ߔQز|{7eQ7 rcZzA`߻w\rͣא=kw3GNO_<Ȣ$%9x'Z\ cF=ĦCd#͡2DOz?!h#[xY5q =63y2vH|^% 7d ocB/8m#! Q[ȏsJEǻ3zŋBϕ|F@qm41Xaے;C '=*I55UNK6o|ovl\[ mdף+E,15$0apZx;+kxb+aD-׃WȲlzia >}7c&wWZ:gT|Y>WC/_KϾx<1Y_LG8Wo>|xO^+%曭l{\Yb•w_@װ/_]ƪ׳ !>j 2~a/.yM*,~J _ky͗XK/I>yn);{L&{.c|ZYcʽn/v*A:=<8`Soo$@^4`;-Ov`ĵy'-d`I87:fg 8HK+ay#2֒S˺(/UaKwv5UN,Z&t>~ׯkl뺜v[*-Z.}?ɪGWVO }rԖ`&A<{}k#œ'kϑg TWc/{wd^c51l|2ћtz|՟h{,rKQO/?|zixa $211d_;c&I#lG}2la$,6s R g: J:_O ;%-F)xo/+pk}À}mt^4iB4grocy*6<#,opkzԻ}C)T@0ij q2S&,B[t 08(?LqU.̭жj 2A"/Ccn$Fs0 2wuy}A&Rrk)}^ k",ڊqI$uD3}(I ΠO,NUMuGƇ;\ҡUe"2>$EoYA%l5ny2:ޔ.հ-{/R&]"h(CLr|bdny3[pBkʗmlq`~V_.GeZ&' rj"4TyQ?uE*,(E`a[4*n7 =hUMՐBls{>2=No)k::Hzp }w),\G.4uޞqJI :VRVq}q" & L-k[:^0‘7N *OB;54BCyxKog@)ATS!m*#MI3FĞ䲫"$1߿ *B၃z~2pw>N >><B"xd+𙳢:o:'<7K3s_[S wܝ!P/&D<>&[֯)}ğDUPH;)̹@aw)۱\Na۞9'@SV:~"4K?ǛD4U4^HɈ'Aaf뎜2~?\ 3cn~y˲řM!w榉uHD֨1]v%r|Y<@|ZbAw, E ۧ ` wd|@}_?)|T>J0mz0)#,\KI- ]p^IXȌY)*N#5ws9-R 'DU{&*B݋YΖOS;a:1Z3QJҷwW01Xc!jT &3D >whfsi;YMe=Ԣ ~N֪q ޓh؞m>ڇ.ia}r1yrn-fDYA9}y㋩j.A`nDEYܺa(۬.ۜ`\PD7ޅ$ rFpo`qL o)VQfK]($$;LUAeS|,´dX!*E-'ڋ!/}Q+Ӡ.6M3! miރ'(,s9 utZYӫcBT$ ":r_Z!elv˗^Aã䝯/W:iBӫ1$rݓغ>mYwJ2XR#Ϥ~>U{g?{GquԻd5K+ƘbŔ HHx! HHզW۸16M,KV:I;]y8tUl5|gfw;3\˜bFdLpq8( \qB[s?l>H﫠u-Ҳ& mmX6s|^Ν\k oM-4-7\ HWמx?{OBu~&N&Gqb.xD̡]%5x^nڒ|su(] ﹗l8Jl&wybU* P' JQJy{)f ־vpIxm)6}vޅYi_E&{+Q V]?즩SaۻZLF+z޸3+Cs&+2vݾo4mB!* ,p6Af t<<0Bl̐JI ͞(\uLz/]&-wzyȘAmI6'<ʦ$ع{,x[}'o N;73 pQi֘;YZ0u_ PŨjA5*84Xxc9nQL| z^]mrܶ%KΉUI U$$v\]ir-i?zt4X*1JpOѿ.l W@}Y^K68_O 'ukfv8̢({S~P)26;۷6ܿ_7{,DevfTrIj"މ=Tw~m51&bѮj緛}fA|-6#,@;6Vkt ڢcCCՎ^eAp8=cٙx=W_ezQsEqroJ@ZEϺ;Z/|m)yحW6 SGSxZfㄔx>2.Gv3mmh*|h1zxgl8kyG%Dp Mr:yG9ښ;<=V\.] /HMᓳ8JvZqR~.Qzd3uҏ"u.*1gȸ|v[&5ۦ.d \Tb40ӎZSwnwlwXe;mMa:BAMI Po̞>^ʝ1MM a1[hMquNCG~[D{PJt%!w:@}D"osE ˀJeVY7t3-L93Y]z-G bt'37*kP^,}'Y:}>ni^U`GzN,Qmtij uJH?(z`@1Dxz@sN1Ak~ڷ A&{[ l@F+\on< 4g}w|O{wL"Ap`O_V~fxkJiUq6_} `0 f0 `0FL3 `0& `0Q `0 ( t`0 cV"$!)GB4UZuTVѤSh*FھHGIpd5ިSCG j;%}q%X8F$}(/cW`$hE ]@|Oƍ-PY :@6a8HE:> 6>^0F*h:^h . ,X>jc62:jbŠW8͑nH&OAkR/gvĄڄdf0 `xU'',kON%HUT}~wh IBx'ɸr=GИt#m`0 c`pȇ$$&_7aջxH0~Y䥯PD- ŋ&qId*ya&$Fŋ~`"69"_~UHhD~ڹ֔V w ƨBИt)0ny[nU#fHU|:;,hbFtBV/^!.J 1)׿XJ?^!iÏ 3^߆* ƌŭϛV&&15\Wg|gYXv*S9 IDAT[jJ+F9cPDd\kJ^Vc9ᶁY' L/g8V qdLn^wf3;goyBϝ #KLΙ>ZLT0 cTM'.|3eK_q}@ArdkgW88hhR0%5yTF锠`lf9V'QX;kۤO?-WU0`􃷟|jtZTc ^iSe]!c_aA)'z˫X9L=CP|ӟ}E2$ć0i e(Kxʛlum=jr% F8{?-54)a !$.xgNW,]p!)GRGږe2&pP͊3bIb\1cMriy vL%:7tVCUMDz y흝gŽ6槓_{ՖCõj۶W]4+O#~_Yybo11$4T#^ƏK&ǡV1yR7n| i3tҒZZr7(2iR*IJ"JO*ecDzHN!YYI$=#;hyY=--6%&GpLh7ٖB VI'5Z`hnH=L6D3 -Fzmmi@DTjCUy%`LZE#, R BƎK%icSHt\$&ZYVchDFS 5y禒y9DUء^CB0ܩ$.)E%.9oiJdAxT-%m)9$>%T9NKS}  RqGDG!KEdCV^7[>1;$il*QVt[ 'QRaLNs2Ixl4*kPSRNFlYHT"2$<{wn=F*Cz&YL/H"u8Fڌ3XC(2RFUSwy辕¤I^"<\O Fٳ/ %KW߾63ji1`Jb|רxaq%`,2LN!^oVbb$))@aaW{=ITze {V}*4x߸a3r23Q{F{?otm&ck=?x`r+Ww+6o^_O ӂW<褲 BDd(}EH%_^Ưd.P~%Sݻ+=\IgGv7?~X>n3,sį?j>,"4`;6/?V2 ڋ]έX۹y}JUG_{FYXj!w}q eς΄C×? Z:-.+.Mmomiw#;.yMR7~Mn9o[ͽp!& {PZtljs)x푿l9~M{~mK#oܫ]eI"o{_m񳧒5 El{b.cpHUa|&r8m3s=D@@ɍے7vmyI@* &pzRH7l=(շܬxrI4n?S\wKΆ΀7I㓹o\&#L!N*@CwW6%utK˛FݟҥSe+墢b#??̙3;T1w 39vAycT0k8\`PAP׋iqD%|~\rFDŽa)\Ffyۄg|_==Fo0~BQ[{`lpkBJK{#-3DDBe(:Sr_q.'I2p;REki^K1?< ;%N[Z`*g`ʹܼfh[ "c" ɛeCS;2rSqsƑ;\TBop w(= Y(3L>\u\EI\]_q+]A`ߎBzxjj7"5;,t19oy$5+{7?x+v#= M%7f gۮAKLOg6FIK[n-F0.F2u\oNZBsaX߷cٍWKuBptw1=^t4"!3._IXDs3cLQI3~DlOiCG.:@!nG ){Hq6EidCĽw, G˚uwX(g_5Pr׭$rqG}Sg9-/xAbHJ^Ѣ.W*y ?+/o깑w76vƎ {wGOキw}!sի.lMG.h>?ew|ǝ+97蜞URY,wǝݷz:~ܭs}~QǎPɊP &e=?>L!Pye$^ݽ]E\#_~S%A  Y) u#a{_^'AW.־ݱy7͢;OnO>gR&d:n란lr`!lWjĵw]-\9l&>~ yQVf;#߰ 2לOLon׽6;[?܂?g>7?Y>|Ξə)dѪ%^y%y{&3mZ^ hPy9wv]oNy_B>y3S%o=0 +e:2bIDTr)/wi/,:VSOq歷өU 7,!(9RC]ܛBqnpw Égz_r8Dtl,S/*sMu]*Mn j{KKHvv񧔢hWɭ>mFlj̜1~}ii"yyA͒('^ͦL <[;>n0vB y}7B6%us/K 2_zep6{奔ޑe4ym-?캋Zp?7/soЎjrٽA/;܃f>K޴]$WsxϹc~R(t%ڇꮓ:b2PNV" >TTŸj Ͽ/9"rݮ2d _wt[x\ ź{T-2ET-b$[<Wow LM#qq^?nKTnܰ/`^QeSaIBZ{`MhK`9GhRyeÄD)ydiQ:'^sbT(PvjGYR@|R 7%LK&M%{\=>9&huٯnKmɏE戮VBT)ֳ]T k˗?0u%3'nl[(ọ,kg[)htZ$ wB竿j]GOT|@4ԶPh[UםL t_S}0&FDiL~١ᡤR{"S X?/5*%"c#ah28DŻ&F6\LC,oT1wb\o[١TG*,yKY$'lӅ sM]xEu%,αdTtt f1N2H:wm5cSZ5f"l#L ܸ(L6M^Dڻ145%ń<::-, +ARbՓ&#>aTɹ9.?RAwvd<)[ex+m{{hmAt{K }Z][jFFfs۶ӳz {K̹?-;PxLr9XAf^h7z3!$Ƒ8r5e÷E?q8p}ZuyM\@CM3=T\JMF3,f L@^0BNG_r3}y&|ΟׯCHX14>Bwkl&ؾyS󫳳H68DES9!&EGB(NٟsNM'賗0#R13^N^>2IpM M=>v0CH Aۯ;"\2*5bg 楓uБv"XQqY(K# Nnd0$yẠ3|5Z  72`e/{.Y>L&|U,N%(*P(iG4yҀ.5Kh12Z)SsN$ nB..!aﺌ]6 撅A)!<@ #fhAyEG8V)nWɔS&q1z|j'$hn6҄T$$DlۺVلHR]' I).ז:_ %˧!z6H#BpqjATU46C'rƥ0'OV#mCm#ij۫sM#]4{ei߂gO'<ϡnۀ1ďڊ:J)!)]{3@w$ &bbCAI xl;hRR8s;:9xshykmLGs+.hBtHFjJ+*{=TZ-QkAH䙙-{W|6Xe@Up) iB5 'N.b]m!ʐD6>H9)M%YMxʵxˑ҆!ŕ،8`J*i*4YqffđVT$OZA[>~vrK +j|9_ a;Zwln?Hٮ/wL^l*wݚ 겡ȉWtcsM .!Mt"b\BH0 h`QS^CnjC\K#iLB r~y9sE*%f }XRyo앋8lv4TY+m h9+:R浿@ ?{*w {WM8Y2M(K&i- ced㬏?エMMGNb[%B{!ryE߫b*\Id֌DM,]::mi pxm2&ݰ<锰%Y\8)_]ƫ :-pv?Ak]#/t-Tr^dY~j8gD^ȗY֠:5Iq1dҴ\/GpݫM<:bd>n£1I^?ycJ)En8H_|$:!xdrս7QMN/!ud*ʞ:3?7&Q Nl~}/P)"k$\t׍ >sNQDdQ5pCE‚iUY==e(x)~yt6,B6>P I+O&~}#CrraB26-f K,k媣 ^[VzI rWfJ_>&;L{}5y׳RO{n|i]wKkiաR\=$%w,Rr܅?4;hrHe%KV gg)z&b y;uG>z|}/}:;u? n m>UyNrLpNG=d%ce~}ZQ_KڽغoesBJ%`Ҹ$.+#$IUM--oJeݎY$$DEjjhS ko[ƐB(E]}[_[&Ap5ۑ:bwֽ@ff< ӐvfT ); Rm?n QG=Eee%ƐHR^VOG IDATuTb"~:~ ~4#3de%xEC{$crV75Ԏ:g_JL$aa:P ݱ|JZ<?!Dń#,ϲ5sIrFRfGGk;=^:|&>vMI#c'f!69TVcf 5+N=Igͽp!&cu:9)dNʁtR?B6ҨHce 5DCqnSrIB4AY!\Uۓly*Re!!#ĥ%Cr:aliCsU JSWHOI>ӍsiO;8W7@W4X: uiH>zwBZ4Pѯ7U}qwyߩnWKqV \㸑*hKH]R$R&G{f?o=ö~ tЀ{'荔#G[G=i@e7 To>~(_"oy>邶G@el%*:m$;w&KWX-Z+N1xK@?'*B£9kҗi9W `ME-r#mقBo`f> ;<3@u J#2qj{#z`0 iC~G&U`+A  ]Ǡ $GFi@\mRW̸Eua0 (OMr1:'sPYEИx^iU8%c4}Sh[GM ;yL3 o%҆ʺA-nՇ@oLj$ #m6k$TR$a,3|m@T ܵvhJiI7?5^ͼ>|& YOiZZ<(a"l ,<)ŖV.{ ;DP=nSvl Gr̸;QpUDf1(t\pD4$Piħ10 1*Jֶmd˄c9-H4R'N7qJ@]m±a^I_D4~zV!Yt`մ:xP+\iϼ9@NcuwF@S&P T`G\p5p1I,28ߣ’/tqP~`0 hB]tCȖlĹ, :]c $ௗN%P+8]R#oUY%i³٫`2]4d:ve8fAQ\2~^\T&> qҽve;"M Bx*I| qQkb[WL8{mD861TGC4P10F}Q𐪱@#%DL)*$u`۬(uhL1s̚6}EJ89:$71 11v9YcDeOeO嘬FJ].UTz+C)!g`0RtI",DdGbMׄX2 }L . J M`@%H)CL)a-2g(.W.X۩hxY +5'P??,ό$᳡:HOuC=ƾW'so|?0VP t|a]V' 'G1`>M38mJE (BxYK(:Ee-o,d Ǡd~ZN͆w$qq@*6R`0(B8Yвό^^I@sdman(ByYc0 1z8C&9ydma0 `0N\_0]dz `0ӞTe+-s7P]#j`0 1 kcO&A04 w+N`0NaZ (dDR"D)Qt$B2%LBdA>I=\Fwt1#,]k )қQ2{wZWԣB=F3J<:]{#+= \wO ԿNcW^.;ҔHB(Q/s2T(eȄRa$1a&nG/>2 PBEJ(;8p';HQ &*DZap+mA9)-ZѭP77/-h{$H4!лv@xqbmF,=—{So]g^(=6{鞇cuP,ە;= P@r=Jm@<R׃ Q vH Q +DjD)HZ3LQ\tf`v: 1ʰK|[U# S YeAp:x x=GV!~>$}\.T4**K1\xI-Qy&V`ˀ"Z'b$!JHGd!JpB2nDuLj38 PH"KvXr4q=b4c\zuOe}r{[lxAL2o6ؕkdvkT%d/4}YzE}4:xB GCy.IጜFʲPFZl}e=z2:Oc"W.7JIM͔FvL8)+Ɓ{^ F NTpQfN^]*dY$.1s0NVyWg.* zѯi3 a)^QMxGZo%{ ޴]g_Vҡ u]@ bx,=vuQЏUٓ;G3o7]7<ɋ U7S3^Eh9ZKt@7焘YQ ա.hkǷ8 ɥeNQ.u>$+O@tx{탮T T|WH hpF9vjR*vl `,TP~9q$<}g]٤K3#b$gÓv+WZ)ԶtvGQU+y-='P${m6[>o=;.S$ Q)5-4dDuBY'tR]dӮG}mYE?o7^72F'$OSmǷ[?=JY7qʑ"% Qjꙵ ^Ih0cSŇ;Zy 7*"BFۊD Q@YčoC~u ({l3W'TSq;C|;PePd%$&B-e%Ybs7 GqN׏(.#bO@cP]!׉ّpՐg]g5q-zyڸt'L4nCYW3OP2wE|mldEWXc|mjp0J|-W_![%OW#R9k"ۚ~?7[GK x~Z-d$mY"EMNrM( &BUT<9~GFw|:@ѐ|_ utu Di.sR06F#K "GV fgE9vr|:q:1.>De$iXN21/ΞM+DCg9$ 6,O MٹMCS䠤s8O ;}: ^bN~L[eΜ(<\*ʺwZbsrLaY s-1##'m#m`([m ,NojA$Bx) K?N#>up |ݭ=⠃eXHnq!;N+MK x~tkbvZ'p IbB^t8DSQjFufv#{|p &fr/TfZ.lPrsָ"W3 M$/-ct:YEN"cs{pRj&{stL/ѶQH\2lA]":0yEǥ6XK2~駏Kɹ : :3ҷu.-5#;nUMJYn^F/J%O f$؀[yiKCI% [6]􄹸atoyeJΙ&@x3~v#S聧Ӣ RSCU{y)T GKSmts*4֑tM$_wP%5rY>[Q  RRAjTn>+jV b8RFAYfS+v̉t w~MM9s~7"g,sÃSVK$?8eXBǧ-1_oILatrWBZb:i/7ֻDևt N3eSqA%)>d"3O+$P=|D.M[B̋s Zvk3rEy "袧 ptNņϙbםsVFa `突Q~8뽝?Dս )nBƙN YJ_o̹9mʕT33 soj=Bkto!'hY$M4rJ(zv؉& ACTؤ7+ŪV#ՒRθM0?F~?eZ` `m |7rP~9H #m c2vSM~5)7kf:[ MU:S/ 3|%պpHoD<4S' OMv-Qc yCPo;w}_QI!H@]RؠvaM}{swՠ&֫[ۭ=PIQ`S#.42j*CGfNޤV/&ظ; pIݯ8Lj9Կoqp5xo 0[mS-PdLHt(QӳZ>]i󪈎)e))#tܳ^Mh‚Sz>pH3RĹuZN-wy]Fa~V(Q-N V9e=5BI^ $Y(iqL ;F#:+֙3?3N'|=A۠fN@}E&K 4C-ʉ^o/F.Ȳxn׻CfN/b8B\D&TJ׃WרSvDSN c{bUgEۧuBYQ9^d@$RBթR-~K*EJA$lll;]w=ș3Μs&:EJWLq\E&Fx`s7N˪f MV%6?{?my ]6×\$WX$r?۪si91~t~.+}C?xؤ~kv 63l[mڬdN$/7Tc(vy+jN{? ]bD'9 Ppώ$mDsGI~G3yhܶХ˖Yy~kdg/5}lטhBc86Z ILoZmaG/~se"g)ͲR=VpӪAVXRD *5le}5I,S7S)E[#){kK6N?^^)]0ch~v+E0M&ɧض{X"/OYVȏϚP,m`wH+m6ɤ.`ʋo{e>EIߌߔ|7<Ce(vL:@C\ݷnنc& 7:B' 9G/#GTtY FrИ01r qy9xvq~rGy6%k'AwLzEvl v\1'lVOr- 1.(ͲLwV!ׇ4=1h`=/*uk 5v !ҫ.-;(NrˤBjq2>1uG[_9iS}jI[;qOxqK]8')qfٌف v-Z);׮}l.U2]]lA08:9}yY/=ا>MnT4I'0ONVqDO@Ti~gfm1Ɍ%qٰP"sPKPa,M)X/8ޤ(oPC$lAni φTj(QX:a|TSsmuGY_`W7(:ϙ|VM.p;6/1ɣ-n5'υu.F])WĸX\EwKK=ݞd'^%> ̜Wn`pUn - IDAT'::W)$7`LHw0{ 8_ܽ|0)]!ޜD2Q|WG,\eox?a~9gGE=Pߞ\k(i:!-c }uڕh\OrBJ?NjImZ?)`^P),p~H$iy ɪ:_/NOruXtzP玟茰@JwZb7=pΫF9}ZSLkl>+/zxbuPYh"._16C{gx4V6|G x3SuM6$'Ȑl1S+ JHRtM69dTk֧c[V2ץ_=asO` GfG0YSj< ]V`~ k" q|ٚW[kjJ="r]MJ&}#'$.П?\`Slv@`$Edjm'l{Xl9C~+n4.L:Pl alz@bv)±F# 8o)~`}7ktt:dO!̣SĭѧPe\pHפ*,H]RF[EIX4/)fF[+$TTVxJ t)+viUȆ V Ϫc Y؅K~OGp~s+%N/4;|pp/,pjO* tC˗%gyAS3{#СUw^bA7ޘ٘4[ `H*؋lY'ܤX^-f{J"*8r~bOgYJs8F۶cuytNFq8ͥw^ie3<#*>W JRE3륍~q%% n@zQZ;e3rlC hY~%YYfm73v>g1.^UH]Dyss}^Q\ڎp }2;WhMo4&d#,i{p Z f3jb;\^:\VHd<#zSPaPЧ8Uì)Ł}0)?(^~eY ʀ0a^H3,J 99 !zA>WC1_LgP脞ūQk3XXCD?r{pi4̀K֕D˦ys $B7tqg !Q\U m;;f/ʋ0E}z'Q\Sɐ͉Xn!fݛ! gu2k9  ==I/u;бO}5ů>݈MM݂{*$%@^"(,-zw<)yJgM=ӔPp.i|Y5Z rf&xɉ2^+X(eǹFtk+0lM8U$.ƈ l_8!<-3W\=5c0 aHvDC Ȝ&]18##^):9Id2L~?ݭ/{4!awǤĴy)!$TJJޥ_5Үϧ w^O_HՄ0)鷽|~8$NI’2TuMzdz~Mk.ӂd* ؏Cz77([)*W}j[gsBBRI75? hOAkf:9E7g-FQ&ML Ekb =I0Z^ͨY(e} 16)Zb{d{CO?sKWaz-"{'ÿ ;ߡ֫4-ݭ?SGJ`+.%za b `x:UHJ |O#GS oJ?ݕ]iK.5=oiŒrSϵ?[mk1&9l1ni޸A1Q;f(* rC.]etRPZ ;cбr6|_XSg"c*l\s*;3kHgJ󧼺:.U<P"d|3PﭲWQHy+51{SC?#ate1IY*앜N)  T`^ZQyQEwco{ƿ"#pwQE̦ M崛~(CY6RRYM_#%Qy5g<|4ěIx4lqX@j=Ϻ0 bd `L7b0k8=qLݪu bq#]5Eh& eZ4 UY"Q3X􇖤TEVQ5mg#wQsGw7r+ccJ4G5) 11 s66N41y9dbZ`2 bэllPWIn[(^&&_MXZ*QXr8d꜒xnӯ5ݙ*}~E(݃A BG4z }~K߹Fוd|0_ǮCQ$ܠrώL \+~wh&`nmX?" څ1eSҙ(!cF *{p^ZV?L!a !Bs@3SMn]Pm+J=|P+B=8ztaZ8OvnV:Ua(+X,PP5r2W.[k}$v& 3\L?r%olC6 -̀/wpBJ(VV2<BwAK*xd[T(*t/{^rl;u%݃:B mg) .qǗOU!'" eϹ4h3EQq X8;Kh)AU->1ˑu3E8Dr`&I}usyQ.3@"waj(gVWƴHK[wi+Cp<{ 8{~*+QS=Dk/NbDB.6 DR_ipHSh\D^4xgK~-?L.j - OXB4b>}QLYT,߁hE"|͹XP` /"!ۊ"P,?K(Eٶ/Lbl(@\cpQCMI ~@g~ژZ8v6MC$#wc:hPBgiG?K37*8P65 1?K|8i$J y%rRR$6cn+ϊʓg8{ J^PzF 3VgE^П}B~jqfy6sGPTh*k\"#Sӧx5CW+*Euq}W 'fduE1-|UM$:v$cjW8>^"gX @q0÷PYF<8 8..=U}@!L tMu>gSYr RB(+1IH&*+*2R=KZ\L[(~{1'~it֗oMU)hC\"61Kv Aj;'E RS]](h 2+Ï)kա\-F1'7ޙ\9MJD xD:ۚvl>De^8f CД1|}[s&&[NƱ!JcwM@#S߾m>02S)EAcIYi(ĔK<׮z1C67, jMcpki(#ѻ>4_Fhi9׹a8 ,̉~{k=6Bvj @y;g+O͜^q:Bl$l;NP XuiuMSSzFŁR$)ЇTQ,`kL\=v䶪-'ѯIqȜ_>6ildWǎ0\@L N=z=;(^vB ͸V]%&/^T98&@R^Q9m_{m)1lic24O8^sPt"Hk5~Bi2;p@GBP`g X0, lkIGǛutb;ȳz13b{l[ dm~L/˗.KU U-ó][&WjDn_O}0Ju zF5Ŋ]\iypgm%+ J^*pN)u/) `r]([¢D[5J<@?yY(xbLEi7rVeld7IsP= Gai=Ǜ*l跃`ôaX3g ԣ-ߚ|C5mU/߉[(ΝLk$ĸ?%,'i/VŁc/HדRx.n(Z" ٲJADWb yARIh쟘;g+[{CjcvtDtc.%}tͨ"cL KF;ezp#S̒襓Ʈnc+]oF~]3r4Lc7p^^1ǧ;$$=-W7sM!JF0%hu[ylk8j[U;5T]#UQ8ߡ*D>5*Pq F٪Wabk<PA*11-C!/XeciWO=,}xRtoPq_p.N?yR|!w_<9c}'%۾n9G r(ßB+A>CG =-\*--CkRVE#5T߉ڿglq 6Kɟloşh9lHͨUAMDE%^Vu\j51pj|H˲,g/e[|~a{OFU5Ѹn~P}f{xŲ1*U[S#Ox\IUI\,y("]赽ںy֪*̷W l۪9$ᆷJ)Ї@{ c #b=H@YҐsژXbyF-eWbH|:B, Ê 9u% w~Vf)ÅXNbuU :^qܓO7|Ue4kbU0SyQ~b[A)PIɛ%',o=xrAxBuNF.]$(KdnMh)3t8_pv<5ZC^ݧD1*[aDOu&" zFGϧkDc i Wk(PX_!'-IhgM ܘ DЖ3/rO<~2FL ʀdCBgE8$6ɐKT:\XyT^BU'<^l׮w_y~ [b'kc8:\BI<|+}aOOѓ-O1s_Osf<'Z(cvx3G:~1Adr38\` !Д7BܸEileΊa8|t$k-C?w^b/GlT3((2[S|p/ò 0w1,,0Ksb(9YN "@$LW^JQ0Al”+Ѓ X-lul Z31 cX2Ӌg}FAaAB滭&" SEYKlJ^y K]A*SV'.6f~ <}ʽPR&{7׆sM4gH}[2)+/l_95&h+yrlj(?iZO=r3C?"Jº `s 6̳r28hIymlk+# uVLL"_WƩBЊC3RX"_b ͽ`c~#dY r*J={L< oG&IU Lg–/M\\(''-vaP-]x}'6,orZ)n?t&C WO7j{{uOh9/JՌXe9@u8?lq u` l?6j'ɹQ*$'rўrږ@96S<}_Z$d*yiLK={diƒ|9(vuXחZM>Ļ$n4~߸[qgriF-Qpjv:|fEvdg8Y!%^Vv,D'&%gzEEv`v^5tSa..(`.R<0_hD,$Pu!6:"A&2zh# :tÐm>K2ԭE-qT(rRf)3C6BYf>M "礄n[&[i&A|t6O,ҕvtJ֦@|x-ʱPVדbG!ՓN#Cإ=jheT+#q][21%n @kҵ$9nxZyYV{T7#vK ]@Xvft΃ ͙P;o[T҆/ rȶ|0-C>^moV> +o5JG|n[֗\gk}wxl4}3o,+􂹂\ju܋WG !ĹAos p i^,d;&+Bƕys>ɹvc Nȧjo>N}QXRLq>ls@T ӟlrWy}Oݶ_bA=󚠾"]zP6&]e/o i;,Xo-gagir?W kގ+X3}m %zT*,)?yW KոҒij;}'[m&1oa/e2xL A5:/qU[VmI2ܷtW h26U\Xi{u2IQdș{=BCLK,twIjY)4E5r`q˲o( 8vL>6`{ꪽO^ipk9GF&c#jq]lJR"*yN%^٫'~Ё@-3$vq~'7)v=!}RX7˯FC, ڌ.-IԵ$^8&{7;81C³.h/4)Z<=,3&1C?]oHU̮7l?6G7Kz)jCiҐ}6<86^}+pc} #Gz8h9 &[ˬܷ'9?4F57+ʦ̚B%G9 fMJZ%= gzޏy{J~r;5ɑ+8tu];dp@ϾJ\[uwYJ& JA;zN\wcĶ[Wze<uNG V)M$6ml8~Il^`fKQҫxz9"LfYIyNe&=OUaNxZ:ţ.X`j]!*SSc5?|pT.2[MW] r޿_ju?[\ҼӼn.rM2FO,gN&K0@Ŝqng>?Jc=G'\.MS$ўWť U/9^ Z 4 PQ!C1g11IO#@{niΝ*vKw;jZzcflJ*:5H e /.s0x'w\Y`j_f2 vrQp(Q{˚|36JLAw=!pkEȞ`=Ak`.SS)b%I #q(8dȱO_TvʱGLsV2'hBCX)e bu=>>eئ@o܂1c͂!Fbg7j\!O}YKsX7^|#Ljy?MK&dw#(m5SN@=.^71\Li9Gr9IS1z=jRNJLJ-J-ϭVf] "Oϭ!bX/b>k dH]DtKmm}TI}Y:"d~s;A82V֖)s X\TiLR%na^C@-4`ॹkKsXUCaMz=4}EmޯiU-MD5͞=̠djd,pꍸ 1/$/7bbbZ`G=;M_L KMdܯf8yhՓ-f!](n]QѪa1wL H mH謫MSx@%:KU4 Sshwi@DAk^Ӧ-T^] ]}3-އCp%UKđS_mj93oo`8xDS\trD69Bhi,A)rq>ΐ'A9or#IF\I9FWc)S9*T` SәLtJ9[>}.6I1X|7P9j;%a^m̸8+Wʲ+v-7\^'@ }te;Te̋{ݻ1k{:wL1&IrUىVe'm*Þ8 J ƹ8s&q$&&c (NNg oPәT :3:GS|~١v6Ls6&ju[Vnݷ.w>fl؄uV_W(u%] K^K ֜˔&QѨӮ̞0$  7Oq?wԾx#3Ny@L#mkYmuZmR9ꔊ/vmeƷ״uuN!eD:ޑ`έ@Gϥ6Ҏ!bejv:=B1SWڶtL" E ŭ?ŌPR?!aLa !@q'X[upm\1Gw&i:Τd+_ 2f}Ⱥɺh;㖿?ʄ՗`Z:/ 3o1O10ifě l4HV%e2)'p ѩf:c Q[!ebb20yDT_V'juOo,)n %[ 1m{y-7*HY+g~oU-A^wa3E(~koB~EaaSBu/~tY闌xfn֯L$X+{<E)&8!8!!z>}de1111(=,1 8G t޶yiBzW_D@wClo93SNLab2\}Xy;R Lz6RMΑܒdEz #[Ln2Q Ҵ+f*2#@!s4O?XȠR)1C@ik^{dݎ)[c7G}mkLcc?]SQ B۰!8,&oYcrEYGrvK/B47'@ ` m݇~?Sq&wH[cM:oCS9b._z[c-kmc:Jxk#r^}I;mZ`:mzn!w>m*CJN&(> ;;9rܿ\f0ɹC䦙;1ݴ~I7$j 'gJ +iKFf0h>Hga#QC:G)=XjmJݐiՀe Ê[`@p,R袛i"ƏKQʇĭ І .1_Sj+ !f҄ I,o.:o!^cu:TOm.Kov!v:ν]bt&Zh$`Êxw ~<3dz1ps!WXB1t At&@u " f %-O\{q} >f䭵 ͪ&&SK4'o?aߖLBoHRԸ;!Ǭ]g!` naa>&b,zCt4eh[~:Qk\0HbuX҅Q&:.εPJT_PVQu4ܑ5y8R¿ cofԿ6v\y9b+!YD"f TzE{nGCu㏵A;BG8*C/1?k6 2CpzzG$# r򩐳刣JWk݂IO}Z.qG恈s @,qLشtri^Е_zT)qt:u9N`#l$)jܓ<ǫu=CJ^sω޸'!7^ K1>mo26mf_`/Ŕf|UbQ|5U‰Q#Î>J?Tu]'1n4ū5-3JvXs1d,c !}qz v=EFB*5?Mwӳ 9u~7}Y`5Xb3P5j}ڬhZ{s#>uO7y2)S?mUj[\7w5ol ' ֬س*[Ml^y}"k׿_爌vLL@۝[k%QuXCJAnvK1UƝV6GfM.d_`e-<ﺫ&.ƆT%|o ;衈_cc /y6v}EPG .ƴ-hd,*U{MniF`\01I !^4<{ {Ka", QQA:g]%L+ jVm*i]@a?|Ɉѧ^6|N\e2kںwFۡݘ5"ؼ&ClǼM|A1LabƠe O,wtyY+d -T>\[PW1`wx?n[kimV">+.T_0G1-٬/~#IG%G}.gEx-kNT#=?*g21h}7S[&લ[9sJL4vWp;if#бf%_W-67͕>k8|~g\>m'uįk>Yse‚Ju[bRLJwF+G8a&+d,)%m<6-&&}a$C9+ 5;W[Q5 IDAT-gC w|zNw{06L3`!@hHBHB~iB I/{3].֙qtNmeK۝۝3<TOxPqJⲋ'] swh]og۞OLs{G| @lwn"rս-ac̾H~'rhw;*y^ ޖ=, mx,sT|JwX]nY(uU g;*8QZ6[ ȡ6K+LsfrҟЩGb?nD7fTڴH⌻XO߅qm7æ!'!DTU]siMhɻN9A-JS.K\H,4PűYm^]`aRxr*=D滯:{jsZ@Mg>[n\~ӎr\pˮw3zCo9ƃ'i g_CԞK3{T?MXIyUjNJj=k:@2fK[ug''%7z[M`cI%g1tmyc{蒬;͹r3;e(iBӢR|C Do8 {3b]]%tNvjOx>86L1Mi<Džʡ## 7?z88 5>$FVuң6a5u;w-'7gϝ^ Oӡ"#^y']lz.VrZɒFkN4|nyDFߚqk |ߕ(`ooisw~H(r":jF&=eDe'x8to&4={n%?ىPg;{уD>DEskx~6羲N{ÿZ˔CWFHl~*ޭ=a{ӍFvg>ȹRN|i} С{Rs K#AuI9YmOH\+f!_yt}Z|&J;?މP2gD-F6|d5` r+]An:TLj32g`lvܿ7u/0 rc߬u.tID ж3ϡ{]r۳;-qH~Zl#2 G}~гYGF#v*2c+WqJ|*ÁBmƝ57pd}?>9#p.Mpl= r,sk3I #3\Z2K[pYf63S;=fS+`D`jlujlOG;ʽʦ%}_Hl0)0GxV=ݗ*ܞZu]r6O"^;.=BS\ҜZ1דϲ3NM~*~[ؼB]Zľ7r7^In`n*SNp$Jc'oUHuW?~` / %kuB1/OK~ʖ'[!Fw1#vE6bKm?NT/b_'M]4mEFN8^ю koD8!V?,TwUʎ;MG66[ҶS6Sf&GdE{i(F䮳nVẗR3+=HFqLqf{GHfn%rwrp8q^A>Sg?^9mr/2m݊*z~yzSn TyGyYuYtu0B >ι>ιb*# 8@~5Sl5}a_}IgqZϲi\'{m6V]O=cN$tDQ^}*/n o\E.ܟdp9bc9O DKWx:FZv1k3%OlAغ|mڛla4׿9Ml)f$/ߗsHW+K(x=#=svOƛK27<̻ҝ9Ws]l/'ŜE\@YDILWv%L魦ͥٝD`%\魦G]1u&UZ*z-Xyгm;8h8}@ |Sp盚Ky5NqgtpR,[. ԡO-IZIumWזDstu^pYqwͅ*Xsw~N[\ VA!>hLodŅns=Gj(1hHV;knQ= OP>~09@ _g]6l供3?~Ÿ(&NyLS?yP;)t8WcH4|["Yyg+E xSsmptXht{vh'R~_hμ$扤afwY"w`՜MW/JjJ[KtYc"### Ľä~"JZaPndضdK_H]\ X"'(?( ^9ne?Ν-)Ǭ+NqhM+l3$K}NF}!Ro^jJ]&?W\V{\h~'s T ~`Fk-/wd,Ҧagr0Ej8pUB՜$Pqqه`abx492S<ǎwzRio#Nزx{{mmQ6qw_c事M`4̎_@ĩY/R!T|].{~ M;؂`J%ͽ}ڭ!1Ds=7C15@#7XGo/?j(M4`]g4}9wt%jB)Fz^kv@!͔$`@5h [XY²ϧ}9Lɩa6CkwYjJno,.\r45)XD| GIv-C`>s`k+=lȪKnVM_P˶sh@#&Es=[L7Sܴ`?虢9d;No^j<+]d 󊱂5vWMn%vQ[T5o*־k-)c_-Xwg"Ufqk+UBɲ1<_8jX)u%`F"c5z t|Q F_LPOj!ewZRd+\  %SU-2UsRж.׈SR;bp+Kd s gx,oRzT3 f#q ԕQ[tW<RZ-~WfLvLGus%C)jP^5o2'=Y[`?xJW_7nA}!ՒRmq5hG奴ww2T5:LmooL#$c~?8)t"5b+ZHHP.8R٘.[o0GO'c4{ZHX5kX0n[$Gn:@hWv/G EGՏ;i&H`lؐϿƻg 8@hRSw\GmAonygEdEwrފ$cAwpDUN;}lbrαͽe )hOByey "Bz7b+sDѽjNd52Ӗ !~ 9ryϥ9ڹ^4sSS.\/??8c 5Q3K>:w4Kwf=KinĵvĖ:J cxKv#6xE{xr*IMZiMW-i^zr-3u4'c@;YODALQe-+uDHN5TdVIJr \onZ~%)D@.jA/ms{uE.0o?G˪kAGw+-)-X2hd꟩ڤYz,&_QіjIG”9bgx$:[Ѧ*=\UHW8œ9ad?|7jJ ܛIB ewɾT8ȿ)jmp2 ]/y-PGdңwZ >4b_qdzl|Vl{چGU|Z8(]oݧ".2QFRMۊ?@lܞnE̷izRK6nx,Z]MͿ#j`U{3$jAE\՞X2]ABD0`U˧۞o+9e]i[(obE-3SSQв ސW|H0/}b\?ܠ'A~j*̒1_xTSS+Ga:ivGaֿt!Z$B)޲eraǷu%Ό=F2e2CSJ5OEn=wKx&G?| }I͹}Cwog,cwhJ\-B?R5ӛte/DZ6/YҳJ@O43Cyqs5j+T5*ZBO+Wvh;P1^90z^Cg jd"B{Mh.4Q!Ln7F89՝m`[k-oeݝ ){3Ҧ\_]2u- yE}aLa-1m¿wQr@KCTx϶_H#lфJ{Xm1b\7ll^4,.ˆu3 h:ntمxt`#U/$cxz[R 9)$fJb֙\%y7lz)7soՒij0U MV<_6Ok8T?|`xغ&{L>j|P3d#% k_2-_n>DKkoZ5Kyb7ۂodF,.:jrWְ3|)=j& z?zj"p .V`)x5gҌC ]& 4Fl ͍=->}_hTpya$K4׳5Vq3hw5`=l'V?pcwL'[⳿JVlJ{_q,".12 ͶZ'zPb*`1?zA?FGOFem=5oΞݗרmcߡʪ yB@s0@xDqQU2MT(f13 9a'9W.u[l!Քݴk(%}Q0Ѵ$aGٝt `sŹ~ZXc|hh# G/?e [1Q: }e?w/'Qۏx6Qv&i%H`2BSrФdcxNц,e=Xv{z|{[CvB|J#Ҟ [/>XO}iێj5'{պ\W[i.=j ׺:pSwv_S#ٗ#:R#UE2WZVI[?&vr?QS4OI{l}_Ski `#Iy0ӲLsixm3MO$D3|x{٩䮑bSl س8&G}urp8XqÚ2ݺn)2{@xз?bLP݈Kfdq"}Am@Pf$%;- [bʱ[g=TX9;Y1m+S\d*bD,^GɗbU`J D j;A+۽.2ٝ>`@-?>^og:U[9[ IDATg*+N!tȾ",%}ǒb-='K]=vv_fμ-Hhʑ1L-\uRE\&Y? a9kVVD5Wl劋l=0zzfA%_,"BST=4EG_'B]d;n&)}S6|ڗ#:z9÷|Ӕ9Vb_ßGIN蛥y#w1{Dp9jl`EwPaNIEK w ÏQs[\ݓƶXb`h梔lPwem!0B4[ )+\Vy'+VƏzCA`乁'Jx+MTPj),˹%]gnl"0Cp(WN٘ݹO;Ch*QIMk 4μLN9_0Ga&myF]{0[-A֑g+yj)mXbJ[[R6Wtuk:*wzy]d{c@0nq^:U _KGI&3#=-Os=5rXiJDG9taymK۲t hO`p~ XD6- \Z)F !n|ːu0[]_W/ kŞӜ3Ѯ%9bü T̔𞅫l,> k] Gdk<)Hnb$|#}5f}y5b*b֛ٸ "~}ߘ ,~c&_)gŸTڟkq/iy)}.m.1Ò /g={蓮 E3zڿtv 6pKԎkr$ìî+įD{1J}:8J8}Pnþz[,w_i9Yd.yRHF9/nV֭B0yXhh i鳺kjK\P;vbx~. Je5;.jc'HO J``@wN.xuRIv4fbqWUKw"t:;Mʛ;f]|뿶y5#D8ʽzu𴮾w5fhHf"ꩌ=Q2BtشXWē=Q8r1J+M9IÓC,ңԽԜM!\WJpbADBpҧŮX@@#/ܪe oXps# =!RxhLg%@'*i_|E\Ynoo HzpfI3kNʕ;,EItV?fW%߹n zUsd6O>1;pKǺj'%$SP1{JUueՒgA"ͩ`z-xIF`bm+B񵆢5ڂÈS;8rBa``77X"ֿ㷬 M [}Zi˺uR lT7>DSH"IQF||>U$ZBm@X} SuEV<:]e8B( F3Ism-N9߲N#M8zR[:YE[.:ɐOlIVG<|ZV|'c!/nѝ|OoI73<$UėOWS.QUPoJs%~=8,E #~#>zZW%1wlw;35=37EOwgf:[XZ,=ٳ+Ll+{?m*6ߝqWfΒ^x$%rT1+~TD;&z*{D7o1L7RaC6y8']X=%fӯ-[sǓ"xkEoGwͶ㵮z,!^}/Y{/VTvN+{Fk(iPÒ:88ss"r0 =o)_ r0}/}S!FD,-0r\પEՊnëqQ*WC t-JY Rq#5MNhXL[crY5BfyFB9^l$\CZ/lAR$XUDH#OflpsݧEŏi$,-P #T /7:S%.jGv%&aDnK׌P#ԏXWW2ˮvÞIm6䱗cCG O(@oַu(w ȝsA-썋[@y /3[3["By 4tw+|+sr_^,y\1ӯ2\wjo.\P 9@XE KHj6oh=˗\tjLsJ]&\j5Ə:.+. ?95bV|})Kkߞ'X[6]P睁NK0Tv7U_5ʑ-W+wShR IE|l{tޚOkͤVTz+ٸTq^뵔Ob#)FEo[wIܕ՟8ԉѿdK%3ܹ.?G;JBq:88]%Zk7sd[Ã['WP_PYc#]=hG~Z{dBwwf붸qMrFNYN[sl%Zl)iDv!/lܑ9aN73JIq:&eVOWsUyK1y;Cv穹,X!tTP{dc[wS MQXE*frPɘxi$;\2mrMc`e ZԒ)g3䉮 ϧ0(!b?˩juI)wTLކ(Qi#ٿo;Ӳ49sp8qz/8iuŶ$[m>Q釖87', v}1тD3Zгjg)yO?JN/Nq[W}O'k+AKF_)d[$0DUcY.;zžTw'FhַKg̮!^"+ѕ:p4WRnh; 2`ǻ&_\ = &),!8`-՚tp848R$;qOqg_~Kqos 3 D/aiDeá@z)t;Lug}~M3A?{cA?@ LPOehw ,^ʽlsCoݡ+T[-ZDw%9wd繫EkSs4|9tes)|c=wp(Yǫ;_8Ec.ݧ咹HX;VZ\Vo{NPŏYxd훈Ef*]1pح83~]Dp04`8.t<&4Yޖܰ3v?ǗwVbvd̫tdwXe]]\Љn\{~Е$5zU7R2 CǠБO&# 8vp1SmSI#}ce>%+?w^s.@Ovr 3݃UlQ(;ݡZ]F'pА[7jC`췷Rݡ5X3NJKFCA-lVh}i 6?<p3GM3ƗLpg_m/oDҡ-O'Jg{2o @|PdealG,T2Օsw1PufϺ F^_Dz`3b:A^w|ᦫ xh5¦' WDw\\i)I~v/0TqϺӯoy:-`hEcO;O(_NCKZߗH j}#aAuV%<ʒ>@qv%뮤:C*]i\s$0q. ʌF7Z.lhBo|weYoy:;fmiJW}KpC+EV"#0E=雿C; לKyGɊMmtګC\%l|"<&,81z@&2:wUrJg-ge@:@ͅ%їj,5y= ЃSm8۟pW?Nvىd~ zKfKJ럲ś+S%i_aXj88,8..j2qPbݣPh+ZY}^(/?]ogYHs=XHm6uDKF_'(bה5 p[/1VSx04Y^rC98 E6e /?-YΤAEj!cS![)"F1葱%vMO& M.<y+JXX6WSLQ[l k oz"uA >l ~ć_n٥_;ϔ׮ttѶ瓾 iS+Yc[Mlf fqTRʷ7eJXA-zSxjO'/0ů:I %\6۝&ߨ3;88tCGKgƩmÖ VE。Կqx#+;ʝ} WOs?f̏;S$n0o[,0977'wNWE؉!6B 8%-Ԗ1\=ߛsq0r_2.ttDűt3Lt^*Cʰ[/Z>5>F9W_&m=55j]д`yC>ԉД&1>e1 Y9{O~K]? ">BUC+V4i[l!4YѦ~Q禿ABk\CC;SC59c@ p\-4Wb!+Ek7J0dBe?JѪ9i vs4'`0lgz\ߴ6|Et"Gsz-,z橜K` ua&#,,T7:9392q-TҕS򎐌t6@bgMHƵ&[x)Z)[)X)*XeNt8tZ>P:ֿ3f?_LfV_s}wKny{.j`|hD7feǸl8ඓoP@ya04qzp5>Upc]m-nϤc}biswL4*8QS}kr{atDpؿPl)qJ m 4e Vj zC=Ew\^}+}z܉(~B%?RP9HV!`A2 9'lȈ>B#{*1էLj_pCs"hD0Qz@g&GF۪}0@uZ`$Tz06ĖTmu30n f*r!)GSEŜZ.H .AoBnAxB|w9eTXo+g6^,z󵖕:k߽ ޣ2sZ(bm3rJ6D%D쒩.-<]E|(ZWMҶ`)1R S#<<[]n㸪YO.ozZeN\ ?ǽQλ_tL<3&^LE/aP(MVus`>wC G#*橪Kmwt׶'{+Ut+pLMoҜ+&3  HV#GJ/ #@n ֆ'-Z7#/FP1e"[kP :}H ^[Z;\w;^O[ -8H33IbY(ZdK;•QwR9W:fUDkmwK(k IDATnֿ _.b#$;' G] vā"撏0Ho/@f%4~Axd+Wy';- ŔR45ASYgbvi+1 qInoC:N94}\?GVvؿ+E{")5l?e$)N٭ U'Rs١4fenx=K,yFCl y&>w[1WJ 2ågբ+u~qƳX;ß:1JtJQ2%v fbsm c=ޛx_X/uύHeu(׷Bq~ %Tb*y }*aW!9[1KFKy UMkKR Mg=ZW^G8 fV4ea$o$oEWjWR>=JɈDed\SEg!~-+mK!'tTՉ̶~[Oᵤ?Vs]p9gA%FZ1םrAwh[OV95PĴ|4`8 +Ph ".0  fVi[ШUXf]sf t1Nшh;t6uit.F/N9)F%F3IykεDP`h%ST;\:`9Ԉ_:QW6״tm\D0ɬ>ɛ򏖇W#{*x@LJLDr\rK޽LQb%.ÒnOU.ؓ6Crc쓯0ѐ]M)恋R" WDc+5eJ'\UuWkf{iObq*oE#)@9¥?{Fygҝ%y۱ = e2 PF[PJe]fH2RFHBd9q%ɚ[/ɱg2C$=<;W/FKZ(<kʏilrV;K=T)RJ%\IѤc^F,?kP|a "򊪙{4mK`E5J(_!r쉼laoqqw44}:V yTWM9!;ArC7BfԻï O7S5|wGK9O1"}țnd6?, 7B|#$-jޏ̊zOrǂb #CZ"c%oSJ8W?RƛkOvD'H^v<>&g9yk R&?tO۠;smib]FVi̯8-8Rٯ%CRJÇQ߹"rÂ.:v%e*cZgr5saWjؙdӧ0vWż/Ͳl2s̨DϾc\p2ooLՙ|g g_an > gq>:8%trh~UPMʹH`p닡c}9yr6'ro <]`ÂA1lc닡`Z~5tf˖A9uk~#1ZϰTiqCЎ:DaW#MU%JI.ikQn lvtmo_+=\WtTi;TUдHU3':;/vK/ =|}qN(]f-g5@ }_|w8ͽW! `.9d#o 4-@ B~]M R Y<93y{9Cȋ~*<3:ύR=YC;Ӧ ȟj?K8>T_8@h%w-x::YvIoS6!"mWy30~[7 ߚC0ExW<#{_14H΋^yɳ%C+QUv;W4Vj6S:ݕ O#o 4E{nSZo$bFm}7M՚c"{(,Su u כr{=͞1#o +rI/U҉7&\Oęv^MOq UOZʖs=1D$)];3Qg^BND]}6z,b1i4Ec#k'jݼ3Qzȃ ֽ g = l]}Z{:ocޗfq(=h+U1_dM1oۮxW2Ffң?߱D.CKv?>y~|de?qis)?/OjO ^vD{FKsҟ)i?{dYZ:}E6Bc뻊¤ >ݚJ0&&7e(`ݷ[#CߛB*CRC=K/ ȣIe} 8naW{t}yp}&r-wGd;K濔tk9'ja}M9}E6x9]*U>匃/79v&3[`  FsnBKU~0- upk9PC$pnAg0Al`b71Aȵmh2a# ݓ1N0C!KhBj1T:3.:6X!Q98m -BP΃z,&0}S)pf߬Pqo$XK1XXIh0|ϛ@Ubt"QT!Z:J0Gn%(ھf)+]ЧnX ixIvxGkLNH0QdǷ|knt.Yi#x0x)i[gu7?ҒSڲyÁ&` z8E\4ř/Ijiuv#E #2ptu.~Yk  o}: T}q[3"k4)c: 欳~iCwGhc 30x 1G+;1o_}p"C g,?m= q~S{엺NuNFԓeo*򡸃X~Zs|.Nsy# >GJfZ| *8%yJVmSi bV5._Wwٴ>srf.s^%iIڱ6A]YC2wF#2c{)\U;۞l/wclR)?b j{8io/M$}}ZzفÍ#DP;LҢk5@#(rnc8sPD|_W?3+~[Osġ\}O<#GNhI_?ܬ9`Q:|"q%Eo?cD!3)o,^R ;QY敄Oۺ ^|g]_]굴 ϐHH77DcFM4;֘|@%gv*ٰY:KQMR*L>\g2[x=MS#]{=C6_sdSFC4S +xHY-$gbp)qQJ֛ gq `Q+8ZIɅmyI%V|#Z17[ߍ:/LdӨeoSlAnxK> paq2)E110jcG )ڶ*ȪGeHKyE;k( AZ>#RQ;bpD&MMCcpb}Gp,Ba@L'LM_A\UakdĮ5hBG#5ScfXCv>UJW&f,66dJɿ~7mg J^DCd o,- v5SLg KX*EK(1UX }8RL)1Gr.K}d^_`0l3g1(U6`,ƜHS= VG#D_y|%^8Zg)?Vbޠ\(^m A{sL&Ѝ( ?S4CK@`|!#9ܰ/?7El0W/tsl o+­^Lб:i)0a\Ay_gFnq}!pE`9<,_?Ǟ % w!`GLwO }{ϓuss_:e6M}kaYeqI iًXh;9l^j ߟp/"{EL7y)hG_̆FOD?-&H2dml+n tmԎtϖҧ %)_O=~ETCy/oNE,.3r[Wwc_Dw.VO *92`ɲs!lRsʽ IDAT 9c 41enD_Yi}rnLwXF8[~;^lia Em8cp{x,]@ѻ&(B}+C9_l3nE__]זݭK>xn @F7cuoh|NҴ֚͢3deC1yUf!Ѡ4g/k : ˥b"LQIU/ `D)ޱ>oSos&>|jfSV!^/+W*DUEc+@m3_!Y7,Te-B8_Wĕ1DC&<`8n8FƳ8aF &b:ћ#9KR/z?w-{3tyQ  "[U`U EtHĎg'c7{xbe*`_ c#y w2MamG x>:G} u`΄k|S*g ) }q!+eXRҕP9!U QA`0Hƾ̈́p_a#?3ٺ*H|)?Jsly'wrYvw?Xa@/>֙Vutz% WP7$Зs=fo eɔP>\PjD.o lsRZ| '^+`ذ濞V濞V|ŘGZaٽ*s/p#X[k[b^$z~@tKTb":;(er;A.̉0ޘz*&?W1; q!֙KxBEi)AuNyW:j0(g٧8Jlv/WYbրflzV#zu|0W*c].C$%g?d#jIW2;]:Q1Q^@OidiqJ2 M㹷X~Lq[ Y:`d',nAX-sbqdzZG* -.UkLs7.Rƅ+W؁R$`2c85CS*OsŽ^ZBZU[3~.?ʡe0t0q?MLo ~碿:x9J֍h4>7c-Q] ڍ]퉗9?&[IkNBjX0zpKZLjF91[jũMmg*vK[ 17vKOpŻKpS v4Ia+/߻V Et L:G , T=ο2*7ܾ%pڥo4Dz w%9&ٵS,Z)|.c!Jc['6CJ;\]j"o`p%]+TM A`9ק{v f7B\=Qcu_/[*E :苴 z$[h+%Zڭ~ VZ-9XWC/A Žb׵W+<}C\0hu+u9iYcw0[;2 3 3G'R0wb--lqvctW27b w ,Q wqr:WBL+?#t  Tdqvv+dwd4+7k2t.`W%VNYnK>'@6XQ"j߽v|Iw:O(ag䖰-J3s޳EE;+Ed"Ā]/h: :.ݢMI%Q`8/5b32+'-A5J4}ku)Q _i"~m k{ÈY `و\6d==T Ddk:dS弴 t^|oxgI;9 sxi "8 :%)`DLU#Z x `1g QOn  ,BJ4WW(+)Wef#7p2f շ @G 2Ӑz]2m (Bԟ;ܣ ]qI:4KF3RDkҐtZČ+'ד,f.'厵-Dk"qTrt}c9I9b~] fCNU_wP cRYu.c>)'x lCxIM33,e:m=#k(3U7w^Uo&\ {HCo&Xfz1#u}m+ fnkaܴ;S mv ^vߌ6]ZWrpuT-*˞HdDՐ ր n5.ROn׿XImh-J̙އQ}#VBjRܪ ?pkoqCF{s߇^3Gşo2nu,:-"["V=, n#5] }#Lo@nC0>gB`R}?᥈_o&\ :=o!9 @G Xǻ2A0hc0W^}PZhN'ɕ:mYZ-BbcPC#xd}Ak5֪-}e2բĺ$Zrqű5٤!E8SE8Sb0"-5,Pʴi {hg+#E6 3'oܹ<0@ j-04p҅/BlZ^.A}V ۤLq;_r^|(fb1μq]>3FHvV5JѼRN` ~ /!`#;.Hd,4f?Đ1}TJx#ӲJ0<'i+4t'q[){K;c3yR u.ZcQ[/7YТha+k/PpRNF%Utbc缔32-_(R6>f"^2KrwΫ 8ғSSwfd4Eu'H0`J[2's@e:蕤sdnSVfnRһOګϓNj0; 뙫5u#SIm*vDR:/W򁈍= Ѳ^`$DFM„"3).Eƙ|CNkB8 [}?Z)=p4g@Z…wR, 97.GNڻi?ScNyŘh w5x "NW< f bZ477\bLU5#DcoybR/y1<љ8@Y[޾)V+|:;OqǂgRj#F81m4`RTpbkR[t&Z3k}1]z ]\/j!S]z~3&̍qosd/FCkt Ʒ'#y;dt$ k 6.Teu1AIɛ^oB tXGZ p5\hS~ZM46'BsOD #RcfTj{oh[Jͦ⻿^CZ8X5V$?Un-_pd􊞠8Hέiy]s@C/GWmKKkF1yŧ­r氱3w^&\id[ ##K9-[ ۘqE IXOgY|&nzk=O^<*:;_J?o*tvş+ s#{;6@ͷ韢׻カ-/6Ic/j;o8QeDEKz'\B. aRb>CF @r)G?j&4.L[g|Pv;>aaR›i[$El dizۿL|o=?7 ]~#g^vgFu쯯K!U)h@Ao7c9+@g @fp56㧒F8٫SE}~ 9deBZt`豒6dnj>˙u35ys&2ҡiQ~*=NI 'W 9hdj Ɲ_FwLyk]ѡ0A5㷩ʰx1FOLNlF_{8S嬛j0LZSY8TKP~ `a*u6~:"HQ7\If&<?=i*t7H3 `bձh$[!`ۜ;<-$=%].,m4#quN@Zpo$}B]0Cp&+c0 N8 c;G}؜lhf@qA6h"'ut;ݐ ˗;ė౜U6k('d&I'gjRCSYaH)AT -ə}AɅhs,#OqcE}K Wh-.D Z'uLurƁd;n8EUř#V~)[Qti$;~4-Vq$%5kr39p9ʄ vS>џNAbW" f)&I!;db{qn1fLMcSW)':.u%ZӞ'j:H,\;))TgΧC)͡We-Z|\DeÂXC`Jڿ5^1מ0מ^e3@yh?Vf=Kkۖk]Tj IDAT1RCgpޜva{׊@vc$K?3Au3ǜ8\Wa!&,~TL>L־vw!"M? \`CrY15MoD8Ȇ\n/{z7/y1]$~|&g^f٣ by}&LfmD %yAHTcz Y\ѵ׉ѧ423kClOMxcمuoScZst:`^<()W0c9(+(Z 3˱#6~'jl Z _`FZtZC4FߖXeRm4DBVKzdCש{hDkZgz`@rF4Ws8hOP,^ Doz?wa4mk3dkbʫZ\cyAFMY| '@zY6В7*dTt*h@d-|Z:ra ύw-jc4,T.?̙JuY7aW66}ZorC&{lO9Ͼ1- z׌xAyz[eӿ /K;^t9ɕ_uGϫ70vKFܐ:$x0Nl\q&o_R97_U|88|Vrp3ACrXyV&RKsw"ֆ43Y҅L(, G%6uZJ:F #NpwEf.o-^hr4Rܕޝu(p_|oV嬁c98q0u;7 s_JOpU2֙|`8_Bߥqg-lO1o1=4DcDC4g3q [gǼ=YЂ3|_XgFgwvq;Dԣ D퍗 KM1Cz]Ԛ,nO''0IIdsmlNr "({ E|.yʖWCg W!۞͡Zoq&_p[כ\[W>zf$\ ʻv\rv^䩿1"Q6֜7e;û}1DWLO3ݻ5 NE58l$nVqS}=!` K~~J);g 'Ȧo;TԜe=JSds(SuJ8Wb^floE;{Ԩ؃&?gPgsaQΤRg3C/ɼv(RERѣWۓ ^L^)ZC6{!x5"/,,P|?|+"I5P:=w=ĞDJlUECܜHTn;b\xشN;ź/SaWRFwHAΪ* ޲C6Ly#< G:7^iqĮ/du&_@OU.?ض\j4}:bui%y{ǻ-4x% Zn C*Mj$o Ey.R,4xl!a ZhS~)O OÊ6Z« )%-~ @@O E˾c@t潸wčP_utf7\ Obѷ7tWFEk.Ʀ=U 'Gޔ?b_]%_18v/淢Q9y{#RXӈ<E# !lco OA1_-NMl;0鍨ww}ǷU|,oy8q7  a#RЖqkKKK)eU#0CB$8{K|<>xޯ^::Z}}¦“"6}F~kX\ ^b2Z8@O0)9z|EgnWL+RnimK}3fݢnV77rB"ktv0zk^0򴖡tʸ[ s2W4gkrX s!0gPqCA;;nt:XƆYe7m|Y5vjce{SA.kjmWh-i`Ut;ThԹ}'Eg\pKs;'崭D[LmN}%YϏl<_E3K+l.E{\ӭ?|e矚 +.C#t:`ܷ J2;W2r9P_̪z=ww)9>ݓJηtn59=KѻtK~НYqwF쎂Ң>oNj_Ծwe,?ǚZ\mb0Fs,n"ijٗ6zYVkQF生lM J'bey˚ձn.]5W%`pQfwF{[ ݣw Nenއ[GsZ("xv1%i}u~#ŧzo[:}Hi5ky3̽sZܠ7ksfB d^gKz2,r:e:EElKݶ}iUE~^\a Ĵz[w|wgNqSwYunpp;LG90Zi\ۦ"O^ipa_]'3,6))jwgԝ9 K{F)-qf!.p =l7kީg@c⒢m|]kVZ9, $dٷ,lݶdt2iN.t%Oۙd#%`ks[R4)z&^&b0$oV-oVj}?Ś]0)ʉr~#{[Um-ÔVlt3Տ0Y~En[aIU[ֻO936,6E[ەYOF?)l0e&IĔw6ixŮ?f.%pyB9 ;oZrvu-R[zˤۤr[J[<5 'ȲAUG_IsÑvu0B! S_R{~g; HN{_>l{m0>|?~=6fmM{8~/A'H1or*:Egh f!Yz)SNѻKOΞhn33c ØS OJI~bz]iIS(i3c!MҴK$q8c1X1c:c1c1tc1b1cc1!3c1C8@g1c,pc1X 1c:c1c1tc1b1cc1!3c1C8@g1c,$o.#`1cF3itGg]10c,qzO}ec`1cC詛83it5ϩ8SZ1c%Ŗާ8H:2y1cٛJlzOvc`1c՛H9sy1c٥Nlz Z1c%9j':,c1{R Y#j+޺^{˨Fc1[_SEyM}%uO>cpH|*бoj1e荟_:cqʸⶫS w8QZ Ks[]õ>RWS15|z9jisZMq0Ƃ8([PrO5{24j=&6rݽigXr8.}oZbvIOו9ڭ~pue4bk-kkUkI@UCpۥ(gCIƮL’ls>ZWvwTVxĴ'M뱱~ԑ}K) /0?,tLzk=Xbܕl]S N'BѝF#=siWG߽EXt5op_.ltg-atܜ7ZK.}}^l(­7lKquF•rK:ea=pJA{V%oמw^g..⒭Ytdk16݊.+ݕQy֏?V5٠bigOڙ7VM:`v.p'_ ŧYe|ԙ}-WB[ k*Lٛx8(gC7}kGKE5lʈc@3ME7uugzӊ kZ_l~3-y#`|In4<\ijݣiG,Znl[k%_des)֕:\bbsuӋ?Wfwm+u۔~Sw.[7񱺲8R SoDkl͍b&GJH\8|WߗVX}IGL;׺['J]:1R$/u􃵣= 4¬hzNsmpk=! ol>~n֕=D/7 `9)ݥ.֍SdG!SNy1S|'3"Dn|4\][vO˘B@a*pw4Ѻ2sz_j[r}/ǻ r޶ drGk~ Ī6L΃|c$PHu?w4c3Ѻ;Ͷٌ:#u|RʋG*V~cew9M!~3[*Yn,6nNؙx+ME׍QtLg?Ȳ++s&֛`ݽK^k(XEo /5;*S+ >/F׌Bxq1Gʬjĺ΄X#!~묇fwEbB@[٪OKSns~IzZ WoB}Sݶ<52c/O[ ./EV99j/kM[mݙ'-ǎ u%&[?^vؚ(+X 4K{ə &Xbsۤx -u٨kw;l|EaRgװҍn)}s|iָmGvt/=o{Ǭ&{ʢFA f1nF+LYDI L@8X2:˽?X6teiYUUJtKj!78.oqv.ꄯuR~ycZ%ZkϹ+dGj=+ =$PRs W_ڤKp4\WRuI=WdCmE.Zo}$֞3,P\R5ƎZӻ;/ȋ >E7 jKs8vLtb}g]֬+.ҋGJxF ["YYq]-ۖz|/=J]Y_MnzK_\x-p UM7x_ڢ-Sd8妢[+b5`sѻ_]\_.GPbSqu#>sW/iRẅ́z`ïUo]ecpUٕ_fXˤǦ)BZ_4ͦF+`F˞vYSjoe|Z5v-Ԗ?XѲx97z>/ ļ+̯:rEq-Kzuڤ2w-5Ř$yi~2>vsYLXߛ~ea:7k¦p_R 4cÍ]v(OrsA2yc9XzJNC)9ݘٖnHmQNѐb <ܔwh:'O^T vt].R%|ߟu/Zp`u޽yɤ(ɈZYMKkީrmE1 <ǔCc?9Tq(,]Ѩո穣NqnK+a-豷ZGt;_Bl\RGtlaO;TUA;5/v( ۵O8@OR%c}UFgh=<x꿞=hF޴rNm.Țp(xks3UZG{)TκS[#,Z>mRw#s+}ieih9 ,g}ǼK֪I},R <PZW{ꗛ 0YOГAw8me ߻uJ{^Qфzԁ:BFu冉n-oOVև6j=XLk 7OKK3v5gMʎ :m}8/=fM?o٫WW6/ PޟAmvX RĨ޴Җ @`f~趧]|f0-dzeqámk}}~Iw?g+/xf/@k+I+uIx?RG>S?ܸԜ 9Tw fʾ>~sj=8@Os{^~n[Xj; bEƼ.;/T_ +biϾzg.dX:l9ʻyyc8ˇ D<i|Q7]wx\ Vzjf/u#+O%_jrOFY6{i-/7;Dglxhz9,c楣_|qlZY}ޱǞr.x E=I4}f͜hsZ,n">J)%쟝ʲ>'M>Wvyyo:fqYe}6[waE}xg_6:z½}pY2ڡb<.}Y]ɅZ9w:&=(bBϪqzbM͹~ϟuD9Y?<ĸ,_v;Gaqfn- zghSb`[REP~0s4C=/WġX064{lÐluAZ}% O8?{iV{|sZŸWk@atdZ}A7b U085L e/YǘƢdXI sV/~\s^qơ9_>׫û}3s?Z0M_wetn?㋑#X1X"r ^2$H7\P_^}c=ٵ/̮FX.uF>lu%g10>r4O:EfeUc?WK_>S66Mٯ~%$<[E(8@g11eau}4 tSȷz\qDK6a1c,qc1X 1cb[w\:5:X%pW`IbcEUpk)_I'6( <p\ݺ($qZ:G+-w2M)6~. Lc;Ǡ)xxz :cp`T-@RVk_,rA!,:%4nLL:sQ=B>1'kL;+ۧ8 LSAg1c,pc1X FEB( @9* CAB333 @ V)K`18@2!D`q\&ӎÍb.isOV)eV!Ld{.YY_T*8Uq?Hbu RC$tQ~XA-VRFoQ"08AQ$K{:N;NpjYZ `B6G@?!D)*Ap6Х |P4en] b>Tb TX +]kEKq NHQ p9bdzn'p: tn>X3"6,Q*%k"}g|h O1xݻ x}vrd16@bB]J;c$Ze(i XLK 9e6iɩjV &YU@S !^RڣyBq}O7 8.ใiF1b f !6$TԼ#H  O%q9az$VvR0>+qix[wL׸SN`B<43X SE6;saz TzΊcsBBxp9Ev7pOMM{U.sˇ4r;BX Jc1->6D# BjYPAD3)oZh&|a1pQP wPek.֞O is%{Ue)NANUO3XD,U+HBT8>kG{‹ճte1J+Ow9+/rR?,̞$ D`gͬ#E!D]͝ !:Y"Bf}yZ_gZQK.)宑tyR[zjh>'@o6}Ϙڪ(W)EN нeX_UkByZ>p=.'1y}*B Wl S~hӂ;)PI@}/Axh!,2\tfe`~9Tx^aEC yfX+RQ$l< * gBvyFѕ1RpvPиA-rpXϻ ](~Ce26R6OCw!wFO@S,иy0WЅvb}.08Od8%9@W,Uz> MT]Ӂ׫-D5Yt!D1TZm6Fi4q!r!zjpPoߥ҂Wea*}E茩h¹'<3=q!t,`,,B5Յt"˘L9ހܛ󻳵?>Alj붖-aeŌJ!^J=HYRO&f\IJqYta,^_ kpW32i=X Pnz&k=5M̦g:Y@n =m;4XP65%Pʍ:PfJ=+GO{2z5[N^_6._7ʄRʺ`o <-P97Pn&opS$xԓxZ) L'L#dAqƻW'oٚ1E ~088d|PzE`7߷R(˨?hYzDj=j5 hud!~'h L`gjނv?f#7R x|G B2yM9jٿZ pNO. WAǝƨIV |RQhl.Gd=wڞ-MBdJ)٘tu I'&%}&PɺCΈ_Ԇ,PiZRBR%Q+}swRNNoWкd_ cemM64u't+PV gP~x5V[lMgJYVcŒ?(߼t=_@i_OzZ#0^,ԁrJiW~@|gA|A%@-S ^/<c3jZYxTתI"AB, |ŵTOţ=΢tS:ЃrR!YƝYlơ;gBFH)|&=j ׅ8?,ŧ蓃 7(-nߝ `W M54\4gxsc {+*>=wG^㾎RXSC{iQXt^w]̠@2Z#߻R~20 rR?F(5F\4 N bs)ebS]cB\wM>PJM+}.WK@tR@spA5[T(0߮(T^8:cЁlWma:~59)(f:c4';}.V*Yv- f#>\Psgg }79wpOA3%.@xPf00Mh}(@ }P8p:l x?|&z4Qe3Iy(x\H7y#msQET)dG|Q`1ʭ^^Tq8LR!zяtL嵕¸ôb~?m!9馉{t!Dm8@؝?CVX4|>T<߯4+9<-|qї?C-73p0Z0O R? lqITt,&q宂}/Ck|O?+ev775ѱb%X X&:^}d} Kz~j+*f1~sZR?@gۆAPI>4T~3>^_ >,|61$@ZWcPy/E?3EQ 3@Kʀj{TqYt10k=hG.a,tj* |;It=^ycJ-nlfƽUT,p|E/ 0UxHv鉺(i<ψgbPK|,;!.,--ˇ)Z1?8=yL3Z0L8@Iq" A pѽ3ׁ>vx3Jkv-D1PEcގ{(}3ojK p$<y=vjw. ?aEy| ]l^ J_%PlR Yr "qFZW4=o6ޠ3^o\"v 1~$1(MZlO0^_!J|(e/L~<;ۨ@VT;R9s_ew1Bg1 C Ϥ& A IGp:a۝>n'Si=zF0'#&'ߔ빯\Z<r˵Ԅ妏FnIIPu HX_G=:@-x EE&!`\]ba`!SGa$<$pWm|zwJ 3?iQR HSL8z0N  s?ޚ%{tDЇ5fзP#/M3K] (t IDAT5;B }Mg RERK@XĤI,?)!h=X 7౛t64I> 4(N_%3Agx1{8Ьu9v u߹_©O| PJ8 ~ #b/CcE&ͬ2DOdKbQ 1}m$71-⺝oũ9N۠~ S@a'T,4# Wx.ޅӓџ$ǧNSJ 6ߊ}y\6}s"e`~R< $ICW# Y zV J|/CͰ`%|Э*~bC3?V9.u tu?"a,A0(HhA蟙_zvM:4{H tSb^aްV囁 \_oJ'('@'us_j|01 8T,5tx@IΒ/@#㦯3=i ةu1sAgot}0,7zY4Xmf~8 X_ R <]N+.W֚%%Yiƀƾ<跸8u>@MΨF 3@o2<D ϑBY;M "Yh|z.*1x͈r5I.[<<ЌE޳x[2|`>k<|=``e PpWa_f;hvtsg߷_:v 3R.tP`$L:ZOvN9xxs:{~[!,( ;ǀm-&?'75n쇠v0k(-͞ӣ`&?嫠S-|44ӳ7@o YӘN٩o-g x934cQ= O3'Yǜ]8 |D ЫC\cwhVy?;^zߝcX73@v{|n-b{',`&J{U";8eA" гۥ^^t,}TE-[> OZyNb>m;>/KScQԌՊUx.jЭyqfF~Շ!}s\CAH7rl&='U./"]WA*2)j|j@?|6ˉ^ ҏbf<f@Am | 4=TS1CXkgNP`}1_J,}=!s\Jy( `sZ5/ |mh'tĈ FmwpXs7KTZtlnPN{k.ueN;8*y Fr :]@3hVw>(c'y ʳ :Nm-:l RP19˛rxC7y )_۴9ϺGn#@W1V3aqΆ^=Jayrw0-xf~~ǡ?Tw22 j ױM4ZBs&_7HgM=HǗ-Uk{Xln64:AU^{;{5B]Avz3B:9@A?l p*[ϟտ8QkVnϐTfo58B ԭ_ ~>ϢS|eNr_/PB3ߟa24젙5/K2Xw *de4%nG.fk=&Y~ܞlRh6tU?suv=`BpRb]`\@6;}xUj^-1V $zVM7̀M)J.Fcl>m~%Sl#{KVLP1U= zju KT 4v)t}W: Jj18'Rn-j}~_OwǟtΉta 8t_Y@mTr B[0ʾ).Qx"Hy|]/4@i }_yA/'ofS@3geX}fz =:4~ݞsp.NЌ 毱7.!v1¢H*(e(Ssh6oSJ-X GASM,jr LIsK'dv)qs#E v2(8wxU *qx5\% L(A)2#} 5{1XX S)<Fp xj  9@!)en8!LS:jۃsjy h Am/"[008fkť&ob ,q16O n;hZϡ:7P;9ޒ- tڈtu4r\f `uRJkt s{]&nPk sRI1ۋ ys|Db (؆S5cV`GC_m`6]HNa.Mk~HzP Ig;ߏ H& Q0yzI z=9sXIťJ8@G3 Y+K7Moy7i2ıgleÕVԙPtxܠ5 I)BZp c,Uf9UQ %: LJL#pM֣)٠x8;TXxK)C)y3X r?BI)+gË[)~y*μ݊ŋ!n \1bݖ`7]=8 R[hUGM!>w<32-\f1vqo KloQTfx ֗f8Ur5k+x cŪ-Rʠќ)"jdW=LP *8 S)=Ηgg[87Rv !xc42x]{.^u^|^4o5\LYͩnsN g`-s`XRf!cņznHxE}_)$nP_ ^Ff^hVa?1F `M(^̳kD`#|ʎc1Ϥa\=2DtcIS)eP!lZc1#6{cA)%kX™f½KA>Av9=ށ67c=Oq: JKQr,cV pR[8@)eVTTK+j b8=ߏBZ [#8KJB`~D1` ^ j`GeAҋ'y(Յ9.7EL~ 3w{.' x: O !>0 th|)zO>7g%滃K(Kj*@Ώg?ýV xG,X27 ^ÿ: spoъ71g,A5xa9zI) !p?{GuLپZr1`0)!KrC NBnHO Hm)ƅfܻlIVu{sXuVJڵϳsf;gNySaw[G8|wMbV@!nKU=6|)T+Nц49= hAK%jl:Bi?(;!MYpo# FS» RΎs8ێS_y#wީ Scʹ_ՃvY8B!Y B:Wεϟn-74h‘F)l*svCB@wW>DG@YeF1^H7.!N+J:HA]"ޫ@5%4t6(d8l-Q 2|7g"\rt#޾!k0 !-#!D X <V`^ǷV]]G9_{Sa^9sJo*3|KRfy:WdDwNJд/9E_x-:qd~%ѷd|d"v=쮇E-~f X"3x$Y {W} 857ږ_3!lo7kC}dYc2H kwږ9dYmY `+jvTߎ=!}pνc/}nG>qi_~,IGA?뎯WB(zqbg@;~qC8칝iY8כop=t 39S ;QLւ;Vv yDh?վa]|v:}ܤ1ۘJ+9 IDAT>y):ѿ˧=ꞭMyWZH ߛFPv_Ujq36mm߶} vv'=ʴi~UE}*ENxL|fw~/NG N40Q3_~vøxK, c~"p%Ho<'7/лlEt7;p<=7>}Ig>ndyI $ЃdjEY $ڀ;rޙ`eU,mdImI|ۥqA}zg@mf3y繂- uz7]}iSU6DQw~!QϻRScfFv`4ѽ'G f9@>#v){'%Ŀ'?cSD|-J9@Mpg;F))p A+7b9Rr%i@e$[_?1qCzxqO6LH~Q7 }i0N+G{<")^^M-ʄ1N#UDݵ++>BlHϿX鋭,=0sY#vxO_ξܺ/yV|xy;l7Vc xB\Q>!FYcVw]7}uWDI5]QǏ@GO䵅&% ^1z GxQ}`}dꪭ̉wNnMhz 8It/ur @~tRCvnO9]qSIZ3,l> ~v:zxS-¨˂&'jSMsOo@ pZ9vY9+qFGOU-e>p? FqN{n_ rYt_]o?GPwt}\Rԛ1%sU,GxNɧ/d +lE9I,/N6vN5BG߭$̥I -=lz4NA`iW)+LύL?NT}C%ȴyI](^a6Xs\78H ' m0.B ;/fUx_>(v+Uͫ郄!h;59DnP՗1%sX`0@G! m>P'#R`ۺShGrW@ `SKNd=A7.Dz@l! RSHνn-!<ꖀ+Ubu++ ƮupO@glpٝm? KnQE(@EQn#Bz'w-NO~ٻ:q鷊}! m0.B(@tZ-ߛ?g*-&(6xمM&Y>'r :a>^1 {g,Gx̞-U5uKB_"Z)ͺRSlD ~l;)hrH9ޫ⤒)7Lڳ)unI#3[-Kf\Kc,nh;l@ ?#>.YeQDxT!Isg03ʞ$Qs~A%V#|0̙#eou `E/,Rg, ;^M:{Gg0^> rlG5jpO@g[0s'Rr|巋I)~@NA؂clpfR, >k)() @}L tTaN؟v{ȄFc ȒVrv;@jPlE ҍ9+0}`}17ߞSm1]~v3L&zg th,mIfxn l%71$ ~6;PI[펛P%㪔/-huJ+}*TkpWpKW_VFyx% ciXVcsHjNAX^.ӸO>r9eu%0g0(۲9@Ǩ  :sd6J'cwdKGt9ءPDŽξ( 蠀m|'cu vw8>gY}҄|+C=e?q`./|=̡/-Xi޶fny0l}/(nQ5eA^oN8nQ㩯4Q哿蝿5;T0{rNFn{n>m1fXҴ哬Y=&}d~ xN͆&UR1.xJ-޴:*.)6 Bvv[f-#-~);+_"\SJJ!ĕn:S/Njc}a?uyoq;4\ ̺ ^+vm}| JN״kCoUhy:XQ{5A!d-TK<se>\:<BOxýH։VimgϜ+{Z#r&nYiuvLG06GȳN☓#A?)SP,z7sx =Av.:țv^^f\3ܹq?/3ez `^ w$:%eɶrM]km 2zs7u G(7+b{ < 퉗lȻ:5*95g _QO#̃3\r;I'ߟ'ːH7L7ﴤ<k̴(U_AD?+_] Q~~Sj ߌT)Dz@ k1G6ׯJ0}796$Q7 4)),f;[Ըs s H,qpLv3G {Shr5't+W< ((|j_{&ex F ]>mN{~1e鋬UB?GPqQ6WԀ :|m L'{Lp\A8_Kb9b+̫'Yr=}7 @{Yw< /\83E9`6֫[/Xi[t|kuW0jK޶K7!L3z`h;lށRso3L3=38+zWѴ\Sצ6WԀ <OڬG^)+@\EmRwjU$g$\d>NW=NS@ƁA(Πb웞)$ۣ\[;g}Q c~6}dÆ^>zf?s&V9 rD ݧ]pg_@ybm& H } #XYlt2kc(:_6t=paFZ'YOܐ}@A# t6  @tZٴO5g8nij%϶oJi/&!@y 􆊵Y?l>Ȍ!J'޸n3:WX̋OJnۺS 1smy@Be٦BB}]SpMé[34|vKDi ȜVzտvsAy0@i##pM00,mZ'Ν9:ύՕEUot01YJ/4Zjlk6X,NnsN=%q}҈כaҷ#T׀(TjAxTGzT:=*^]t*##s# tQA(-ܱ3& U*ReRRB(| ).VK ! U)@W $=F0=u.8=KIgBAR60.>A}mޣCP!vi} !^Y֑76x"˞p|Fv;kڹjag[ydfŻ%:8SdVXQWݨ,=[)>Ө0LU(s%R0l4ђJ- ! ~I# _! 2-s >dN#;Eyߴ%tԳy@'~u j q}.Ś@\򌶡d[4x{ʸm,iT%JV}^pxtcXS]01Sa%3J m[et2\zq'p>*hx=_6{u_v;ElQG^E7z=HGk8 밿ż-e Jދwv'B;kK,CA(`WHOWYlMhR&^p)D{+o7UiZ e\V6cr>gV6gf;a/6$xkӉ"z"ap.S҅EUN(rj]-{ (<-(qDI$5ყu|v씩EK&SbNNrٿ`y7Ւ7 hKMĞwi Y-OɷJ"8+}*=Y~)n I-H^_},Y(UE 9@(ޯ䂭jrlݧ/NpmAl8JV: F tC #J^E bλg/8hoyܖR"A{>nQ-Z׭W dt²,Mw;.oI nM O4Mkc"('~Ph):@Ȃ\0Kϳeۧ/_USvؽ(]PW0gA3+{aʟbkjš},?MPp_n\LVAu t9 @)(lU mGhuys[Ngk[Å C ,̥l Y2j N$i ^UT\XV`ؾQZu)5~J3S'H]q}R)K.5/^:|LzΣo˚&Nδ}8{L) yTrt|B i,mn8=;dN]𲥍cm_04;a(lGF[MeBʭ5>ic\d@sLk9zZqٷLH]7jok;{] Fj*) :~6zĎ{m83yd~J]}S2^R*z{N::l>mNv݉%!EB9I"59M_81rg}cEX t>@Eܦ3[&2k'RDžq 3n`uiW-g=F1G?jQE~D\˄D|Gg6W\7eBXuh$o -zcRTzpq7s^nÆEF%ز)t߾ .MMo2!0f_ּY8F=VK@p]v}^9)Ea*eU6i*5=1JBV2#!Kaz:P/47ıb[kOyϣ?,{Ɍ$.h9fnnVS*JcmS"ǿC\6fM9b'u˄/Ey9b37/k?aX4ڄ@WDgpuWӾA= * 9:I!xA~$5I2 F7͜3KlRj*MǥBQAъ V}ko/W<=v 5 IDATP*o嗧1_%yaz 3bN)ř״ >=CT-@ʄ)+G]g qOdvS-34j .BTr 3;=ܻV=*$Lz VHT^p@zf*Ѱ@gфDg{!yGﯚ47E.72aAVNG}{Ǐqi_}~WP^"ϵ IęN|aHmrNJL0/{8guQK/t6$,~DERqU'. ة$qXVOzXWu]^p4ȂriCq 0'5-__eR]Ѡ|}) /sBct/O,eHanKNy\2aCU K9^ G/pa)EW+,%;3i?op%R=s.uy~RXHkKZc ˎpGOܵfYW>Mt9x _jt -˄%jAXN߶9IӔJ矙B[*-2aGW8_cmHNYV_`S mEϊ:NªO窘)Z!9NJO ]CdÖemC6. VW5:ѧOמ:f֫5LD?gaJgpP\쬮tto8 {sYӺo}Xj~=Igh>5ogN_K;p3۪N}M(22Rs+QA_ʞd-e"wDi8~_,g/1qR:TA OJճIx݋ZcIܙ0sGvQ}_44vG#HJP:-,kTϛO7=un]S< TF2*.1^-=Slv>B_1}w.-P*f5]a Y:]P'p ClXrah K[tό9%l6e9)ΩaD%M^Mbp*t Ѓbw͸hlH'xH >y}s5s) 'SeǏUx`qJFI7}Ym"@h}]X_"{ک7 =iΓV_4P]py|M?z47&6FΜlWcP+&XVc-_ރqQ?jGq.;;1W4B@eo䔛sRǟ~b!߷7va^C\x+o'tO٭/?CMeb^B,xeuw!3'}$.;%79'5ֵ~ ǒ''k,y躘v)Я7p1?Vtm|)xi0R"ƩkYm۵ZX+(p:[I@ Uxu5:cAYTΫQw8S@zqTV4 jqHj)8r8-U 2-= ؼzXڼlrxMhcMIֿ~vSomnת n-<[5Zjr}񞛵G0sί]ѓ)nRm7C}5[_]m0X>zm;Z;\r9mjB{2M?`J*(3+?{2 %UnΣf)>NXU9dlѩfhNWL'λV(&9%LTj~:~'LEze:S0Hfc &bvT3|L|z[aƱg8@WL% )`򹶹3 C`vV衃0 e8N P VSa 9tV4BJ"íEj.'_{\M-= Fу:#Obik6JPŷfLN߽W|~[H^}1, ڦ(RG%X8^T N1~pgL:ˀZk)(we/fS˿H*MUh*6JͲڄk=mt][>S f]wEE0R >b:ǵ9 .3P@ vvi`c xov1JE,G #j*ߵm"Ys)+ c)]>1P'7ld?FԚţMQim;b恜2)b?;F5vL?g ,omq +ERY]l<(UŰL p9uNpnJ/k ~6S%1,zu|P/3߃\ĀcwvEwrXy.7f29|6}j5%!,E?/btZD"]۪?=.gv:NbSIh~xs=Ph=3ONqI.k凰Ζ%C !w2uA>Q(/Fg$q{1AT&0 tV67[Ēs -'J,nzԹ}QBɑX& E1uZ")9ѱܷ߿j^bX* BGGL2%68-.mWkɉjlvo&$]yIremQtK|ivҶlR=DE%-CI[.=IΣމKCno?io{f}⊅ژN ] !@MwaY[L r,!=T!Ӷx^Nc8ݚfJ?QcX0Yh6!F*gSǿ4Ϳf#f2=ᔂ0q::ti?M`U.h:@_#2NgVS]tؽEyvPi~8c{S7pyۋT%oOM ".=_Z/o=lY˗Nh4J9lO@m C(z9}ٹwh.'ƫxdzDPlmeE]oxPbI0!AV q v'% r9ŗ:%CWvMdN5cR}˾2w RZ$83xuABeOtҽK_]f8ܒ㈭m1kܺ0*'XˢfૄT %5\ Tr"0)b ay]V& UtzK|=1ozcM$% qꀕ::{flIEqT覔ڬ"$'ʓ`68}&h3"HD9W.Nvq9~:[+!NP9Ǫ«) 5vSB750"&ؗł\缲F=/Nj<.*Fv٬zs ,Λ&dzJIݸ 0'K6z֨VMJwjZ<6Hԣy hKX tTl,n:.C.M]cJ>e]_U^eUOAp"&)Jeڌ1U^E\5[Fu @KIZ7hmq?o%D{$Z^HCbɃw-۪zm\Sg/ q]UuVyNF&wb`OZ[k"ZßLkFn,'zO|9KILNEo1̊W,nk%ѷ_53.Km1^ZksHbj~ꨙSOtXkD7YhJW$ }4$H6a7(ɠe+jbϭ׷^bMogkl\4-Sdy1;>5WFfb"{*Yp_2 !fѹy8iMKQh"ZX tTdJrW3ąfk=*jB2" &Iw>8RTUJ66sSU c٫V۶͚͞ǛOBW_*~)l'Hকi e")(p:݌Z0y0Bf BP0HNTqI *.7KO5u\?<|^˳>9/N7:pDTd|~wOVqD?ןCEeHHʃʵ6+9vN*dyN1:K/XMI^`3)OH)y.5.*:|`;$ K+Zl.kO-Un3RxͽDP9G$ 3Q &iLl˴v]&ij,r""z$^M[N<%S`xeU DgcmbDQTCxGM|YdY?.ʹ˞W IDATSsbS]U19̄I Y?<ҕtz%lT&= bSI$g`&NTFEyߜ=S޷TPň꠾0Akf^/⮕Qw^ZauXfڵoTmU˧ >%Q?إ)Gkyp KWFݦDxqbէ" -Q̽W%3lr*6B]$:v4t>⧐;rX㪞6WdLEc(\vҞ̒5W1˟^nmHMx}vcg.)Tj3xUNBE4 FĞ9ܒg`\ܾ}W]b5rl1jIH ġ]gVKl83€0`GɎѱL" Kt_scZH qLⳓRAQ6-jo&Z]ݮ:Z|J8\i<&?DΗ ~Ł٢ Yf-*:J{W-?Q/!Q㛣鳋5^tޢ{y9`՘)/*Np$qvON}ԙObt(w={ 0yĀ(<ض=iƠƟX2rwE/aj*fJ T͏? 1="}B*X?"TS`䃋>xtmupm;tʌ";҂h6 *Tߕv~RlȅnfgB, Tڞh[Np%&lֲ5nDPWm /ۧ4>I%z?ˆfׇgyhFЫI[zNɞYC 99~ZE~ˆ훗ϩA4;-IB҂ 8}4ngUKQ2S'x(\})$/& عq)ChI:BSmcz񂥍C=o%UHc&c eFn$@צ/N~8/f @sfILh) $.Ѧ#Y'/PKAN0B HVڬ˛:{ȱ)Y6ˡWI3a>1||ZɈ f#Ul@Q;!ހ!rA$FھY}.VOn ~IcLWF߼|Eם$ KkPp]afi#;$Q I)iM:Ⱦ!DU"cZHfF?-9M,B_|ԢLIS9$;0}#(}.M:[挜5!LFP|o7$ږ")EB^6hOl@(FC&dL&ږ$):ֹ!}$i$z*@?EMOb__{˴J]9> Y '8|;h1v!ޫyL_472'LseO-n+MLѺq{ۨKR`phz?MsArQ;t&_7eR-vן6g?Mg X5q "mレVWmXp+;߾f7(rcՅN4xsBw;Ѷ RxɁFko8\`C e~=sO3Tu7U9bN8ГQiEdAϿhx^t&VW&Ln]׳$ !i~BWsv8°WMsナ|/%&"txoֽ}Œ~5Ki#jd,:g.E_fLm]MiӖPƼ+ҟYK^f3au /B~CIޓa*yΊc !O}Pݺ6n}RE O$}| 'dMQ]ykKߪQrD2pQd }%Q\r-_Bk_<{3|I_w,dN8i=}a#;ıW Wa4?q9:C -)`&*{vy譜'Ζ8pΕ;WG$N:xG~;͒[r+Nu1SA ~˽v#C usϗ&!stEl鍤GPBhs<򈢱-iSbtJ-8~ZFxEGK[ͿPhZhvyl$$%>Il^x<`0@8c>z燯: `|BD +hwܻoLp֝k $2ޑpV5BG3odic''z% Uow,Eyz''nl2\H*ac cz>Ӆn[4RRM\Zsa/K?T IITڜ go^r+)Ɖl ,{Gjoy 4s Z% Z~fs%-z,# \{iF~B&m2X5g"'iN{~ZQT޺9&K~h: " M#>Te--YIB(g|gƄiwzAхvD a%pаi/կXSƨDNt>|d-p460z7v8bʶG #J:tzrOVWjZ*Yo^d4H U4z8a񲆂s1NNo!kyDkoQ*& p P'ǎum+~<5t°0oU7*54ֽ+l,g/ӵB ͻU9EzЏSP((ɩuueٳu R5[v:,>hP~0%{¤c`w}zֲMz~(sBiGKH"e'K2󲊜obcDx}S'?';]8Lu?8؉}c o+5qR]p~TV$oq6@οq}DZs{DZ}~<{>rZAQ65s~,ig`iNs'@R1 E3WPx_ds;OQI .Bl@GKp8Ά{ y/%y,_vy;As1Lc a]yBjxǀp3( T| sظt8ZleE-_UUT7  5{^nN/=Sxcߗnۢ6*/96 Gku-+T<UwĦ{MTGmum@pױ2Y:߳<}]y,H#g)(\:##oo{ \uHZsV_Gx¦D[y+~z{If4Fs4;dc2Edr\b,!,pd7ĖgЕ^Wpg%~Ν:7zѲtͦ1f9|igK ^ǔs;'Q  F5~yplg0uοɟp۫xWr'dLp.P= U}޽R6}WߟCyFE8Ɗ)Ё֤!;=yYExƗ, ]<3hG]{X_*>s XքiD |~磛[:3JAQZ`ߵsл4gΟ1 j4GNxN4ډ .TyH fJ)4(^w0!8xGqaYՖ7ΝUR1kt)*)#70[PD/+ ֱ bfc+: 9NhU[R {,)ĥ5?~+hUp@8V3.]&.]"ǯCۙװM2HTSD>IhUU|C_KO{ۧ C\N6$*(%i6b~eCݴ=u .ƥ{}W")`Ԩ C+#j`* }gE~G;~ާ>i=m{}8@~uYug͐ԝ!, hYW_pםҳ+^_]gV89e9DFjէ(RpJ0"5_ӦY1us CTVb8"#B(ZcљCCB'ѸEU:1䆠cG_"NBs4j=U~d?ۆ&O#ӗ ߇ +7e@w޷ ' 9$SLqd#yf>2}ۀ? {nwhۋSGY(P{oAe9.>:ﺿǷϪ>݈;1 ~qn q!T,sc A6xGpCV @ yLfH@ aLC\([(S-TԬQ}Ni@ %)z,e*-Si{hSo٪V>@ @a$@]GpG?T}f!DZIVRJ{֪ޚ5 s@ 肎cO*Ǟ:r.tPZ!sisP!Pԭ#C`@ #]`.]rJ{ҤΣsI<Ɍukڠzj>T|-ߐ!0@ I .oZ[ӚtϾ2\B!03/PJЁ=uԶcOX %t@ a$eŁ͸Ŀگ.7^#N(+R$L#@ aD1b<}8CQ Sf-$,@ $c:! L0C -t(@CAZ%@1{XfW_ĸ=uaLCJCK'r]j$jt֐Ծ><cG~w>)G0RF*U 0)VcR@@,!5ǭs2݆.ޚJa t2r/Y+)58UGZ0% iZj뵭 zY+4T/Vhfr)5#@FLQFLFLSXYGS'?.eKEyH춽zcA1lg>r8;^Dqtڈ%wd?ٸs?<:tAh~uuޣߑc p\Hv z(QG^vy#QL <!/(|NQp=DUD]t1bw$F1:IGK)}Υ OXu׬Q⣓a0iҖoI\ Vhz&F4oPhޠpPgcH:_AC>{N~&z[)k*d|~dA;N':5XAs.4sQ$bרpx!"Br1e,N}&rJ\MR(J7%/Y򂖉"}Mfֽ1!d,ht^eRYr%$ԹHeqD ԮQuI@.dIBT-7Kb5eW/ ьcR@4pPV1s2J:؎]>0}jȟdxne2쑔]Gi al޺TwUT \#ȣ^-J!^Tn-eDgVolsn͹NtDZR]j>y|fG(}Ԧsn8a,בh[G;I)cjUOj X%CX#YV hSvv$a(pM0@` zhf] w i IDAT3Io )@X`&V6[tRɄN~Y,ɨnx}F͉fALқG䄥2B˜BbybvEuMXze t\-vVVcoWNUDo!+R;4_ӡmqȴ/58ΆY6RSe 1B#B‘"vPx>: pPdgH a@H1M3BCԞovlg4u⮭bu!rT:Q;(.‘!()]?@-i#8QT;߲ncFcUQЮROnJ9 ++e͛YX}8gImuܵT݄gw^ j/ProeyAT{Z 3`QUEgwڳsmo]6aS$ '1ndSFK}N^.;@3EY@ 4i}~@YU3UaA]O16tIJBQ^>J- gU5KEp(…Ł~@Ǐk^ǧik5dQnoixղ%M` 'F65?Ci? mvƗt:D7IRVh].h-Ue失S, JܢxBIxBQ`}nY.d9f:UNCbgm$@̥(u4g8P]uiP@ݘtpb ܸ@`PDwl._^2~u [KmHc [ YwbJy<(i&:-|~uXĢz͂Z͖]^ֽpI=J~ƺ;ջενhַqD1"I+iisfhX @VZIv*ybȹ֦C~2ȑ0|㣇S:\(.%\H}3Zxu oƺ6UsmHb?|ƚFVI^GVCd5Θ$ydv˖WsmH )_L8SXcpӐŸɁfqFN8mzEQA[hjp;2&ږdp~+~%kx;fAhVwնw(qsjE۪O fMy8K2,3,PVǞJ͌T1izgBn{>LOINR֦q< X 9!>& +0#446hW c \s{-'nmS2QWY}_om iI]jT gZ]">|Y^b6U]/߹جFÒy[%sT9Q=lݝSk4Z Ez48Bb]^b5]}qJJn1 B~d}cEmH=vLwde<4;sDjfoy?zdif,b_tSo>p?LCU,Ƚ`ɘ쨪7^a,7<@uC#]b|nLeBN?]rv,c;@G$ٗXتܽldzmStS( `H.sEpJVt6L\*@EY&Ѷ$/@Ŋ<%''d̒R )|\^vXQ|65K[v2(~(%Z>]+PԭW٬{!/{v}^OA/,eQ*?]tCFH^>!}+?[":kDۓl$ehm;[zГ@M:J+pq{-@'<4QV^tT8+33k .vNq6M`AXUuag¿x4]Q 5ހ{(zQ4yy ~$貿7oMNM i̠ZEml~}7K*il6(6Mz9'?#p`tj/-ne񺃜8фDqhP2st[=u+){ zd( ٹ#D ~2i {{ܖϏK剶'H1DQ\ SURzQa` p섇9dʌbϡ' lsn;ޤ d"F:Zxݐof [}qcAoѣb<.2OmR*aB:<cU&3HrR_(_jukRu|SiKCDr'K3`=ciƩR8>_[4fT=pV( p}?nՙVC'e[4G$zǂ#-i]QXNGQXlg7'b}Щ㵂Q?| 䦓J9wh[%޺n-}gÖv f ]ʬ\fdSnzK9p)&cHMP+VSYtղ(pk_ii[Ԅvn}u哴V&: bHVA 6)*k(EQi UW6YDsٽiw*ǯR(*l fn*q9z큣PM$4B.E͟u&{|cg) Z%Yc}K͎G,.WMCH8DeqR(W.qYۧ[%s)λ>$# 3͞.Izb00诏LҌ+EL*ptI^}ywx !..[=N`.gbhXgbL0gNW_Q^yeіP53' g l-dOR:sp X5'j4{jer^}ûu?IK2QVgNr{^49..8ר/)4z +Z^)_j^}Q5v%oho2cSy f*)t#tZ|4ـ%D_ t$֛ul[Z*6GiK m}w9MxIP?|dhLτzNt ?Rs/7esLQ.BZ,- y߸S.=xP6Fƒ%m1}m58H'i:職Bu6@qF`هrv`nU\Hb0)Th3$7WC͝kaຏ%! --A5&랡$_q|Do >!0$a(*p`tPg}SDa bQV?Pk~ $zPq䄁DG3` pFOֈFVZjE)r-Il#$)m[FzAkґVJm QNznPm/{V #B8%ڜAJVrapуxMz5~9,c,w :'0ƀ x~Gݞ[>W,/Fe>;*ZMQ[ﴷ& 0!G1v$)I[e W%{(yWPau+~#68;f B97O;~lNiƉ`_b/y?p%Ǐ%(buY{N Ta 4RIA\sيAVb_'jGso'䩌(hg1\4D94`mƀTG\LNٞ25z%}[YY+$xǎ2-IO18&({ cVT.!v$P҂~OGٱW+kj4H4"ͧq5{4S~E9D>ApJMg$ڌ9tȭ=Q&ŋ̼;w˛7JG^"ĒoZZ?niiee#~ҡ\ޤCAP K Y[CJ7`NR|\L(6?QK$@NϏ`N}z [$EaN B1:e}JZ߮H! %WLV;34g0xTC)C6mtH^oW|, u诺*?n E!<"І$+!xTK$}@ F% kG|E8 jqGſ ӈ@rU>*b.<@A+^b Vya2j$#5o~ ;w^*0w:C_ԋFH cATYTC +G2cDQhTK_@ $j  2,SBSi)$w pt{É)4"ˌbog/ G] &ڴT]sVE%;|qhQ7*/zՖ^q` %ڎDxnd_ VMr {ya䐚ªҜh3G\k^sC&XǏw(6@ Y^8pcNJ#ǚ,Qћ4N\tt%y1o$!y1y!..Ò^uTE4& I#yQ3k+";6;O33YWeՁ1/F YS#$\ScXr*p&}qńa Bu6c@Aↆ.gC>yңg/ `cߗl|}`Ӑ=F 5d3F~Tq.ݲ`T|BYFU~ I9 ?X/&T)yY8$W:9ٽ[_muDCӥ$e%cu+`1[$ڎDP("+byxVV%w狈btHF Ae\NnA:|ݫjfժLKQU ~y=" /oT۫^,I XtԒ%EOq>~oyE{(*45?%^di7ŰnjaQFWblO~htQḾQ1TTy680 i3ͱo2\lZhT\uge]JHZP3c-&t]c%Ѷ$ t'yڥY(F3?Uxis̒sLu_=yҧ44TKĩ*db&M2݄5^塇{NcOխ^] zz²<m2&+aan4 Ţ~EQk>Y᨟%J1$Q4=ht%%-3so`ǒ@NKWR1 :E3Ts$ol2Enw -$C# M"+C6*@](58;{0/;βޝ~ۯ;ߨ)ECNȰB(;cI dl}L# &;{GyM!H)A@ʎ{ս{]:/_Kk{Dvj_{2u{sݵ%\V{kOnuFâYVpCKw&7ۧ9qEcbۿx-O[y[T};_on|Xֽg0Xb4P/jl ֮(tTKr|Gyb1hh{ IDAT gbM[A!N*ϳ5+՞e!Bfh]i1ΞY쵘h:0.k.hhj寷|Z-EB}c}U6keϙk <{恼tVՇB~ޮbYt+VXRfjuWU^*΃>ҹFӕ+R, tFeQG3wt qalT#co }}PШyݥc:C#/ n"onse8GN/љ^dUqvw2 B>w xi L+L+ԙ 3 񸏮O ՚yt[mIF YpAM`P;p!)n7o`@TBHֵ.!t k8`M/ &mKnuʄ4eNQ˗i9j[*M?)z׭z^ Zn?oo}פ[0Wý+^0[2vE7KQj\-m?*r/,T~__tzpcyi]H)~?߽l|_g^qrQL![;2m,{ǣ/5e _cŦV5_!=}tliG b`̡rd}HwӦ -bG*W!1 3'"pu}N|#YSS!ձ:;R3~|m٧;ΨMAKSZatېdq \h tWQx3.;/ֶ\bX9MFM_-[:EAK7^dϒd{Ue[cm~ cѶ$ 0HPdB. }rpoq1ʞhvs0? ƣm2q<|ieӧY/fY^GiB Ro>]:>~񃵾^h|L/:OS!h)y`i)uW eGX/u*-9g;ݟ95,7lIr:Ƿ~6Rʝ43Jͻ=uwy.i(nk6o51zCHG{4D3@#,jB<18N#hx ڤ^=_d Q{eCE̱#c =H5|L%Ucb`H"jtoE`@*I 0$ZK)$2Օ W7:]lS _LRA KQVjdO}!O 4@UMajY:v]qd[@;<ofvzEB !z ;5r9;N.\ ĹKǗKĉKsgp978vc0MB]B{lZa wv7usw*=ӭ^cDYi=\{Q'8ɲj?y h]x9bReVsY7>UL%"‚;o*,8 TBLǹmlpD-1VuNhu:jw?z͜rϛMr=`>ǥ+pqEܸBm)ϟ;=ϯ3_guݏm;v<4t _̕\V] ?6ݱ&蒓'E%q :Ĕ&1cW]-TڻvzQw .!>BrUlxh4Q{m!_ր=8:G|h_}RKEUin>+_̡5+ x~ao-lXiwQaGG?Ow("}=a-_wc./pI72e=et-`G$k"1>%ؖ}fs_>[Bn\SVUxwO~8eQo`h׀MeBKы'g_kye;~y`>0#=)_`0c\Ѫ_g ?؋en77?kF\2QѦnmWOh2gKaGKOy濫¶tԟlDc;Z%'?8;=1σ\wG[[a٢#:uJnj4f1KVNvZݞ=N"JԴG_;rˊ?s2L~mXXvͶn]u\S~~V n"(X&Ɍ81lKV6w7nUz+K#ˇm}##vènE9|1ʐU_ovU=Mc,4q'I\IJ!SXDqr|h1O iI$QO n%Cp=g|t9z[˱qSpq q-rn7灞.]v-qz|biO_;O_;O b,y9=FVHYDyȹ";;zZ #n?E7 ci(J哢^}1wqnؘ1jEMiIJgOd%h\@yvrF\:9@9c;#e:-qs*"Q38"I]^߰U:'q;t*piۊXyL*>_ScsT+B38F%:Lwx{x!ssgy~SBE" _W_"!٨8RfsQ1BOuImAx11z3{c \_0SlRKIcID;۷U=EILvn"ЃR9E>~ cOZ`Rce$}gEy O_AC솛.Ot)d>> :,+;/Q|h׾RVh#*3 A',^D|`s=AO{$rc3t&]Q\!$q HI?0kKlxQmUSIzs(QtZaY&ogi0(½+E.K;O^غzn \|3zL>fnxmgWhOME=l>=S0OigA $3c){zeW7k.LY z/ֶ[}m#dt2ڭkzb˅{[Trٗ̽Ĭ"AS`vvv詷*u9/?t}RM0DZwT=IDj(?$:~ cOZ`RcsOy'{DŽ?<ٚӗ'ZLߓu:Ne(BG>+;V,cS}'ovUk߾l1DQiLKlu˗X[}cwiOǥad4W]F27)VTlkiJGKΉ.Aڈjuy0o^s5 zݕdZ/N(ڪo8yfUW/ Sf|{͢ӭStUxd0ۧ](?Nz~XcI`-]n Q-9$v:MI"U2^&ܦ M}iʣP[ ަMF!M$k^]&.3ޭp >>2~%hx;kxа1.VDr&L-PxN@6`YymD֬VT_m)}|BL;޵3ðwJNjeQw3\+rhKҘ1rh:ą&i{bpgy˷4fխ8=Gˇ۶U?HieG Dtd/)MC}"AO]`Rc/crGյC0<l67S( ͚%%+p],/4y$$y4&;}hP=Ix)VNXRVI1J5յn.94'$q1$v zPo4=7w(jeQw7\#i e" z1rHCt$ :cdkۛmmK}_o[jWw~kg%^"n۶괞1 z#FF6%%PvH/B$?A4ձyK~Đd_'.b1׏ŐdڳN#c >9}!f_)HZe>!A9#=t!A &xͳ~x@ks/c(qN; z}pϷm~4UmЉfskGˎOr903dV|`cNᣣ٧=ٌzn$h1v-5y2;lO HwhZ,lxSҋo;lC]!g'O:LiDt5]|3d]3ta>>fc{h6pOR҈ A\څVP40: d<9$:z]'&{쵞13E5>j*.^umsz6K&KDkV-MCS%e{u< .@cLP*ܾBB&. !}M\&rt;Bo{qLa{d7Ȓ4E#(oa<͈[[/d3^0+{\dM n2YM\Äg'%TM\ (K'ą?:&.ӱX4D~D'i\#"8cH {kd]#{kC}>FvD54ZYSj7VX 56Ӭy6KƜWCq0u M\dF܃m۪e{u!#"G4E>~ cOZ`R2<IDATc :!AgHC D5ccFuƱQqۥ܂x^hnd@xVEO%Ag Z>t&7K+=v㬹.8W􈹜#_ny¹hBDD5k6."8Wq{J=Vn(¹NA貨N8IIH*i%=iTn?nFZ 1&f  +u U΄cLYVnŽY^h 2JU9&D0A'"Sռ*"zy,$Aiۤ}Lc|J"M3AOt Y5g}1C?7Pm5i=(s~[oN}K]@Ds 0EG[kv~MK9-'11LDt_֚ɘ9mMOD`|DT9oMLzm}s!{}DDow&;9'f/LjV" '6o"A[$ӧ>KDDTPk%כڦzaJЃ7)Dи}n.]ADʧ36DtѦsUG?=BD;:"zQai >-d"ۉhZu cq邶*@EtA"HT : AP$*@EtA"HT : AP$*@EtA"HT : AP$*@EtA"HT : AP$*@EtA"HT : AP$*@EtA"HT :?4B>IENDB`nut-2.8.3/docs/images/simple.png0000644000200500020050000003717014553676503013461 00000000000000PNG  IHDRiNsRGBbKGD pHYs B(xtIME8 IDATxwW}>n{ijI.rMq)偄NL$;TMcB w.YeXeҶ9̽{j%t?ݙ;sf|ηJ)!R P@|E)B\|0ۀo+$uQ 6vg|X7['YI p3~:8JI)Aq&p`` 0p0RuqjHPk HxST3`!pYXuqj> Dj@ǀeJ !ˀf3]GJV> PJm×Guv0u 84M(JRJRy)e^Jw'_, DR3[?/@++௔R/;u x{8ytݗK%u(J"] !l!p$(. Wlr kiV5- #iI5mP]ד뺹r\( ={$gTɝ`qk#ݽ]F)/+W.j¶}㽕I*!_ȓ(Ki躎똦eL0ui2 Cj&5Mp5!\p5M!FGakB+jQ$jD_2J7/,8v>_燇S' uG~s4˥ZON63#dm\ץ//)e4M0tt0 ]0 t0t }a~BwMu[(%J)%QRDJ*RʶmL66|4b4 ǕrJb* CA %%v٦qlWخSc?> C!%BнA7 a1ߦX,uƍ _)w[ns`xqQH)QCIR]|h ݷ''_M7tz> aG!e-٩}|';ujc@ @ \p: _B h>w뮻r{ ti[ ^U G.))ʔTT,Q*(8t%RH)q\RGN^D:ס$R()\P.UCP.BhJ"DHE0u BB( b}/㗬>iE'm7p" (^/캸Ryv] n͋Mc/\0wh#ɽxD2׽uU]WJcARyu"`X!E@GKpKjrsMNJl[q2nv_B8e.t.<S!&0u ,]=6R! 4|M͋_+,_qFqR,].Sr8k*VZͤrD)gD"z[ ?⦛X,vS,rB 4|]ḪN.q]wܺD8眵Y!BDt!?%on3T̪MmK^FOAJWjcNYTO~xdbw2Rxu~1 tT*iGॗ^W% IS>V/X@,ބmI&ory`\ ˖eC,A$fլYRL>'ϒdd2)ҩ4t0D"b1q8x#xX M}²,fj;sxkGIK9jS;vUJxoTuntp,c9w_k̵= Uc]C ]yG7o 5tDM D3טH%)("puJȯyK 㓾4*Lu1toB.?XGJV\Iٶ=t*E(\"ICfOˬY7^uLoyG,FeR4`F臇p8jk !ZUS`!D/xR=yR)׆ۮJ\9etC)Hw0 aR ~ރj(t   1ˠ3Eth4ogNG!XwV|vp0ͪfQUET۷d2EP@.g;Tӑ`׮]< Ķm6<4/ s=>~!N:x) O瀿?jWrK)H:Swi!RK);I4:+G)%2yWR B6w:KЏ%R^`€_s9lE 2DŽJt:P9A,g W !>k Bn_ÿ@-xwo>TF"^\ è\=U}8H\ J5EuJ^kH=Y0h vL QqhO: mOJR_QJ];<9ZR#0ؿhpRJ}xh\[ RR`'A)uWͱ˄/=_O A5dӪ窖qoZ2ON"c$RYz5O(_w[o~=WG*ddumg%`)Cl- ;!Y?~/9g*25Ͻ+ha_ je~ W[ބWfsG*hجT>FRy 밅(R`ۥd)Uix47&qd)MO["j4\iUѐ'qcv{,cl}oHKH O‡C!͛˶ۘ5qNpc# B gj?B\K7#nl f_ﴚ}GdORUk4mPӄR'叾OMp੩sGŁ7tH̚{Wr =|:R)oX롯lkw&7SEwWzIGx.͝KP$ bcWH/BmGR !m䇔R_AU71z+BpۓYPE_Z.ū$svfpz`moJJuPq|Q"Lk^ҍ(B @hrw$;_Tr%Z $m1Óհ4klt$ rdב5so,q_aI5SR׷WJ |fs=P}{9weƕSJmYz{$L M\WFP\@:uηCu)&))FV``hz ^aZFUlv 8hҥFHԄmi]^4UdrܔηCpUU̢AvMbVM$eΔBT1<aq΍m1_wxYX gvV'ꄯPR| itj AsS:x!,RPF8uN3&dRi=:.U]5[Cu*nvat/YZiC=ON#jqƟ79L-ْ=d0+5eH1_І?jW'i^ =iG (;tc´x_YP釴~fO—نR@ )t\_]FÐ!h鴅 Z::FH׎ЁǡףqMh7Fjݼ{5JժOeaghF%jp̲*;V},ƎX,8g  ҈S#kMAC44LARagSx Q Jj̙{Oj_ײ|2׎;uR"|VHqmG+6uC'"UVkք d%4LBxNQΡ;,/cIz*>SrOFJa's!(!NX4-@R:MtA:]~Vj oHJ!{Xk4uZh=)P1 T,tUHO4A4k'J:.BFp&{ZZV7dsTkʵ[cWwcWǢ P2]u |neBӜ:8Z~B0sqBru }4/ ypO*jr86bt6/]w2[GxpN x[*Y}U1[U٨M=)/5И܆Q/?V7L;DN-Au0>L]:x+6_fh Ox*^@>߂V'1}J;܃h`M?ioմ;i D{-mVT]£#|JXn&C`'WҪk^Y9ƆZc$cuCu\^'cDp,>3I{d&fRzZj!pl\蔅;FjTZ^ ٫iJONc3ݏ`MBu2C(Ib7= 斪J?]c _TRk'$I L0L߉Zz'5IA)]WPN5B/Ѱ57m^j_Z1er46ӯV{?&ȯAy15CצiR/:퀠6ΏGJb{ P $PHbM13мj& T{¦2zTM? ,}cTlh!N%(rO{ǝF.\ǩ:1z&(b'|awrtKxqH$H ' V UclMvQe)]0̡W=8md򦚻bR'2Pɛ$x6b(Ƈ?7/}1iOx[[CQsPTy!"^Ӎn&AT*ef6oތil&rt*yߧ溒@ 믾 .8ĩ;-6:u9u#Iv 17>M7“'a()i GU5뺟K/%Rh4OA4!@gGqt]womOB׮ y 7vm|󟟴I=36Eꦱv|Rgw+ى2>5~{n&x4^=9ri'n 6^ML)\E:~2uQ@ss3.8gCuvfdYٷo/-mtlfJ)044Ă'U3٬?aT޾i2}/j FSA@ ߱+_%FN$o WO;©ꄗUdr9]]c5gݝv Qq]`;RLPĕ.q'FC&m`E(!FV`gaϞ=S̹U)ܯ%ʬZ۝fO?M-oDp-Ө⶙i\DJP%HwLc \'m\.l"Tdw땣muuI7C]ž\ ;l( s$yGs$%W[l=MXdP)A4 Opc+ nI=|c r`*1{&J|/7& _^jo8!|Gyj+!(udS.KYB-$i h-qJbۑRR\_o_\[U[ٲ,/X^H\:$_6Ɍ>AR^\u5ݫp#N A!:LWZF-OfE7T3kN RE4!ѕn@VvZۧĺ暿ձ(X56 4?ǟ%~mX(\.wx UUńs(\`&Pd%F_>fJIٳ I&%fW5|5a,˚'Ԉ7fLZa_ Ý2& |P&O2;h[U0 #Ӧi0 sskkSi)J}Tj{-[]{2#;v۱?U*ޜ5TU51IuJJMRH/.mñ'Rz&gu&=ȄQu,?<)OJ(>/j=@Ü9׼^&^# XU!Ki0m&bؗNw넔zo?Q5;R|~~ﴄL^zAvțarfJFJV 2f2v2X8R=0@C4H~:/ٝ gE#477O8~*hhX,wxoNYMo8w\'s7_Ś{{ h*i߼~e3_IE]U(痊EQ,% <3]K({NQ($_C}>O~B~{.ɍO"蟟V[EGG'ljKYɧhDR( gלB׼OΝ;wtm͛w3 ..o|;,-g r8 X).^ĒK%ZZZB(fc7OC+fPܳ@DC489,]>_=ᰝvRJo A2NV]@3,= `ᥗ]~/N{࠱|Ŋj s7U_XJ&/d3 3/r C DXf {#L&(mݖ>ehkE~3䟺K(9zA)_7}4FG`jll.,wGҟX Jȯ.OYbkx;+M־o߾MpK3_wE ˺XA(%ihh`ʕDQeYsϽ_W %eMCUS:#=#\~S.0}'۶49s0NP ޽pʥbôڒΜ9sې ֬^}޳fD (lw/AfLG%cijn.ٻMh477B8h4Jkk+^E3G>ݽwܳwN-^mX(pƪUtu!k  hiin^m޶m?#jṭgجG7wtPD,y8*:}J)2RBP%x.%NS,)"0466oxhxWk׮E?(v(J 63Yb9 /5p(@6C!֬*o~yaΣq?0nhtu%c.fLTfdy֭Hp-lŊP8? ub񳽻iH;wĂ 5k (eQ(X|YkSSӭ>/}߆.OYGS(lM #A;:?ϓOR465Q(KvR ds9;Ys;wᬳ׳^Ymm_x/y%BPJe2Y"E6em{ٝoΫ Bx>~:ȅ.uB ֳw.+t6!]׫4 X,IdxxHRD&!1fϞ͎;8YmsFX$ reqgSٻ)gZɢ پ};Ֆ/KCeHql!va>w/vvɖ^`o4ʺuSOGݻft/Y%9#]I8$G~,\aC4&Jwο]{_<?:+%/rz%?淾C+_uq @'$T~>Dڊt3 ֬^mI3 7o>MMعDbR S sf/Lv.I$x.477ol!q\&?Ͼ'HP*) bUWkiw}7gut}zIDÙkV37oFpE((K uݴ %]"13L Z[bzz  tw/X)Nks M X&`uk$J فדeٷovT*mh Y|pt:C*ddxm7344@.fY֯_o7W|phA$m XV0W(d~/ψBP"m+YQ7C{tT ]Yl9P(@IoK5hCWu]1io}[x0tB>?F_Sde/N㏫x$iq饗p""0HP(@;Ri{q-ZDnl۶;v+ seWг{ lݺYrYo2KwO/{6RkVyafR+  5qs4: pR&S.1WeD/Eߡcm Lxc!XxJ)6=,.ba1Mt:Ž=@<'sEH'SRI3$f38iZ@ 8 Ϟ;s-'367|wfac_ڿV¡֯Ƕp7d7I[{>Lzcp/ *~뮫OrпaR"ɐL尒IʶM `nt/BAGǥBǹP"#M,?fb({R.900Hwbz{ /9+s޹slݶ Wr9"0/'P(93|D\&/ 4AKK+;;Y{}Fz{nn݇eYbqb]sr\!JNؽk'C 'f3iv #fߧ366lx³Y{Occ:@T"dNI\ r=D!Iݛ֩wbJiesŲ,{1 "g:8@׾3Vm];wdI\tE8]= ',[ٳр\&^D"675o.R={ٻo/%KY{ZlF\0-΅]iN LC:HR?z P/}_\S"P]zM2q xvQHP^k[S^*J咶kF%f_ٳkuڝX,Ys9] EW{ X?颋 Bn|9]D"%‘ѳ}}},[V[H(1gV ͦMʕ+(J F#8.#F8 XEOOnzzzؿ?J)q_rbq Q"dJ!FFgrHb SHhs8y$Ƨ7XgQ&mVK]sͻL&4.B^uTWiU*غe\pbijjDuzA‘8`0eY<,ZliY^h u0tϡ\{{ٵkULj#9)tO#\aH+`eBȶP0oz-?k_:ƨh·aZg"JԓOḒUV XXE8J,^eYRw}̚5YZD"\}UR⸒r.O.#2@=g${COOA8!:Ee3];I In2¡;`kwyg|Il޼}s̟PWO7wLY0sk֬s4MvIP 4yzJgZE0DeY~\~٥ݞJg "B1ix Ӱ䮨# FFH*`YP$;b_CUu1 /\xEcy7"QR$ps9֭#P*3)qPc.KچkD# s8U*7tt:M*$JJ&I$I% ܚ2- {CЃV8{kS _a{kZZ9o|C7L2 Xs;5g 2i6iӳ ,`n(4#v,;*+I$H%Ge4MSeáp_(C،~nꄯh~p$yC4}|==ISSKm IkT ]BXUCcF8瞓LB\ x])@RjN: .ܹ<{nBEoi!/P(xaUu<i{󖏌$H'8]ya1-Ãpp}(ɘv}W6`)ޤRp R _QAsc6y^1{_]Jp$LTƷ="9 J#7W@` Ñ3@{'BaJ!ZO+zU]:>S} o+~!x+H)2`\ o›@o瀥u1cjb,[{يd31ONF7 n( ›B/N,i SJ=>nGp A;P> |Ѐ7-MwkRB#p1*;ss|o[uX`۶oЖG&1 ]F# p8%<'9;?ipkrr.ORr&OYxE@~t.+]RwkmbRjZh:8$ڽ{yެ qiz0YjӠWʷ_ \ h^ H-?"!ģ"`pOhg5MC@ 0MKQǡ`[﮻j^J)%xoKz)v !©_-po|Z'wup PwQѶRIRC z>\q~N(qJ] T:ONP~Ȏ?nؾO|wwΤ.VuQ'|uqtmI'8ؾq:8ݷOo;N`: 2 득c.h`$:Nq.ꄯSG:NbmG_uqd<3Խuq%Hz8Lu̘b0JIENDB`nut-2.8.3/docs/images/advanced.png0000644000200500020050000014012114553676503013724 00000000000000PNG  IHDR.:sRGBgAMA a pHYs oyIDATx^]~^νi6tSR $4H# @ )$@(!@轛bƽ~So$>}6h?x~=ifXXsoC񯐾WoF(y r+M0acb(4-02WKʉ8d d"9qE &L0񱱯ĵ7kѰ\M ? &L0񱱯E.YuH,=T̈́ &J\-`tjIW@悴 }2䧐R?!!י0a¾vΏz3'8;3t;h=򘭰\Fx$x:`RSwj5! ?Ҿxƹʤ9C\& /.hTdfYFCVZUfU 4i S7nO@d4.iPN,jkk׿K4q$,Ƴ/\ h۳"iMZk]Z;PzOev;LәeјaQ[J+!94=Nfqu֮J3_Օ!Yr嚓O:a ġ>pǭ--DVݲZ! eح8jɦtSD%$ϥj8I=bgk$KOWfWzu7w9+gɜq$,3-|= +isOQOJ  ,P( Bp) xVҴÕI>$K @FLj>иel8Hɾ1q:v IV eL?UYUuę/X}k&$ꫯϘ9΂cm6kak[k˖1xx<_ Kƕ#3O:#<ѝާru{mk9ԐN%ݮgu+s7Wg\i3a©$A҈)8gG2w''M'<;m|Hgtu KKIn^. X}-,Y"aꪫlgP\ZRb[i%9t?r{[tN!^otx;.b*?/O󥰠@!EERX/%%%R I$jh;[?3/s _xt8d"v^ЂL6]y=[O򪮌\wϋ9v߫j  2B 4H6o$;$*3f̔|+P(>|Ly38ƺ:}Q2tpillP0č7KY<{_iY7!㞉ˢ:j.BV轔'g~GW'ĕڭBb 9hfT/4ݨtRө q.֛^Gny]M<]~-'A9$XmԀjQHl!H?gcKO ;~ ~R֯_4d 6 0^1BF%njj&4 =mx\ǃ!?T'{ΗOs&X鏅:￿Tuu;NJ㙡KHvB? 9}Y (?7 Q'3`79>ʨA\dIKj:3/l. DhIv#k ! "l@H($3᧐ӎw嘗uAfUtmXliu:\ʵNC3@wr/.?JlȜW$">) U7SǼGu$iXiTbڪ~eW NAy.!22? _p2.N}m[G \ҳ O@Yh!j8+2w7~gBA*_Yq?|g_NK&ބ\jz:s)B-)Cp%(K;7f:CH!3#!$=d>ʕA<a\x[?֣!%4(FJСTcW8Rr*ʥh&%zjZVg%?3Euܟ^S K ߁PU4aqj}.2$-7}pDl.I*,?_WrRRG<!} U>C*!Ch&Hh>s\u#ƿ\q6 r%lR9 BxC39߇UTCC!H_6-#[7/_,m?NWp1v'\ƚ?,^\r-!Ƙeǵ/B/i [TfwQ*hXA8 RH~lOwk\ZGJ]ڵyZuyZ9J׵i:YG֯.]WD V}b+VoP7_"K JѧW~Go1Ĕŵ/ù.ut$i}p ͗?_C^(ݐA ,O3V* Q kϰ¥;ZHlؔ||tj! W!u*GԢuOoF B4@7" A? {bgp{=Hj 1x||޴5|MHS<]kHJ]y*Χ_*Ot]nzQ|tm8/3$f'( j=I[dGE?(u/Eo0 Q0VUxfhYZ{gT墢@ԠYAo] 򥸰H*++SdÆrv@6@×I7_zK|#)9_wL<-AMT IBӝn!t0tdH{t <yu!#~7bE@I^=jD?Y#5RU^yCPNO=KQw:zB{:qUԭeq`# !SK]m~qD6I7wđUT>-ŃgU#X.V]Eidx"W3&BOU3ť$NEoDE?NO 7. 9%ƾ~6tMn[NIeaơ,$8}UFG_H"{<:±#Q_1FbH*"h-pD%hzڝa=,͑HZ]g07<:Y ;А" ̝ގNᓙI;݉y:UTZסNd{7Z]C,0+4Ң>ŅS$winy]Ozv֣ν Q/G%v`;)O R a=t y:_,yH%d%e|YK!~ /-,*qjl{fU^^r0 !S3d):\|wyнrԻ]CP{aPD3Fl~M6q:u$1s޳FBċg>Ds#YDM P F4gK#NOZ%-R] .'MX.RZ:-Ͳi5~2[qqߗO=8S]<0],G¢Rbi+$\eGgD6>gSܰEX$(Z"oz]>y. kZø&*A }p4〥+#yL}O&V/-0(֐_k/+Y0?I''ECaGc|&z ݂tW׾HLQ?;!+p St;)eɨ$^Fȳ>pFknw|QGΙ*^&A2=$,G".-tCb16ԨX>3t"{%n I)r2NRڸՕfI$ J`j>ucsv HMrتec2%9, S"jdMDRJb\cԡԉmaw2G y=V܍;;CI\Y^M x#6Hk(eIJ/$]Y}t:Aug}3iq^Q6aW#/7o'UFlVVKB0HJ5`7zY )]E."hXp  pA.wc,rgp8Mh6.t xC>HFRԞ4@hA#$ku}LSz8aZq >5 nfow\ EZ_XCh0>&a+I\SDKJ .5 $<51c,Վ(:>n4up0Lt F-gc.;n<q~2~'R $ $ i}Z=[ZԈy6X$.]8824X-H>C8q>uօ;1gDXHD f|* tɰE&xO yYY 8'$muZZi m.nqA8>el]}\,.J{RB س3F Ղ0K5;/oh(p>{ ["tI,."=T&\ Kw3,3`]ETj0IA^}'.n+} 4,g"%R>u{GRԪL&qŕJPI(R ֯C7f!L{py4G<bqt%"*)%ƍWѽFT)-IA25E-x؋ECKE[\/kD"RWW';w풝;w;rvٶRn&[n͛ȦMeMj7ȺuݽE,?P}p7 MrK l]#[ MO6 w1&?D#I@lbњRH*Eƀ{^b|M̖E6;v쐏>HZ[ZLZ_9Xɐ!C _8KBg6I,k,Z6r8jw9ƛdq-78L?i?1Qv-*=mL9i߉킙c<,F&H RϹ 5%`p\/ǭEYyYr{ឈY+8KcGS RHq̷q Z[0/ x˭2bo{B,gM-EC`І>e߸1O(~O?>"&җT${&)Ͼ+c:#Ȕ0:yGd̘2,.. 8yJNN<*2y|XB8rDihh/~eaWՇdzE\<\Jf͚BB!qdۇn%رI\$'ΔSO9u7VQøg)$"5~pIKl~+5(xS7ڛswdMt(;_{G-o.'N?_s]tR9f[u}]<2/둣Hk[D#QQ1 H;CHv',vkik{{fm֭[eRcs?ꅣ%g}nXI"!- kK%"i.g\Y߅/_$sZIy IDIMvՀ5xQ#2@V-F"Kg#NuSZt<bYGĵj*==Ȉ`n?Z/dϠUG]'a|ɇXnSN'ȏV(p$B/ƈ%o _TouS~5OY?h% v qCjENYVY%53@,KX\'+֣>/IJ0#G"!HgzkeW,,.=C%ݺ7O5 Ƞn]E``C7'yKAZM\Ebo|voW+yIF. 3; E7%~b[_8sÁmy}w{553Y3,VlKnRC.Xro;ح֟yW*N.Gt%"5WZ1XxV+;ڠ]\.L:]Nٸ~]~߽wߠn.WWG 9q<ŏɨZZGPР> Kw ݿkKi9E8ULw'Y$jtW{~n92^@+Vdku/̖r'',̟' 8SN8$9cdҔ2lxTUɦ z|k["1 <~LCk+Y!aH~S ⶗~)/.Vyy;=)}\jѐNHUi!9[$aV+[^~=(޹I- {jO2h RISH+uOii;A.ťeb٥Y-@zuyweeúujkvQ5f[Xi^(7W73w=&_ [#q,\EHIѮwt 2(2z 2]/ɈIly%rٟ&^(_7Oro3Y@Z t <&qPA׌ތ&qzb7J|n,}uZrŭ؃Qp_ss<-cOgxwH^fɯ_)ŻޒMˀo/]%C_ ^YH@H޺CJ>(EkJ^{j*6-|rퟮ'}?,q\_ ig>&w')ꍅs1ÃH\B! ci]pY;P=Xť~+2)++[犊@ %??OE!D4MZE@~鳡=W'77IUc #2|vMRڸJlzFx [r {w2kdnS},}X ׼(yX1d;vTJ Hro~#?yn!|!߁u%?c9rކ:IeAV+"_]%a|/Ƞҭ M-()ntL>yM{Ǔfb{_93"z)Jy` nA+eH2 Tdka/dt{:){RʿH>)w"qo_.*RSn[ $&NP8O|K_2W"~|>Guws_y12b(4h#p iuca 0Z!;d:O6Ӈ$+HHB22 [݆C\yUz :s^ױgcC+/pLApfsX_,+w'U=Puv=x߽I{%q{<"vX`rvV^/&eQ58 Z\ +"Jΐa/FX9 U`b<ij6b6!S4]CH<{Bծj >c&N-KE:7F2ʟ揔~]K3<Ջ:wtv8L.~CuR󺎵bcuR󺎵 CXg6N!+x/رR֬Hf>/lx yHDom];,SO=ѣY^P);ڴC(3\9h#p>r9*|aSyg}sw{_z~\.p~_?/?c֬)~[-QWIr׾rv_-}[a9u]aeHa7aq ;U- "SE_~[׿u:7f518lQ hՃiqukB fqs+ vfHK߷}JI1}+V/))ov=p8xVAkPCQOܫu=? :\ Ze*++Ղێ^[<%uٽƶ[drQGK[b^oH1\d'M)pD⑰?^wbW'&-f*W—1qmݺM%M*8\a,|$u x1%I\mmڈ@/~l#.u< u&} 6oVG{[s~RryAPv}-Hk);`UccK~{A\ǂԋ?g' #R*gMqz9z\in\B㞍фuH D9)bˈx"{䀻"J\/A\^E\sQdJ\mjjVҶHj^],YP.:҆S |ȁ/l$Cۍ9Æ+_sS2q ºpM,/,UXBpN l[o  O0$ hR/[A\@\s=Nʑ% b IS$huZ#z)õNeqE"^^[*앸~ &(,KKW?UFWA@2J%.Yk6b2p eeĵ5'joo:m:'uOR=eb$}8^c|#¡D2 >$(t}t=UTTȦM[:h$N=_|t6TKV"kk[$hѷ`CߩEvbue'y)$.u$&~ 4H~_ĕe.gEbH$,#j⯑z"]v1pb Ń5qǼyeniP <'̄E5. 6|(HiZ7bʤ ޸7È r)jt4HMk8^qحqX,u <{u=ࢋ~2Mq/(oo޸q .̮յWb\rɼRHhW '+L ꫯ}q3, \$F-W!Si1c˗-S{".2nx `hK/=KGֶ;fvtC~QR\*'N2xdҥjuqرcAL!rb;#V s>JH)C=6_u=9ۮ^O7}aqIհo'sa\p~۹j~_^g?<)$^2o~>CxW[luGmm+(. דv &n npaӧJ>>晴ԹΓ|5j6 b +!nܸA)Ej@#'ЯXоZڄKd 7իÑp߲y=N$sϛ{WLSA`$NZ# OF]#,6"wZKtT궗S r }V@~jzח&˗/ HQ tHj}uXX6U=lfGy.bydGkn@,_嫸qcJ2ecYߒk꩐A++- H1\.ZWy9  Q`Z{Qrܼy*ߗ+VJy9s*N@S\{WxAyK;p\i+\~RdeӖRSS+ƌ⪅u7udY1|Ȼsů7|%oc}5[_gE$L~t[aiߵ1Sn-|vʂS[O%8jĄahϊ6_b0P G:41)a䪫2-aյ.gQ>ID ˅ƫK.1XObamٵ*k_9,c{ _8,rs8h@ǕR Wp8m[*%4fhiSCIjg*WvqURXQQ'Æ B!ke-jZR'#GP>ChmAܸ#GIiY :D,ɘDUWض|%Vϣ%5 ǁ]KR3gqM,/e3;t)\U.P^]^rIN=4ɥ9,]LN>Ytժ+VR .Z455ɷ9?6hisH\U;鍨⪫6ugZفl;Ug<]':l6E r˅e*,M2tS@tv2ct wZ62dxHN~ܶ]j&.4IQa XVH d9]@se;xFiv=#`%:}pEԢѸg~i 2H}1t9JبBps;׎v3-5 zIO:v|1yrfuEcp2]ttz`aa+~p5/ץ^*M2{xu5k{;_|-Ǜr; 1 .0Wi/8}, MG{}sp$U]rTߨ ώѣȤɓ{VoL1|xHrXcW_J ĵOGEE5[ GJ f+_ltQ9 y\XxyVl4Y3fj/&X"HN$fUDʇ[݊aqQuzֺss }tiph1l=uso0 F{'d+ S/zXQgI?4qa5k.^GX_pѾ1g>K7tˁd?Um߰IN7i,~5y7Q#C NJaXdy wsvB S?|1P6lTGnGU:?} ]'#AJAztHp yť媳}5qϳ[ EW^ܰ~*y.yտwX*#i]fX\]pϧY\L9pcRy3|U(u`r[nʭ[ TZeq`3:W0-^Y 8/!Vp:(XUsa=ac;%ӧP;ie[n/3Z֪7Ȅ T85keqIMMrd& Yp/@2 %9~DRڵ2r~UVJYYzYPsd !GR7"Zu~9 8|Ewj'ȸۮFz(mԒM%w8>'w'ǫgzÊ_-*.)B+(.)Vl5Gm iwQ Hg@by=:l"EN'x$XnF"ώ⒤U$T$,vgQa &v#.f̜u[AA~=wszkc#-ȕJiLs^v/IԱU9UV'/mV <{:;/N$/ǎ[~5vYl"#g:nGO\? UISLV¸$F3| cr@v3gLSI o wRg9$I,]!|hVV%UCSQSzP[k4p%4H}q޴xĴCWV$^D7z̛C uط8$vϛwh̑ans#VXƏҚVC׋qL! @;rg<\N{$NS377O!Zd$),x/$ѽX<*vݒR$բ[IRt/mV[pO'Nn^޿_z饷O?gGeĕ aGi3$#L<֐]<."Uܫx XJ`]M _{mR@ =Z}AJ d`3IUUUUW(늱V]D{4kJ,?Nz/Ii|q_|^}xur5ŐV@PyoR&qe$}#f8}hr2rH6Ϗ` - ܽ*xM21MFz˖~"|t̩vJ0+z{QPFRz9=}EnwDwǝ“o>*<y b'ݐ! -G,_UqٌZ@\KHepܨLB,/fPpa'byoRp`W&LXY1˥E^vMg״daᰫ.ئ[Eíjkjd붭2yd9\~q?XE6 (e`*YOx59ߐw_@z!t=D? Id$!\TK^pEp0,A-|O!V?w8 g0+&q}"C~wАpQDPm2eWVW!߂p 0=1!H;iֱBR"p!I2({|J\?R:浬}I\0cыV ?ks4;t+w`x0/Hp%lT\=-S#)\(V[vwz^l7}:A"\ه۰H:Yq' ߇5S2ףSp~"Γ쳮!BR2:W!hu 'O/CaW&LĘI\0k`С TT2t1RF9imopkCŚktxvy\or\x1 ؑO-LʄI\ #G__Q4 hDt9COn;̀[^z饴wL>6CLʄI\c**&}xv=ې˯Nb=gmĕ L8J\% &' 'Pza (@󠴝?5B'$nq>0˄C\P&@3 yL =b,H$[i1@J Cx@z(dsuS!g3?2yZta  @ ]H3vkp̀RS8mX\-Nao-91i;Pe89^ Nyz <5Pv1 $.&Mps\@)A`p)qufPYQ\Ui#Q Z%1a+a|'S??+Uqb7 Z$.&MoQKM)Ӧϰ:-DkFs.bw lHrΕdAI\&L{w\3˘8blhbEn)=ǀhQjI$>ArtXj"L2a٫uH\(ehAA,/ܽ#،4bXo Y;`J{I\&LYSFZ4*$V'^ڮ%J/! ŵH-Cs^VuFѷEbeSQ&q0q肋 YKjiMC2{HsfO=Vw.qsa (@$?6}J2vK۠R8fAI\&LQ0vρ$ǹL2a\CJUe„OL2aħ&q0aSL0I\&L$.&L|%,d#KלǜmlVkkHHG;6(k.x<bP(hkm<{%#MC9'J`n,%x+Wh?!g $ZOJ"0Z_D88g('<1\i$1\eq4 QTtVmZMFH 1cX _vS >LD׻HH>տW ~NB#a  U:O q: p&v;%nVhLܣBOBvɆM5fX2d 8H/eeRRZ,RRT,EEȗ2?q:NXj555vJĕ@[jF3Bf Vy䑖qz ([F>,4I֛rs'b/K?$U!Gf)fXC(>)4:kPH "Jyr?p \.'-nKI= A ޮ5S4kZ\&V-!aX\є>.p;cj=O;6H!C3_KkHi`5zmRY)#:xH VW\ T`,BY:QsCcciZ!3WV".n&qNa[-րbs R`#J'#{2\QF5|iZuZgdutuDarŅ[SGiܔARI:OoN1sO{KbhWVO1;aWdaZB VF_ggJÇ\-/,t`Kk :'E#?Yw [ Ŗ8s`X\$r?G,AP3jfG2~x!غ^ֽDݶKsM2ntٟmmAbj ?XiS%n0IJTQ7ЮM;<E\E;,. ཱӒNSN8Ԕ%[n ؤ?_{&Ê2,$YBDa[a_յFF9z)GSTuĦ*> q@΅}u+-oZ7VދiqĕըUj`Xhc rH!WJ tJ^y:2wSojA!w{mN{ϧvG8r[\\%"xANt(` mj\4KM.cyPt:+aWm2^Z>O>&zƫr黍rêVW^ְ4Q^.'ͪRydBrFy-/%QGZݪ~>Y"1 Gp%E@$L IZѵԧ%~1Ld/,".C1.U9$/W^qM\Y.aEkmܻCAlؼ4~E(DCWQNH@)gqn9uGRI 14ZC۝ iH&q!O!!-Z";aWm!H$qEC=ⲫ3*a-m ʒڀ,+r?umM^yr{/j lHȱDI'c\(0]KN+G WM%zCNN :[Jqi$zōfq;}ڪ8#L2lAm]x.(kd.:6'h\^zjc{XֵduKHV>lʲƐ"@leH6\SPW HKF`sh$OͩY[8zCNVeR4i"brq*Q8p8 9vU3@U u0+aZY\QD8,0%HR`'C *1DaC+ƸJ͂}~wCqNBݑS*I%.h9q%Į:i12BP{!r󿺢R&qe9D3Zh, }wJꔲ!$tO1\)n#]ɀ?X֮,I\YU7(ՒŒ:"^TZY]cXZ]dERy?}VX-tmcshpSjR-76ICh e%RI)S5ȈO'tK+U%x-ynuaBv@j!C 999;'F\1I\ 2-.nXb5ڋ̺'.DžnuqdD.l*Iln S#k~Xت[ /ndnHJдqYK[;6W*X".?Pv$!gIMbu׋$ h.+aW&֠}?$a}d$beSO$eTv*vWw]d2VLҵMF%Q{5B,q㪁B8>hW$QT$ސ!sЌ"ԧJfxN\]&q<22\/ JեE}p( [x´o"kW_8bzARi"XQ 2Q$l6LA\X$1K">tV] v[ A1gpM.ecHj7WR`eZ JLMҵMW»"Q3j-{N'Cq9ldp~myi Iy3ՓN\07%L{ 9Z*Ar䀂iQEl.C֮Y-[{MXI\DquJ~ Xxn]kFT_,Z_gѩnSi6>?N|fdRB86c4e DN=inȣ<,F 'JsKk:q?\B;HAA$_\.aTV|\MvHY*~&zMZTu z3efȬѬR3_Z[Vڒ?]n8>/fuHK[L8V֭Y+sŵR ĥN\/% K<O掞Z.oD`w|],G2ΰ2qpmwu~L0z);Z [tEF#\J^Ji\m]s 񪟋U5x z:s$)@|%%t1eRPXRusY+8q8MWo@kzRpRR_+kAZoD3] Fg9+r xd:a!E=hgZp1,Kّ'I/EF͔h)p,,QoX[k$qLzNq'"r&W=] |5  R"-lājw9uRGp&ن͡D׈OUOr>DEƢ*7oUK/J$_ye2?*3]'9;db^?$inN> &qD`3aC5S%aɟ/@&Ilw2qt9k99UP VXzqwTCvm~ZXRH*StK,EP.aao+#=&Sޓ52GN=09erigȱ1I~dۖicr&T$L:x<Š`;_ ȼ]3|V^ ;Wgx;%eׯ]oI٦dɐ7*_Z| 3x Ri " J!-#-EhZШfٯ\PT(#F~QHw~Kz Yz*ٴa^)iI\6ѷREZZe]G6T'.4|[ȫV#VR*)m|F,[, {J52dТȀ%_^S rd~HN8T{e)r%ߗo~4(77/t-Y'EfobggMLݵzHdI\jd$ҿeNL`x]],.B+Xqow^r:%TJw)럖KaQ*^FH/Q#FK="kIj%֘`ioTt}ɂOK/L?D9cd1dy\넓Nt*11#iѭ `X0Na~hVXUS:Z-+@w` 38t&J) N |"; yn> Ci;D'%,$%7eL쉈XXM>&F׉K+qnc̑1c=.?^x}+'7?_TdziYD!\.\|z)zC&jkdi=eRyfuɟw['~"D Gw=5H 0{%{.Yb?@>D_≧ΛonxDWKk3">qZAFVXKnlѠXCb j󵈥QmHWAHEŐRI\ -ttʢb`)e-*2Z=}W+W,fI]ӆGlȯ/TΜ0PAjkeC}ݓuI\{zrVxբ9n?}{{t Udo)'!4Bt67HV$կ[H1H/)-Dm6[tulݶYjkkF}H绱X|2\7[O#Y1:];e2}L KKObV}FWD߬eg.2ĕ'.:J%KMxg֟8|wq{JLCaaf)KYi}ˇfZNGZj R*}f}U[lwWܸiuL.F#ш}baܹCVZ)3g.PjnjT7I:GʰoI^pw+~ILD[TɁzOo[w_Wg?H 4K4^RR/ȏjst dajkkeǎRmkC|kp`(xx8vDZ}֬Hf>Bp S--ӶO=DWX$L=q  A6Ano*G @J徕a E#v#@]r\Y}]wޟCȐCe4vm*e{#O<{> G~ n>*muk#Ws K|quO`JAlѧ|+?`W&5@pz-W,S>%vt`)E)lHrz-۵lyiU^7ڶ? ~I 9@pZn"֭#:F۵Tz;EI߷U=|!?Qjkp}['ONZ&ĕC\yna޶[_<9yaRtv4n{ey~+h[o|N|u,MAwP(sXa|={زylܰ^>f4h.!w'w'v;rQ KGnxs 9c 8Pv}GK($Lĕտ9v؂}>;y6r9{}Q[IIIQf+\YQx}Pz#/IƊ՚p'H f)+j;\ɜc&yr$8T "%lӗiiWGo9yAڱ#GoXK:ĕ  {y nRaӦ-bni㛖ØY$zΗ9o74MlmifBv}`0pr٤/Ν;e萊 ٴi)/κ]lHK!)y%OEX-@?{M>`W&LS\}VɐZY! ˈꪪHX=׮];9s@> [n>{&5YZF<I@Cq"&N(XD>ZZ &ݢѷZ$Wwl߾CqԶ#ؙp8l11|<F'\zOt8Gz]u]}?`W&L: X|{f(4L|ϖhCq:mdlҥԞr;N#_ _Xxm7߬Ŏq@?*NB~i 'O2]1cprrrexBnNS}WN͗\FFN{ qosחK.Җo]ZZRlڸA}qCyRVV* h{fǎ332a~Ţ%KfYjHnh۫F%j7$qvءva8-zXY*AxUUR\ZS͑AP9b5bi%?@.@y]5Oyǂ<@RaeI|ea}Z >9M-k]R䐚)/,x>'Gm@ Moٰn4|#o˷87 qj=\?lʕ۶n/3bĕ  6Y |,m6m@rRK*=kkoWQ\n*qbviBӦOSʕ+#PuTV)R$I$̪j^1\Ǝ߾sbU/im b4e ,5%PX\LZk^HVohl}ŔV1b:}aDss֖+n1`'2nQ:d`Xcd̙2h@E$0AoW/W_ۿ|jaW&Lo袋pܼScDz!ƸN; ӮֲŢۄ ?@EWW픵k*O/Kk֊VCA$\Ul K~ qq'k.gItSam0#5llj-*͛7IԵJ]}L>]uD7ڲe3j"7*q+α~MUJsS:6ޮ]2mT #qVdVN4 Z 1(;vnWn&) m붭?qvn זFRhoSPcv7^h';i8䱹ysGLNdy?B/I\0k_7@8 'áv:bHIk`feVx@e-{ʵ;ldVr).<A/Ӧ>IͰFVPwznpĉ8giVt͔; ,_btZaQ0+ H$!hUh5BuܯZJZATUtH9 )pa e8};,I\0k)MiinfB kkk-\IL̝,"̙3`tNq3{Rdb?>RK,/P 3`۶m 78].T)DqѪs.]Kv8P\6l)H6e"UȾ*z9Jőʲi„q-%c_Ԛ5kH$?]u]fXRS$ _rE~uH 2aWpĬX[<9._ ڟ0+&qcF|uAy/cFi$<ZhƐهϒf'{agΝes,6UYCCs$-\p78|`իNo#ّԌO]b:Gj;i4=>)W5:qO[aIU’ZK^ڮ>I\0׀Î&a̘5SN:Aj~r`ɚիK+Na.ڼiH!&&J#{-O\SӳŊ鋐;A$ↅccoߦ,1z>ÚJkqc)$EK#~p XRA;9{<^Zr2n &qe$}ȫr3txŘr>gV>"Z-$-PU] 2@"1y@JԨ.,Y8g9.[\ Vc bܰ"FvXi*nIKTw}eb@j:L+H V`gWmT\} $uˋ*c; -hUf$LĵyMdUN9@NVx?N&LLG;uiF񃬦NȎ&G{=&V$' 9 N0׉1R79iM)FZ_tMG8s伏:/ 2@Zá^A@[X}P|ֵZΡ2a¢ AWR/7m 9} S[edkjd-&tWSv6| }hlhAm+WN9%)qDOAsfMc<IѢs8wrۓsW?*<}mOAnNjgAHfɆḰTAj!Cu8|yyː7eOCpBH܁Ole4 v6+&q}l~C Z`a;8>"E҉#ȳJ-ȫVi >(+UUlwjSbIiDt8j]$iiH_uv= jII=t:4tomj-GIfܞm1deDzK!/A8?Ij\}qȹo@ģ8_'#M:

    )q3<󜓗AR$; CI1|35#wN yLeCˈ<RYa-܏{9UqL,0c]3u!??Vg !I>Sĕ @^=99oT9lʺ2F#:ARL3@R KjNހ6Le@ٌ|1p]v\C6hN\+vE>Ɍ>OF#Y:#~qLwH&qe$yyգ0Fʀ")+,xHR/sN\Ct$Lĵ_: 1$v=[//J0o0+&q0q#iK`&LB<(#cן'&q0qFϰmBA>hGQ\=}a  =`I$r2#yIx*}I92^b^9d Hπ g38ɴƑ7²S,y3KfU+䁇I\&LDB'H3ԡ);cbb([HsZx'܄o@KBArC'0?ƘF( P xeُp| !#_ V(?g\L8ZRd: .:4`,4py|Z9?[3~,l҂3Pk&AI!(L2aUSq|%2Bys!t8M+DJSĂE#9qL l4!$  egBi}ЊR9rʏ7AbNUꓹ&q0qp>+ T `^b_<x|!q~!-|؉ϲ< Y\b&T yפnFzSKXj $8*K֖Ёu0Y:G"2Ob!&ڋ+Q{;[!xbp8|MMM>wWS/%sLd)q=<‡4l%? 7XEˉp >K,P2܏," K,!(ұh4bNX}NwvoA=6f7)$F\CN_KKKk3&qe=^|/ GDHK= :y{*rD2`($ $E4btaO8ԎnOjKh1LCjEHs LKukjlE^+MFi)O>e5F¾mMصK&qe;}phzZ齜SsN/9,PBaEb ,M@f’ijuLCHjЯ@C&4:;H n"McqZAx$ /2V(=`W#kkjd> 9CM=H((,Rux4ӈ*5-Nn)iڮ*zٔ4%+6|(%d3qٌc xmji Y]ktWN] :4 JE+U񝻪858x0]Ld/qvrppɌOU 1Z9)D5 .=oO&uj򩄙ZkQ i#EIGN(ˍKPb 6;,7"vYJv N9D!j},Rʥ>>&M>5j܁`FCp?jm'Ԣ56;ֳEd5LD>)̑Y' "#M>]Hv[o\GHA~\c<XbpO$!Yzd0G"=ȫ&uus.ini_ ^_;lK[[4JSK467IuuBټa}C[&qe36\.?N:Ee<;.$ѯy ٩:!_ C| xGA\s%,qdXCeR Wig^/`*ٸiqceX02d 4H 尬J`YIaa!@JJe¤ vJmmx;Y hKrPoJP L`CT%ϧ:Uyg\!Jw'b!9âl eWgPQiD ʕ3B񝐼8O }G92ftIQa1T ae2j=v?QLKK+65mӋlI\ٍFE3\Ii6BMg:&ӯMӪ)Zum2o:yCv)"n"/v㤎(,4;!Ѱ#YSpĩ.vIDYՂԫJĕŀu(q^ә䐡r]5C:ruudiٲRV`*IAO߷qwL㾴t\:::TjN~aZ\&V- sh]UD3Q[kDZCO4FA=HZ]'MdkӴ*uQצ|&]0 hVW\B*|BC ˆIS[\O)*2ԸA4.EjVKTąߍxd-LbaY-aqHTklq > BP.*S1Ю1H94c%(zY@iq #q ;YHkths*A n-*A 9'W\)W\uXqqaLd)cC Zz3A<#t:Yi:5?|F:%ϸ;b9dݩ7E8:I\,#b;,aqy { Y58<K (cV/} q5o]EO2+aWeXFG4t7T5id3Sע]:ޮ:NOlF=!=RaqӨA.壖qpYt_]"hMrj*WQ[1kaW#tlֈrب>N)FxT^YFv)[FV6iM&*j^#"N~~ ⊦X\IE12eVp_Nj4lX\&qNԶZm6xiII*|&yP/ו< UvlԑZoR ӯM>Ku^Ǟx(-.Z>"\x2an BQumiUZ#d:Cv]!Q(uec|qoL2OA,.}d1 TK%MRBOz>Wt]P֯M;=WYmueC"R)#A~6COV_- _] OWr߯Wҡ&qe9"ÌWR#AhBVy$ 1" kSiӎ$M8gԙ{u@L*jEM!78ibl,.b}O28$?L.B.n *WZĕy۷U͛e%(5eWgTBt۷Ҹ6LT9St /yruyUq)qH^%Wr24dj3\YS8pUGXdF: ‹$V*pI\ $* *8 |,?|AZ-ryi_Vk!F) H!M3OƵyheACN[3.ԡ|, .)wY\)$9:tm Mpy -iejI\YX@\֋Ǻ6A`Lֶ<+me57W];Ny/K-,վAPeW2D5:DbW߅1H{ $hܵUfFky)?ėA\W鄘e"{aZqiek"q=,+CV]@^S;-^kSܺ] b{ N |>(6d qK{Dv-e= ɎpLфٿP1Q㳙fNj=/U>.0l0n@LwCN=ϐn)2HBsdI^m)3D*: (lʶp\1emFdKGX62[p?W>l r2Xm@l_r[;"Ť1\K(m1=9,.I V*$'{ʒi11rrp.q $-q:ܒ/yyyIWPj!.AԬ묄I\Y4v66%LCDeDC )KO縔3ˑ28yUH Yn j7"FX/1d." c`UѲANȊRS[nWWTj$,H3*h, C#.XEIꆔ2)M@H=bm7WJu!@ܓ*Zq%qųZ4 H[r2tI% ֡"ĕni SRx?V0d4d5K>C^^NC[vodheW~ɨ$2ť b2v̸M*X#łnupHDp9t5}4fmWۊݭ1g;$jMBA")R Ij,H\VcTS$^֣j0HoI7xaWgXCpQFX+4GY)遤ӜNb8W*QK1TSqY,&qDߣrGTv:nW3 6RPH"SGoHJː8X*⿞R%u~@\]&qP!Dx$|i9DqM\˅c!] :D5RUD}R 2tj|{1#GINY m#+8_@HM"F.!q.60=ARZIgQY|3e`ۼ 2Zoxfнov^noֽ!"U o/\t\wmzׁ>-(xL͘)'-X4rٝy--#˨cdIҜN\)OΝ+W.j-.?(Ebr7!d6oA3]E#>?To^T^4 ?`E8zB ~uu·!՝sCH'Grrs%''b$Νs/99{|e?WO>IsNɓ(+! 8x k]7-Ll9qc9-C"3{ [Bj~FBӧ\y-8''k gGىR*=~DIZ$ @$ƆigzRƎ'#GֶV "2x@?mq3H$$@H ǰ;$bsJ+2sXYf l(;Rg ]yI\}&8]y"Z~a-D,n&;wL(zoدɚU:[߰J=f\p%5E-YAwwN^|9xj1o+Gž %.-W<%⏂Ԣ hP<~p\Yl{T\ti_B`əi;ebi*f9BZB\^9,]Z+%:QY$is$6aS$Z2TN\uNvJA&$tHVoKwih0Ra cw8Y:ۭzU`@(r w'+]wKVy5Xt2![7#5o>/m/-ᇯHbOdSWW,/Lwʉ'"Mz=&qշ` G.WBx$ TIX p!8p85d˫D\6qykݱK>o-2bZ~{CAa{"0+a©/.\'{wqDy'A)ΨOa!] zh[g`Q>HGԓ9sa]#%p:pJW&9;;ݣs`oI+5e2e4މ2)v5ȸ]/5@: HW~0[oXKK&WS<ƧL-Jԟqt:KnpxbqX`!@HVkX" $K[]EEERHB&JAJyy.Qr`ir5N="vSO UUrr:mT5Mki΃`-__v9aei,Rqq -{zd$刵bBCK6_WK _(RqBGJ ֑xD`ۡѐ)KQ S4~jT>0pxΫ^o׿O?y XB~.md{wg?0 '@P๐`C׿%Wp4A u{a7,"Vt+WV}{|yi𐡿:d :T@*e۶J^kF8ΏF×h i}Tn*֮G%^fE5z0V\0ԓg}0˄­x'vsp}+))I ;v9X[րSI7qmZyw}P`?V֭[dúrQH{n(!n 8%6wȸTpjkkk'0˄_ټi";.\Itg3 #)uvv׾_q?(~O1{lܰ^3Gn8N :P+RH?2bcrD0pڹcPL_kpo%{o;r[y^bO8\Z%(%xsY:>>FcCr.Qp0 PP`픝;dݺ52㤱IlyqDK%W&~q%l|фM0"і:ՊA ˆTnݖŢ,ze]L28vD\p:NƅkÒYGl A}shcwxGm mB!ߔ9@`:1v_{G}RV^.Kii?2xܹSV\!^VQk狷]|jHK$ vU~'%nXp)q"ݏReϱdwX2 sDUu%r2 'bX1s檎}@A,XЫ%{,.׸?@ 0%UH8l9j .0$ 8qpիATNKm޼Yv!X\Z 6kbºMcmr.:" /*)^RVm|n&mg&q8` A]enB I'Mwܾ5AKBVX)t ̝2F\;VqɮWV=2S{n߉:V~;WViw=8bs-2|xR)I^\=q͚5Uk6l.zebsù'^!{z>Ng,_g$ ê ;7/W-9|L5WqrY fH1Ƀ5adر ΨX4 XDccriMM< 7m&0k 7! 2d`4PtɈ% luܶl{+^|nCB4K<;`@=z̘1SF`.Rn^444%^|qox$.߻7w`m"1mdJ$J'hчV@իW0_y?o^۬lε4KG[➹swGŒVP[ՀHNƎzFYU`ݤs47MJKqРAj% cYd`*ܱk2i]M7ҍlsso e}+9{qǝ%AU/\ق$F.gL:EYw\{n W}` /36#+c;g-h=(y> NYAR>4ƦFE.pITEqiȩPvL 'r3<} 5L>Mu]NuQ^]vr)(,PkbusZ }2t巑RSkʔɒqK]qDU>>H3nCmmCQ'ILY]Mͪ_ 5"jjaCI"@dIz~? h^|O3P$/JS駟o\h&qدn/klڱ0Ún 1pPܡZ#Ϋ;]?Z"3gΒ2 ^[D>ÒGVj XY$I>m񊬪v1՜GjhģF2_~Alݺ]FMmr$\z;?\hTNIdWÅ[[`^xԼL#$s1[[[Y AE* +m~qa7c-ZmWN8 䕏H7%'Z[z~ze/< -g~A}H$-rr]!F(hˋb;餓ڤUuO2dS7l+ju$]͛*b<.7mAeY3 eǿCv쨔M jmxZaiyTRDn1jL4QH~$P8$Iy?m6e)Ii8Hq{;S@\5p6j Kl*}{DP,qᣏ>^/I\&n70@00s"PY=JUmx@X+VɇD">X*6MM&S:aՀHpBohh+ʝ2}t)d{( VEMagaYعcĢ1 .ɢbq*n+>Po! Y+zͫȑaCrWpS׫- DE.$I AZ .;n{דhѢEYO*L2ϸK[;B3M cAJ<8!]VV.w 2HYTM MA"-*"k֬Ғ26}| 9Ѹ];પ;{/@XegK @PFD)h-ejgکNVGZgZm :EkC]! -BHXϹAK̗{ywyw~skG ׊R,|Y>۰H`DѝfkKkK k&';Me9ITuo;ĭY[]-l!uΜU9kTۘɓ'$rKYXuC wBQ'"zb͚ }OケEs22G>n4+;#6Ezy32[w˭4jh3|uBN[ 5`4Nؑm3crǚ^];w9މKu/7htʅ:e,3XM M{[DL\jC.ɓ K$f G{f̘\+6q9ϏXtD+L=s׿mŎ{=D.p`ޕdlnlHwO%+-bUZ0UnbU!,|dPĂ6ήv+0@D$>iAQIbtm&Ubv9VLުǞ3|xSVܴ{pı[0c܋YƆW^#::BmHBܸT[9Wm2rHdIB'ۡHxyVS=$$P_tln✱cP;U2~Hm6AsԩI/:Id/kS$ K,{޾4'5b dzjMV[΂;2%KC ;86,.F-^wu\rG?(MͦX,SzLj +:D:ˑtgɊ+[H|q_T\9.wKXS`3-6`z{#qg(fp 6="XW@D[۷!tJI!^3G@MBLqtYC܇\+CDP/k?~V19;Z%R(_ĕǶ6DW rk #u~eISUU~>ph5Lޘ;.o,s\/<3fڌr^~O<.9r4mɨ+P"qu mټ&n+uf;N>7?e-/]WύIμEo>T GHډF^r>|qI(-,I+^a`ln?+jbRUYiJKl|\7a&-$(EV^>͊G 7֏<*Cd^Ge^TȱnI֒lE"JD*%/ GhՔd0+WB"{ڬ{~,.F x.7Y I*NH?Je~SbC)n܎ww'ل3]գy<+\= )XR6">-#8'pO:)ki]H G79ȣUUX]i@Ut/d+ |C%.X̬H H"A7̵[F8F;xf֒ڹs͝U<*%5Ŝ:YRqjn1Oy],5XqpIzn,춆Ӝ'W~~1jsLY|\P"aIKHdEv;ڏxmXmȢĤp,ğXK:7!k[?$p#qs_Tɀo`# T-Dꜫ7fcnL k3]gy<@ ȶP$tSӑeN}!qig81'?UGUWjOR{gDfVFD}XǾ2xZ@02w=ڋ"+b`•K^ιj΀`Gyzd,3%uN(aDqN4RDu?i&B b; 1gD7"Jba%ݫ8AA"4ͫE5KdGǚ5"!k"vX_).^+~VED}JR\^3r3%>*7.P"ETԾpd$y7zxg[~Y `7jĶ\6bXĥ>Lw.+}>ǭDjErJp/9#B$+M|JR\^]=thFu8=zڴwT Fp$T >X]]}8)?a?ilQHĚ6Ku|>3gr6귾n/\I+܋<$зB@0hFCUV1W_Oou{>Y+I,}C;,&xI & >. ziCP~@3]2nu _|8|OdIBoB".2Ņ") jW9m~@PDžƋ;_cufxyMcu .C2#@zMì@ܵ}dē7rHb*#qޱC [Hk@8>ޱ_Јa"3rzǓH&mF:%L}nDˢ-"uȌ'QzyɿHrą#;gqâҝ ҝǼn!F$ 4/r4})bA_Do DVKцo,"A9GgX\r6K@D<)q˙i x@zV g{!9B,pG]PE,ƅ.!ˇ%86%Hv WrվG}׋l$R#fEB')u]AJzA1,KtXyuV5QHgeT\,>MV$I42IA|&g7/WQH ;į5D>V c9{},xmfAj<ƅF#k#Ekw߲Z3dʚz/{v>$2+Rx mw>kŏ(zR}O]ڧ1a+I,}0CIVX4n/\^ X5mP$ p%)|@ς Y,MT_7?dXv͸IENDB`nut-2.8.3/docs/images/blue-arrow.png0000644000200500020050000000106214553676503014236 00000000000000PNG  IHDR w&sRGBbKGD pHYs  tIME *wtEXtCommentCreated with GIMPWIDATMνka{{!1-zTVDZ2b  覛BB EҡkNhD 1IM.]ug qp~*` &/rg"VK:P8CedT<5)7^9Ku.@ Dcι9yJ2+$0tB-qW . ێrѥ]ɦ,g],3o7q_ 1X%spq;P dN6EK`!n5wWF @16njD!rCd3t)6!Pc^6PPxfl2txi30PԦ?[uJ0]YIENDB`nut-2.8.3/docs/images/old-cgi.png0000644000200500020050000002100114553676503013470 00000000000000PNG  IHDR  gAMA a8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATx;۸.PwU8蠂AuP < n [`{yuWQ|@"D~E@!wD6d#H6d#H6>/M9V?V&>W=}oĵmjlFlFlFlFq~wX?ՁSx[FgpF5}TM`ǿjSd#H6d#H6d#=m8o dϝ5GWs?}Zyp.oW\7%9{3Ԭ~Vͮ_j)2g``=mJuEvۛ˛`gǽa8Rʷc؝! rp5}.ƻk_Ҧ;[yn>\5E*.OXUavgY\n-HwK9QtJƶzVsX(p7k0P=hX{晶9+R>E:b?]ڸnejQ+7TUmk~9+rW@@< \7h`]YNgÐFlFl}wؙ::@=وE`ghSd#H6d#H6d#H6d#H6掋ׯE|gaUցQxfQ3TkSPXyy" " Z/60-[a֏eVseVt4Ձ{[nDn|)7*Puǁ[LXQxܻ?sRs[.W28`u#ZtWO#ru\"jlQX:q"(TWfRIM6nVhS ^}d#xChn657MpRl-HhE{_Pn65roZd#j4r9M@;Z6mj{ lR@]xb\lD ǵ7On:'UvE&1i:- " " " " " Z>_|YՂkkە/ɯru~u]'\6ۦFNQ.cgxgF}ܺ3tk޲֙;9OwzwJa9GMrCJ6EׯZܳ:s 4O[O~КQu߆[_/4<<dzqv26nӝ7mfp Fc*=4lZo[!R ;}jd0Zo˕ܺhF׍}sr7LYpܥʾؽHYrL[w1 6-zB9.R2vݟ 6v'yu- ٨O/6J{mpb:'&9Cyo}ZTe7?ܜœmj3}NȲXÜyԳMʏm9ȧeF0OAu/vJCw0 @œCj -dY*9ҜƖ%ecmFQ_5c? ZY R>dp1;g䕛-ܲS%2)ɺ<qɗV,^¿kT SxiMppjkSt;vC57OG`gjMeRHG P^?$'I%8VQ6W?~{7 omn(w_بw+-|w*p ]7J޺U9gl^ƅP9[hFl>ƒߧ6@%^΍ϷJ ;އs&Y>#K>b!*?-?sZh9A,AMu×kLݸ@*}4٨רTh*YŻˎ>vvlڦdєBwlT0k](FԀ+q=u}(~}Vz+fR!N#ov >{r}!k|U}J ցoyx+4X6Qί6:\UÝZ:P[VFO5Wg6DO/\9r6KI8D|̑ 5ϣHzyݿ?bop44:c?Ǡ᜽Od>`zuD|/-P7qnt?7V8TPe_%׹Ɔ^$*Цsd09s+|7K}ܒ;:Wԍ^p وΈ__?Κ\Cz)YԍIQ4NѺ9 ?+FɫF4GHeub\.E~z[?ϟB=:!|v[}>G;^Oou lmok^o1@د}M8Hhغ^=nbk |*qAhSE4c!A-rbl0L6F0jB2@ dlDszrָxЦ~W7Q8>Ў k :{5pqF4*w{P 'A"9=?ϲS6@$D@$Dw[d4yڻ,j+ ӓ[p%3?f2{3t4\~׶)Tan"9N2hla:lFɶ`K_&J) ^,Ҵ.Mp4e\ߠķQԏfsT\}JE/Ҵ.qp4e³\d[ -oUYXv`7SGWd->mj/k<8P]zsnvSJJHnV[5>aͺŔk|#w@ " 'QyZDp_C) zii<q\7"ɣul\HK%$H׍A䁈vPnH$hIFa N>GPMςfΞH-EyЂY/WD[sb;:uS9(\ʅp3-NJgm ;Ӭݸ~dzxX=r6iO74*аxk뾋EJPFs\QdS4 ,z-^s|oo>-O K^߭*SʟIwC;:G6uxZҭ 3gCxSœ5S٫p659d#Fy-ǥ L6d#H6d#H6d#H6d#H6d#H6d#H6d#cn>BNz<=ܕ]j_L6]ÃcsgG! Ӄq9h_7NrkqOVtDt hmj~|BB>=~__?)Om^mڟ)?y_uu{r@X^M֝.[Ƿ]m:{3|!$Fp;k{"u`cݿҡ>iS99% Qp F1klE;FrQ} " f?.Rؒ`DFucDq1׹16oD׭s !7f ;.وFåc*@aubHѐuu7d#H6d#H6ާׯE|ޥ:cCؑ,mjlFlFlFlFlFlFlFlFlFlFlFl}]Bؚ{|,Hq " " " " " " Zp6[WNznV7ۧ_F4uRsӹ)ш>sѦFzi?Ns G6Qc%:n\H65Zt ?>Bx=|vg3n][=O߶@A@|)^icŏO[ܐxϯ!>ƏԎxUʿ&uvoB9+Y8 Ѻ_%}^9Ő㲺ǁuϧ5G=&z8~%&,W9ekw&'"ۙsw߼V2a(G8fLܹ~#uZz'1zs`ܧ\RshNƮpqqяN&oBwJob&]& MΑ`kp`Wbn{+Qxw.&}2Ԍin\Cr?u(%Y%96u7P°_ǁnhz=w{똓e &ubޞkh9Nwޥ6:n&˓uZpl=z⡮R +=z]j.qOxܛw|*M&|l1&UUnwݴ5qz.hHچOLP[kغMm3f%ɜT@ДMQ]aNM#Nnp Nɍٝr'pv\7ꝰsOO.;*5簃vβ%On}8t{˶5 G|6p8edBXXsTc'T]e;ަF˒" Z>}VJ}o|lCT*,|tl.wY F{r},7ulݦv3E)ܷSc8.}mz2y+qa.> ;[n᜽5\F[X֦(w;awʄcz*YrcD2K~sgAc$nDewWnhr!{:GP9$К#f9'aߣmP5j¢8.c?.rb;*o@sVfF'';?4OH xrw-yrÉ{}X+p:gB)OGm('\.؉!FerQ&d#H6jJ>4'pne,焎~ce{hAF94X^c-|w:GJmjlpif3FN7pKJ;mjC3Vhzy%?2gÍN(y.->t$ιQqg9|͍s߆xp4FoɄmÂ_|ZΞǂERb/g5x_אr]fz aJqݨi3_^|krM_䲅,}(Noug) Qde#dmp3#GVBh}͐l4/;\+nþ&I_l9}jee8 3֨TjqGT&9gɇ4e8Ծ8ԍvlԦ6kط o%G?!#{_ ;} !kaB6^`],Vց#a@۔ ><=cex~ޟyJ*8m\.}}]hO-uu FɋIwn*_|lw$ =7tdx=\z,嚄*1E)ypC;_)Br:]=.q5by=xv}6t;Y00H:M6Ū܏y\hlTeZ  e3 3T.B_'lח|a[ü5/yr= МQ;n4¾&I]u5CGoTv{5Α!D@$D@$D@$D5 \Vt%_M/rkf):8jOߛm?%z:s<5ӋsǮ휕gQ(|ߏ5hGҰb_^99w׍G,(W{'^v;L*4G!ACE /6GnN#9vz܉*!d/.yp/y9G$;/vgg]_l`uzyn|Mcg/ï^wl{Bz`cR-4}F^7'y/Rnyv wMs}pߝ6a&!U׿2QVhMf'F@R5m.ˉ'ԃcRE}!5cu #cn=T>\vyGI>䧽;>;%ru 7}}jk˕3yTOo-FpAo^N/_r8[UIDAT_#}v\"oRvFМ4ec}}ʣ}" " " " " " " " " ֣P{>ܬ4ϟ?+g֦FlFlFlFlfȯ_6(yf@SD@$D@$D@$D@$D@$D@$D@$D@$D@$D[`tIME 1;̵]IENDB`nut-2.8.3/docs/daisychain.txt0000644000200500020050000001736414777767434013111 00000000000000ifndef::external_title[] [[daisychain]] NUT daisychain support notes ============================ endif::external_title[] NUT supports daisychained devices for any kind of device that proposes it. This chapter introduces: * for developers: how to implement such mechanism, * for users: how to manage and use daisychained devices in NUT in general, and how to take advantage of the provided features. Introduction ------------ It's not unusual to see some daisy-chained PDUs or UPSs, connected together in master-slave mode, to only consume 1 IP address for their communication interface (generally, network card exposing SNMP data) and expose only one point of communication to manage several devices, through the daisy-chain master. This breaks the historical consideration of NUT that one driver provides data for one unique device. However, there is an actual need, and a smart approach was considered to fulfill this, while not breaking the standard scope (for base compatibility). Implementation notes -------------------- General specification ~~~~~~~~~~~~~~~~~~~~~ The daisychain support uses the device collection to extend the historical NUT scope (1 driver -- 1 device), and provides data from the additional devices accessible through a single management interface. A new variable was introduced to provide the number of devices exposed: the `device.count`, which: * defaults to 1 * if higher than 1, enables daisychain support and access to data of each individual device through `device.X.{...}` To ensure backward compatibility in NUT, the data of the various devices are exposed the following way: * `device.0` is a special case, for the whole set of devices (the whole daisychain). It is equivalent to `device` (without `.X` index) and root collections. The idea is to be able to get visibility and control over the whole daisychain from a single point. * daisy-chained devices are available from `device.1` (master) to `device.N` (slaves). That way, client applications that are unaware of the daisychain support, will only see the whole daisychain, as it would normally seem, and not nothing at all. Moreover, this solution is generic, and not specific to the ePDU use case currently considered. It thus support both the current NUT scope, along with other use cases (parallel / serial UPS setups), and potential evolution and technology change (hybrid chain with UPS and PDU for example). Devices status handling ^^^^^^^^^^^^^^^^^^^^^^^ FIXME: To be clarified... Devices alarms handling ^^^^^^^^^^^^^^^^^^^^^^^ Devices (master and slaves) alarms are published in `device.X.ups.alarm`, which may evolve into `device.X.alarm`. If any of the devices has an alarm, the main `ups.status` will publish an `ALARM` flag. This flag is be cleared once all devices have no alarms anymore. NOTE: `ups.alarm` behavior is not yet defined (all devices alarms vs. list of device(s) that have alarms vs. nothing?) Example ^^^^^^^ Here is an example excerpt of three PDUs, connected in daisychain mode, with one master and two slaves: device.count: 3 device.mfr: EATON device.model: EATON daisychain PDU device.1.mfr: EATON device.1.model: EPDU MI 38U-A IN: L6-30P 24A 1P OUT: 36XC13:6XC19 device.2.mfr: EATON device.2.model: EPDU MI 38U-A IN: L6-30P 24A 1P OUT: 36XC13:6XC19 device.3.mfr: EATON device.3.model: EPDU MI 38U-A IN: L6-30P 24A 1P OUT: 36XC13:6XC19 ... device.3.ups.alarm: high current critical! device.3.ups.status: ALARM ... input.voltage: ??? (proposal: range or list or average?) device.1.input.voltage: 237.75 device.2.input.voltage: 237.75 device.3.input.voltage: 237.75 ... outlet.1.status: ?? (proposal: "on, off, off) device.1.outlet.1.status: on device.2.outlet.1.status: off device.3.outlet.1.status: off ... ups.status: ALARM Information for developers ~~~~~~~~~~~~~~~~~~~~~~~~~~ NOTE: These details are dedicated to the `snmp-ups` driver! In order to enable daisychain support for a range of devices, developers have to do two things: * Add a `device.count` entry in a mapping file (see `*-mib.c`) * Modify mapping entries to include a format string for the daisychain index Optionally, if there is support for outlets and / or outlet-groups, there is already a template formatting string. So you have to tag such templates with multiple definitions, to point if the daisychain index is the first or second formatting string. Base support ^^^^^^^^^^^^ In order to enable daisychain support on a mapping structure, the following steps have to be done: * Add a "device.count" entry in the mapping file: snmp-ups will determine if the daisychain support has to be enabled (if more than 1 device). To achieve this, use one of the following type of declarations: + a) point at an OID which provides the number of devices: { "device.count", 0, 1, ".1.3.6.1.4.1.13742.6.3.1.0", "1", SU_FLAG_STATIC, NULL }, + b) point at a template OID to guesstimate the number of devices, by walking through this template, until it fails: + { "device.count", 0, 1, ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.%i", "1", SU_FLAG_STATIC, NULL, NULL }, * Modify all entries so that OIDs include the formatting string for the daisychain index. For example, if you have the following entry: + { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.0", ... }, + And if the last "0" of the the 4th field represents the index of the device in the daisychain, then you would have to adapt it the following way: + { "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.%i", ... }, Templates with multiple definitions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If there already exist templates in the mapping structure, such as for single outlets and outlet-groups, you also need to specify the position of the daisychain device index in the OID strings for all entries in the mapping table, to indicate where the daisychain insertion point is exactly. For example, using the following entry: { "outlet.%i.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.4.1.3.0.%i", NULL, SU_OUTLET, NULL, NULL }, You would have to translate it to: { "outlet.%i.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.4.1.3.%i.%i", NULL, SU_OUTLET | SU_TYPE_DAISY_1, NULL, NULL }, `SU_TYPE_DAISY_1` flag indicates that the daisychain index is the first `%i` specifier in the OID template string. If it is the second one, use `SU_TYPE_DAISY_2`. Devices alarms handling ^^^^^^^^^^^^^^^^^^^^^^^ Two functions are available to handle alarms on daisychain devices in your driver: * `device_alarm_init()`: clear the current alarm buffer * `device_alarm_commit(const int device_number)`: commit the current alarm buffer to `device..ups.alarm`, and increase the count of alarms. If the current alarms buffer is empty, the count of alarm is decreased, and the variable `device..ups.alarm` is removed from publication. Once the alarm count reaches "0", the main (`device.0`) `ups.status` will also remove the "ALARM" flag. [NOTE] ====== When implementing a new driver, the following functions have to be called: * `alarm_init()` at the beginning of the main update loop, for the whole daisychain. This will set the alarm count to "0", and reinitialize all alarms, * `device_alarm_init()` at the beginning of the per-device update loop. This will only clear the alarms for the current device, * `device_alarm_commit()` at the end of the per-device update loop. This will flush the current alarms for the current device, * also `device_alarm_init()` at the end of the per-device update loop. This will clear the current alarms, and ensure that this buffer will not be considered by other subsequent devices, * `alarm_commit()` at the end of the main update loop, for the whole daisychain. This will take care of publishing or not the "ALARM" flag in the main ups.status (`device.0`, root collection). ====== nut-2.8.3/docs/support.txt0000644000200500020050000001204514777534446012473 00000000000000ifdef::website[] Support instructions ==================== endif::website[] There are various ways to obtain support for NUT. Documentation ------------- - First, be sure to read the link:docs/FAQ.html[FAQ]. The most common problems are already addressed there. ifdef::website[] - Else, you can read the link:docs/user-manual.chunked/index.html[NUT User Manual]. endif::website[] ifndef::website[] - Else, you can read the linkdoc:user-manual[NUT user manual]. endif::website[] It also covers many areas about installing, configuring and using NUT. The specific steps on system integration are also discussed. - Finally, link:docs/man/index.html#User_man[User manual pages] will also complete the User Manual provided information. At least, read the manual page related to your driver(s). Mailing lists ------------- If you have still not found a solution, you should search the lists before posting a question. Someone may have already solved the problem: ifdef::backend-xhtml11[] ++++++++++++++++++++++++++++++++++++++
    ++++++++++++++++++++++++++++++++++++++ endif::backend-xhtml11[] ifndef::backend-xhtml11[] link:http://www.google.com/search?as_q=&as_oq=nut-upsuser+nut-upsdev&domains=lists.alioth.debian.org&sitesearch=lists.alioth.debian.org&btnG=Search+NUT+lists[search on the NUT lists using Google] endif::backend-xhtml11[] Finally, you can *subscribe* to a NUT mailing list to: Request help ~~~~~~~~~~~~ Use the link:http://lists.alioth.debian.org/mailman/listinfo/nut-upsuser[NUT Users] mailing list. In this case, be sure to include the following information: - OS name and version, - exact NUT version, - NUT installation method: package, or a custom build from source tarball or GitHub (which fork, branch, PR), - exact device name and related information (manufacturing date, web pointers, ...), - complete problem description, with any relevant traces, like system log excerpts, and driver debug output. You can obtain the latter using the following command, running as root and after having stopped NUT: /path/to/driver -DD -a If you don't include the above information in your help request, we will not be able to help you! Post a patch, ask a development question, ... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use the link:http://lists.alioth.debian.org/mailman/listinfo/nut-upsdev[NUT Developers] mailing list. Refer to the ifdef::website[] link:docs/developer-guide.chunked/index.html[NUT Developer Guide] for more information, and the chapter on how to link:docs/developer-guide.chunked/developers.html#_submitting_patches[submit patches]. endif::website[] ifndef::website[] linkdoc:developer-guide[NUT Developer Guide] for more information, and the chapter on how to link:../developer-guide.chunked/developers.html#_submitting_patches[submit patches]. endif::website[] Note that the currently preferable way for ultimate submission of improvements is to link:https://github.com/networkupstools/nut/pulls[post a pull request] from your GitHub fork of NUT. Benefits of PRs include automated testing and merge-conflict detection and resolution, as well as tracking discussion that is often needed to better understand, integrate or document the patch. Discuss packaging and related topics ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use the link:http://lists.alioth.debian.org/mailman/listinfo/nut-packaging[NUT Packagers] mailing list. Refer to the ifdef::website[] link:docs/packager-guide.chunked/index.html[NUT Packager Guide] endif::website[] ifndef::website[] linkdoc:packager-guide[NUT Packager Guide] endif::website[] for more information. IRC (Internet Relay Chat) ------------------------- Yes, we're open! There is an official `#nut` channel on https://libera.chat/ network. Feel free to hang out with whoever is on-line at the moment, or watch reports from the NUT CI farm as they come. Please don't forget the basics of netiquette, such as that any help is done on a best-effort basis, people have other obligations, and are not always there even if their chat client is, and that respect and politeness are the norm (this includes doing some research before asking, and explaining the context where it is not trivial). GitHub Issues ------------- See https://github.com/networkupstools/nut/issues for another venue of asking (and answering) questions, as well as proposing improvements. To report new Devices Dumps Library entries, posting an issue is okay, but posting a link:https://github.com/networkupstools/nut-ddl/pulls[pull request] is a lot better -- easier for maintainers to review and merge any time. For some more detailed instructions about useful DDL reports, please see link:https://www.networkupstools.org/ddl/#_file_naming_convention[NUT DDL page]. nut-2.8.3/docs/Makefile.in0000644000200500020050000027736515001555010012250 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: main docs # FIXME: There is a lot of shell-scripting below which gets processed by # whatever system shell there is. While bash handles expressions like # VAL="`cmd "some params"`" # in a way that "some params" are a single token passed to "cmd" as an # argument, and the stdout of such command execution is collected into a # single-token string as "VAL" (even if with white-spaces). Some other # shells, e.g. "ksh" seems to actively dislike unbalanced double-quotes # inside the backticks (e.g. matched in some grep/sed regexes below), # although generally the approach works for such "VAL" assignments too. # Note that the newer "$(...)" syntax is not portable, older shells # have no idea about it, and it is cumbersome with `make` substitution. # Keep a lookout with multi-platform NUT CI jobs, and try to use single # quotes where possible (e.g. where pre-expanded `make` variables are # involved - so shell should not process them again anyway). VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_SPELLCHECK_TRUE@am__append_1 = spellcheck @WITH_HTML_SINGLE_TRUE@am__append_2 = $(ASCIIDOC_HTML_SINGLE) @HAVE_ASPELL_FILTER_TEX_PATH_TRUE@@HAVE_ASPELL_TRUE@am__append_3 = --filter-path="$(ASPELL_FILTER_TEX_PATH)" @HAVE_ASPELL_TRUE@am__append_4 = $(NUT_SPELL_DICT).bak-pre-sorting $(NUT_SPELL_DICT).bak-pre-interactive .$(NUT_SPELL_DICT).sorted $(NUT_SPELL_DICT).sorted subdir = docs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = docinfo.xml CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(htmldocdir)" "$(DESTDIR)$(pdfdir)" DATA = $(htmldoc_DATA) $(pdf_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/docinfo.xml.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ # Is "egrep == grep -E" always valid? (maybe all a job for configure.ac) #EGREP = egrep EGREP = grep -E EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ # Possible man page section remapping in some distros: MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ # Other rewritable properties: NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ MAINTAINERCLEANFILES = Makefile.in .dirstamp \ $(NUT_SPELL_DICT).usage-report # NOTE: ALL_TXT_SRC does not include sms-brazil-protocol.txt because it # primarily includes samples of configuration files with a lot of Spanish # (Brazilian) words which confuse the spell-checker. Adding them to common # NUT_SPELL_DICT would compromise its usefulness for purely English documents. # FIXME: Add support for custom additional dictionaries for specific document # files, e.g. "something.txt.dict" if present? There is precedent and code in # nut-website recipes by now... EXTRA_DIST = $(ALL_TXT_SRC) $(SHARED_DEPS) $(IMAGE_FILES) \ $(IMAGE_LOGO_FILES) $(IMAGE_LOGO_FILES_JENKINS_NUT) \ $(CABLES_IMAGES) $(NUT_SPELL_DICT) docinfo.xml common.xsl \ xhtml.xsl chunked.xsl asciidoc.txt asciidoc-vars.conf \ sms-brazil-protocol.txt IMAGE_FILES = \ images/asciidoc.png \ images/hostedby.png \ images/nut_layering.png \ images/nut-logo.png \ images/note.png \ images/warning.png \ images/blue-arrow.png \ images/simple.png \ images/advanced.png \ images/bigbox.png \ images/bizarre.png \ images/old-cgi.png # Logos which pop up in README.adoc acknowledgements and maybe other places: IMAGE_LOGO_FILES = \ images/ci/AppVeyor_logo-2x.png \ images/ci/AppVeyor_logo-ar21.png \ images/ci/CircleCI_vertical_black_logo.png \ images/ci/DO_Powered_by_Badge_blue.png \ images/ci/DO_Powered_by_Badge_blue_140pxW.png \ images/ci/fosshost_org_Host_Dark_56px.png \ images/ci/fosshost_org_Host_Light_309px.png \ images/ci/fosshost_org_Host_Light_38px.png \ images/ci/gandi-ar21.png \ images/ci/gandi-ar21.svg \ images/ci/GitHub-Mark-140pxW.png \ images/ci/GitHub-Mark-ea2971cee799.png \ images/ci/OC_logotype.png \ images/ci/OC_logo-watercolor-256.png \ images/ci/OC_logo_merged_171x32.png \ images/ci/OC_logo_merged_140x26.png IMAGE_LOGO_FILES_JENKINS_NUT = \ images/ci/ci-root.css \ images/ci/jenkins-nut-large-256px.png \ images/ci/jenkins-nut-large-squared.png \ images/ci/jenkins-nut-large.pdn \ images/ci/jenkins-nut-large.png \ images/ci/jenkins-nut-small-256px.png \ images/ci/jenkins-nut-small.pdn \ images/ci/jenkins-nut-small.png \ images/ci/jenkins-nut-squared.png \ images/ci/jenkins-nut-transparent-bg-140pxW.png \ images/ci/jenkins-nut-transparent-bg-40px.png \ images/ci/jenkins-nut-transparent-bg.png \ images/ci/jenkins-nut.css \ images/ci/jenkins-nut.png \ images/ci/jenkins-nut.txt # Only track here the local deps SHARED_DEPS = nut-names.txt daisychain.txt asciidoc.conf asciidoc.txt # See also conversions included via FULL_USER_MANUAL_DEPS USER_MANUAL_DEPS = acknowledgements.txt cables.txt config-notes.txt \ configure.txt download.txt documentation.txt features.txt history.txt \ outlets.txt scheduling.txt security.txt support.txt user-manual.txt # See also conversions included via FULL_DEVELOPER_GUIDE_DEPS DEVELOPER_GUIDE_DEPS = contact-closure.txt design.txt developers.txt \ developer-guide.txt hid-subdrivers.txt macros.txt new-clients.txt \ new-drivers.txt net-protocol.txt nutdrv_qx-subdrivers.txt \ nut-versioning.adoc snmp-subdrivers.txt sock-protocol.txt # See also conversions included via FULL_QA_GUIDE_DEPS QA_GUIDE_DEPS = nut-qa.txt config-prereqs.txt ci-farm-do-setup.adoc \ ci-farm-lxc-setup.txt qa-guide.adoc CABLES_DEPS = cables/apc-rs500-serial.txt \ cables/apc.txt cables/ge-imv-victron.txt cables/imv.txt \ cables/mgeups.txt cables/powerware.txt cables/repotec.txt \ cables/sms.txt CABLES_IMAGES = images/cables/73-0724.png images/cables/940-0024C.jpg \ images/cables/belkin-f6cx-rkm-xu-cable.jpg images/cables/Lansafecable.jpg \ images/cables/mac-940-0024C.png images/cables/mge-66049.png \ images/cables/mge-db9-rj12.jpg images/cables/mge-db9-rj45.jpg \ images/cables/mge-usb-rj45.jpg \ images/cables/SOLA-330.png ALL_TXT_SRC = nut-names.txt daisychain.txt \ $(USER_MANUAL_DEPS) $(DEVELOPER_GUIDE_DEPS) \ $(CABLES_DEPS) $(QA_GUIDE_DEPS) FAQ.txt packager-guide.txt snmp.txt \ release-notes.txt ChangeLog.txt solaris-usb.txt ASPELL_FILTER_PATH = @ASPELL_FILTER_PATH@ # NOTE: This can be set by caller such as nut-website builder: NUT_SPELL_DICT = nut.dict ASCIIDOC_HTML_SINGLE = \ $(top_builddir)/docs/ChangeLog.html \ user-manual.html \ developer-guide.html \ packager-guide.html \ qa-guide.html \ release-notes.html \ solaris-usb.html \ cables.html \ FAQ.html ASCIIDOC_HTML_CHUNKED = \ $(top_builddir)/docs/ChangeLog.chunked \ user-manual.chunked \ developer-guide.chunked \ packager-guide.chunked \ qa-guide.chunked \ release-notes.chunked \ solaris-usb.chunked \ cables.chunked \ FAQ.chunked ASCIIDOC_PDF = \ $(top_builddir)/docs/ChangeLog.pdf \ user-manual.pdf \ developer-guide.pdf \ packager-guide.pdf \ qa-guide.pdf \ release-notes.pdf \ solaris-usb.pdf \ cables.pdf \ FAQ.pdf # Note: "man" subdir is handled separately via all-local and check-local # for a few goals, and among SUBDIRs directly from the top-level Makefile # due to some potential dependency collisions with parallel builds. SUBDIRS = cables SUFFIXES = .txt .html .pdf .txt-spellchecked-auto .txt-spellchecked \ .txt-prepped .adoc-spellchecked-auto .adoc-spellchecked \ .adoc-prepped .in-spellchecked-auto .in-spellchecked \ .in-prepped .sample-spellchecked-auto .sample-spellchecked \ .sample-prepped .conf-spellchecked-auto .conf-spellchecked \ .conf-prepped # This list is defined by configure script choices and options: CHECK_LOCAL_TARGETS = @DOC_CHECK_LIST@ $(am__append_1) # htmldocdir and pdfdir are set by autoconf/automake htmldoc_DATA = $(am__append_2) # FIXME: Install tools refuse to work with directories in this context # and html-chunked documentation has a separate tree per document. # Maybe an "(un)install-data-local" or "install-data-hook" for this? #if WITH_HTML_CHUNKED #htmldoc_DATA += $(ASCIIDOC_HTML_CHUNKED) #endif WITH_HTML_CHUNKED @WITH_PDFS_TRUE@pdf_DATA = $(ASCIIDOC_PDFS) CLEANFILES = *.xml *.html *.pdf *-spellchecked* *-contentchecked* \ .check-* docbook-xsl.css docinfo.xml.in.tmp \ docinfo-since-v*.xml* *-docinfo.xml* \ $(top_builddir)/INSTALL.nut $(top_builddir)/UPGRADING \ $(top_builddir)/ChangeLog.adoc $(top_builddir)/*.adoc-parsed \ *.adoc-parsed .ChangeLog.adoc-parsed.latest \ $(NUT_SPELL_DICT).usage-report.tmp # These two "must be" there per autotools standards, so a "make clean" # should not compromise a rebuild: DISTCLEANFILES = $(top_builddir)/NEWS $(top_builddir)/README \ $(am__append_4) ### TODO: general automatic dependency generation MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG = no @WITH_PDF_NONASCII_TITLES_FALSE@A2X_ASCII_IDS = ":ascii-ids:\n" # BSD Make dislikes the path resolution here and does not always populate '$<' # (and claims why: "Using $< in a non-suffix rule context is a GNUmake idiom"), # but it has a "$?" for "list of dependencies that are newer than the target". # For more details see https://man.freebsd.org/cgi/man.cgi @WITH_PDF_NONASCII_TITLES_TRUE@A2X_ASCII_IDS = # Timeout for ChangeLog.adoc rule to wait for competing threads to maybe create # (or start creating) the file first - then this "make" thread just waits for # it to be done, and exits, as the goal is fulfilled. MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY = 10 # Add other directory deps (not for local EXTRA_DIST) and generated contents FULL_USER_MANUAL_DEPS = $(USER_MANUAL_DEPS) $(SHARED_DEPS) \ $(top_builddir)/README.adoc-parsed \ $(top_builddir)/INSTALL.nut.adoc-parsed \ $(top_builddir)/UPGRADING.adoc-parsed \ ../TODO.adoc ../scripts/ufw/README.adoc FULL_DEVELOPER_GUIDE_DEPS = $(DEVELOPER_GUIDE_DEPS) $(SHARED_DEPS) \ ../scripts/augeas/README.adoc ../TODO.adoc \ ../lib/README.adoc \ ../tools/nut-scanner/README.adoc FULL_QA_GUIDE_DEPS = $(QA_GUIDE_DEPS) $(SHARED_DEPS) \ $(top_builddir)/ci_build.adoc-parsed # Note: without the "-v", asciidoc (circa 8.6.2) sometimes hangs when # generating the chunked HTML. In this case, export the environment # variable ASCIIDOC_VERBOSE to "-v", ie: # $ ASCIIDOC_VERBOSE=-v make # Note: `(top_)srcdir` and `(top_)builddir` must end with a path # separator, or be empty -- so in all cases letting the resulting # string resolve meaningfully in the filesystem during docs build. A2X_DOCINFO_DIR = $(builddir) A2X_COMMON_OPTS = $(ASCIIDOC_VERBOSE) \ --attribute=icons \ --xsltproc-opts="--nonet" \ --xsltproc-opts="--stringparam nut.localdate \"`TZ=UTC date +%Y-%m-%d`\"" \ --xsltproc-opts="--stringparam nut.localtime \"`TZ=UTC date +%H:%M:%S`\"" \ --xsltproc-opts="--stringparam nut.nutversion \"$(PACKAGE_VERSION)\"" \ --attribute=docinfodir="$${A2X_DOCINFO_DIR}" \ --attribute=iconsdir="$(srcdir)/images" \ --attribute=badges \ --attribute=external_title \ --attribute=tree_version="$(TREE_VERSION)" \ --attribute=srcdir="$(abs_srcdir)/" \ --attribute=builddir="$(abs_builddir)/" \ --attribute=top_srcdir="$(abs_top_srcdir)/" \ --attribute=top_builddir="$(abs_top_builddir)/" \ --attribute=MAN_SECTION_API_BASE='$(MAN_SECTION_API_BASE)' \ --attribute=MAN_SECTION_CFG_BASE='$(MAN_SECTION_CFG_BASE)' \ --attribute=MAN_SECTION_CMD_SYS_BASE='$(MAN_SECTION_CMD_SYS_BASE)' \ --attribute=MAN_SECTION_CMD_USR_BASE='$(MAN_SECTION_CMD_USR_BASE)' \ --attribute=NUT_WEBSITE_BASE='$(NUT_WEBSITE_BASE)' \ -a toc -a numbered --destination-dir=$${A2X_OUTDIR} # NOTE: a2x newer than 8.6.8 says "--destination-dir" is only valid for HTML. # As of version 8.6.9 it lies, and the argument is required for our distcheck # (and does affect PDF builds, as found during work on collision-avoidance - # true with at least asciidoc/a2x versions 9.0.0rc2). # For more details see issues https://web.archive.org/web/20201207082352/https://github.com/asciidoc/asciidoc/issues/44 # and https://github.com/networkupstools/nut/pull/281 (in short, attempts # to "fix" this warning broke NUT build). If this is to be retried later, see # https://github.com/networkupstools/nut/pull/281/commits/fe17861c4ea12679b3ebfefa8a6d692d79d99f2d # and do not forget to fix up docs/man/Makefile.am too ;) # NOTE: a2x tends to copy some files into its working area, preserving original # permissions. If those files are read-only in origin (e.g. packaged stylesheet # or our resources coming from EXTRA_DIST) the next a2x can not overwrite it. # Also note that such hoarding of files has potential to break parallel builds # (or cause them to produce undefined results if some bad timing happens). # As a brutal workaround for the former problem, we chmod. For second one we # might try magic with .SEQUENTIAL recipe hints, but that is gmake-dependent. # Note that empirically it treats "destination-dir" as the source root for # PDF generation (even though it claims the argument is ignored for non-HTML # targets) so we have to provide the "images/" in this case. ONLY for PDF! # Note we only remove the original target (if present), if it is a directory - # e.g. created by "html-chunked" targets. # NOTE: MKDIR_P may be defined via expanded $(top_builddir)/install-sh # so should be run from $(abs_builddir) to be safe, as we jump around # the build workspace DOCBUILD_BEGIN = { \ if test -n "$${A2X_OUTDIR}" && test "$${A2X_OUTDIR}" != '.' ; then \ rm -rf "./$${A2X_OUTDIR}" || true ; \ test -d "$@" && rm -rf "$@" || true ; \ _CWD="`pwd`" && (cd '$(abs_builddir)' && $(MKDIR_P) "$${_CWD}/$${A2X_OUTDIR}") || exit ; \ case "$${A2X_OUTDIR}" in \ tmp/pdf.*) ln -s ../../images "./$${A2X_OUTDIR}" ; \ case "$(@F)" in \ qa-guide.pdf) \ ln -s ../../docinfo-since-v2.8.3.xml "./$${A2X_OUTDIR}/docinfo.xml" ; \ ln -s ../../docinfo-since-v2.8.3.xml "./$${A2X_OUTDIR}/qa-guide-docinfo.xml" ;; \ esac \ ;; \ esac; \ else A2X_OUTDIR='.' ; fi; \ if test -s "${builddir}/docbook-xsl.css" \ && test -r "${builddir}/docbook-xsl.css" \ && ! test -w "${builddir}/docbook-xsl.css" \ ; then chmod u+w "${builddir}/docbook-xsl.css" ; fi ; \ chmod -R u+w "./$${A2X_OUTDIR}" || true; \ } # When moving "*" hope a2x did not make any "hidden" files # like ".*" that would be required for resulting documents. # Leave the "images/" dir there, though. # Otherwise, we would have to `find` them all. DOCBUILD_END = { \ if test -n "$${A2X_OUTDIR}" && test "$${A2X_OUTDIR}" != '.' ; then \ chmod -R u+w "./$${A2X_OUTDIR}" || true; \ test -d "$@" && rm -rf "$@" || true ; \ rm -f "./$${A2X_OUTDIR}/"*docinfo*.xml* || exit ; \ mv -f "./$${A2X_OUTDIR}/$(@F)" ./ || exit ; \ mv -f "./$${A2X_OUTDIR}/"*.* ./ 2>/dev/null || true ; \ rm -rf "./$${A2X_OUTDIR}" ; \ fi ; \ } # PORTABILITY NOTE: POSIX Make forbids the suffix rule definitions with # prerequisites like done below, and GNU Make of some versions complains; # https://www.gnu.org/software/make/manual/html_node/Error-Messages.html # says the prerequisites were ignored while a suffix rule was created; # eventually the POSIX stance would be taken to define a rule for a weird # verbatim target file name with prerequisites: # ../docs/Makefile:936: warning: ignoring prerequisites on suffix rule definition # Changes from ".txt.pdf: docinfo.xml" to "*.pdf: docinfo.xml" = ".txt.pdf:" # as done below may be pointless in the end (with regard to a portable way # to trigger builds by a changed dependency), but at least predictable and # not toxic. ###.txt.txt-prepped: $(abs_top_builddir)/docs/.prep-src-docs ###.adoc.adoc-prepped: $(abs_top_builddir)/docs/.prep-src-docs # NOTE: inference rules can have only one target before the colon (POSIX), # so we use helper snippets to share code for *.adoc and *.txt sources GENERATE_HTML_SINGLE = ( \ A2X_OUTDIR="tmp/html-single.$(@F).$$$$" ; \ echo " DOC-HTML Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(A2X) $(A2X_COMMON_OPTS) --attribute=xhtml11_format --format=xhtml --xsl-file=$(srcdir)/xhtml.xsl '$<' || RES=$$? ; \ $(DOCBUILD_END) ; \ case "$(@F)" in \ *ChangeLog*) \ if [ -s '$(top_builddir)/ChangeLog' ] ; then \ $(MAKE) $(AM_MAKEFLAGS) "`basename '$(@F)'`"-contentchecked || RES=$$? ; \ if [ "$$RES" != 0 ] ; then \ echo " DOC-HTML Generating $@ (retry once)" >&2; \ rm -f "$@"; \ A2X_OUTDIR="tmp/html-single.$(@F).$$$$-retry" ; \ $(DOCBUILD_BEGIN) ; RES=0; rm -f "`basename '$(@F)'`"-contentchecked || true ; \ $(A2X) $(A2X_COMMON_OPTS) --attribute=xhtml11_format --format=xhtml --xsl-file=$(srcdir)/xhtml.xsl '$<' || RES=$$? ; \ $(DOCBUILD_END) ; \ $(MAKE) $(AM_MAKEFLAGS) "`basename '$(@F)'`"-contentchecked || RES=$$? ; \ fi ; \ fi ;; \ esac ; \ exit $$RES ; \ ) # Note: extra age check here because *.chunked is a directory and not all # "make" implementations check its age vs. source files, just always build: GENERATE_HTML_CHUNKED = ( \ if [ -d "$@" ] && [ x"`find '$@' -newer "$<" 2>/dev/null`" != x ] ; then \ echo " DOC-HTML-CHUNKED SKIP: keep existing $@"; \ exit 0 ; \ fi ; \ A2X_OUTDIR="tmp/html-chunked.$(@F).$$$$" ; \ echo " DOC-HTML-CHUNKED Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(A2X) $(A2X_COMMON_OPTS) --attribute=chunked_format --format=chunked --xsl-file=$(srcdir)/chunked.xsl '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES ; \ ) # Note: non-HTML a2x modes may ignore the destination directory GENERATE_PDF = ( \ A2X_OUTDIR="tmp/pdf.$(@F).$$$$" ; \ echo " DOC-PDF Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ if [ -s "$${A2X_OUTDIR}/docinfo.xml" ] ; then A2X_DOCINFO_DIR="$${A2X_OUTDIR}"; fi ; \ $(A2X) $(A2X_COMMON_OPTS) --attribute=pdf_format --format=pdf -a docinfo1 '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES ; \ ) # Used below for spellcheck and for .prep-src-docs SPELLCHECK_SRC_DEFAULT = $(ALL_TXT_SRC) \ asciidoc-vars.conf \ ../ci_build.adoc ../README.adoc ../NEWS.adoc \ ../INSTALL.nut.adoc ../UPGRADING.adoc \ ../TODO.adoc ../scripts/ufw/README.adoc \ ../scripts/augeas/README.adoc ../lib/README.adoc \ ../tools/nut-scanner/README.adoc \ ../AUTHORS ../COPYING ../LICENSE-GPL2 ../LICENSE-GPL3 ../LICENSE-DCO # Non-interactively spell check all documentation source files. # This is useful for Buildbot and automated QA processing # FIXME: how to present output (std{out,err}, single file or per target)? # NOTE: ../ChangeLog is nowadays generated from commit messages, so # its spelling (or errors in that) are not fixable and thus irrelevant. # Similarly for the ../INSTALL file that is prepared by autoconf and not # tracked as a source file by NUT Git repository. # Note that `docs/asciidoc-vars.conf` is included into docs and so impacts # their resulting spellcheck verdicts. @HAVE_ASPELL_TRUE@SPELLCHECK_SRC = $(SPELLCHECK_SRC_DEFAULT) # Directory SPELLCHECK_SRC files are relative to. Overridden by other Makefiles. @HAVE_ASPELL_TRUE@SPELLCHECK_SRCDIR = $(srcdir) @HAVE_ASPELL_TRUE@SPELLCHECK_BUILDDIR = $(builddir) # Note: de-facto our documentation is beyond ASCII (at least in names of # international committers). The grep tests below look if the aspell output # contained something other than the OK lines (tagged with asterisk) and # aspell's version (tagged with @) and if it did - those lines must be the # spellcheck complaints. Empty OUT is ok. # We also must indent the input, because certain piped-in characters are # interpreted as commands, and seems this feature can not be turned off. # See also http://aspell.net/man-html/Through-A-Pipe.html # TODO: Is "grep -a" or "grep -b" (treat input as ascii/bin) portable enough? # Set SPELLCHECK_ERROR_FATAL=no if there are some unavoidable issues # due to spellchecking, to temporarily not fail builds due to this. # For Travis CI in particular, see ci_build.sh in NUT codebase root. @HAVE_ASPELL_TRUE@SPELLCHECK_ERROR_FATAL = yes @HAVE_ASPELL_TRUE@SPELLCHECK_ENV_DEBUG = no @HAVE_ASPELL_TRUE@ASPELL_NUT_COMMON_ARGS = -p \ @HAVE_ASPELL_TRUE@ $(abs_srcdir)/$(NUT_SPELL_DICT) -d en \ @HAVE_ASPELL_TRUE@ --lang=en --ignore-accents --encoding=utf-8 # Note: If there is a need to use filter path (e.g. in mingw/msys2 builds), # it must be before --mode=tex (-t) option! @HAVE_ASPELL_TRUE@ASPELL_NUT_TEXMODE_ARGS = $(am__append_3) -t @HAVE_ASPELL_TRUE@ASPELL_ENV_LANG = en.UTF-8 @HAVE_ASPELL_TRUE@ASPELL_OUT_NOTERRORS = (^[ \t]*[\*\@]|^$$) # WARNING: The percent wildcard is a GNU extension; otherwise we need # a ".txt.txt-spellchecked" type of rule and files like "README" all # renamed to *.txt, or lots of rules for files without the extensions. # Maybe this will get simplified with renaming to *.adoc though ;) # # Other Makefiles have a relatively simple life, dealing with just a # few texts and name/extension patterns in their directories. #?#.txt.txt-spellchecked: Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) #%-spellchecked: % Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) #*-spellchecked */*-spellchecked: $(@:-spellchecked=) $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # # NOTE: For some reason, at least GNU make insists on bogus calls: # update target 'asciidoc-vars.conf' due to: asciidoc-vars.conf-spellchecked # when we e.g. `make dist` after a `make spellcheck` and ended up # with removed and touched (emptied) file, only this one so far. # # NOTE: This portable rule RELIES on just one SPELLCHECK_SRC defined # at a time, with an outer Makefile caller ensuring the looping: @HAVE_ASPELL_TRUE@SPELLCHECK_RECIPE_DEBUG_STREAM = /dev/null # If NUT_MAKE_SKIP_FANOUT!=true we have a hack to spellcheck certain files more # quickly (in parallel). This approach is constrained to files with a known # extension and located in same directory as the Makefile that called them # (extension-less docs and relative links are built sequentially). @HAVE_ASPELL_TRUE@SPELLCHECK_AUTO_ONE = ( \ @HAVE_ASPELL_TRUE@ SPELLCHECK_SRC_ONE="`basename '$?'`" ; \ @HAVE_ASPELL_TRUE@ rm -f "$@".failed ; \ @HAVE_ASPELL_TRUE@ $(MAKE) $(AM_MAKEFLAGS) -k -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_SRC="" SPELLCHECK_SRC_ONE="$${SPELLCHECK_SRC_ONE}" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" "$(SPELLCHECK_BUILDDIR)/$${SPELLCHECK_SRC_ONE}-spellchecked" \ @HAVE_ASPELL_TRUE@ || { RES=$$? ; touch "$@".failed; exit $$RES; } \ @HAVE_ASPELL_TRUE@) # NOTE: In "make SPELLCHECK_INTERACTIVE=true ${docsrc}-spellchecked", # after an interactive "aspell check" we follow-up by a run of usual # non-interactive spell-checker to verify that the developer actually # has fixed all of the files that the tool had concerns about, and # that the touch-file is updated if the file is okay (to speed up # any future re-runs). We also must update all relevant *-spellchecked # touch-files after "make spellcheck-sortdict" which updates "nut.dict" # file which is a prerequisite for docs checks. # After the (possibly SUBDIR-based) run we may report to the developer # that their dictionary was updated and may need a Git recommit - either # if it did change, or if caller's SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes. @HAVE_ASPELL_TRUE@SPELLCHECK_REPORT_MAYBE_UPDATED_DICT = no # When building out-of-tree, be sure to have all asciidoc resources # under the same dir structure (tool limitation) PREP_SRC = $(EXTRA_DIST) $(SPELLCHECK_SRC_DEFAULT) all: all-recursive .SUFFIXES: .SUFFIXES: .txt .html .pdf .txt-spellchecked-auto .txt-spellchecked .txt-prepped .adoc-spellchecked-auto .adoc-spellchecked .adoc-prepped .in-spellchecked-auto .in-spellchecked .in-prepped .sample-spellchecked-auto .sample-spellchecked .sample-prepped .conf-spellchecked-auto .conf-spellchecked .conf-prepped .adoc .adoc-parsed .chunked .conf .in .sample $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu docs/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu docs/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): docinfo.xml: $(top_builddir)/config.status $(srcdir)/docinfo.xml.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-htmldocDATA: $(htmldoc_DATA) @$(NORMAL_INSTALL) @list='$(htmldoc_DATA)'; test -n "$(htmldocdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldocdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldocdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldocdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldocdir)" || exit $$?; \ done uninstall-htmldocDATA: @$(NORMAL_UNINSTALL) @list='$(htmldoc_DATA)'; test -n "$(htmldocdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(htmldocdir)'; $(am__uninstall_files_from_dir) install-pdfDATA: $(pdf_DATA) @$(NORMAL_INSTALL) @list='$(pdf_DATA)'; test -n "$(pdfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; \ done uninstall-pdfDATA: @$(NORMAL_UNINSTALL) @list='$(pdf_DATA)'; test -n "$(pdfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pdfdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: check-recursive all-am: Makefile $(DATA) all-local installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(htmldocdir)" "$(DESTDIR)$(pdfdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-htmldocDATA install-pdfDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-htmldocDATA uninstall-pdfDATA .MAKE: $(am__recursive_targets) check-am install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ check check-am check-local clean clean-generic clean-libtool \ clean-local cscopelist-am ctags ctags-am distclean \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-htmldocDATA install-info install-info-am install-man \ install-pdf install-pdf-am install-pdfDATA install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-htmldocDATA uninstall-pdfDATA .PRECIOUS: Makefile # Note: "doc" ensures the `configure`-specified list of documents we actually # want, while the default generated "all: all-am" target historically causes # some but not all of these targets to get built (e.g. ChangeLog html/pdf is # usually not made there). Post-processing "doc" as part of "all" helps # ensure that we do not rebuild stuff in vain during parallel builds (where # "all-am" and "doc" would be unordered parallel goals of the "all" target) # while getting those further goals achieved eventually in the default build. # Crucially, this allows to make sure "ChangeLog(.adoc*)" files have been # generated once (can take a looong while), settled into place, and only then # we revisit them for html/pdf rendering (another long while) without randomly # confusing the system with new timestamps and needless regenerations later on. all: @echo " DOC-FOLLOW-UP Basic 'make $@' in `pwd` is done, following up with 'make doc' to ensure complex document types" +@$(MAKE) $(AM_MAKEFLAGS) doc check-local: $(CHECK_LOCAL_TARGETS) +@cd $(builddir)/man && $(MAKE) $(AM_MAKEFLAGS) check # Make sure sources are there for out-of-tree builds: all-local all-am-local \ @DOC_BUILD_LIST@ $(ASCIIDOC_PDF) $(ASCIIDOC_HTML_SINGLE) $(ASCIIDOC_HTML_CHUNKED): $(abs_top_builddir)/docs/.prep-src-docs all-local: +@cd $(builddir)/man && $(MAKE) $(AM_MAKEFLAGS) all-optional # This list is defined by configure script choices and options: doc: $(abs_top_builddir)/docs/.prep-src-docs @DOC_BUILD_LIST@ # This target can be called by developers to go around the configure # script choices at their risk (e.g. missing tools are possible): docs: pdf html-single html-chunked man-man html-man all-docs: docs check-docs: check-pdf check-html-single check-html-chunked check-man # Not called by default, but handy for maintainers to check which words # in the custom dictionary are used or not by the current NUT codebase. # Note that historically many words were added to facilitate rendition # of the nut-website (long ago splintered from main nut repository), # but since recently it has a way to track its own additions to the # dictionary file. This code should help populate it as well, and keep # only relevant entries in the appropriate corner of the sources. # Note this can take 5-10 minutes! spellcheck-report-dict-usage: $(NUT_SPELL_DICT).usage-report pdf: $(ASCIIDOC_PDF) # also build the HTML manpages with these targets html-single: $(ASCIIDOC_HTML_SINGLE) html-chunked: $(ASCIIDOC_HTML_CHUNKED) # the "for" loops might better use $^ but it might be not portable check-pdf: .check-pdf .check-pdf: $(ASCIIDOC_PDF) Makefile @FAILED=""; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(ASCIIDOC_PDF) ; do \ test -s "$$F" && { file "$$F" | $(EGREP) -i 'PDF document' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED PDF sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED PDF sanity check"; exit 0 @touch $@ # Regarding ChangeLog check: sometimes asciidoc gives up early # (we have megabytes of text and thousands of sections here). # In some cases, the intermediate XML is broken and a2x=>xmllint # notices it. In others, it is truncated at just the right place # structurally and leads to a short HTML with only part of the # expected contents. We should no longer have several processes # trying to create the files involved (or rather do so atomically # and rename into final path, in case we still have competition # here); earlier when several generators appended to the same # file we could have several copies overlaid, with one of the # document's copies starting mid-sentence of another. # The two expected mentions are in the table of contents and # in the eventual section. Checking for first/second entries, # and not exactly two mentions, should allow to catch the case # of overlapping documents. Checking for the last entry allows # to catch incomplete parses, where asciidoc gave up early. # NOTE: Technically it may be more than two, if the author and # date were used several times in the original ChangeLog file # (either with different e-mails, or if different author's work # is interleaved during the day, e.g. many PRs merged, and no # CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR=true setting was in place. # NOTE: No dependencies, avoids (re-)generation and log messages # but causes re-run of the check every time. ChangeLog.html-contentchecked: @FAILED=""; \ if [ -s '$(top_builddir)/ChangeLog' ] && [ -s ChangeLog.html ] ; then \ SECOND_ENTRY="`grep -E '^[0-9]' '$(top_builddir)/ChangeLog' | head -2 | tail -1 | sed 's/ *[\"<].*//'`" || SECOND_ENTRY="" ; \ FIRST_ENTRY="`grep -E '^[0-9]' '$(top_builddir)/ChangeLog' | head -1 | sed 's/ *[\"<].*//'`" || FIRST_ENTRY="" ; \ LAST_ENTRY="`grep -E '^[0-9]' '$(top_builddir)/ChangeLog' | tail -1 | sed 's/ *[\"<].*//'`" || LAST_ENTRY="" ; \ if [ -n "$${FIRST_ENTRY}" ] ; then \ O="`grep -cE "^$${FIRST_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${FIRST_ENTRY}" 'ChangeLog.html'`" ; \ MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ echo "FAILED ChangeLog.html check: does not contain expected first entry the right amount of times (huge doc, must have got aborted mid-way): $${FIRST_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ FAILED="ChangeLog.html" ; \ fi ; \ fi ; \ fi; \ if [ -n "$${SECOND_ENTRY}" ] ; then \ O="`grep -cE "^$${SECOND_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${SECOND_ENTRY}" 'ChangeLog.html'`" ; \ MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ echo "FAILED ChangeLog.html check: does not contain expected second entry the right amount of times (huge doc, must have got aborted mid-way): $${SECOND_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ FAILED="ChangeLog.html" ; \ fi ; \ fi ; \ fi; \ if [ -n "$${LAST_ENTRY}" ] ; then \ O="`grep -cE "^$${LAST_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${LAST_ENTRY}" 'ChangeLog.html'`" ; \ MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ echo "FAILED ChangeLog.html check: does not contain expected last entry the right amount of times (huge doc, must have got aborted mid-way): $${LAST_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ FAILED="ChangeLog.html" ; \ fi ; \ fi ; \ fi; \ if [ x"$$FAILED" = x ] ; then \ echo "PASSED $@" >&2 ; \ exit 0 ; \ fi ; \ if [ x"$$FAILED" != x ] && [ -s '$(top_builddir)/ChangeLog.adoc' ] \ && [ "`head -1 $(top_builddir)/ChangeLog.adoc`" = "=== Failed to generate the ChangeLog" ] \ ; then \ FAILED="" ; \ fi; \ fi; \ if [ x"$$FAILED" = x ] ; then \ echo " SKIP $@ : because input files were not available" >&2 ; \ exit 0 ; \ fi ; \ exit 1 check-html-single: .check-html-single .check-html-single: $(ASCIIDOC_HTML_SINGLE) Makefile +@FAILED=""; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(ASCIIDOC_HTML_SINGLE) ; do \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(XML|HTML.*document)' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ case "$$F" in \ *ChangeLog*) if [ -s '$(top_builddir)/ChangeLog' ] ; then \ $(MAKE) $(AM_MAKEFLAGS) "`basename "$$F"`"-contentchecked || FAILED="$$FAILED $$F" ; \ fi ;; \ esac ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED HTML-single sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED HTML-single sanity check"; exit 0 @touch $@ check-html-chunked: .check-html-chunked .check-html-chunked: $(ASCIIDOC_HTML_CHUNKED) Makefile @FAILED=""; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for D in $(ASCIIDOC_HTML_CHUNKED); do \ for F in "$$D"/*.html ; do \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(XML|HTML.*document)' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; \ for F in "$$D"/*.css ; do \ test -s "$$F" && { $(EGREP) -i 'CSS stylesheet' "$$F" > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; \ done; if test -n "$$FAILED" ; then \ echo "FAILED HTML-chunked sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED HTML-chunked sanity check"; exit 0 @touch $@ # Note: usually the results from man-page check will be reported twice: # once as a SUBDIRS child makefile, and once via DOC_CHECK_LIST expansion # Note: default `make all` in the man directory caters to drivers etc. # chosen during configure script execution. The "all-man" and "all-html" # rules build everything documented. # NOTE; we rig it up with a DOCS_NO_MAN option to simplify parallel work # from top-level Makefile, while allowing legacy "cd docs && make" to # still do the right thing by default :) check-man check-man-man all-man man-man all-html html-man: +@if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then echo " DOC-NOT-MAN SKIP: $@ called in docs/Makefile" ; exit 0 ; fi ; \ cd $(abs_top_builddir)/docs/man/ && $(MAKE) $(AM_MAKEFLAGS) -f Makefile $@ man: +@if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then echo " DOC-NOT-MAN SKIP: $@ called in docs/Makefile" ; exit 0 ; fi ; \ cd $(abs_top_builddir)/docs/man/ && $(MAKE) $(AM_MAKEFLAGS) -f Makefile all # Prepare text files (currently a manually tracked list) # with known presence of GitHub links to convert them from # short notation into asciidoc link markup # before rendering into HTML/PDF. # Work around some documents that have originally included # the asciidoc markup (use double-hash to avoid conversion). # The $< is okay here, it is used in a suffix rule below .adoc.adoc-parsed: @if [ -s '$@' ] && [ x"`find '$@' -newer '$<'`" != x ] ; then \ echo " DOC-ASCIIDOC-GITHUB-LINKS SKIP: $@ already exists and is newer than $<" ; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ ls -lad $@ $< || true ; \ stat $@ $< || true ; \ fi ; \ exit 0 ; \ fi ; \ echo " DOC-ASCIIDOC-GITHUB-LINKS Parsing GitHub link patterns $< => $@"; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ ls -lad $@ $< || true ; \ stat $@ $< || true ; \ fi ; \ cat '$<' | { $(SED) \ -e 's%\(link:https*://github.com/networkupstools/[a-zA-Z0-9./-]*/[1-9][0-9]*/*\[[^]]*\)\#\([1-9][0-9]*\)%\1\#\#\2%g' \ -e 's%\(issue\) *\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/nut/issues/\2[\1 \#\#\2]\3%g' \ -e 's%\(PR\|pull request\) *\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/nut/pull/\2[\1 \#\#\2]\3%g' \ -e 's%\([[ ,]\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%\1link:https://github.com/networkupstools/nut/issues/\2[\#\#\2]\3%g' \ -e 's%\(issue\) networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/\2/issues/\3[\1 \2\#\#\3]\4%g' \ -e 's%\(PR\|pull request\) *networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/\2/pull/\3[\1 \2\#\#\3]\4%g' \ -e 's%\([[ ,]\)networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%\1link:https://github.com/networkupstools/\2/issues/\3[\2\#\#\3]\4%g' \ -e 's%\#\(\#[1-9][0-9]*\)%\1%g' \ ; } > "$@.tmp.$$$$" \ && mv -f "$@.tmp.$$$$" "$@" @if [ x'$@' = x'$(top_builddir)/ChangeLog.adoc-parsed' ] ; then \ touch -r '$@' '$(top_builddir)/docs/.ChangeLog.adoc-parsed.latest' || touch '$(top_builddir)/docs/.ChangeLog.adoc-parsed.latest' ; \ fi $(top_builddir)/ChangeLog.adoc-parsed: $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest: $(top_builddir)/ChangeLog.adoc-parsed @[ x"$?" != x ] && touch -r '$?' '$@' || touch '$@' dummy: $(top_builddir)/ChangeLog: dummy @+echo " DOC-CHANGELOG-GENERATE-WRAPPER $@ : call parent Makefile to decide if (re-)generation is needed" \ && cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # Probably due to the web of makefiles and an overwhelmed job server in some # implementations, during parallel builds we can end up scheduling several # threads creating this asciidoc (and adoc-parsed later). This step only # costs a few seconds, however the updated timestamp may cause new HTML/PDF # builds which cost a lot more. Below we try a few ways to detect a build # already running and bail out early if the file exists. Otherwise we bite # the bullet and spend a few seconds, and then re-check if another thread # did exist and finished first. $(top_builddir)/ChangeLog.adoc: $(top_builddir)/ChangeLog @INPUT="$?"; \ test -n "$${INPUT}" || INPUT="$$(top_builddir)/ChangeLog" ; \ test -n "$${INPUT}" && test -n "$@" && test -s "$${INPUT}" \ || { \ MSG="FAILED to resolve input or output filename with this make implementation, or input was not generated!"; \ echo " DOC-CHANGELOG-ASCIIDOC SKIP: $${MSG}" >&2; \ test -n "$@" && { printf '=== Failed to generate the ChangeLog\n\n%s\n\nNOTE: See https://github.com/networkupstools/nut/commits/master for change history.\n\n' "$${MSG}" > "$@" ; } ; \ exit ; \ } ; \ if [ -s '$@' ] && [ x"`find '$@' -newer "$${INPUT}" 2>/dev/null`" != x ] ; then echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : SKIP (keep existing)"; rm -f "$@.tmp.$$$$"; exit 0 ; fi ; \ W=0 ; \ if [ "$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" -gt 0 ] 2>/dev/null ; then \ echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : Block for up to $(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY) sec, maybe another thread will make the file first" ; \ while [ "$${W}" -lt "$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" ] && [ x"`find '$@.tmp.'* '$@' -newer "$${INPUT}" 2>/dev/null`" = x ] ; do sleep 1 ; W="`expr $$W + 1`"; done ; touch "$@.tmp.$$$$"; \ if [ x"`find '$@' -newer "$${INPUT}" 2>/dev/null`" != x ] ; then echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : SKIP (keep existing)"; rm -f "$@.tmp.$$$$"; exit 0 ; fi ; \ fi ; \ if [ -s "$@" ] ; then echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : RE-GENERATE" ; else echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : GENERATE" ; fi ; \ { if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then ls -la "$${INPUT}" "$@" || true ; stat "$${INPUT}" "$@" || true ; fi ; } ; \ if [ "$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" -gt 0 ] 2>/dev/null ; then \ echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : PROCEED, waited for $${W} sec" ; \ fi ; \ printf "ifdef::txt[]\n== Very detailed Change Log\n"$(A2X_ASCII_IDS)"endif::txt[]\n\n" > "$@.tmp.$$$$" \ && TABCHAR="`printf '\t'`" \ && $(SED) \ -e 's,^\([0-9a-zA-Z]\),=== \1,' \ -e 's,^=== \(NOTE: \),\1,' \ -e 's,/[+],/\\\\\+,g' \ -e 's,[+][+],\\\+\\\+,g' \ -e 's,^\([ '"$${TABCHAR}"'][^+]*\)\([^+/\]\)[+],\1\2\\\+,g' \ -e 's,^\([ '"$${TABCHAR}"'].*\)\([~|^]\),\1\\\2,g' \ -e 's,\[\[\([^]]*\)\]\],[\1],g' \ -e 's,^\(\s\s*\)\([0-9]\),\1{empty}\2,g' \ < "$${INPUT}" >> "$@.tmp.$$$$" \ && if [ x"`find '$@' -newer "$${INPUT}" 2>/dev/null`" != x ] ; then echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : SKIP (keep recently born competitor)"; rm -f "$@.tmp.$$$$"; \ else mv -f "$@.tmp.$$$$" "$@" ; fi user-manual.html user-manual.chunked user-manual.pdf: $(FULL_USER_MANUAL_DEPS) developer-guide.html developer-guide.chunked developer-guide.pdf: $(FULL_DEVELOPER_GUIDE_DEPS) packager-guide.html packager-guide.chunked packager-guide.pdf: packager-guide.txt asciidoc.conf qa-guide.html qa-guide.chunked qa-guide.pdf: $(FULL_QA_GUIDE_DEPS) release-notes.html release-notes.chunked release-notes.pdf: release-notes.txt $(top_builddir)/NEWS.adoc-parsed $(top_builddir)/UPGRADING.adoc-parsed asciidoc.conf solaris-usb.html solaris-usb.chunked solaris-usb.pdf: solaris-usb.txt asciidoc.conf # We intentionally evaluate that the original generated ChangeLog file is # up to date (from dist or against git) every time we look at it. However # we do want to skip re-generation of heavy file formats afterwards if it # is still valid (for make, a need for re-evaluation without timestamps # to look at is cause to run a recipe always). We define recipes outside # the suffix-based handling and require *them* for default target builds. ChangeLog.html ChangeLog.chunked ChangeLog.pdf: ChangeLog.txt .ChangeLog.adoc-parsed.latest asciidoc.conf $(top_builddir)/docs/ChangeLog.html $(top_builddir)/docs/ChangeLog.chunked $(top_builddir)/docs/ChangeLog.pdf: ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf @+if [ -s '$(@F)' ] && [ x"`find '$(@F)' -newer '$(top_builddir)/ChangeLog.adoc-parsed'`" != x ] ; then \ echo " DOC-CHANGELOG-RENDER-WRAPPER SKIP: `pwd`/$(@F) already exists and is newer than ChangeLog.adoc-parsed" ; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ ls -lad `pwd` $@ ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf $(top_builddir)/ChangeLog $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest || true ; \ stat `pwd` $@ ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf $(top_builddir)/ChangeLog $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest || true ; \ fi ; \ exit 0 ; \ else \ echo " DOC-CHANGELOG-RENDER-WRAPPER `pwd`/$(@F) does not already exist or is older than ChangeLog.adoc-parsed" ; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ ls -lad `pwd` $@ ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf $(top_builddir)/ChangeLog $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest || true ; \ stat `pwd` $@ ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf $(top_builddir)/ChangeLog $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest || true ; \ time $(MAKE) $(AM_MAKEFLAGS) $(@F) || exit ; \ else \ $(MAKE) $(AM_MAKEFLAGS) $(@F) || exit ; \ fi ; \ echo " DOC-CHANGELOG-RENDER-WRAPPER `pwd`/$(@F): SUCCESS" ; \ fi # Assume revisions are sorted in the file, from newest to oldest # FIXME: If we ever get more than one file to chomp this way, make it a snippet docinfo-since-v2.8.3.xml: docinfo.xml @OLDEST_REL="2.8.3"; \ IN_REVISION=false ; OLDEST_SEEN=false ; \ while read LINE ; do \ case "$${LINE}" in \ *''*) if ! $$OLDEST_SEEN ; then IN_REVISION=true ; fi ;; \ *''"$${OLDEST_REL}"''*) if $$IN_REVISION ; then echo ''; OLDEST_SEEN=true ; fi ; echo "$$LINE" ;; \ *''*''*) if ! $$OLDEST_SEEN ; then if $$IN_REVISION ; then echo ''; fi ; echo "$$LINE" ; fi ;; \ *''*) if $$IN_REVISION ; then echo "$$LINE" ; fi ; IN_REVISION=false ;; \ *''*) echo "$$LINE" ;; \ *) if ! $$OLDEST_SEEN || $$IN_REVISION ; then echo "$$LINE" ; fi ;; \ esac ; \ done < "$?" > "$@".tmp \ && mv -f "$@".tmp "$@" # Some versions of asciidoc ignore the argument of :docinfo: tag # and require (TXT_BASE_NAME)-docinfo.xml to exist: qa-guide-docinfo.xml: docinfo-since-v2.8.3.xml @rm -f '$@' || true @$(LN_S) '$?' '$@' ### Call the prep step consistently to create symlinks (out-of-tree) ### or just touch-files for peace of mind (in-tree builds). Then we ### use these path names (truncated "-prepped") now surely located ### in the builddir as the sources for rendered docs. *.txt-prepped *.adoc-prepped: $(abs_top_builddir)/docs/.prep-src-docs *.html: common.xsl xhtml.xsl .txt-prepped.html: +@$(GENERATE_HTML_SINGLE) .adoc-prepped.html: +@$(GENERATE_HTML_SINGLE) *.chunked: common.xsl chunked.xsl .txt-prepped.chunked: @$(GENERATE_HTML_CHUNKED) .adoc-prepped.chunked: @$(GENERATE_HTML_CHUNKED) *.pdf: docinfo.xml # Technically only needed for PDF generation, but some other recipes still complained qa-guide.adoc-prepped \ qa-guide.pdf: docinfo-since-v2.8.3.xml qa-guide-docinfo.xml .txt-prepped.pdf: @$(GENERATE_PDF) .adoc-prepped.pdf: @$(GENERATE_PDF) #SPELLCHECK_RECIPE_DEBUG_STREAM = &2 # Note: if we do an interactive spell-check, it updates "nut.dict" # timestamp even if contents remain. If the caller left a copy of # the file as "$(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting", # and/or "$(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive", # and the dictionary was NOT in fact modified, restore the timestamp. @HAVE_ASPELL_TRUE@$(SPELLCHECK_BUILDDIR)/$(SPELLCHECK_SRC_ONE)-spellchecked: $(SPELLCHECK_SRCDIR)/$(SPELLCHECK_SRC_ONE) $(abs_top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @HAVE_ASPELL_TRUE@ @LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ @HAVE_ASPELL_TRUE@ if test x"$(SPELLCHECK_SRC_ONE)" = x ; then echo " SKIP Bogus spellcheck call for empty target filename (with make target $@ from `pwd`)" >&2 ; exit 0; fi; \ @HAVE_ASPELL_TRUE@ case "$@" in *-spellchecked) ;; *) echo " SKIP Bogus spellcheck call for non '*-spellchecked' target filename (with make target $@ from `pwd`)" >&2 ; exit 0;; esac; \ @HAVE_ASPELL_TRUE@ rm -f "$@" || true ; \ @HAVE_ASPELL_TRUE@ $(MKDIR_P) "$(@D)" || exit ; \ @HAVE_ASPELL_TRUE@ REPORT_SRCDIR="$(SPELLCHECK_SRCDIR)"; \ @HAVE_ASPELL_TRUE@ REPORT_SRC_ONE="$(SPELLCHECK_SRC_ONE)"; \ @HAVE_ASPELL_TRUE@ REPORT_PREFIX="" ; \ @HAVE_ASPELL_TRUE@ case "$(SPELLCHECK_SRC_ONE)" in \ @HAVE_ASPELL_TRUE@ /*) ;; \ @HAVE_ASPELL_TRUE@ */*) if [ x"$${REPORT_SRCDIR}" = x ] ; then \ @HAVE_ASPELL_TRUE@ echo EMPTY >$(SPELLCHECK_RECIPE_DEBUG_STREAM) ; \ @HAVE_ASPELL_TRUE@ REPORT_SRCDIR="`dirname '$(SPELLCHECK_SRC_ONE)'`"; \ @HAVE_ASPELL_TRUE@ else \ @HAVE_ASPELL_TRUE@ echo "APPEND: SPELLCHECK_SRCDIR='$(SPELLCHECK_SRCDIR)' SPELLCHECK_SRC_ONE='$(SPELLCHECK_SRC_ONE)' dirname='`dirname '$(SPELLCHECK_SRC_ONE)'`'" >$(SPELLCHECK_RECIPE_DEBUG_STREAM) ; \ @HAVE_ASPELL_TRUE@ REPORT_SRCDIR="$${REPORT_SRCDIR}/`dirname '$(SPELLCHECK_SRC_ONE)'`"; \ @HAVE_ASPELL_TRUE@ fi ; \ @HAVE_ASPELL_TRUE@ REPORT_SRC_ONE="`basename '$(SPELLCHECK_SRC_ONE)'`"; \ @HAVE_ASPELL_TRUE@ ;; \ @HAVE_ASPELL_TRUE@ *) ;; \ @HAVE_ASPELL_TRUE@ esac; \ @HAVE_ASPELL_TRUE@ if [ x"$${REPORT_SRCDIR}" != x ] ; then \ @HAVE_ASPELL_TRUE@ tmpREPORT_PREFIX="NUT source root :: $${REPORT_SRCDIR} :: " ; \ @HAVE_ASPELL_TRUE@ REPORT_SRCDIR="`cd "$${REPORT_SRCDIR}" && { pwd >$(SPELLCHECK_RECIPE_DEBUG_STREAM) ; pwd | sed 's|^'"$(abs_top_srcdir)"'/*||' ; }`" \ @HAVE_ASPELL_TRUE@ || { REPORT_SRCDIR="$(SPELLCHECK_SRCDIR)" ; REPORT_SRC_ONE="$(SPELLCHECK_SRC_ONE)" ; REPORT_PREFIX="" ; } ; \ @HAVE_ASPELL_TRUE@ fi ; \ @HAVE_ASPELL_TRUE@ echo "=== Got REPORT_SRCDIR='$${REPORT_SRCDIR}'" >$(SPELLCHECK_RECIPE_DEBUG_STREAM) ; \ @HAVE_ASPELL_TRUE@ case "$${REPORT_SRCDIR}" in \ @HAVE_ASPELL_TRUE@ "") ;; \ @HAVE_ASPELL_TRUE@ */) ;; \ @HAVE_ASPELL_TRUE@ *) REPORT_SRCDIR="$${REPORT_SRCDIR}/" ;; \ @HAVE_ASPELL_TRUE@ esac ; \ @HAVE_ASPELL_TRUE@ if [ x"$(SPELLCHECK_INTERACTIVE)" = xtrue ] ; then \ @HAVE_ASPELL_TRUE@ echo " ASPELL Spell checking (interactively) on $${REPORT_PREFIX}$${REPORT_SRCDIR}$${REPORT_SRC_ONE}"; \ @HAVE_ASPELL_TRUE@ LANG=$(ASPELL_ENV_LANG) LC_ALL=$(ASPELL_ENV_LANG) $(ASPELL) check $(ASPELL_NUT_COMMON_ARGS) '$(SPELLCHECK_SRCDIR)/$(SPELLCHECK_SRC_ONE)' || exit ; \ @HAVE_ASPELL_TRUE@ if [ -s $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive ] && [ -s $(abs_srcdir)/$(NUT_SPELL_DICT) ] && diff $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive >/dev/null ; then \ @HAVE_ASPELL_TRUE@ touch -r $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive $(abs_srcdir)/$(NUT_SPELL_DICT) ; \ @HAVE_ASPELL_TRUE@ else \ @HAVE_ASPELL_TRUE@ if [ -s $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting ] && [ -s $(abs_srcdir)/$(NUT_SPELL_DICT) ] && diff $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting >/dev/null ; then \ @HAVE_ASPELL_TRUE@ touch -r $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting $(abs_srcdir)/$(NUT_SPELL_DICT) ; \ @HAVE_ASPELL_TRUE@ fi ; fi ; \ @HAVE_ASPELL_TRUE@ else \ @HAVE_ASPELL_TRUE@ echo " ASPELL Spell checking on $${REPORT_PREFIX}$${REPORT_SRCDIR}$${REPORT_SRC_ONE}"; \ @HAVE_ASPELL_TRUE@ fi ; \ @HAVE_ASPELL_TRUE@ OUT="`(sed 's,^\(.*\)$$, \1,' | $(ASPELL) -a $(ASPELL_NUT_TEXMODE_ARGS) $(ASPELL_NUT_COMMON_ARGS) 2>&1) < '$(SPELLCHECK_SRCDIR)/$(SPELLCHECK_SRC_ONE)'`" \ @HAVE_ASPELL_TRUE@ && { if test -n "$$OUT" ; then OUT="`echo "$$OUT" | $(EGREP) -b -v '$(ASPELL_OUT_NOTERRORS)' `" ; fi; \ @HAVE_ASPELL_TRUE@ test -z "$$OUT" ; } \ @HAVE_ASPELL_TRUE@ || { RES=$$? ; \ @HAVE_ASPELL_TRUE@ echo "FAILED : Aspell reported errors here:" >&2 \ @HAVE_ASPELL_TRUE@ && echo "----- vvv" >&2 \ @HAVE_ASPELL_TRUE@ && echo "$$OUT" >&2 \ @HAVE_ASPELL_TRUE@ && echo "----- ^^^" >&2 ; \ @HAVE_ASPELL_TRUE@ exit $$RES; } ; \ @HAVE_ASPELL_TRUE@ touch "$@" @HAVE_ASPELL_TRUE@.txt.txt-spellchecked-auto: @HAVE_ASPELL_TRUE@ +@$(SPELLCHECK_AUTO_ONE) @HAVE_ASPELL_TRUE@.adoc.adoc-spellchecked-auto: @HAVE_ASPELL_TRUE@ +@$(SPELLCHECK_AUTO_ONE) @HAVE_ASPELL_TRUE@.in.in-spellchecked-auto: @HAVE_ASPELL_TRUE@ +@$(SPELLCHECK_AUTO_ONE) @HAVE_ASPELL_TRUE@.sample.sample-spellchecked-auto: @HAVE_ASPELL_TRUE@ +@$(SPELLCHECK_AUTO_ONE) @HAVE_ASPELL_TRUE@.conf.conf-spellchecked-auto: @HAVE_ASPELL_TRUE@ +@$(SPELLCHECK_AUTO_ONE) @HAVE_ASPELL_TRUE@spellcheck: @HAVE_ASPELL_TRUE@ @if test "$(SPELLCHECK_ENV_DEBUG)" = detailed ; then \ @HAVE_ASPELL_TRUE@ echo "ASPELL DEBUG : information about the setup follows:"; \ @HAVE_ASPELL_TRUE@ LANG=$(ASPELL_ENV_LANG); LC_ALL=$(ASPELL_ENV_LANG); export LANG; export LC_ALL; \ @HAVE_ASPELL_TRUE@ $(ASPELL) --help || true; \ @HAVE_ASPELL_TRUE@ (command -v dpkg) && ( dpkg -l | grep -i aspell ) || true ; \ @HAVE_ASPELL_TRUE@ echo "ASPELL automatic execution line is : ( sed 's,^\(.*\)$$, \1,' < docfile.txt | $(ASPELL) -a $(ASPELL_NUT_TEXMODE_ARGS) $(ASPELL_NUT_COMMON_ARGS) | $(EGREP) -b -v '$(ASPELL_OUT_NOTERRORS)' )" ; \ @HAVE_ASPELL_TRUE@ echo "ASPELL proceeding to spellchecking job..."; \ @HAVE_ASPELL_TRUE@ else true; fi @HAVE_ASPELL_TRUE@ +@FAILED="" ; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ @HAVE_ASPELL_TRUE@ if [ x"$(NUT_MAKE_SKIP_FANOUT)" = xtrue ] ; then \ @HAVE_ASPELL_TRUE@ for docsrc in $(SPELLCHECK_SRC); do \ @HAVE_ASPELL_TRUE@ if test "$(SPELLCHECK_ENV_DEBUG)" != no ; then \ @HAVE_ASPELL_TRUE@ echo "ASPELL MAKEFILE DEBUG: Will see from `pwd` if '$(SPELLCHECK_SRCDIR)/$${docsrc}-spellchecked' is up to date" >&2; \ @HAVE_ASPELL_TRUE@ else true ; fi ; \ @HAVE_ASPELL_TRUE@ $(MAKE) $(AM_MAKEFLAGS) -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_SRC="" SPELLCHECK_SRC_ONE="$${docsrc}" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" \ @HAVE_ASPELL_TRUE@ || FAILED="$$FAILED $(SPELLCHECK_SRCDIR)/$$docsrc"; \ @HAVE_ASPELL_TRUE@ done ; \ @HAVE_ASPELL_TRUE@ else \ @HAVE_ASPELL_TRUE@ SPELLCHECK_AUTO_TGT="`for docsrc in $(SPELLCHECK_SRC); do case "$${docsrc}" in */*) ;; *.adoc|*.txt|*.in|*.conf|*.sample) printf '%s ' "$${docsrc}-spellchecked-auto" ;; esac ; done`" ; \ @HAVE_ASPELL_TRUE@ SPELLCHECK_NOEXT_DOCS="`for docsrc in $(SPELLCHECK_SRC); do case "$${docsrc}" in */*) printf '%s ' "$${docsrc}" ;; *.adoc|*.txt|*.in|*.conf|*.sample) ;; *) printf '%s ' "$${docsrc}" ;; esac ; done`" ; \ @HAVE_ASPELL_TRUE@ if test "$(SPELLCHECK_ENV_DEBUG)" != no ; then \ @HAVE_ASPELL_TRUE@ echo "ASPELL MAKEFILE DEBUG: from `pwd`: SPELLCHECK_NOEXT_DOCS='$${SPELLCHECK_NOEXT_DOCS}' SPELLCHECK_AUTO_TGT='$${SPELLCHECK_AUTO_TGT}'" ; \ @HAVE_ASPELL_TRUE@ else true ; fi ; \ @HAVE_ASPELL_TRUE@ if [ x"$${SPELLCHECK_AUTO_TGT}" != x ] ; then \ @HAVE_ASPELL_TRUE@ $(MAKE) $(AM_MAKEFLAGS) -k -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_SRC="" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" $${SPELLCHECK_AUTO_TGT} ; \ @HAVE_ASPELL_TRUE@ FAILED="`for docsrc in $(SPELLCHECK_SRC); do if [ -e "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked-auto.failed" ] ; then printf '%s ' "$(SPELLCHECK_SRCDIR)/$${docsrc}" ; rm -f "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked-auto.failed" ; fi ; done`" ; \ @HAVE_ASPELL_TRUE@ fi ; \ @HAVE_ASPELL_TRUE@ if [ x"$${SPELLCHECK_NOEXT_DOCS}" != x ] ; then \ @HAVE_ASPELL_TRUE@ for docsrc in $${SPELLCHECK_NOEXT_DOCS} ; do \ @HAVE_ASPELL_TRUE@ $(MAKE) $(AM_MAKEFLAGS) -k -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_SRC="" SPELLCHECK_SRC_ONE="$${docsrc}" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" \ @HAVE_ASPELL_TRUE@ || FAILED="$$FAILED $(SPELLCHECK_SRCDIR)/$$docsrc"; \ @HAVE_ASPELL_TRUE@ done ; \ @HAVE_ASPELL_TRUE@ fi ; \ @HAVE_ASPELL_TRUE@ fi ; \ @HAVE_ASPELL_TRUE@ if test -n "$$FAILED" ; then \ @HAVE_ASPELL_TRUE@ echo "=====================================================================" ; \ @HAVE_ASPELL_TRUE@ echo "FAILED automatic spellcheck for the following sources (relative to `pwd`) using custom dictionary file '$(NUT_SPELL_DICT)': $$FAILED" ; \ @HAVE_ASPELL_TRUE@ echo "=====================================================================" ; \ @HAVE_ASPELL_TRUE@ echo "Please 'cd $(abs_top_builddir) && make spellcheck-interactive'"; \ @HAVE_ASPELL_TRUE@ echo "to either fix document sources or update the dictionary of accepted"; \ @HAVE_ASPELL_TRUE@ echo "words and spellings listed in the '$(NUT_SPELL_DICT)' file there."; \ @HAVE_ASPELL_TRUE@ echo "Either way, please follow up by posting a pull request or a patch"; \ @HAVE_ASPELL_TRUE@ echo "to integrate your fixes into the common NUT codebase."; \ @HAVE_ASPELL_TRUE@ echo "=====================================================================" ; \ @HAVE_ASPELL_TRUE@ test x"$(SPELLCHECK_ERROR_FATAL)" = xno || exit 1; \ @HAVE_ASPELL_TRUE@ echo "NOTE: SPELLCHECK_ERROR_FATAL == no so this make does not break the build!"; \ @HAVE_ASPELL_TRUE@ echo "=====================================================================" ; \ @HAVE_ASPELL_TRUE@ fi >&2 ; exit 0 # Interactively spell check all documentation source files below (so a human # can edit the documentation errors and/or add words to custom dictionary). # Note that here we do not restrain reported issues, so this might catch more # than the automated test above. @HAVE_ASPELL_TRUE@spellcheck-sortdict: $(abs_builddir)/$(NUT_SPELL_DICT).sorted # Note that the source file may be not overwritable (distcheck, cdrom, ...), # so we'd ignore that failure. But the practical use-case is a developer's # in-tree workspace, so we want the working copy of the dictionary fixed up # for easy `git diff`ing if possible. # Note also that "$( "$@" @HAVE_ASPELL_TRUE@ @cp -f "$@" "$(abs_builddir)/$(NUT_SPELL_DICT)" @HAVE_ASPELL_TRUE@ @if [ "$(abs_builddir)" != "$(abs_srcdir)" ] ; then \ @HAVE_ASPELL_TRUE@ cp -f "$@" "$?" || true ; \ @HAVE_ASPELL_TRUE@ cp -f "$(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting" "$(abs_srcdir)/" || true ; \ @HAVE_ASPELL_TRUE@ fi @HAVE_ASPELL_TRUE@spellcheck-interactive: @HAVE_ASPELL_TRUE@ @cp -pf $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive @HAVE_ASPELL_TRUE@ +@FAILED="" ; for docsrc in $(SPELLCHECK_SRC); do \ @HAVE_ASPELL_TRUE@ if test "$(SPELLCHECK_ENV_DEBUG)" != no ; then \ @HAVE_ASPELL_TRUE@ echo "ASPELL (INTERACTIVE) MAKEFILE DEBUG: Will see from `pwd` if '$(SPELLCHECK_SRCDIR)/$${docsrc}-spellchecked' is up to date" >&2; \ @HAVE_ASPELL_TRUE@ else true ; fi ; \ @HAVE_ASPELL_TRUE@ $(MAKE) $(AM_MAKEFLAGS) -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_INTERACTIVE="true" SPELLCHECK_SRC="" SPELLCHECK_SRC_ONE="$${docsrc}" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" \ @HAVE_ASPELL_TRUE@ || FAILED="$$FAILED $(SPELLCHECK_SRCDIR)/$$docsrc"; \ @HAVE_ASPELL_TRUE@ done ; \ @HAVE_ASPELL_TRUE@ if test -n "$$FAILED" ; then \ @HAVE_ASPELL_TRUE@ echo "FAILED interactive spellcheck for the following sources (relative to `pwd`) using custom dictionary file '$(NUT_SPELL_DICT)': $$FAILED" >&2 ; \ @HAVE_ASPELL_TRUE@ exit 1; \ @HAVE_ASPELL_TRUE@ fi ; \ @HAVE_ASPELL_TRUE@ $(MAKE) $(AM_MAKEFLAGS) spellcheck-sortdict || exit ; \ @HAVE_ASPELL_TRUE@ for docsrc in $(SPELLCHECK_SRC); do \ @HAVE_ASPELL_TRUE@ if test -e "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" ; then \ @HAVE_ASPELL_TRUE@ touch "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" ; \ @HAVE_ASPELL_TRUE@ fi ; \ @HAVE_ASPELL_TRUE@ done @HAVE_ASPELL_TRUE@ @if [ "$(SPELLCHECK_REPORT_MAYBE_UPDATED_DICT)" != no ] \ @HAVE_ASPELL_TRUE@ || ( [ -s $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive ] && [ -s $(abs_srcdir)/$(NUT_SPELL_DICT) ] \ @HAVE_ASPELL_TRUE@ && ! diff $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive >/dev/null ) \ @HAVE_ASPELL_TRUE@ ; then \ @HAVE_ASPELL_TRUE@ echo "------------------------------------------------------------------------"; \ @HAVE_ASPELL_TRUE@ echo "Custom dictionary file $(NUT_SPELL_DICT) may have been updated now."; \ @HAVE_ASPELL_TRUE@ echo "Use e.g. 'git add -p docs/$(NUT_SPELL_DICT) && git checkout -- docs/$(NUT_SPELL_DICT) && make spellcheck-sortdict && git add -p docs/$(NUT_SPELL_DICT)'"; \ @HAVE_ASPELL_TRUE@ echo "to review changes (please DO NOT REMOVE LINES that aspell chose to drop,"; \ @HAVE_ASPELL_TRUE@ echo "because other systems might not know these words in their system dictionaries)"; \ @HAVE_ASPELL_TRUE@ echo "------------------------------------------------------------------------" ; \ @HAVE_ASPELL_TRUE@ fi # This rule would probably just fail; normally with no ASPELL there are no callers for it @HAVE_ASPELL_FALSE@*/*-spellchecked *-spellchecked: Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @HAVE_ASPELL_FALSE@ @echo " SKIP-ASPELL $@ : Documentation spell check not available since 'aspell' was not found (or missing its English dictionary)." >&2 @HAVE_ASPELL_FALSE@spellcheck: @HAVE_ASPELL_FALSE@ @echo "Documentation spell check not available since 'aspell' was not found (or missing its English dictionary)." @HAVE_ASPELL_FALSE@spellcheck-interactive: @HAVE_ASPELL_FALSE@ @echo "Documentation spell check not available since 'aspell' was not found (or missing its English dictionary)." # Note that NUT_SPELL_DICT may be an include snippet without the header line. # To exclude files like `docs/nut.dict` or `nut-website.dict(.addons)` from # the usage lookups, we assume that a `*.dict*` pattern fits any used names. # Entries prefixed with '+++' mean something used in NUT sources in context # that aspell is likely to treat as a word (standalone or surrounded by certain # chars); otherwise in entries prefixed with '---' we print hit counts and # contents (if any, ending with '^^^') for the character pattern across the # whole Git-tracked codebase (case-insensitively for good measure). # Note this can take 5-10 minutes! # TOTHINK: Constrain to (caller-specified or default) SPELLCHECK_SRC? $(NUT_SPELL_DICT).usage-report: $(NUT_SPELL_DICT) @echo "Preparing $@"; \ LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ grep -v -E '^personal_ws' < $? \ | while read W ; do ( \ cd "$(abs_top_srcdir)" || exit ; \ git grep -q "$$W" -- ':!*.dict*' || git grep -qE "[0-9_,./\ -]$$W[0-9_,./\ -]" -- ':!*.dict*' ) \ && echo "+++ $$W" \ || ( \ HITS_CS="`git grep "$$W" -- ':!*.dict*'`" || true; \ HITS_CI="`git grep -i "$$W" -- ':!*.dict*'`" || true; \ if [ -n "$$HITS_CS" ] ; then HITC_CS="`echo "$$HITS_CS" | wc -l`" ; else HITC_CS=0; fi; \ if [ -n "$$HITS_CI" ] ; then HITC_CI="`echo "$$HITS_CI" | wc -l`" ; else HITC_CI=0; fi; \ printf '%s (%d case-sensitive/%d case-insensitive)\n' "--- $$W" "$$HITC_CS" "$$HITC_CI"; \ if [ "$$HITC_CS" != 0 ] ; then echo "$$HITS_CS" ; echo "^^^"; else \ if [ "$$HITC_CI" != 0 ] ; then echo "$$HITS_CI" ; echo "^^^"; fi; \ fi; \ ); \ done > "$@.tmp.$$$$" \ && test -f "$@.tmp.$$$$" \ && mv -f "$@.tmp.$$$$" "$@" @echo "Reporting words from $? possibly not used in current inspected code base revision under $(abs_top_srcdir)" >&2 ; \ grep -E '^--- ' < "$@" | grep '(0 ' || echo "SUCCESS: None found" # NOTE: Some "make" implementations prefix a relative or absent path to # the filenames in PREP_SRC, others (e.g. Sun make) prepend the absolute # path to locate the sources, so we end up with bogus trees under docs/. # Code below tries to detect and truncate this mess, including possible # source texts located in/under parent dirs. # We also handle man page links (section-aware) for platforms where they # differ from common defaults. # NOTE: MKDIR_P may be defined via expanded $(top_builddir)/install-sh # so should be run from $(abs_builddir) to be safe, as we jump around # the build workspace prep-src-docs: $(abs_top_builddir)/docs/.prep-src-docs $(abs_top_builddir)/docs/.prep-src-docs: $(PREP_SRC) Makefile @cd "$(@D)" || exit ; \ linkroot="$(abs_builddir)" ; \ MAN_SECTIONS_DEFAULT=false ; \ if [ x"$(MAN_SECTION_API)$(MAN_SECTION_CFG)$(MAN_SECTION_CMD_SYS)$(MAN_SECTION_CMD_USR)" = x3581 ] ; then \ MAN_SECTIONS_DEFAULT=true ; \ fi ; \ if test x"$(abs_srcdir)" = x"$(abs_builddir)" ; then \ COUNT=0; \ for F in $(PREP_SRC) ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed 's#^$(abs_top_srcdir)/*#./#'`"; \ if test x"$${linkroot}" = x"$(abs_builddir)" ; then \ linkroot="$(abs_top_builddir)" ; \ cd "$(abs_top_builddir)" ; \ fi ;; \ esac ; \ if $$MAN_SECTIONS_DEFAULT ; then \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' ; \ else \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' \ -e 's,\(linkman:[^ []*\[\)3\],\1$(MAN_SECTION_API)],g' \ -e 's,\(linkman:[^ []*\[\)5\],\1$(MAN_SECTION_CFG)],g' \ -e 's,\(linkman:[^ []*\[\)8\],\1$(MAN_SECTION_CMD_SYS)],g' \ -e 's,\(linkman:[^ []*\[\)1\],\1$(MAN_SECTION_CMD_USR)],g' ; \ fi < "$${F}" > "$${F}-prepped" || exit ; \ COUNT="`expr $$COUNT + 1`" ; \ done ; \ if ! test -e "$@" ; then touch "$@" ; fi ; \ else \ COUNT=30 ; \ touch "$@.$$$$" ; \ while test -e "$@.working" -a "$$COUNT" -gt 0 ; do sleep 1; COUNT="`expr $$COUNT - 1`"; done ; \ touch "$@.working" ; \ if test -n "`find "$@" -newer "$@.$$$$" 2>/dev/null`" ; then \ rm -f "$@.$$$$" "$@.working" ; \ exit 0; \ fi ; \ rm -f "$@.$$$$" ; \ COUNT=0; \ linksrcroot="$(abs_srcdir)" ; \ for F in `echo $(PREP_SRC) | tr ' ' '\n' | sort -n | uniq` ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed 's#^$(abs_top_srcdir)/*#./#'`"; \ if test x"$${linkroot}" = x"$(abs_builddir)" ; then \ linkroot="$(abs_top_builddir)" ; \ linksrcroot="$(abs_top_srcdir)" ; \ cd "$(abs_top_builddir)" ; \ fi ;; \ "$(srcdir)"/*) F="`echo "$$F" | sed 's#^$(srcdir)/*#./#'`" ;; \ */*) ;; \ *) \ linkroot="$(abs_builddir)" ; \ linksrcroot="$(abs_srcdir)" ; \ cd "$(abs_top_builddir)" ;; \ esac ; \ D="`dirname "$$F"`" ; \ (cd '$(abs_builddir)' && $(MKDIR_P) "$${linkroot}/$$D") || { rm -f "$@.working" ; exit 1 ; } ; \ if ! test -s "$${linkroot}/$$F" && test -s "$${linksrcroot}/$$F" ; then \ echo " LN '$${linksrcroot}/$$F' => '$${linkroot}/$$F' (PWD = '`pwd`')" ; \ ln -fs "$${linksrcroot}/$$F" "$${linkroot}/$$F" || { rm -f "$@.working" ; exit 1 ; } ; \ COUNT="`expr $$COUNT + 1`" ; \ fi ; \ case "$$F" in \ *.txt|*.adoc) IS_TEXT=true ;; \ *.*) IS_TEXT=false ;; \ *) IS_TEXT=true ;; \ esac; \ if $$IS_TEXT ; then \ grep -w linkman "$${linkroot}/$${F}" > /dev/null || IS_TEXT=false ; \ fi ; \ if $$MAN_SECTIONS_DEFAULT || ! $$IS_TEXT ; then \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' ; \ else \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' \ -e 's,\(linkman:[^ []*\[\)3\],\1$(MAN_SECTION_API)],g' \ -e 's,\(linkman:[^ []*\[\)5\],\1$(MAN_SECTION_CFG)],g' \ -e 's,\(linkman:[^ []*\[\)8\],\1$(MAN_SECTION_CMD_SYS)],g' \ -e 's,\(linkman:[^ []*\[\)1\],\1$(MAN_SECTION_CMD_USR)],g' ; \ fi < "$${linkroot}/$${F}" > "$${linkroot}/$${F}-prepped" \ || { rm -f "$@.working" ; exit 1 ; } ; \ COUNT="`expr $$COUNT + 1`" ; \ done ; \ fi ; \ if test "$$COUNT" -gt 0 -o ! -e "$@" ; then touch "$@" ; fi @rm -f "$@.working" # Dirs to clean, etc. clean-local: $(AM_V_at)rm -rf *.chunked *.bak tmp $(AM_V_at)for F in $(PREP_SRC) ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed 's#^$(abs_top_srcdir)/*#./#'`"; cd "$(abs_top_builddir)" ;; \ esac ; \ if test x"$(abs_srcdir)" != x"$(abs_builddir)" ; then \ if test -L "$$F" || test -h "$$F" ; then \ rm -f "$$F" ; \ fi ; \ fi ; \ rm -f "$${F}-prepped" ; \ done ; \ rm -f "$(abs_top_builddir)/docs/.prep-src-docs"* .PHONY: html html-chunked html-single pdf man # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/docs/docinfo.xml.in0000644000200500020050000001500714777767434012774 00000000000000 2.8.3 2025-04-07 JK Some changes to docs and recipes, libusbclient API and functionality. Updated NUT SEMVER definition and added scripting around it. Groundwork for vendor-defined status and INSTCMD buzzwords like "ECO". Fixed some regressions and added improvements for certain new device series. 2.8.2 2024-04-01 JK Some changes to docs and recipes, libnutscan API and functionality. Added nutconf (library and tool). Fixed some regressions and added improvements for certain new device series. 2.8.1 2023-10-31 JK Some changes to API, docs and recipes, in particular to simplify local builds and tests (e.g. to help end-users check if current NUT codebase trunk has already fixed an issue they see with a packaged installation). Revived NUT for Windows effort, further improved other OS integrations. NUT became reference for "UPS management protocol", Informational RFC 9271. Documentation files refactored to ease maintenance. More drivers and new driver categories introduced. 2.8.0 2022-04-26 JK Change of maintainer. Many changes to API, docs (both style and content), and recipes, with a stress on non-regression test-ability, run-time debug-ability, general codebase maintainability, as well as OS integrations (notably nut-driver-enumerator for systemd and SMF service instance maintenance). Added a lot in area of CI support and documented pre-requisite package lists for numerous platforms, and CI agent set-up. Added libusb-1.x support and many new driver categories (and drivers), and daisychain device connection support. Instant commands enhanced with TRACKING to enable protocol-based waiting for completion of a particular INSTCMD or SET operation. 2.7.4 2016-03-09 AQ NUT variables namespace updated, in particular for outlet groups, alarms and thresholds, ATS devices, and battery.charger.status to supersede CHRG and DISCHRG flags published in ups.status readings. NUT network protocol extended with NUMBER type; some API changes. 2.7.3 2015-04-22 AQ Documentation revised, including some API changes. Added NUT DDL links. NUT variables namespace updated. 2.7.2 2014-04-17 AQ The nut-website project was offloaded into a separate repository. FreeDesktop HAL support was removed (obsoleted in GNOME consumer). Introduced nutdrv_atcl_usb driver. 2.7.1 2013-11-19 CL NUT source codebase migrated from SVN to Git (and from Debian infrastructure to GitHub source code hosting). jNut binding split into a separate project. Introduced libnutclient (C++ binding), al175, apcupsd-ups and nutdrv_qx drivers, Mozilla NSS support for simpler licensing than OpenSSL, and a newer apcsmart implementation. Documentation support enhanced with a spell checker, contents massively updated to reflect project changes. 2.6.5 2012-08-08 AQ New macosx-ups driver, new implementation of mge-shut driver. NUT variables namespace updated. Docs cleaned up and revised. 2.6.4 2012-05-31 AQ New NUT network protocol commands (LIST CLIENTS, LIST RANGE and NETVER), and socket protocol commands (ADDRANGE, DELRANGE). NUT variables namespace updated. Introduced nut-recorder tool. 2.6.3 2012-01-04 AQ No substantial changes to documentation. 2.6.2 2011-09-15 AQ Introduced nut-scanner tool and nut-ipmipsu driver, systemd support, and a new apcsmart implementation. 2.6.1 2011-06-01 AQ Introduced default.* and override.* optional settings in ups.conf, an ups.efficiency report, and outlet.0 special handling. 2.6.0 2011-01-14 AQ First release of AsciiDoc documentation for Network UPS Tools (NUT). nut-2.8.3/docs/man/0000755000200500020050000000000015001555412011020 500000000000000nut-2.8.3/docs/man/nutscan_add_option_to_device.txt0000644000200500020050000000531315001555412017377 00000000000000NUTSCAN_ADD_OPTION_TO_DEVICE(3) =============================== NAME ---- nutscan_add_option_to_device, nutscan_add_commented_option_to_device - Add option data to the specified device. SYNOPSIS -------- ------ #include /* Add enabled option data to the specified device. */ void nutscan_add_option_to_device( nutscan_device_t * device, char * option_name, char * value); /* Since libnutscan version 2.5.0: * Add option data to the specified device with an optional comment tag * for options suggested, but not currently enabled for actual use. */ void nutscan_add_commented_option_to_device( nutscan_device_t * device, char * option_name, char * value, char * comment_tag); ------ DESCRIPTION ----------- The `nutscan_device_t` contains the following variables: nutscan_device_type_t type; char * driver; char * alt_driver_names; char * port; nutscan_options_t opt; struct nutscan_device * prev; struct nutscan_device * next; This is a double linked list of devices. Each 'device' is described by its `type`, its `driver` name, its `port` and any number of optional data. The *nutscan_add_option_to_device()* adds an optional data in the given 'device'. Optional data are made of an 'option_name' and an associated 'value', and optionally a 'comment_tag'. Copies of the 'option_name', 'value' and 'comment_tag' are stored in the 'device', so the caller can safely linkmanext:free[3] all of the original strings used as arguments. NOTE: A non-`NULL` value of the 'comment_tag' makes the option not-enabled for current use. Depending on the output format, it may be either completely ignored, or rendered as a comment with this value as a prefix (a zero-length string `"\0"` may be passed to have no prefix). Such options and their values may be further sanity-checked and reported as warnings by *nutscan_display_sanity_check()* dispatcher and its related methods which implement the logic of particular checks. This is used for example when generating an `ups.conf` file content suggestions with *nutscan_display_ups_conf_with_sanity_check()* method. NOTES ----- Technically, the function is currently defined in 'nutscan-device.h' file. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_device_to_device[3] nut-2.8.3/docs/man/upsd.80000644000200500020050000004166315001555047012022 00000000000000'\" t .\" Title: upsd .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSD" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsd \- Network UPS Tools data server .SH "SYNOPSIS" .sp \fBupsd\fR \-h .sp \fBupsd\fR [\fIOPTIONS\fR] .SH "DESCRIPTION" .sp \fBupsd\fR is responsible for serving the data from the drivers to the clients\&. It connects to each driver and maintains a local cache of the current state\&. Queries from the clients are served from this cache, so delays are minimal\&. .sp It also conveys administrative messages from the clients back to the drivers, such as starting tests, or setting values\&. .sp Communication between \fBupsd\fR and clients is handled on a TCP port\&. Configuration details for this port are described in \fBupsd.conf\fR(8)\&. .sp This program is essential, and must be running at all times to actually make any use out of the drivers and clients (except for final UPS power\-off commands just before your server goes down, which NUT driver programs can do alone when called as drivername \-k in a shutdown hook or late ordered SysV init script)\&. .sp Controls in the configuration files allow you to limit access to the server, but you should also use a firewall for extra protection\&. Client processes such as \fBupsmon\fR(8) trust \fBupsd\fR for status information about the UPS hardware, so keep it secure\&. .SH "OPTIONS" .PP \fB\-c\fR \fIcommand\fR .RS 4 Send \fIcommand\fR to the background process as a signal\&. Valid commands are: .PP \fBreload\fR .RS 4 reread configuration files .RE .PP \fBstop\fR .RS 4 stop process and exit .RE .RE .PP \fB\-P\fR \fIpid\fR .RS 4 Send the command signal above using specified PID number, rather than consulting the PID file\&. This can help define service units which start upsd as a foreground process so it does not create a PID file\&. See also \-FF option as an alternative\&. .RE .PP \fB\-D\fR .RS 4 Raise the debugging level\&. upsd will run in the foreground by default, and will print information on stdout about the monitoring process\&. Use this option multiple times for more details\&. .RE .PP \fB\-F\fR .RS 4 upsd will run in the foreground, regardless of debugging settings\&. Specify twice (\-FF or \-F \-F) to save the PID file even in this mode\&. .RE .PP \fB\-B\fR .RS 4 upsd will run in the background, regardless of debugging settings\&. .RE .PP \fB\-h\fR .RS 4 Display the help text\&. .RE .PP \fB\-r\fR \fIdirectory\fR .RS 4 upsd will \fBchroot\fR(2) to \fIdirectory\fR shortly after startup and before parsing any configuration files with this option set\&. You can use this to create a "jail" for greater security\&. .sp You must coordinate this with your drivers, as upsd must be able to find the state path within \fIdirectory\fR\&. See \fBupsdrvctl\fR(8) and \fBnutupsdrv\fR(8)\&. .RE .PP \fB\-u\fR \fIuser\fR .RS 4 Switch to user \fIuser\fR after startup if started as root\&. This overrides whatever you may have compiled in with configure \-\-with\-user\&. .RE .PP \fB\-V\fR .RS 4 Display the version of the program\&. .RE .SH "RELOADING" .sp upsd can reload its configuration files without shutting down the process if you send it a SIGHUP or start it again with \-c reload\&. This only works if the background process is able to read those files (permissions, chroot jail), and if the daemon did save a PID file when it started (for the reload command to find the older instance)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Service instances wrapped by systemd or SMF might not save them by default \(em use respective reload/refresh framework actions instead then), e\&.g\&. systemctl reload nut\-server .sp NUT releases after 2\&.8\&.0 define aliases for these units, so if your Linux distribution uses NUT\-provided unit definitions, systemctl reload upsd may also work\&. .sp .5v .RE .sp If you think that upsd can\(cqt reload, check your syslog for error messages\&. If it\(cqs complaining about not being able to read the files, then you need to adjust your system to make it possible\&. Either change the permissions on the files, or run upsd as another user that will be able to read them, or restart it fully (may be needed e\&.g\&. if running in a chroot jail)\&. .sp DO NOT make your \fBupsd.conf\fR(5) or \fBupsd.users\fR(5) files world\-readable, as they hold important authentication information\&. In the wrong hands, it could be used by some evil person to spoof your primary\-mode upsmon and command your systems to shut down, for example\&. .SH "DIAGNOSTICS" .sp upsd expects the drivers to either update their status regularly or at least answer periodic queries, called pings\&. If a driver doesn\(cqt answer, upsd will declare it "stale" and no more information will be provided to the clients\&. .sp If upsd complains about staleness when you start it, then either your driver or configuration files are probably broken\&. Be sure that the driver is actually running, and that the UPS definition in \fBups.conf\fR(5) is correct\&. Also make sure that you start your driver(s) before starting upsd\&. .sp Data can also be marked stale if the driver can no longer communicate with the UPS\&. In this case, the driver should also provide diagnostic information in the syslog\&. If this happens, check the serial or USB cabling, or inspect the network path in the case of a SNMP UPS\&. .SH "ACCESS CONTROL" .sp If the server is build with tcp\-wrappers support enabled, it will check if the NUT username is allowed to connect from the client address through the /etc/hosts\&.allow and /etc/hosts\&.deny files\&. Note that this will only be done for commands that require to be logged into the server\&. Further details are described in \fBhosts_access\fR(5)\&. .SH "FILES" .sp The general upsd configuration file is \fBupsd.conf\fR(5)\&. .sp The administrative functions like SET and INSTCMD for users, and various upsmon roles, are defined and controlled in \fBupsd.users\fR(5)\&. .sp UPS definitions are found in \fBups.conf\fR(5) (shared with actual drivers)\&. .SH "ENVIRONMENT VARIABLES" .sp \fBNUT_DEBUG_LEVEL\fR sets default debug verbosity if no \fB\-D\fR arguments were provided on command line, but does not request that the daemon runs in foreground mode\&. .sp \fBNUT_CONFPATH\fR is the path name of the directory that contains upsd\&.conf and other configuration files\&. If this variable is not set, \fBupsd\fR uses a built\-in default, which is often /usr/local/ups/etc\&. .sp \fBNUT_STATEPATH\fR is the path name of the directory in which \fBupsd\fR keeps state information\&. If this variable is not set, \fBupsd\fR uses a built\-in default, which is often /var/state/ups\&. The \fBSTATEPATH\fR directive in \fBupsd.conf\fR(5) overrides this variable\&. .sp \fBNUT_ALTPIDPATH\fR is the path name of the directory in which \fBupsd\fR and drivers store \&.pid files\&. If this variable is not set, \fBupsd\fR and drivers use either \fBNUT_STATEPATH\fR if set, or ALTPIDPATH if set, or otherwise the built\-in default \fBSTATEPATH\fR\&. .sp \fBNUT_QUIET_INIT_UPSNOTIFY=true\fR can be used to prevent daemons which can notify service management frameworks (such as systemd) about passing their lifecycle milestones from emitting such notifications (including those about lack of system support for such modern features, once per run)\&. .sp \fBNUT_QUIET_INIT_BANNER=true\fR can be used to suppress NUT tool name and version banner\&. NOT recommended for services due to adverse troubleshooting impact, but may be helpful in shell profiles or scripts which process NUT tool outputs\&. .SH "SEE ALSO" .SS "Clients:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsc\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupscmd\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsrw\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupslog\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsmon\fR(8) .RE .SS "CGI programs:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsset.cgi\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsstats.cgi\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsimage.cgi\fR(8) .RE .SS "Driver control:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnut-driver-enumerator\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsdrvctl\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsdrvsvcctl\fR(8) .RE .SS "Drivers:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutupsdrv\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBadelsystem_cbi\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBal175\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBapc_modbus\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBapcsmart-old\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBapcsmart\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBapcupsd-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBasem\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbcmxcp\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbcmxcp_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbelkin\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbelkinunv\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbestfcom\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbestfortress\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbestuferrups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbestups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbicker_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBblazer-common\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBblazer_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBblazer_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBclone-outlet\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBclone\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdummy-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBetapro\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBeverups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBgamatronic\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBgeneric_gpio\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBgeneric_modbus\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBgenericups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBhuawei-ups2000\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBhwmon_ina219\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBisbmex\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBivtscd\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBliebert-esp2\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBliebert-gxe\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBliebert\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmacosx-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmasterguard\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmetasys\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmge-shut\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmge-utalk\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmicrodowell\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmicrosol-apc\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnetxml-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnhs_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnut-ipmipsu\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnut_usb_addvars\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutdrv_atcl_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutdrv_qx\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutdrv_siemens_sitop\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBoneac\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBoptiups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBphoenixcontact_modbus\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpijuice\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpowercom\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpowerman-pdu\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpowerpanel\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBrhino\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBrichcomm_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBriello_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBriello_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsafenet\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsms_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsnmp-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsocomec_jbus\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsolis\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtripplite\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtripplite_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtripplitesu\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupscode2\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBusbhid-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBvictronups\fR(8) .RE .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/snmp-ups.txt0000644000200500020050000001564415001555412013275 00000000000000snmp-ups(8) =========== NAME ---- snmp-ups - Multi-MIB Driver for SNMP UPS equipment SYNOPSIS -------- *snmp-ups* -h *snmp-ups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the snmp-ups driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The snmp-ups driver automatically detects and supports a wide range of devices by loading various MIBS, such as: *ietf*:: UPS that is RFC 1628 (UPS MIB) compliant, e.g. MGE UPS SYSTEMS, Liebert, perhaps others (default) *mge*:: MGE UPS SYSTEMS and MGE Office Protection Systems devices with SNMP cards (ref 66062, 66045, 66074 and 66244) *apcc*:: APC AP9605, AP9606, AP9617, and AP9618 APC network management cards, as well as any others supporting the APC POWERNET MIB *netvision*:: Socomec Sicon UPS with Netvision Web/SNMP management card/external box *eaton_pw_nm2*:: Powerware devices with ConnectUPS SNMP cards, as well as UPSes with Eaton Gigabit Network Cards (Network-M2) (renamed from pw) *eaton_pxg_ups*:: Eaton devices with Power Xpert Gateway UPS Card (renamed from pxgx_ups) *aphel_genesisII*:: Eaton Powerware ePDU Monitored *aphel_revelation*:: Eaton Powerware ePDU Managed *raritan*:: Various Raritan PDUs (Dominion PX, PM, RPC) *raritan-px2*:: Various Raritan PDUs (Dominion PX2) *baytech*:: Various BayTech PDUs *cpqpower*:: HP/Compaq AF401A management card, perhaps others *cyberpower*:: Cyberpower RMCARD201. Should also support RMCARD100 (net version), RMCARD202 and RMCARD301 *huawei*:: Huawei UPS5000-E, perhaps others *tripplite*:: TrippLite UPSes; at this time this is the IETF MIB mapping with just the Tripplite entry point OID to verify the device vendor, and a real hardware-specific configuration will be added in the future development. For a complete and up-to-date listing, you can query the driver by passing the *mibs=--list* argument (see below). EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *port*='hostname[:port]':: Set SNMP hostname, or IP address, and port number of the peer SNMP agent. There is no default for the hostname, but the default port is 161. *mibs*='--list':: A special option which allows to list the currently known MIB-to-NUT mappings and exit the driver binary, intended for command-line usage like this: + ---- :; snmp-ups -a snmp-test -x mibs=--list ---- *mibs*='name':: Set MIB compliance (default='auto', allowed entries: refer to SUPPORTED HARDWARE above). + With "auto", the driver will try a select set of SNMP objects until it finds one that the device responds to. + Note that since NUT 2.6.2, snmp-ups has a new method that uses `sysObjectID` (which is a pointer to the preferred MIB of the device) to detect supported devices. This renders void the *requirement* to use the "mibs" option. *community*='name':: Set community name (default is 'public') for SNMPv1 and SNMPv2c connections. Note that an RW capable community name is required to change UPS settings and send commands (such as for a power-down). *snmp_version*='version':: Set SNMP version (default = v1, allowed: v2c, v3) *snmp_retries*='retries':: Specifies the number of Net-SNMP retries to be used in the requests (default=5) *snmp_timeout*='timeout':: Specifies the Net-SNMP timeout in seconds between retries (default=1) *symmetrathreephase*:: Enable APCC three phase Symmetra quirks (use on APCC three phase Symmetras): Convert from three phase line-to-line voltage to line-to-neutral voltage (default: not enabled) *pollfreq*='num':: Set polling interval for full updates, in seconds, to reduce SNMP network traffic relative to the quick updates performed every "pollinterval" (the latter option is described in linkman:ups.conf[5]). The default value is 30 (in seconds). *notransferoids*:: Disable the monitoring of the low and high voltage transfer OIDs in the hardware. This will remove input.transfer.low and input.transfer.high from the list of variables. This should only be used on APCC Symmetra equipment which has strangeness in the three-phase power reporting. *secLevel*='value':: Set the securityLevel used for SNMPv3 messages (default=noAuthNoPriv, allowed: authNoPriv,authPriv) This parameter is mandatory if you use non-trivial authentication. *secName*='value':: Set the securityName used for authenticated SNMPv3 messages (no default) *authPassword*='value':: Set the authentication pass phrase used for authenticated SNMPv3 messages (no default) *privPassword*='value':: Set the privacy pass phrase used for encrypted SNMPv3 messages (no default) *authProtocol*='value':: Set the authentication protocol (MD5, SHA, SHA256, SHA384 or SHA512) used for authenticated SNMPv3 messages (default=MD5). Note that the exact protocol list depends on Net-SNMP library capabilities; check help of the `snmp-ups` binary program for the run-time supported list. *privProtocol*='value':: Set the privacy protocol (DES, AES, AES192 or AES256) used for encrypted SNMPv3 messages (default=DES). Note that the exact protocol list depends on Net-SNMP library capabilities; check help of the `snmp-ups` binary program for the run-time supported list. REQUIREMENTS ------------ You will need to install the Net-SNMP package from http://www.net-snmp.org/ before building this driver. SNMP v3 also requires OpenSSL support from http://www.openssl.org. LIMITATIONS ----------- Shutdown ~~~~~~~~ The shutdown sequence should be tested before relying on NUT to send a shutdown command to the UPS. The problem is that the host network stack may have been torn down by the time the driver is invoked to send the shutdown command. The driver attempts to send +shutdown.return+, +shutdown.reboot+, and +load.off.delay+ commands to the UPS in sequence, stopping after the first supported command. INSTALLATION ------------ This driver is only built if the Net-SNMP development files are present at configuration time. You can also force it to be built by using +configure --with-snmp=yes+ before calling make. EXAMPLES -------- The hostname of the UPS is specified with the "port" value in `ups.conf`, and may include a non-standard (161) remote peer port: ------ [snmpv1] driver = snmp-ups port = snmp-ups.example.com community = public snmp_version = v1 pollfreq = 15 desc = "Example SNMP v1 device" [snmpv3] driver = snmp-ups port = 166.99.224.132:170 snmp_version = v3 secLevel = authPriv secName = mysecurityname authPassword = myauthenticationpassphrase privPassword = myprivatepassphrase desc = "Example SNMP v3 device, with the highest security level" ------ AUTHORS ------- * Arnaud Quette * Dmitry Frolov * Jim Klimov SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] NUT SNMP Protocols Library ~~~~~~~~~~~~~~~~~~~~~~~~~~ Available at: https://www.networkupstools.org/ups-protocols.html#_snmp Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/rhino.txt0000644000200500020050000000226315001555412012623 00000000000000RHINO(8) ======== NAME ---- rhino - Driver for Brazilian Microsol RHINO UPS equipment SYNOPSIS -------- *rhino* -h *rhino* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the rhino driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver has been tested with: * Rhino 6000 VA * Rhino 7500 VA * Rhino 10000 VA * Rhino 20000 VA All Rhino models are sinusoidal on-line. EXTRA ARGUMENTS --------------- This driver support the following extra optional settings in linkman:ups.conf[5]: *battext=*'n':: Default = 0, no extra battery, where `n` = Ampere*hour. COMMANDS -------- *load.on*:: Turn on the load immediately. *load.off*:: Turn off the load immediately. *bypass.start*:: Put the UPS in bypass mode. *bypass.stop*:: Put the UPS out of bypass mode. *shutdown.stayoff*:: Shut down in 3 minutes and do not return. AUTHOR ------ Silvino B. Magalhães SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_sendline.txt0000644000200500020050000000252715001555412014667 00000000000000UPSCLI_SENDLINE(3) ================== NAME ---- upscli_sendline, upscli_sendline_timeout - Send a single command to a UPS SYNOPSIS -------- ------ #include #include /* or on some platforms */ int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen); int upscli_sendline_timeout(UPSCONN_t *ups, const char *buf, size_t buflen, const time_t timeout); ------ DESCRIPTION ----------- The *upscli_sendline()* and *upscli_sendline_timeout()* functions take the pointer 'ups' to a `UPSCONN_t` state structure and transmit a buffer 'buf' of size 'buflen' to the server. The data in 'buf' must be a fully formatted protocol command as no parsing of the buffer occurs within this function. The difference between the two functions is that *upscli_sendline_timeout()* lets the caller decide the amount of time ('timeout' seconds) after which it should give up and return, whereas *upscli_sendline()* does not offer this freedom, and uses an immediate timeout (0 second). RETURN VALUE ------------ The *upscli_sendline()* and *upscli_sendline_timeout()* functions return '0' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_fd[3], linkman:upscli_get[3], linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/NUT-Monitor-py3qt5.80000644000200500020050000000002715001555117014270 00000000000000.so man8/NUT-Monitor.8 nut-2.8.3/docs/man/powerpanel.txt0000644000200500020050000001156115001555412013661 00000000000000POWERPANEL(8) ============= NAME ---- powerpanel - Driver for serial PowerPanel Plus compatible UPS equipment SYNOPSIS -------- *powerpanel* -h *powerpanel* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the powerpanel driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports CyberPower BC1200, PR2200 and many other similar devices, both for the text and binary protocols. The driver will autodetect which protocol is used. If your Cyber Power Systems UPS has a USB port, you may wish to use the linkman:usbhid-ups[8] driver. The linkman:snmp-ups[8] driver supports several network cards via SNMP. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in linkman:ups.conf[5]: *protocol=*['text,binary']:: Override the default autodetection of the protocol. *manufacturer=*'value':: If you don't like the autodetected value, you can override this by setting it here. *model=*'value':: Like manufacturer above. *serial=*'value':: Like manufacturer above. *ondelay=*'value':: Time to wait before switching on the UPS (1 - 9999 minutes, 0=indefinite). Only available with the text protocol driver (see <<_support_status,Support Status>>). *offdelay=*'value':: Time to wait before shutting down the UPS (6 - 600 seconds). Values below 60 seconds will be truncated to 6 seconds intervals, values above 60 seconds to 60 seconds intervals. Only available with the text protocol driver (see <<_support_status,Support Status>>). VARIABLES --------- Depending on the type of your UPS unit, some of the following variables may be changed with linkman:upsrw[8]. If the driver can't read a variable from the UPS, it will not be made available. *input.transfer.high*:: writable: high transfer voltage point in V *input.transfer.low*:: writable: low transfer voltage point in V *battery.charge.low*:: writable: remaining battery charge percentage for low battery warning *output.voltage.nominal*:: writable: nominal output voltage in V *ups.start.battery*:: writable: allow cold start from battery COMMANDS -------- Depending on the type of your UPS unit, some of the following commands may be available. * test.battery.start.quick, test.battery.stop * beeper.enable, beeper.disable, beeper.toggle * shutdown.return, shutdown.reboot, shutdown.stayoff On many devices, these commands are unreliable, so before using them you must verify that these work as expected (see <<_shutdown_issues,Shutdown Issues>>). * shutdown.stop SUPPORT STATUS -------------- Vendor support is absent for this driver, so if you need some features that are currently not available, provide ample documentation on what the driver should sent to the UPS in order to make this work. If more information would be available on the binary protocol, it would probably be possible to make 'ondelay' and 'offdelay' configurable. So far, nobody has taken the time to investigate what we should tell the UPS to make this work, and CyberPower isn't willing to share this with us. SHUTDOWN ISSUES --------------- If the *shutdown.return* command on your UPS doesn't seem to work, chances are that your UPS is an older model. Try a couple of different settings for 'offdelay'. If no value in the range 6..600 works, your UPS likely doesn't support this. In order to get the expected behaviour, it requires *shutdown.stayoff* (when on battery) and *shutdown.reboot* (when on mains). The driver will automatically fallback to these commands if *shutdown.return* fails, and tries to detect which one should be used when called with the '-k' option (or through *upsdrvctl shutdown*). This isn't bullet-proof, however, and you should be prepared that the power will either not be shutdown or that it doesn't return when the power comes back. All models supported by the binary protocol and many supported through the text protocol are affected by this. KNOWN PROBLEMS -------------- The CyberPower OP series don't offer direct voltage, charge, frequency and temperature readings. Instead, they will return a binary value that needs conversion to the actual value. The exact conversion needed is unknown at the time of this writing, hence an estimation was made based om readings from actual devices. This may (probably will) be off, possibly a lot. Unless you can tell us the exact mapping between values from the UPS and actual readings, don't bother to complain. We've done the best we can based on the limited information available. Remember, a UPS isn't a measuring instrument. AUTHORS ------- Arjen de Korte , Doug Reynolds SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Other drivers: ~~~~~~~~~~~~~~ linkman:usbhid-ups[8], linkman:snmp-ups[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_display_sanity_check_serial.txt0000644000200500020050000000274615001555412020775 00000000000000NUTSCAN_DISPLAY_SANITY_CHECK_SERIAL(3) ====================================== NAME ---- nutscan_display_sanity_check_serial - Display sanity check warnings about "serial" (serial number/code string) optional values in the specified `nutscan_device_t` structure on stdout. SYNOPSIS -------- ------ #include void nutscan_display_sanity_check_serial(nutscan_device_t * device); ------ DESCRIPTION ----------- The *nutscan_display_sanity_check_serial()* function analyzes "serial" optional field in all NUT devices in 'device', and in case of duplicate or otherwise seemingly invalid values, prints comments to `stdout`. It displays them in a way that it can be directly copied into the `ups.conf` file. It is called from *nutscan_display_ups_conf_with_sanity_check()* to provide an aggregate content for `ups.conf` file in one shot. SEE ALSO -------- linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/asciidoc.conf0000644000200500020050000000471214777767434013425 00000000000000## Borrowed from 'linkgit' in the Git distribution. ## linkman, linkman2 macros # # Usage: linkman:command[manpage-section] # Usage: linkman2:command-page[displayed-command,manpage-section] # # Note: # - in linkman, {0} is the manpage section, while {target} is the command. # - in linkman2, {0} is the whole list of attributes, {1} is the command to be # shown, {2} is the manpage section, while {target} is the command page. # - linkmanext and linkmanext2 macros repeat the behavior of the default ones. # These macros are intended for system man pages (e.g. HTML links might lead # to a generic internet site, or possibly to a distro-provided library # online or locally). # # Show NUT link as: (
    ); if section is defined, else just show # the command. [macros] (?su)[\\]?(?Plinkman):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Plinkman2):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Plinkmanext):(?P\S*?)\[(?P.*?)\]= (?su)[\\]?(?Plinkmanext2):(?P\S*?)\[(?P.*?)\]= ifdef::backend-docbook[] [linkman-inlinemacro] {0%{target}} {0#} {0#{target}{0}} {0#} [linkman2-inlinemacro] {2%{1={target}}} {2#} {2#{1={target}}{2}} {2#} [linkmanext-inlinemacro] {0%{target}} {0#} {0#{target}{0}} {0#} [linkmanext2-inlinemacro] {2%{1={target}}} {2#} {2#{1={target}}{2}} {2#} endif::backend-docbook[] ifdef::backend-xhtml11[] [linkman-inlinemacro] {target}{0?({0})} [linkman2-inlinemacro] {1={target}}{2?({2})} # FIXME: Allow to define external man page URL structure and whether # sections should change via configure script options: [linkmanext-inlinemacro] {target}{0?({0})} [linkmanext2-inlinemacro] {1={target}}{2?({2})} # Override HTML footer, to include NUT version [footer-text] Last updated {docdate} {doctime} -- Network UPS Tools {nutversion} # Format-detection to prevent smartphones from being too smart [+docinfo] endif::backend-xhtml11[] nut-2.8.3/docs/man/etapro.txt0000644000200500020050000000140115001555412012767 00000000000000ETAPRO(8) ========= NAME ---- etapro - Driver for ETA UPS equipment SYNOPSIS -------- *etapro* -h *etapro* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the etapro driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports ETA UPS equipment with the "PRO" option for smart mode. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. AUTHOR ------ Marek Michalkiewicz SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/huawei-ups2000.80000644000200500020050000004701415001555101013423 00000000000000'\" t .\" Title: huawei_ups2000 .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "HUAWEI_UPS2000" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" huawei-ups2000 \- Driver for Huawei UPS2000 (1kVA\-3kVA) UPS with USB or RS\-232 serial Modbus connection\&. .SH "SYNOPSIS" .sp \fBhuawei\-ups2000\fR \-h .sp \fBhuawei\-ups2000\fR \-a \fIDEVICE_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the huawei\-ups2000 driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports Huawei UPS2000 series, online (double conversion) UPS with the following characteristics\&. .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} Output power: 1 kVA to 3 kVA (higher power models are unsupported)\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} Connection: USB or RS\-232 (for most UPS models, USB is only supported on Linux 5\&.12 and newer kernels, but there are exceptions, read the section \fBCabling\fR carefully)\&. .RE .sp The UPS2000 series has two variants: UPS2000\-A with a tower chassis, and UPS2000\-G with a rack\-mount chassis\&. Within these two variants, there are also two sub\-variants: a standard runtime model powered by an internal battery pack denoted by an "S" suffix, and a long runtime model powered by an external battery pack denoted by an "L" suffix\&. .sp All of these models should be equally supported, but more testers are needed\&. Currently, it has been tested on the following models\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} UPS2000\-A\-1KTTS (firmware: UPS2000A, V2R1C1SPC40, P1\&.0\-D1\&.0) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} UPS2000\-A\-1KTTS (firmware: UPS2000A, V2R1C1SPC50, P1\&.0\-D1\&.0) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} UPS2000\-A\-2KTTS (firmware: UPS2000A, V2R1C1SPC50, P1\&.0\-D1\&.0) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} UPS2000\-G\-1KRTS (firmware: UPS2000A, V2R1C1SPC40, P1\&.0\-D1\&.0) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} UPS2000\-G\-1KRTS (firmware: UPS2000G, V2R1C1SPC50, P1\&.0\-D1\&.0) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} UPS2000\-G\-3KRTS (firmware: UPS2000A, V2R1C1SPC40, P1\&.0\-D1\&.0) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} UPS2000\-G\-3KRTS (firmware: UPS2000G, V2R1C1SPC50, P1\&.0\-D1\&.0) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} UPS2000\-G\-3KRTL (firmware: UPS2000A, V2R1C1SPC40, P1\&.0\-D1\&.0) .RE .sp If your model is not in the list, we encourage you to report successful or unsuccessful results to the bug tracker or the mailing list\&. Make sure to include the full model number of your UPS manually in your report, because many units only report themselves as "UPS2000\-A" regardless of their models, including the G series\&. .sp As of 2022, there is also a new hardware variant with a WCH CH341 USB\-to\-serial chip instead of a MaxLinear/Exar RX21V1410 chip and reports itself as "UPS2000G"\&. Driver support has been added since v0\&.03\&. .sp huawei\-ups2000 uses the libmodbus project, for Modbus implementation\&. .SH "CABLING" .sp The UPS has a USB port and a RS\-232 port\&. Both are supported, but on most UPS models, USB is only usable on Linux 5\&.12 and later, via the \fBxr_serial\fR kernel module\&. But for the newer hardware variant with a WCH CH341 chip, it should have better compatibility via the \fBch341\fR kernel module\&. See subsection \fBUSB\fR for details\&. On the other hand, RS\-232 is always supported on all operating systems\&. .sp Only one port can be used at a time\&. When USB is used, RS\-232 should be unplugged from the UPS, and vice versa\&. Further, optional adapter cards, such as RS\-485 or SNMP, are not supported\&. They should be removed from the UPS\&. .sp Because the UPS port can be unresponsive under certain circumstances, it\(cqs recommended to power cycle your UPS after making a cabling change, especially after changing the port type\&. That is, turn off the UPS power output via the front panel, then unplug the UPS from line power input\&. Wait for the LCD screen to go black\&. Finally reconnect line power and restart your UPS\&. .SS "USB" .sp The USB port on the UPS2000 is originally powered by a MaxLinear/Exar RX21V1410 USB\-to\-serial converter chip, it\(cqs only supported by Linux 5\&.12 or newer, via the \fBxr_serial\fR kernel module\&. Its \fBlsusb\fR report is: .sp .if n \{\ .RS 4 .\} .nf 04e2:1410 Exar Corp\&. XR21V1410 USB\-UART IC .fi .if n \{\ .RE .\} .sp However, a recent hardware variant switched to the WCH CH341 serial chip: .sp .if n \{\ .RS 4 .\} .nf 1a86:5523 QinHeng Electronics CH341 in serial mode, usb to serial port converter .fi .if n \{\ .RE .\} .sp If your unit has a WCH CH341 chip (likely only found in units made after 2022), when the UPS2000 is connected via USB, you should see the following logs in \fBdmesg\fR\&. .sp .if n \{\ .RS 4 .\} .nf ch341 2\-1\&.2:1\&.0: ch341\-uart converter detected usb 2\-1\&.2: ch341\-uart converter now attached to ttyUSB0 .fi .if n \{\ .RE .\} .sp If so, you should be able to proceed without worrying about kernel compatibility\&. This CH341 chip has been around for a decade and should be compatible with your system\&. .sp On the other hand, if your unit has a MaxLinear/Exar XR21V1410 chip, like most users do, when the UPS2000 is connected via USB to a supported Linux system, you should see the following logs in \fBdmesg\fR\&. .sp .if n \{\ .RS 4 .\} .nf xr_serial 1\-1\&.2:1\&.1: xr_serial converter detected usb 1\-1\&.2: xr_serial converter now attached to ttyUSB0 .fi .if n \{\ .RE .\} .sp The driver must be \fBxr_serial\fR\&. If your system doesn\(cqt have the necessary device driver, you will get this message instead: .sp .if n \{\ .RS 4 .\} .nf cdc_acm 1\-1\&.2:1\&.0: ttyACM0: USB ACM device .fi .if n \{\ .RE .\} .sp The generic driver \fBcdc_acm\fR is incompatible and cannot be used\&. You should upgrade your Linux kernel to Linux 5\&.12 or newer\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br .sp On an unsupported system, the XR21V1410 USB device can still be recognized as a USB ACM device, but communication is impossible, please don\(cqt waste your time on \fBcdc_acm\fR\&. .sp .5v .RE .sp If you\(cqre already running on Linux 5\&.12 or newer kernels, but still cannot see the \fBxr_serial\fR driver, it means the driver is not enabled in your kernel build\&. If you\(cqre a regular user, you should file a bug report to your Linux distro maintainers and ask them to enable \fBxr_serial\fR (kernel option CONFIG_USB_SERIAL_XR)\&. .sp When upgrading the Linux kernel isn\(cqt an option, or when you are using another operating system (e\&.g\&. FreeBSD), RS\-232 must be used\&. Even for CH341 users, one can try this option if USB somehow refuses to work\&. .SS "RS\-232" .sp RS\-232 is supported on all operating systems, either via a built\-in serial port on your computer, or by using an external USB\-to\-RS\-232 converter\&. If you plan to use an USB\-to\-RS\-232 converter, make sure it\(cqs supported by your operating system\&. .SH "INSTALLATION" .sp This driver may be not built by default\&. You can build it by installing libmodbus (with development packages) and running .sp .if n \{\ .RS 4 .\} .nf configure \-\-with\-serial=yes \-\-with\-modbus=yes .fi .if n \{\ .RE .\} .sp You also need to give proper (R/W) permissions on the local serial device file to allow the NUT driver run\-time user to access it\&. This may need additional setup for start\-up scripting, udev or upower rules, to apply the rights on every boot \(em especially if your device nodes are tracked by a virtual filesystem\&. .sp For example, a USB\-to\-serial converter can be identified as /dev/ttyACM0 or /dev/ttyUSB0 on Linux, or /dev/ttyU0 on FreeBSD (note the capital "U")\&. A built\-in serial port can be identified as /dev/ttyS0 on Linux or one of /dev/cua* names on FreeBSD\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file: .PP \fBoffdelay=\fR\fIvalue\fR .RS 4 Time to wait before shutting down the UPS (seconds), acceptable range is 6 seconds (0\&.1 minutes) to 5940 seconds (99 minutes)\&. Defaults to 60 seconds\&. Must be a multiple of 6 seconds\&. To ensure your system has adequate time to shut down after a power failure, it\(cqs highly recommended to adjust \fBoffdelay\fR\&. .RE .PP \fBrebootdelay=\fR\fIvalue\fR .RS 4 Time to wait before rebooting the UPS (seconds), acceptable range is 6 seconds (0\&.1 minutes) to 5940 seconds (99 minutes)\&. Defaults to 60 seconds\&. Must be a multiple of 6 seconds\&. This is used by the \fBshutdown\&.reboot\&.graceful\fR instant command\&. If you\(cqve adjusted \fBoffdelay\fR, you should also adjust \fBrebootdelay\fR\&. .RE .PP \fBondelay=\fR\fIvalue\fR .RS 4 Time to wait before switching on the UPS (seconds), acceptable range is 60 seconds (1 minutes) to 5940 seconds (99 minutes)\&. Defaults to 60 seconds\&. Must be a multiple of 60 seconds (not 6 seconds)\&. You don\(cqt need to adjust this delay unless you have special requirements\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Due to hardware limitation, in this driver, \fBondelay\fR is respected only when line power is available\&. If a power failure has occurred, the UPS and the load is always immediately switched on, as soon (or as late) as line power is restored\&. .sp .5v .RE .SH "INSTANT COMMANDS" .sp This driver supports some instant commands (see \fBupscmd\fR(8)): .PP \fBshutdown\&.stayoff\fR .RS 4 After an \fBoffdelay\fR, turn off the load\&. When line power is back, remain off\&. .RE .PP \fBshutdown\&.return\fR .RS 4 After an \fBoffdelay\fR, turn off the load\&. When line power is back, turn on the load, possibly after an \fBondelay\fR\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Normally, the load is turned on as soon as line power is back\&. But if line power is never lost, or has came back unexpectedly in the middle of an ongoing shutdown (an undesirable "power race" condition that many entry\-level products on the market fail to recover from), the load is turned on after an \fBondelay\fR\&. Thus, UPS2000 is unaffected by a power race, the load is guaranteed to always restart\&. .sp .5v .RE .PP \fBshutdown\&.reboot\fR .RS 4 Like \fBshutdown\&.return\fR, except that the load is turned off immediately (6 seconds in this implementation)\&. .RE .PP \fBshutdown\&.reboot\&.graceful\fR .RS 4 Like \fBshutdown\&.return\fR, except that the load is turned off after a \fBrebootdelay\fR, not an \fBoffdelay\fR\&. .RE .PP \fBbeeper\&.enable\fR .RS 4 Enable the UPS beeper\&. .RE .PP \fBbeeper\&.disable\fR .RS 4 Disable the UPS beeper\&. .RE .PP \fBbeeper\&.toggle\fR .RS 4 Toggle the UPS beeper\&. .RE .PP \fBbypass\&.start\fR .RS 4 Put the UPS in bypass mode\&. Use with caution\&. It exposes your equipment to unregulated line power and provides no protection from power failures\&. Also, the UPS may shut down whenever the bypass input voltage is out of the nominal range\&. As a warning, the UPS beeps once every 10 seconds in bypass mode\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The driver has a basic foolproof mechanism\&. If the bypass input is already abnormal due to a power failure, the driver refuses to enter bypass mode by aborting the command and logging an error\&. However, it offers no protection after the UPS has entered (or in the middle of entering) bypass mode\&. Thus, again, use with caution\&. .sp .5v .RE .PP \fBbypass\&.stop\fR .RS 4 Put the UPS out of bypass mode\&. .RE .PP \fBload\&.on\fR .RS 4 Turn on the load immediately\&. .RE .PP \fBload\&.off\fR .RS 4 Turn off the load immediately\&. Use with caution, everything on the UPS will lost power\&. .RE .PP \fBtest\&.battery\&.start\&.quick\fR .RS 4 Perform a short battery test\&. .RE .PP \fBtest\&.battery\&.start\&.deep\fR .RS 4 Perform a long battery test\&. .RE .PP \fBtest\&.battery\&.stop\fR .RS 4 Stop a running battery test\&. .RE .SH "VARIABLES" .sp This driver supports some writable runtime variables (see \fBupsrw\fR(8)): .PP \fBups\&.beeper\&.status\fR .RS 4 Enable or disable the UPS beeper, \fBdisabled\fR or \fBenabled\fR\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The beeper can only be disabled completely, it cannot be temporally muted until the next alarm, but the option \fBmuted\fR is also accepted for convenience, \fBmuted\fR is treated as an alias of \fBdisabled\fR\&. .sp .5v .RE .PP \fBups\&.delay\&.shutdown\fR .RS 4 Seconds to wait after shutdown with delay command\&. It\(cqs the runtime equivalent of \fBoffdelay\fR\&. See description of \fBoffdelay\fR\&. .RE .PP \fBups\&.delay\&.reboot\fR .RS 4 Seconds to wait before rebooting the UPS, it\(cqs the runtime equivalent of \fBrebootdelay\fR\&. See description of \fBrebootdelay\fR\&. .RE .PP \fBups\&.delay\&.start\fR .RS 4 Seconds to wait before restarting the load, it\(cqs the runtime equivalent of \fBondelay\fR\&. See description of \fBondelay\fR\&. .RE .SH "KNOWN ISSUES AND BUGS" .SS "Battery status has a non\-fatal read failure" .sp It\(cqs usually harmless and can be safely ignored\&. It\(cqs only logged for informative purposes (\fBLOG_INFO\fR), not as a warning or error\&. .SS "Data stale" .sp Under certain circumstances, some registers can return invalid values and trigger a "data stale" error\&. Once a data stale error has occurred, you should see error messages similar to the example below in the system log\&. .sp .if n \{\ .RS 4 .\} .nf huawei\-ups2000: register 2002 has invalid value a000, upsd: Data for UPS [huawei] is stale \- check driver upsd: UPS [huawei] data is no longer stale .fi .if n \{\ .RE .\} .sp So far all known problems have been fixed by the author, but an unknown one cannot be ruled out\&. If you have encountered "data stale" problems during normal uses, please file a bug report with full logs attached\&. .sp Before troubleshooting or reporting a problem, it\(cqs important to check your \fBdmesg\fR log for USB connect and disconnect events to avoid wasting time on the NUT driver when the actual problem is USB\&. .sp For example, if someone yanks the cable out of the USB port, or if a new USB device is plugged into a USB host/hub that is struggling to power its ports (common on single\-board computers like Raspberry Pi), or if you have flaky cabling or EMI noise, due to all these and similar reasons the serial converter can get disconnected from USB, at least briefly\&. .sp This creates a permanent data stale situation, and the driver must be restarted (plugging the USB back won\(cqt fix it, since the driver is still using the nonexistent serial device, if the system kernel initializes a new device driver instance internally)\&. .sp These USB problems usually have nothing to do with NUT\&. If it\(cqs the case, you should solve the underlying USB problem \(em check the cable, check the converter, try a powered USB hub, try a full\-speed USB isolator, etc\&. .SS "Serial port becomes unresponsive" .sp Some malformed commands are known to lock up the serial port (including USB, which is a USB\-to\-serial device)\&. Upon receiving them, UPS2000 stops all serial communications\&. The result is a completely unresponsive UPS, regardless of what you do \(em restarting NUT, rebooting the computer \(em can not restore connectivity, as if someone has unplugged the RS\-232 cable\&. .sp To recover, simply power cycle the UPS: Turn off the UPS output via the front panel, then unplug the UPS from line power\&. Wait for the LCD front screen to go black\&. Finally reconnect line power and restart your UPS\&. .sp That being said, a serial port lockup is unlikely to happen\&. To our best knowledge, this driver never sends malformed commands to the UPS (it was only a problem during early development)\&. Furthermore, due to a CRC checksum, they\(cqre unlikely to be accidentally generated\&. .sp Still, we recommend to power cycle your UPS after making a cabling change, especially after changing from RS\-485/USB to RS\-232, just to ensure the UPS selects the correct communication interface\&. Also, if you have discovered a reproducible serial port lockup problem, it can be a previously unknown bug, so please make sure to file a bug report\&. .SS "USB chip (MaxLinear/Exar RX21V1410) is unsupported" .sp As previously stated, only RS\-232 is supported on all systems\&. On most UPS units, the USB chip RX21V1410 is used, and it requires a device\-specific driver \fBxr_serial\fR, which is only available on Linux 5\&.12 and newer kernels\&. .sp On an unsupported system, the USB device can still be recognized as a USB ACM device, but in reality, communication is impossible\&. It can only be fixed by implementing a driver for your system, nothing can be done within NUT\&. Please use the RS\-232 port instead\&. .sp Alternatively, if your unit has a WCH CH341 chip (likely only found in units made after 2022), it should have better compatibility\&. .sp See the previous section \fBCabling\fR for more information\&. .sp Finally, in the unlike scenario that you are using NUT on Microsoft Windows, you should be able to install the USB device driver following the steps in the Huawei UPS2000 (1 kVA\-3 kVA) Modbus Protocol Development Guide\&. .SH "AUTHOR" .sp Yifeng Li .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Huawei UPS2000\-A (1 kVA\-3 kVA) User Manual: https://support\&.huawei\&.com/enterprise/en/doc/EDOC1000084260 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Huawei UPS2000 (1 kVA\-3 kVA) Modbus Protocol Development Guide: https://support\&.huawei\&.com/enterprise/en/doc/EDOC1000110696 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} libmodbus home page: http://libmodbus\&.org .RE nut-2.8.3/docs/man/riello_usb.80000644000200500020050000002362115001555077013203 00000000000000'\" t .\" Title: riello_usb .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "RIELLO_USB" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" riello_usb \- Driver for Riello UPS Protocol UPS equipment via USB .SH "SYNOPSIS" .sp \fBriello_usb\fR \-h .sp \fBriello_usb\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the riello_usb driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp riello_usb supports all recent Riello UPS with USB\&. .sp Older Riello UPS products are not supported\&. .SH "EXTRA ARGUMENTS" .PP \fBport =\fR \fIstring\fR .RS 4 Some \fIvalue\fR must be set, typically \fBauto\fR\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This could be a device filesystem path like /dev/usb/hiddev0 but current use of libusb API precludes knowing and matching by such identifiers\&. They may also be inherently unreliable (dependent on re\-plugging and enumeration order)\&. At this time the actual \fIvalue\fR is ignored, but syntactically some \fIport\fR configuration must still be there\&. .sp .5v .RE .RE .sp It is possible to control multiple UPS units simultaneously by running several instances of this driver, provided they can be uniquely distinguished by setting some combination of the \fBvendor\fR, \fBproduct\fR, \fBvendorid\fR, \fBproductid\fR, \fBserial\fR, \fBbus\fR and/or \fBdevice\fR options detailed below\&. For devices or operating systems that do not provide sufficient information, the \fBallow_duplicates\fR option can be of use (limited and risky!) .PP \fBvendorid =\fR \fIregex\fR, \fBproductid =\fR \fIregex\fR, \fBvendor =\fR \fIregex\fR, \fBproduct =\fR \fIregex\fR, \fBserial =\fR \fIregex\fR .RS 4 Select a specific UPS, in case there is more than one connected via USB\&. Each option specifies an extended regular expression (see \fBregex\fR(7) for more information on regular expressions), which must match the UPS\(cqs entire respective vendor/product/serial string values (minus any surrounding whitespace), or the whole 4\-digit hexadecimal code for vendorid and productid\&. .sp Try \fBlsusb\fR(8) or running this NUT driver with \-DD command\-line argument for finding out the strings to match\&. .sp Examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendor="Foo\&.Corporation\&.*" .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendorid="051d*" (APC) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x product="\&.*(Smart|Back)\-?UPS\&.*" .RE .RE .PP \fBbus =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB bus or group of buses\&. The argument is a regular expression that must match the bus name where the UPS is connected (e\&.g\&. bus="002" or bus="00[2\-3]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .RE .PP \fBdevice =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB device or group of devices\&. The argument is a regular expression that must match the device name where the UPS is connected (e\&.g\&. device="001" or device="00[1\-2]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br device numbers are not guaranteed by the OS to be stable across re\-boots or device re\-plugging\&. .sp .5v .RE .RE .PP \fBbusport =\fR \fIregex\fR .RS 4 If supported by the hardware, OS and libusb on the particular deployment, this option should allow to specify physical port numbers on an USB hub, rather than logical device enumeration values, and in turn \(em this should be less volatile across reboots or re\-plugging\&. The value may be seen in the USB topology output of lsusb \-tv on systems with that tool, for example\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br this option is not practically supported by some NUT builds (it should be ignored with a warning then), and not by all systems that NUT can run on\&. .sp .5v .RE .RE .PP \fBallow_duplicates\fR .RS 4 If you have several UPS devices which may not be uniquely identified by the options above (e\&.g\&. only \fIVID:PID\fR can be discovered there), this flag allows each driver instance where it is set to take the first match if available, or proceed to try another\&. .sp Normally the driver initialization would abort at this point claiming "Resource busy" or similar error, assuming that the otherwise properly matched device is unique \(em and some other process already handles it\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This feature is inherently non\-deterministic! The association of driver instance name to actual device may vary between runs! .sp If you only care to know that \fBat least\fR one of your no\-name UPSes is online, this option can help\&. .sp If you must really know \fBwhich\fR one, it will not! .sp .5v .RE .RE .PP \fBusb_set_altinterface =\fR \fIbAlternateSetting\fR .RS 4 Force redundant call to usb_set_altinterface(), especially if needed for devices serving multiple USB roles where the UPS is not represented by the interface number 0 (default)\&. .RE .PP \fBusb_config_index\fR, \fBusb_hid_rep_index\fR, \fBusb_hid_desc_index\fR, \fBusb_hid_ep_in\fR, \fBusb_hid_ep_out\fR .RS 4 Force use of specific interface, endpoint, descriptor index etc\&. numbers, rather than defaulting to \fI0\fR (rarely other values in certain drivers for some devices known to use non\-zero numbers)\&. Specified as a hexadecimal number\&. .sp As a rule of thumb for usb_hid_desc_index discovery, you can see larger wDescriptorLength values (roughly 600+ bytes) in reports of lsusb or similar tools\&. .RE .PP \fBLIBUSB_DEBUG =\fR \fIINTEGER\fR .RS 4 Run\-time troubleshooting of USB\-capable NUT drivers can involve not only raising the common NUT debug verbosity (e\&.g\&. using the DEBUG_MIN setting in \fBups.conf\fR(5) or protocol commands to change the driver\&.debug value), but may also benefit from LibUSB specific debugging\&. .sp For the latter, you can set the LIBUSB_DEBUG driver option; alternatively you can classically export the environment variable LIBUSB_DEBUG before starting a NUT driver program (may be set and "exported" in driver init script or service method, perhaps via \fBnut.conf\fR(5)), to a numeric value such as 4 ("All messages are emitted")\&. .sp For more details, including the currently supported values for your version of the library, see e\&.g\&.: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/group__libusb__lib\&.html .RE .RE .sp You may need to tweak some settings, depending on the make and model of your UPS (see \fBups.conf\fR(5)): .PP \fBlocalcalculation\fR .RS 4 When enabled, driver will calculate values of battery\&.runtime and battery\&.charge "locally" in the driver\&. This is for some Riello models (iPlug and iDialog series) which provide incorrect values in hardware readings, or none at all\&. This "local calculation" is done according to nominal battery capacity, nominal battery voltage, actual battery charge, maximum and actual UPS load\&. .sp You may want to also configure \fIdefault\&.battery\&.voltage\&.low\fR and \fIdefault\&.battery\&.voltage\&.high\fR in case the built\-in default range (from 10\&.7V to 12\&.9V) does not match your hardware, or give a shot to \fIdefault\&.battery\&.voltage\&.nominal\fR (e\&.g\&. \fI24\fR) if your device does not serve that either\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br Lead (PbAc) battery charge graph is not linear, so guesstimated charge value may not be perfectly accurate\&. However it should be good enough to determine battery actual status and roughly estimate the time it can still power the system\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This keyword may be deprecated in future releases of the driver, in favor of runtimecal and other settings which it requires (as seen in \fBnutdrv_qx\fR(8), \fBblazer_ser\fR(8) and \fBblazer_usb\fR(8) drivers)\&. .sp .5v .RE .RE .SH "AUTHOR" .sp Massimo Zampieri .SH "SEE ALSO" .SS "Related drivers" .sp \fBriello_ser\fR(8) .SS "The core driver" .sp \fBnutupsdrv\fR(8) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nut_usb_addvars.txt0000644000200500020050000001360015001555412014664 00000000000000//////// This file is included into other man pages, where appropriate, by their choice of markup and sectioning (usually lands into "USB INTERFACE ONLY" for serial/usb or "EXTRA ARGUMENTS"). Keep in sync with nut_usb_addvars() method provided by * drivers/libusb0.c * drivers/libusb1.c * drivers/usb-common.h and matching code in tools/nut-scanner/scan_usb.c //////// *port =* 'string':: Some 'value' must be set, typically *auto*. + NOTE: This could be a device filesystem path like `/dev/usb/hiddev0` but current use of libusb API precludes knowing and matching by such identifiers. They may also be inherently unreliable (dependent on re-plugging and enumeration order). At this time the actual 'value' is ignored, but syntactically some 'port' configuration must still be there. It is possible to control multiple UPS units simultaneously by running several instances of this driver, provided they can be uniquely distinguished by setting some combination of the *vendor*, *product*, *vendorid*, *productid*, *serial*, *bus* and/or *device* options detailed below. For devices or operating systems that do not provide sufficient information, the *allow_duplicates* option can be of use (limited and risky!) *vendorid =* 'regex':: *productid =* 'regex':: *vendor =* 'regex':: *product =* 'regex':: *serial =* 'regex':: Select a specific UPS, in case there is more than one connected via USB. Each option specifies an extended regular expression (see linkmanext:regex[7] for more information on regular expressions), which must match the UPS's entire respective `vendor`/`product`/`serial` string values (minus any surrounding whitespace), or the whole 4-digit hexadecimal code for `vendorid` and `productid`. + Try linkmanext:lsusb[8] or running this NUT driver with `-DD` command-line argument for finding out the strings to match. + Examples: - `-x vendor="Foo.Corporation.*"` - `-x vendorid="051d*"` (APC) - `-x product=".*(Smart|Back)-?UPS.*"` *bus =* 'regex':: Select a UPS on a specific USB bus or group of buses. The argument is a regular expression that must match the bus name where the UPS is connected (e.g. `bus="002"` or `bus="00[2-3]"`) as seen on Linux in `/sys/bus/usb/devices` or linkmanext:lsusb[8]; including leading zeroes. *device =* 'regex':: Select a UPS on a specific USB device or group of devices. The argument is a regular expression that must match the device name where the UPS is connected (e.g. `device="001"` or `device="00[1-2]"`) as seen on Linux in `/sys/bus/usb/devices` or linkmanext:lsusb[8]; including leading zeroes. + NOTE: device numbers are not guaranteed by the OS to be stable across re-boots or device re-plugging. *busport =* 'regex':: If supported by the hardware, OS and libusb on the particular deployment, this option should allow to specify physical port numbers on an USB hub, rather than logical `device` enumeration values, and in turn -- this should be less volatile across reboots or re-plugging. The value may be seen in the USB topology output of `lsusb -tv` on systems with that tool, for example. + NOTE: this option is not practically supported by some NUT builds (it should be ignored with a warning then), and not by all systems that NUT can run on. *allow_duplicates*:: If you have several UPS devices which may not be uniquely identified by the options above (e.g. only 'VID:PID' can be discovered there), this flag allows each driver instance where it is set to take the first match if available, or proceed to try another. + Normally the driver initialization would abort at this point claiming "Resource busy" or similar error, assuming that the otherwise properly matched device is unique -- and some other process already handles it. + [WARNING] ========= This feature is inherently non-deterministic! The association of driver instance name to actual device may vary between runs! If you only care to know that *at least* one of your no-name UPSes is online, this option can help. If you must really know *which* one, it will not! ========= *usb_set_altinterface =* 'bAlternateSetting':: Force redundant call to `usb_set_altinterface()`, especially if needed for devices serving multiple USB roles where the UPS is not represented by the interface number `0` (default). *usb_config_index*:: *usb_hid_rep_index*:: *usb_hid_desc_index*:: *usb_hid_ep_in*:: *usb_hid_ep_out*:: Force use of specific interface, endpoint, descriptor index etc. numbers, rather than defaulting to '0' (rarely other values in certain drivers for some devices known to use non-zero numbers). Specified as a hexadecimal number. + As a rule of thumb for `usb_hid_desc_index` discovery, you can see larger `wDescriptorLength` values (roughly 600+ bytes) in reports of `lsusb` or similar tools. *LIBUSB_DEBUG =* 'INTEGER':: Run-time troubleshooting of USB-capable NUT drivers can involve not only raising the common NUT debug verbosity (e.g. using the `DEBUG_MIN` setting in linkman:ups.conf[5] or protocol commands to change the `driver.debug` value), but may also benefit from LibUSB specific debugging. + For the latter, you can set the `LIBUSB_DEBUG` driver option; alternatively you can classically export the environment variable `LIBUSB_DEBUG` before starting a NUT driver program (may be set and "exported" in driver init script or service method, perhaps via linkman:nut.conf[5]), to a numeric value such as `4` ("All messages are emitted"). + For more details, including the currently supported values for your version of the library, see e.g.: * https://libusb.sourceforge.io/api-1.0/ * link:https://libusb.sourceforge.io/api-1.0/group\__libusb\__lib.html[https://libusb.sourceforge.io/api-1.0/group\__libusb__lib.html] /////////////////// // EDITOR NOTE: There are no backslashes in the URL above, just that // asciidoc sees them as "emphasis" markup, they had to be escaped. // If a link from this asciidoc source file is needed, please visit: // https://libusb.sourceforge.io/api-1.0/group__libusb__lib.html /////////////////// nut-2.8.3/docs/man/nutclient_get_device_variable_values.30000644000200500020050000000004215001555117020431 00000000000000.so man3/libnutclient_variables.3 nut-2.8.3/docs/man/upsdrvsvcctl.80000644000200500020050000002476315001555047013613 00000000000000'\" t .\" Title: upsdrvsvcctl .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSDRVSVCCTL" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsdrvsvcctl \- Network UPS Tools driver service instance controller .SH "SYNOPSIS" .sp \fBupsdrvsvcctl\fR \-h .sp \fBupsdrvsvcctl\fR [\fIOPTIONS\fR] {start | stop | status} [\fIups\fR] .SH "DESCRIPTION" .sp \fBupsdrvsvcctl\fR provides a uniform interface for controlling your UPS drivers wrapped into service instances on platforms which support that (currently this covers Linux distributions with systemd and systems derived from Solaris 10 codebase, including proprietary Sun/Oracle Solaris and numerous open\-source illumos distributions with SMF)\&. It may be not installed in packaging for other operating systems\&. .sp When used properly, upsdrvsvcctl lets you maintain identical startup scripts across multiple systems with different UPS configurations\&. .sp The goal of this solution is to allow the services of \fBupsd\fR(8) data server to start up even if some of the power devices are currently not accessible, and for NUT drivers to be automatically restarted by the system in case of problems (driver bug, startup failure)\&. It also allows for faster startup of systems which monitor several devices, by letting each driver to start in parallel with others and as soon as the required subsystem for the specific driver\(cqs media is available, i\&.e\&. not with a sequential loop like was done previously\&. .sp Independent service instances for each NUT driver also allow one to configure further dependencies, such as that networking must be available for SNMP and similar drivers (but is not needed for local\-medium drivers such as serial or USB)\&. .sp The old monolithic "all or nothing" solution requiring that all drivers must be running, which sufficed for deployments with a few UPSes, did not really work well for monitoring larger deployments\&. It was also not easy to strike a pre\-packaged balance between early UPS protection for USB/serial home setups vs\&. waiting for network on larger ones\&. .sp \fBupsdrvsvcctl\fR is a script which mimics the operation of \fBupsdrvctl\fR(8) program (where possible) to provide similar end\-user experience when manipulating drivers wrapped into service instances rather than as directly executed daemons\&. It relies on \fBnut-driver-enumerator\fR(8) for a large part of actual operations\&. .sp You should use upsdrvsvcctl instead of direct calls to the drivers and daemon\-based management with \fBupsdrvctl\fR(8) whenever possible (that is, for "production" use on compatible OSes)\&. Otherwise (testing, other OSes) the upsdrvctl is a recommended option\&. .SH "OPTIONS" .PP \fB\-h\fR .RS 4 Display the help text, including the built\-in version of the script\&. .RE .PP \fB\-V\fR .RS 4 Display the version of NUT binaries (calling \fBupsdrvctl \-V\fR), which normally should not differ much from the built\-in version of the script shown in help\&. But with custom builds everything is possible, so it may be useful to know\&. .RE .PP \fB\-t\fR .RS 4 Enable testing mode\&. Testing mode makes upsdrvsvcctl display the actions it would execute without actually doing them\&. .RE .PP \fB\-\-timeout\-cmd \fR and \fB\-\-timeout\-args \fR .RS 4 Service management calls will be time\-limited by calling the specified program with its args\&. By default, if coreutils timeout is found, it would be used to limit service calls by 90 sec, to avoid/work around certain hangs that happen in some systemd version under stress\&. .RE .SH "OPTIONS OF UPSDRVCTL NOT (CURRENTLY) APPLICABLE TO UPSDRVSVCCTL" .sp Options like \fI\-r\fR, \fI\-u\fR or \fI\-D\fR could be handled by properties of the service instances themselves, with this script helping to configure them (assuming proper privileges of the user who called it)\&. This is not a "production" use case, though, to change such options on a configured system \(em so for experiments and troubleshooting, it may be better to stop the service instance and play with \fBupsdrvctl\fR directly\&. .PP \fB\-r\fR \fIdirectory\fR .RS 4 If starting a driver, this value will direct it to \fBchroot\fR(2) into \fIdirectory\fR\&. This can be useful when securing systems\&. .sp This may be set in the \fBups.conf\fR(5) with the chroot directive in the global section\&. .RE .PP \fB\-u\fR \fIusername\fR .RS 4 If starting a driver, this value will direct it to \fBsetuid\fR(2) to the user id associated with \fIusername\fR\&. .sp If the driver is started as \fIroot\fR without specifying this value, it will use the username that was compiled into the binary\&. This defaults to \fInobody\fR (if not otherwise configured), which is far from ideal\&. .sp This may be set in \fBups.conf\fR(5) with the user directive in the global section\&. .RE .PP \fB\-D\fR .RS 4 Raise the driver debug level\&. Use this multiple times for additional details\&. .RE .SH "COMMANDS" .sp \fBupsdrvsvcctl\fR supports three of the commands processed by \fBupsdrvctl\fR \(em start, stop and shutdown\&. They take an optional argument which is a UPS name from \fBups.conf\fR(5)\&. Without that argument, they operate on every UPS that is currently configured\&. .sp Note: shutdown is currently supported by stopping the driver service instances to release the potentially held ports etc\&., calling the \fBupsdrvctl\fR directly for issuing the shutdown command, and restarting the driver service instances to reconnect when the device comes back online\&. .PP \fBstart\fR .RS 4 Start the UPS driver(s)\&. In case of failure, further attempts may be executed by using the \fImaxretry\fR and \fIretrydelay\fR options \(em see \fBups.conf\fR(5)\&. .RE .PP \fBstop\fR .RS 4 Stop the UPS driver(s)\&. .RE .PP \fBstatus\fR .RS 4 Query run\-time status of all configured devices (or one specified device)\&. Currently defers work to \fBupsdrvctl\fR(8), to list known device configurations and their driver daemon details (PID, responsiveness, ups\&.status) and to \fBnut-driver-enumerator\fR(8) to map device names to service unit instances to report their names and states in the service management framework\&. .RE .sp \fBupsdrvsvcctl\fR also supports further operations for troubleshooting the mapping of NUT driver section names to the service instance names (which may differ due to limitations of various systems)\&. .PP \fBlist\fR .RS 4 list the currently active mapping of service instances to device sections .RE .PP \fBresync\fR .RS 4 update the mapping of service instances for NUT drivers to device section names used in \fIups\&.conf\fR (register new instances, tear down obsoleted ones)\&. .RE .SH "COMMANDS OF UPSDRVCTL NOT (CURRENTLY) APPLICABLE TO UPSDRVSVCCTL" .PP \fBshutdown\fR .RS 4 Command the UPS driver(s) to run their shutdown sequence\&. Drivers are stopped according to their sdorder value \(em see \fBups.conf\fR(5)\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br .sp this will probably power off your computers, so don\(cqt play around with this option\&. Only use it when your systems are prepared to lose power\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp refer to \fBups.conf\fR(5) for using the \fBnowait\fR parameter\&. It can be overridden by NUT_IGNORE_NOWAIT environment variable (e\&.g\&. used to work around certain issues with systemd otherwise)\&. .sp .5v .RE .SH "ENVIRONMENT VARIABLES" .sp \fBNUT_CONFPATH\fR is the path name of the directory that contains upsd\&.conf and other configuration files\&. If this variable is not set, \fBupsdrvsvcctl\fR (or rather \fBnut\-driver\-enumerator\&.sh\fR) would use a built\-in default, which is often /usr/local/ups/etc\&. .SH "DIAGNOSTICS" .sp upsdrvsvcctl will return a nonzero exit code if it encounters an error while performing the desired operation\&. This will also happen if a driver takes longer than the \fImaxstartdelay\fR period to enter the background\&. .sp Any messages issued by the \fBupsdrvctl\fR program used to start the NUT drivers as part of the service instances\*(Aq implementations, or by the drivers themselves, will be logged by the service management framework facilities and will not appear in your interactive terminal used to manage the driver\&. .sp Use upsdrvsvcctl list or upsdrvsvcctl list NUT\-device to find out the service instance name for the NUT driver (section name) you are interested in\&. Then look up the service logs (where the outputs of the service implementation program as well as the framework messages about this service are stored), as suggested below: .PP \fBLinux systemd\fR .RS 4 Messages will normally be kept in the service journal, so: .sp .if n \{\ .RS 4 .\} .nf journalctl \-lu nut\-driver@instance\-name .fi .if n \{\ .RE .\} .sp Note that your local system configuration may be impacted by such nuances as passing the journal data to a standard syslog server, and/or by having a small cache for locally stored journal messages (so older entries would disappear)\&. There may also be or not be a copy of the journals stored in the persistent filesystem at all\&. .RE .PP \fBSolaris SMF\fR .RS 4 Look for /var/svc/log/system\-power\-nut\-driver:instance\-name\&.log file\&. .RE .SH "AUTHOR" .sp Jim Klimov .SH "SEE ALSO" .sp \fBupsdrvctl\fR(8), \fBnutupsdrv\fR(8), \fBupsd\fR(8), \fBnut-driver-enumerator\fR(8), \fBups.conf\fR(5) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/clone.txt0000644000200500020050000002163615001555412012611 00000000000000CLONE(8) ======== NAME ---- clone - Clone an UPS, treating its outlet as if it were an UPS (with shutdown INSTCMD support) SYNOPSIS -------- *clone* -h *clone* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the clone driver. For information about the core driver, see linkman:nutupsdrv[8]. DESCRIPTION ----------- This driver, which sits on top of another driver's local UNIX socket file (or Windows named pipe), allows users to group clients to a particular outlet of a device and deal with this output as if it were a normal UPS. Unlike the linkman:clone-outlet[8] driver, this driver represents a manageable device that can be used both for monitoring and for client computer and UPS/ePDU outlet shutdowns (it supports sending relevant instant commands during run time). Unlike linkman:dummy-ups[8], this driver does not require a running `upsd` data server nor use the networked NUT protocol to talk to the "real" driver (which may be remote in case of `dummy-ups` repeater mode). This driver does not create a completely new virtual device, but replaces or extends some of the original readings reported by the "real" driver using information from the specified outlet, and relays all other readings as they were. Remote clients like `upsmon` can `MONITOR` the device entry presented by the data server with this driver (and the "real" driver) running and published. A larger deployment with one or more lower-priority devices collected on a manageable outlet of an UPS or ePDU would likely see several drivers set up on the system actually capable of interactions with the UPS and running the NUT data server linkman:upsd[8] (and likely powered by another outlet): * a "real" driver talking to the UPS; * a `clone` driver talking to the "real" driver and issuing outlet power-off (or power-cycle) based on relatively high thresholds for remaining battery charge and/or runtime of the actual UPS (or explicit instant commands), with such operations first setting the respective timers for the outlet on the "real" driver, and the "FSD" flag among states of the virtual UPS status; * possibly a `clone-outlet` driver which is read-only and interprets the outlet timer values as triggers for "FSD" or "OFF" flags reported among states of the virtual UPS status. With this approach, the lower-priority systems collected on such outlet would run the NUT linkman:upsmon[8] client to `MONITOR` the virtual UPS presented by the read-only `clone-outlet` driver and shut down as soon as the "FSD" flag is raised (fairly early, based on charge and/or runtime thresholds configured for that driver) allowing the higher-priority devices (likely including the NUT server) to enjoy a longer on-battery life. The `clone` driver responsible for outlet power state changes would not normally be monitored directly (e.g. to avoid unfortunate direct shutdown requests from those clients), although it can be (instead of `clone-outlet`) in sufficiently trusted networks. EXTRA ARGUMENTS --------------- This driver supports the following settings: *port*='drivername-devicename':: Required. The standard NUT driver `port` setting, here it provides the name of the local Unix socket file (or Windows named pipe) for connection to the "real" device driver. *load.off*='command':: Recommended. Set the command on the "real" UPS driver that will be used to switch off the outlet. You need both *load.off* and *load.on* in order to power cycle the outlet. Otherwise, shutting down the clients powered by an outlet is a one way street (see <<_important,IMPORTANT>>). *load.on*='command':: Recommended. Set the command on the "real" UPS driver that will be used to switch on the outlet. You need both *load.off* and *load.on* in order to power cycle the outlet. Otherwise, shutting down the clients powered by an outlet is a one way street (see <<_important,IMPORTANT>>). *load.status*='value':: Recommended. Set the variable on the "real" UPS driver that will be used to indicate the outlet status (i.e. on/off). If not specified, the clone driver will attempt to keep track of the outlet status, but this is less reliable. *offdelay*='num':: Set the timer (in seconds) before the outlet is turned off after the shutdown condition (+OB LB+) for this outlet is met or a command to shutdown was issued. Defaults to 120 seconds. *ondelay*='num':: Set the timer (in seconds) for the outlet to switch on in case the power returns after the outlet has been switched off. Defaults to 30 seconds. *mincharge*='value':: Set the remaining battery level when the clone UPS switches to LB (percent). *minruntime*='value':: Set the remaining battery runtime when the clone UPS switches to LB (seconds). IMPLEMENTATION -------------- The port specification in the linkman:ups.conf[5] should reference the local driver socket (or Windows named pipe) that the "real" UPS driver is using. For example: ------ [realups] driver = usbhid-ups port = auto [clone-outlet-1] driver = clone port = usbhid-ups-realups load.on = outlet.1.load.on load.off = outlet.1.load.off load.status = outlet.1.status desc = "Outlet 1 of the Real UPS" [...] ------ This driver supports instant commands to initiate a forced shutdown for `upsmon` or similar clients which `MONITOR` this virtual UPS device, if the outlet status is currently 'on' and no other shutdown was initiated yet (setting the virtual UPS shutdown delay timer to `offdelay` and issuing an FSD via `ups.status`): * `shutdown.return` -- power the outlet back on after `ondelay`; * `shutdown.stayoff` -- keep the outlet 'off'. Such commands are propagated to the "real" driver using the NUT socket protocol (using command names specified in the `load.off` and `load.on` driver configuration options), if the shutdown or start timers are set at the moment, or if the "real" device is not "online" and its known battery charge or runtime are below the configured "low" thresholds. The outlet status is determined using the name specified by the `load.status` driver option if set, or is just assumed by latest completed shutdown/start operation (using unknown outlet number). The driver does not support a common NUT device shutdown operation as such (`clone -k` just prints an error and bails out). This driver also supports setting certain NUT variables at run-time: * `battery.charge.low` -- see `mincharge` in driver options; * `battery.runtime.low` -- see `minruntime` in driver options. Compared to the "real" driver's readings, this driver also adds (or overrides) the following data points: `ups.delay.shutdown`, `ups.delay.start`, `ups.timer.shutdown` and `ups.timer.start`. It keeps track of "real" driver's values of `battery.charge` and `battery.runtime` (actual current readings) to decide on automated outlet shutdown later on. IMPORTANT --------- Unlike a real UPS, you should *not* configure a upsmon primary mode for this driver. When a linkman:upsmon[8] primary sees the `OB LB` flags and tells the linkman:upsd[8] data server that it is OK to initiate the shutdown sequence, the server will latch the FSD status, and it will not be possible to restart the systems connected without restarting the `upsd` server. This will be a problem if the power returns after the clone UPS initiated the shutdown sequence on its outlet, but returns before the real UPS begins shutting down. The solution is in the `clone` driver itself, that will insert the FSD flag if needed without the help of an upsmon primary. CAVEATS ------- The clone UPS will follow the status on the real UPS driver. You can only make the clone UPS shutdown earlier than the real UPS driver, not later. If the real UPS driver initiates a shutdown, the clone UPS driver will immediately follow. Be aware that the commands to shutdown/restart an outlet on the real UPS drivers are not affected, so if you tell the real UPS driver to shutdown the outlet of the clone UPS driver, your clients will lose power without warning. If you use service management frameworks like systemd or SMF to manage the dependencies between driver instances and other units, then you may have to set up special dependencies (e.g. with systemd "drop-in" snippet files) to queue your `clone` drivers to start after the "real" device drivers. ////////////////////////////////////// TODO later: declare the driver as "optional", see https://github.com/networkupstools/nut/issues/1389 ////////////////////////////////////// AUTHOR ------ Arjen de Korte SEE ALSO -------- linkman:upscmd[1], linkman:upsrw[1], linkman:ups.conf[5], linkman:clone-outlet[8], linkman:nutupsdrv[8] Dummy driver: ~~~~~~~~~~~~~ The "repeater" mode of 'dummy-ups' driver is in some ways similar to the 'clone' and 'clone-outlet' drivers, by relaying information from a locally or remotely running "real" device driver (and NUT data server). linkman:dummy-ups[8] Internet Resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/bestfcom.txt0000644000200500020050000000164515001555412013311 00000000000000BESTFCOM(8) =========== NAME ---- bestfcom - Driver for Best Power Fortress/Ferrups SYNOPSIS -------- *bestfcom* -h *bestfcom* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the bestfcom driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ Best Power Fortress/Ferrups implementing the Fortress UPS Protocol (f-command set). (For older Fortress units, see linkman:bestfortress[8].) EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. AUTHORS ------- * Kent Polk (bestfcom) * Andreas Wrede, John Stone (bestuferrups) * Grant Taylor (bestfort) * Russell Kroll (bestups) SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_upserror.30000644000200500020050000000427415001555054014275 00000000000000'\" t .\" Title: upscli_upserror .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_UPSERROR" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_upserror \- Get current error number for connection .SH "SYNOPSIS" .sp .nf #include int upscli_upserror(UPSCONN_t *ups); .fi .SH "DESCRIPTION" .sp The \fBupscli_upserror\fR() function takes the pointer \fIups\fR to a UPSCONN_t state structure and returns the value of the internal error number, if any\&. .sp This is typically used to check for certain error values like UPSCLI_ERR_UNKCOMMAND\&. That specific error can be used for detecting older versions of \fBupsd\fR(8) which might not support a given command\&. .sp Some error messages have additional meanings, so you should use \fBupscli_strerror\fR(3) to obtain readable error messages\&. .SH "RETURN VALUE" .sp The \fBupscli_upserror\fR() function returns one of the UPSCLI_ERR_* values from upsclient\&.h, or \fI0\fR if no error has occurred\&. .SH "SEE ALSO" .sp \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_strerror\fR(3) nut-2.8.3/docs/man/everups.80000644000200500020050000000437115001555071012530 00000000000000'\" t .\" Title: everups .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "EVERUPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" everups \- Driver for Ever UPS models .SH "SYNOPSIS" .sp \fBeverups\fR \-h .sp \fBeverups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the everups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver should recognize the NET *\-DPC and AP *\-PRO models\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "BUGS" .sp This UPS can only switch off the load if it\(cqs running on battery\&. This means you may be vulnerable to power races if your shutdown scripts don\(cqt sleep and force a reboot\&. .SH "AUTHOR" .sp Bartek Szady .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutclient_device_login.30000644000200500020050000000003515001555117015540 00000000000000.so man3/libnutclient_misc.3 nut-2.8.3/docs/man/nutclient_tcp_disconnect.30000644000200500020050000000003415001555117016107 00000000000000.so man3/libnutclient_tcp.3 nut-2.8.3/docs/man/upscli_init_default_connect_timeout.30000644000200500020050000001074215001555052020335 00000000000000'\" t .\" Title: upscli_init_default_connect_timeout .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_INIT_DEFAULT_" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_init_default_connect_timeout \- Initialize upsclient module aspect of default timeout for initial connections\&. .SH "SYNOPSIS" .sp .nf #include int upscli_init_default_connect_timeout( const char *cli_secs, const char *config_secs, const char *default_secs); .fi .SH "DESCRIPTION" .sp The \fBupscli_init_default_connect_timeout()\fR function initializes upsclient module aspect of default connection timeout for \fBupscli_connect\fR(3), which may be important when e\&.g\&. \fBupsc\fR(8) scripting or \fBupsmon\fR(8) configuration refers to unresponsive hosts, or when the host name resolution lags, etc\&. By default, \fBupscli_connect\fR(3) blocks indefinitely in its attempts to connect (or until the system transport layer interrupts such an attempt)\&. .sp It populates the value from different sources, mostly C strings which represent a floating\-point non\-negative number (invalid parsing is logged and may impact the return value), any or all of them may be NULL to skip, and in specific order (last valid hit wins): .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} built\-in \fI0\fR meaning indefinitely blocking (NUT default for this method over at least 20 years); .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the number from default_secs as a particular NUT or third\-party client program\(cqs built\-in preferred (low\-priority) default; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the number from NUT_DEFAULT_CONNECT_TIMEOUT environment variable as a site\-local preference (generally pre\-set in \fBnut.conf\fR(5)); .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the number from config_secs as a particular NUT or third\-party client program\(cqs configuration file default; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the number from cli_secs as a particular NUT or third\-party client program\(cqs setting from command line (highest priority)\&. .RE .sp Internally, calls \fBupscli_set_default_connect_timeout\fR(3) for most of the string related processing\&. .sp The upsclient module tracks if \fBupscli_init_default_connect_timeout()\fR function was called and succeeded, in order to call it once (if never used) from the \fBupscli_connect\fR(3) or \fBupscli_init\fR(3) methods\&. This allows unmodified (legacy) NUT clients to consistently benefit from presence of the NUT_DEFAULT_CONNECT_TIMEOUT environment variable\&. .sp This tracking does not preclude programs from explicitly calling the method any amount of times\&. .SH "RETURN VALUE" .sp The \fBupscli_init_default_connect_timeout()\fR function returns \fI0\fR on success (either if all strings were NULL so the built\-in default is applied, or at least one of those strings that were set was valid and its value got applied), or \fI\-1\fR if an error occurs (at least one string was not NULL, and none of the strings was valid)\&. .SH "SEE ALSO" .sp \fBupscli_connect\fR(3), \fBupscli_tryconnect\fR(3), \fBupscli_set_default_connect_timeout\fR(3), \fBupscli_get_default_connect_timeout\fR(3), \fBupscli_init\fR(3) nut-2.8.3/docs/man/nut-driver-enumerator.80000644000200500020050000001560415001555047015321 00000000000000'\" t .\" Title: nut-driver-enumerator .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUT\-DRIVER\-ENUMERA" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nut-driver-enumerator \- Tool to map NUT device entries to service instances .SH "SYNOPSIS" .sp \fBnut\-driver\-enumerator\&.sh\fR \-h .sp \fBnut\-driver\-enumerator\&.sh\fR (no args) .sp \fBnut\-driver\-enumerator\&.sh\fR [\-\-COMMAND] .SH "DESCRIPTION" .sp \fBnut\-driver\-enumerator\&.sh\fR implements the set\-up and querying of the mapping between NUT driver configuration sections for each individual monitored device, and the operating system service management framework service instances into which such drivers are wrapped for independent execution and management (on platforms where NUT currently supports this integration \(em currently this covers Linux distributions with systemd and systems derived from Solaris 10 codebase, including proprietary Sun/Oracle Solaris and numerous open\-source illumos distributions with SMF)\&. It may be not installed in packaging for other operating systems\&. .sp This script provides a uniform interface for further NUT tools such as \fBupsdrvsvcctl\fR(8) to implement their logic as platform\-independently as was possible and practical\&. It is not currently intended for end\-user consumption (and so is located in the \fIlibexec\fR directory), with \fBupsdrvsvcctl\fR exposing the most useful data and actions with its \fIlist\fR and \fIresync\fR arguments\&. .sp One part of the platform complexity that \fBnut\-driver\-enumerator\&.sh\fR hides is the difference of rules for valid service instance names in various frameworks, as well as system tools and naming patterns involved\&. .SH "COMMANDS" .PP \fBnut\-driver\-enumerator\&.sh (no args)\fR .RS 4 Update wrapping of devices into services .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-daemon(=freq)\fR .RS 4 Update wrapping of devices into services in an infinite loop; Default freq is 60 sec\&. .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-daemon\-after(=freq)\fR .RS 4 Update wrapping of devices into services in an infinite loop; first do one run of the loop though, then daemonize (this way service unit is deemed started only when NUT config and driver instances are in sync)\&. Default freq is 60 sec\&. .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-reconfigure\fR .RS 4 Stop and un\-register all service instances and recreate them (e\&.g\&. if new dependency template was defined in a new version of the script or package) .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-get\-service\-framework\fR .RS 4 Print the detected service management framework in this OS .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-list\-devices\fR .RS 4 Print list of devices in NUT config .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-list\-services\fR .RS 4 Print list of service instances which wrap registered NUT devices (full name of service unit) .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-list\-instances\fR .RS 4 Print list of service instances which wrap registered NUT devices (just instance suffix) .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-get\-service\-for\-device DEV\fR .RS 4 Print the full name of service unit which wraps a NUT device named DEV .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-get\-device\-for\-service SVC\fR .RS 4 Print the NUT device name for full or instance\-suffix name of a service unit SVC which wraps it .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-list\-services\-for\-devices\fR .RS 4 Print a TAB\-separated list of service units and corresponding NUT device names which each such unit wraps .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-show\-all\-configs\fR .RS 4 Show the complete normalized list of device configuration blocks (same as used later by the parser in the script to make decisions) .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-show\-device\-config DEV\fR .RS 4 Show configuration block of the specified NUT device .RE .PP \fBnut\-driver\-enumerator\&.sh \-\-show\-device\-config\-value DEV KEY\fR .RS 4 Show single configuration key of the specified NUT device .RE .SH "ENVIRONMENT VARIABLES" .sp By default \fBnut\-driver\-enumerator\&.sh\fR executed without arguments would automatically start any newly registered service instances wrapping the NUT devices, and would also restart the nut\-server service if the configuration was changed\&. Environment variable AUTO_START=no disables this default part of the action\&. .sp Also see below for environment variable REPORT_RESTART_42=no value\&. .SH "DIAGNOSTICS" .sp \fBnut\-driver\-enumerator\&.sh\fR will return a zero exit code if it had nothing to do (all currently defined drivers match all of the currently defined service instances, one\-to\-one) and if it had no errors in its operation\&. .sp Other codes can be returned as a result of re\-synchronization of mappings: .PP \fB42\fR .RS 4 NUT device sections and system service instances differed before, but now match up \(em so now the caller should likely restart some services\&. Note that the drivers\*(Aq service instances may have been started or stopped as required (by AUTO_START=yes) \(em but maybe the upsmon or upssched services should restart\&. If you pass environment variable REPORT_RESTART_42=no then this codepath would return 0 (as a non\-error exit code)\&. In default mode, such non\-null reconfiguration should cause the nut\-driver\-enumerator service to restart and this would propagate to other NUT services that depend on it\&. .RE .PP \fB13\fR .RS 4 Sections and services differed, and still do not match up .RE .PP \fB1\fR .RS 4 Bad inputs, e\&.g\&. unrecognized service management framework .RE .PP \fB2\fR .RS 4 Absent or unreadable ups\&.conf file .RE .SH "AUTHOR" .sp Jim Klimov .SH "SEE ALSO" .sp \fBupsdrvsvcctl\fR(8), \fBups.conf\fR(5) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/apcsmart.80000644000200500020050000004432015001555064012651 00000000000000'\" t .\" Title: apcsmart .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "APCSMART" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" apcsmart \- Driver for American Power Conversion Smart Protocol UPS equipment .SH "SYNOPSIS" .sp \fBapcsmart\fR \-h .sp \fBapcsmart\fR \-a \fIUPS_NAME\fR [\-x option=value \&...] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the apcsmart driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The apcsmart driver should recognize (or at the very least, work with) the majority of Smart\-UPS models \(em which includes Smart\-UPS, Matrix\-UPS and Back\-UPS lineups, among few other ones\&. .sp Currently, we can roughly divide APC hardware into four groups (note that the division isn\(cqt strict by any means, and the borders between those are pretty fuzzy): .PP [very] "old" models .RS 4 These models usually have old APC logo, white color and \fIno\fR programmable EEPROM; you won\(cqt find them listed anywhere on APC\(cqs site either\&. The support for those will be usually based on driver\(cqs compatibility tables, or if the model (firmware) is not listed in those \(em the driver will try to follow the very basic subset of features, while still trying to remain useful\&. Despite "smart" tagname, they often tend to behave in pretty dumb way (see the section below about shutdown behaviour)\&. .PP \fBExample models:\fR .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Smart\-UPS 2000I .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Smart\-UPS 900I .RE .RE .PP "new" models .RS 4 These models usually come from late 1990s / pre\-2009 times\&. They are often referred to as "3rd\&. gen"\&. For the most part, they have programmable EEPROM, report supported commands and capabilities, and should work just fine with the apcsmart driver\&. .RE .PP "microlink" models .RS 4 WARNING: these are not \fInatively\fR supported by \fBapcsmart\fR (or as of this writing by \fBapcupsd\fR, for that matter, if you\(cqre wondering)\&. Around 2007, APC (now APC Schneider) decided to go back to its proprietary roots, and all the new models (SMT, SMX, SURTD) use completely different protocol and cables\&. If you purchased a new APC UPS \(em that uses cable with RJ45 on the one end, and DB\-9 on the other \(em then you have such model\&. Your only option to support it through \fBNUT\fR is to purchase a "legacy communications card" \(em part #AP9620 (google \fIAP9620\fR for more details)\&. Or if that\(cqs not an option, rely on official software\&. .PP \fBUPDATE:\fR. Later releases of \fBapcupsd\fR claimed support for new APC protocols, so it is worth checking if \fBapcupsd\fR software would work with your device, and \fBapcupsd\-ups\fR NUT driver would handle it as part of NUT\-managed ecosystem\&. .RE .PP Microsol models .RS 4 Several Microsol serial models sold in Brazil have been rebranded as APC Back\-UPS, and the model numbers tend to start with "BZ"\&. If you have one of these "Nobreaks", they will not work with the \fBapcsmart\fR driver \(em please see the \fBsolis\fR(8) driver instead\&. .PP \fBExample models:\fR .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Back\-UPS BZ1200\-BR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Back\-UPS BZ2200BI\-BR .RE .RE .sp Another thing to remember is that Smart protocol is not USB protocol\&. If you have UPS with both USB and serial ports, then depending on how you connect it, you will need either apcsmart or usbhid\-ups driver\&. .SH "CABLING" .sp This driver expects to see a 940\-0024C cable or a clone by default\&. You can switch to the 940\-0095B dual\-mode cable support with the \fIcable=\fR definition described below\&. .sp If your 940\-xx24X cable is broken or missing, use this diagram to build a clone: .sp https://www\&.networkupstools\&.org/cables\&.html#_940_0024c_clone .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The "xx" is either "00" for a short cable, or the number of feet of a longer cable\&. The "X" is a letter representing the minor revision of the physical cable and its connectors ("C" and "E" are commonly found revisions)\&. All minor revisions should use the same pin\-outs and wiring\&. .sp .5v .RE .sp You can specify alternate cable in \fBups.conf\fR(5): .sp .if n \{\ .RS 4 .\} .nf *cable*=940\-0095B .fi .if n \{\ .RE .\} .sp Alternatively, you can also provide it on the command line using: .sp .if n \{\ .RS 4 .\} .nf \-x *cable*=940\-0095B .fi .if n \{\ .RE .\} .SH "TTY MODES" .sp By default the driver works in canonical mode, but it proved to be a problem in Windows systems\&. Furthermore there\(cqs a possibility of some obscure serial cards or serial\-USB converters that could cause problems as well\&. You can use \fIttymode=\fR option to force non\-canonical discipline in \fBups.conf\fR(5): .sp .if n \{\ .RS 4 .\} .nf *ttymode*=raw .fi .if n \{\ .RE .\} .sp Alternatively, you can also provide it on the command line using: .sp .if n \{\ .RS 4 .\} .nf \-x *ttymode*=raw .fi .if n \{\ .RE .\} .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Any other value will make the driver work in the canonical mode\&. .sp .5v .RE .SH "EXPLANATION OF SHUTDOWN METHODS SUPPORTED BY APC UPSES" .sp APC hardware supports a lot of shutdown methods, that themselves can differ in behaviour quite a bit, depending on the model\&. .PP \fBS\fR (soft hibernate) .RS 4 This is most basic command present in probably all APC models\&. It will hibernate the UPS, and subsequently wake it up when the mains supply returns\&. \fBThe command doesn\(cqt work if the UPS is running on mains\&.\fR .PP "old" models: .RS 4 The behaviour here is unfortunately pretty primitive \- when the power returns, the UPS just wakes up\&. No grace periods, no min\&. battery charge condition, etc\&. This is probably not what you want\&. .RE .PP "new" models: .RS 4 The behaviour here is as expected \(em the power is cut off after the EEPROM defined grace period\&. The UPS will wake up when the power returns, after the EEPROM defined delay AND if the EEPROM defined min\&. battery charge level is met\&. The delay is counted from the power\(cqs return\&. .RE .RE .PP \fBCS\fR (aka "force OB hack") .RS 4 This is a trick to make UPS power down even if it\(cqs running on mains\&. Immediately before issuing \fBS\fR, "simulate power failure" is issued\&. The remaining behaviour is as in \fBS\fR case\&. .sp There\(cqs a delay between "simulate power failure" and \fBS\fR \(em by default set to 3\&.5s\&. You can control it through \fBcshdelay\fR option (allowed values are from 0 to 9\&.9)\&. .sp The name came from APC CS models, where such trick was used to power down UPSes in consistent fashion using only \fBS\fR\&. It\(cqs better to use \fB@nnn\fR command if your UPS supports it (and is not too old, see below)\&. .RE .PP \fB@nnn\fR (hard hibernate) .RS 4 This is basic command used to hibernate UPS regardless if it\(cqs running on batteries or on mains\&. The option takes 3 digits argument which can be used to specify additional wake\-up delay (in 6 minute units)\&. .PP "old" models: .RS 4 The behaviour is \(em unfortunately \(em similarly primitive to \fBS\fR\&. The UPS unconditionally wakes up after nnn*6 minutes: \fBit doesn\(cqt care if the power returned !\fR .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br If \fInnn = 000\fR, then UPS will do precisely nothing\&. On those models you should better specify \fInnn > 0\fR, if you can estimate the kind of power problems that might be happening in your environment\&. .sp .5v .RE Another thing to consider with "old" models \(em you might lose the connection with the UPS, until it wakes up (with \fBS\fR, the serial connection is kept alive)\&. .RE .PP "new" models: .RS 4 All the usual variables defined in EEPROM are respected (see \fBS\fR)\&. Additionally, if \fInnn > 0\fR, the nnn*6 minutes are added to EEPROM defined delay\&. UPS will not power up if it\(cqs running on batteries, contrary to what "old" models used to do \(em the combined delay is counted from the moment of power return\&. .RE .sp Supposedly there exist models that take 2 digits instead of 3\&. Just in case, NUT also supports such variation\&. You have to provide exactly 2 digits to trigger it (\fBawd\fR option, or argument to one of the supported instant commands)\&. .RE .PP \fBK\fR (delayed poweroff) .RS 4 This is permanent poweroff \(em the UPS will not wake up automatically\&. On newer units, it will respect applicable EEPROM variables\&. .RE .PP \fBZ\fR (instant poweroff) .RS 4 This is also permanent poweroff \(em the UPS will not wake up automatically\&. The poweroff is executed immediately\&. .RE .SH "SHUTDOWN CONTROL BY NUT" .sp There are three options used to control the shutdown behaviour\&. .PP \fBsdtype\fR=[0\-5] .RS 4 This option takes a single digit (0\-5) as an argument\&. See below for details\&. .RE .PP \fBadvorder\fR=no|[0\-4]+ .RS 4 This option takes string of digits as an argument\&. Methods listed are tried in turn until one of them succeeds\&. Note that the meaning of digits is different from \fBsdtype\fR\&. See below for details\&. .RE .PP \fBawd\fR=[0\-9]{1,3} .RS 4 This option lets you specify additional wake\-up delay used by \fB@\fR\&. If you provide exactly 2 digits, the driver will try 2 digits variation (see previous section for more info)\&. Otherwise standard 3 digits variation is used\&. \fBNote: the time unit is 6 minutes !\fR .RE .sp Keep in mind that \fBsdtype\fR and \fBadvorder\fR are mutually exclusive\&. If \fBadvorder\fR is provided, \fBsdtype\fR is ignored\&. If \fBadvorder\fR is set to \fIno\fR, \fBsdtype\fR is used instead\&. .sp If nothing is provided, \fBNUT\fR will assume \fBsdtype\fR=0 \(em which is generally fine for anything not too ancient or not too quirky\&. .SS "SDTYPE" .sp The values permitted are from 0 to 5\&. Only one can be specified\&. Anything else will cause apcsmart to exit\&. .PP 0 .RS 4 issue soft hibernate (\fBS\fR) if the UPS is running on batteries, otherwise issue hard hibernate (\fB@\fR) .RE .PP 1 .RS 4 issue soft hibernate (\fBS\fR) (if on batteries), and if it fails (or on mains) \(em try hard hibernate (\fB@\fR) .RE .PP 2 .RS 4 issue instant poweroff (\fBZ\fR) .RE .PP 3 .RS 4 issue delayed poweroff (\fBK\fR) .RE .PP 4 .RS 4 issue "force OB hack" (\fBCS\fR) .RE .PP 5 .RS 4 issue hard hibernate (\fB@\fR) .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Hard hibernate\(cqs additional wake\-up delay can be provided by \fBawd\fR\&. .sp .5v .RE .SS "ADVORDER" .sp The argument is either a word \fIno\fR, or a string of 1\&.\&.5 digits in [0\&.\&.4] range\&. Each digit maps to the one of shutdown methods supported by APC UPSes\&. Methods listed in this way are tried in order, until one of them succeeds\&. .sp If \fBadvorder\fR is undefined or set to \fIno\fR, \fBsdtype\fR is used instead\&. .sp The mapping is as follows: .TS tab(:); lt lt lt lt lt lt lt lt lt lt. T{ .sp 0 T}:T{ .sp soft hibernate (\fBS\fR) T} T{ .sp 1 T}:T{ .sp hard hibernate (\fB@\fR) T} T{ .sp 2 T}:T{ .sp delayed poweroff (\fBK\fR) T} T{ .sp 3 T}:T{ .sp instant poweroff (\fBZ\fR) T} T{ .sp 4 T}:T{ .sp "force OB hack" (\fBCS\fR) T} .TE .sp 1 .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Hard hibernate\(cqs additional wake\-up delay can be provided by \fBawd\fR\&. .sp .5v .RE .SH "IGNORING LB STATE" .sp APC units \(em even if they report LB mode \(em will not go into shutdown automatically\&. This gives us even more control with reference to "when to actually shutdown PSU"\&. Since version 2\&.6\&.2, NUT supports \fBignorelb\fR option in driver\(cqs section of \fBups.conf\fR(5)\&. When such option is in effect, the core driver will ignore LB state as reported by specific driver and start shutdown basing the decision \fIonly\fR on two conditions: .sp .if n \{\ .RS 4 .\} .nf battery\&.charge < battery\&.charge\&.low .fi .if n \{\ .RE .\} .sp \fBOR\fR .sp .if n \{\ .RS 4 .\} .nf battery\&.runtime < battery\&.runtime\&.low .fi .if n \{\ .RE .\} .sp Of course \(em if any of the variables are not available, the appropriate condition is not checked\&. If you want to explicitly disable one of the conditions, simply override the right hand variable causing the condition to always evaluate to false (you can even provide negative numbers)\&. .sp APC UPSes don\(cqt have battery\&.charge\&.low \(em you will have to define it if you want to use such condition (prefix the variable with override\&. or default\&.)\&. .sp "New" units have battery\&.runtime\&.low, but depending on battery quality, firmware version, calibration and UPS load \(em this variable can be underestimated quite a bit \(em especially right after going into OB state\&. This in turn can cause LB to be asserted, which under normal conditions will cause \fBNUT\fR to initiate the shutdown\&. You might want to disable this condition entirely, when relying on \fBignorelb\fR option (this was actually the main motivation behind introduction of such feature)\&. .sp Simple example: .sp .if n \{\ .RS 4 .\} .nf [apc] ignorelb override\&.battery\&.charge\&.low = 15 override\&.battery\&.runtime\&.low = \-1 .fi .if n \{\ .RE .\} .sp This would cause apcsmart to go into shutdown \fIonly\fR if detected battery charge < 15%\&. Runtime condition is always false in this example\&. .sp You could ask \(em why bother? Well, the reason is already hinted above\&. APC units can be very picky about the batteries, and their firmware can underestimate the remaining runtime (especially right after going into OB state)\&. \fBignorelb\fR option and \fBoverride\&.*\fR let you remain in control of the UPS, not UPS in control of you\&. .sp Furthermore, this allows to specify conditions similarly to how it\(cqs done in apcupsd daemon, so it should be welcome by people used to that software\&. .SH "SUPPORTED INSTANT COMMANDS" .sp The apcsmart driver exposes following instant commands: .PP shutdown\&.return .RS 4 executes soft hibernate .RE .PP shutdown\&.return cs .RS 4 executes "force OB hack" .RE .PP shutdown\&.return at: .RS 4 executes "hard hibernate" with *6 minutes additional wake\-up delay ( format is the same as of \fBawd\fR option) .RE .PP shutdown\&.stayoff .RS 4 executes "delayed poweroff" .RE .PP load\&.off .RS 4 executes "instant poweroff" .RE .sp All the above commands must be issued 2nd time to have any effect (no less than 3 seconds, and no more than 15 seconds after the initial call)\&. Those commands are mostly useful for manual testing, when your machine is not powered by the UPS you\(cqre testing\&. .sp Other supported commands: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} load\&.on .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} test\&.panel\&.start .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} test\&.failure\&.start .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} test\&.battery\&.start .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} test\&.battery\&.stop .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} bypass\&.start .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} bypass\&.stop .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} calibrate\&.start .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} calibrate\&.stop .RE .SH "PREVIOUS DRIVER VERSION" .sp Previous driver is still available as \fBapcsmart\-old\fR, should there be any need to use earlier version (bugs, incompatibilities with new functionality, etc\&.)\&. In due time, \fBapcsmart\-old\fR will be phased out completely, but this won\(cqt happen until the new version gets solid exposure with no pending issues\&. .SH "BUGS" .sp Some older APC UPS models return bogus data in the status register during a front panel test\&. This is usually detected and discarded, but some other unexpected values have occasionally slipped through\&. .sp APC UPS models with both USB and serial ports require a power cycle when switching from USB communication to serial, and perhaps vice versa\&. .SH "AUTHORS AND HISTORY" .sp Nigel Metheringham (drawing heavily on the original apcsmart driver by Russell Kroll) wrote a driver called newapc for a time, which was renamed in the 1\&.5 series\&. .sp In 2\&.6\&.2 that driver was renamed finally to apcsmart\-old, being superseded by this updated version with new features which currently holds the apcsmart name, and is maintained by Michal Soltys \&. .SH "SEE ALSO" .sp \fBnutupsdrv\fR(8), \fBups.conf\fR(5), \fBusbhid-ups\fR(8), \fBsolis\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/libnutclient_devices.txt0000644000200500020050000000237315001555412015704 00000000000000LIBNUTCLIENT_DEVICES(3) ======================= NAME ---- libnutclient_devices, nutclient_get_devices, nutclient_has_device, nutclient_get_device_description - Device related functions in Network UPS Tools high-level client access library SYNOPSIS -------- ------ #include typedef void* NUTCLIENT_t; typedef char** strarr; strarr nutclient_get_devices(NUTCLIENT_t client); int nutclient_has_device(NUTCLIENT_t client, const char* dev); char* nutclient_get_device_description(NUTCLIENT_t client, const char* dev); ------ DESCRIPTION ----------- These functions allow to manage devices. * The *nutclient_get_devices()* function retrieves the list of devices monitored by a client. + The returned strarr must be freed by 'strarr_free' (see linkman:libnutclient_general[3]). * The *nutclient_has_device()* function tests if a device is monitored by a client. * The *nutclient_get_device_description()* function retrieves the device description. + The returned description string must be freed by linkmanext:free[3]. Common arguments: * 'dev' is the device name. SEE ALSO -------- linkman:libnutclient[3] linkman:libnutclient_commands[3] linkman:libnutclient_devices[3] linkman:libnutclient_general[3] linkman:libnutclient_variables[3] nut-2.8.3/docs/man/Makefile.am0000644000200500020050000017335615001552635013017 00000000000000# Network UPS Tools: man pages # # Notes: # - sources (.txt) and groff formats are both distributed, # - only sources are versioned ; groff files are generated at worst # during 'make dist' (while preparing a release tarball) # - HTML files are built upon request, if AsciiDoc is available, # - groff update will only happen if AsciiDoc is available too, # - all this can probably (and hopefully) be improved, but I've not # found a way to do pattern replacement on the fly for target deps! # FIXME: investigate an autogen.sh hook # - Ref: http://www.gnu.org/software/hello/manual/automake/Man-pages.html # - WITH_MANS can be enabled if either we are building man-pages, or if # the --with-doc=man=auto detected an inability to build the man-pages # but enabled the DOC_INSTALL_DISTED_MANS toggle so we deliver disted # files from source tree # - Man page lists are collected into several patterns of make variables # (FIXME? to simplify?) : # * INST_MAN_xxx_PAGES, INST_HTML_xxx_PAGES: what we would install # (if building of man/HTML pages, and perhaps an optional tool building, # are enabled); # * MAN_xxx_PAGES: what we actually enable to build and deliver (may be empty); # * HTML_xxx_PAGES: populated most of the time, buildable optionally; # * DIST_ALL_PAGES: all known page file names, to help ensure dist archive # contains everything that any build may want (even if missing tools to # build the docs from scratch, or choosing not to do that for speed). # * DIST_ALL_MAN_PAGES: all known MAN page file names, to help ensure dist archive # * DIST_ALL_HTML_PAGES: all known HTML page file names, to help ensure nut-website # Is "egrep == grep -E" always valid? (maybe all a job for configure.ac) #EGREP = egrep EGREP = grep -E SRC_ALL_PAGES = index.txt # Used for dist completeness checks; the actual build products # (depending on enabled features) are in MAN_MANS and HTML_MANS. # This does not necessarily trigger the build, just allows us # to check if they all exist. DIST_ALL_MAN_PAGES = DIST_ALL_HTML_PAGES = index.html # HTML collection is for nut-website primarily, not for tarballs... so far... DIST_ALL_PAGES = $(DIST_ALL_MAN_PAGES) # Possible man page section remapping in some distros: MAN_SECTION_API_BASE=@MAN_SECTION_API_BASE@ MAN_SECTION_CFG_BASE=@MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS_BASE=@MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR_BASE=@MAN_SECTION_CMD_USR_BASE@ # Other rewritable properties: NUT_WEBSITE_BASE=@NUT_WEBSITE_BASE@ PACKAGE_VERSION=@PACKAGE_VERSION@ TREE_VERSION=@TREE_VERSION@ # Groups and locations for man pages manapidir = $(mandir)/man$(MAN_SECTION_API_BASE) manapi_DATA = mancfgdir = $(mandir)/man$(MAN_SECTION_CFG_BASE) mancfg_DATA = mansysdir = $(mandir)/man$(MAN_SECTION_CMD_SYS_BASE) mansys_DATA = manusrdir = $(mandir)/man$(MAN_SECTION_CMD_USR_BASE) manusr_DATA = ALL_TGT = if WITH_MANS if !KNOWN_UNABLE_MANS # Give it our best shot; do not try if we know we would fail # Do not distcheck-light-DIST_ALL_MAN_PAGES for fake pages either - # this is up to caller and use-case ALL_TGT += all-man endif !KNOWN_UNABLE_MANS endif WITH_MANS if WITH_HTML_SINGLE ALL_TGT += all-html else !WITH_HTML_SINGLE if WITH_HTML_CHUNKED ALL_TGT += all-html endif WITH_HTML_CHUNKED endif !WITH_HTML_SINGLE # Ensure early build by default automake "all" rule, if it gets used. BUILT_SOURCES = $(abs_top_builddir)/docs/man/.prep-src-docs all-optional # Note: this intends to be used instead of the "all" target that may have # been provided by automake, since we want to do nothing in certain cases. # Ideally it would refuse "make all" in certain cases, but we can't override # the automake-generated rules in each make implementation we care for. all-optional: $(abs_top_builddir)/docs/man/.prep-src-docs +@case "$(ALL_TGT)" in \ ""|" "|" "|" ") echo " DOCS_NO_MAN SKIP: $@ called in docs/man/Makefile: No format of man page rendering is enabled" ; exit 0 ;; \ *all-*) \ if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then echo " DOCS_NO_MAN SKIP: $@ called in docs/man/Makefile: requested to not work in this code path" ; exit 0 ; fi ; \ echo " DOC-FOLLOW-UP Basic 'make $@' in `pwd` is done, following up with 'make $(ALL_TGT)' to ensure complex document types (if enabled)" ; \ $(MAKE) $(AM_MAKEFLAGS) $(ALL_TGT) ; exit ;; \ esac ; exit 0 # Quickly check that we have all needed files (e.g. from configure script) # Do not ensure they are built/valid/etc. LIST_FILES = ( \ echo " HELPER $@" >&2 ; \ MISSING=0; \ TOTAL=0; \ for P in $${FILENAMES} ; do \ TOTAL="`expr $$TOTAL + 1`" ; \ F="`basename "$$P"`" ; \ if [ -s "$(abs_builddir)/$$F" ] ; then \ echo "BUILDDIR: $(builddir)/$$F" ; \ else \ if [ -s "$(abs_srcdir)/$$F" ] ; then \ echo "SRCDIR: $(srcdir)/$$F" ; \ else \ echo "MISSING: $$F" >&2 ; \ MISSING="`expr $$MISSING + 1`" ; \ fi ; \ fi ; \ done ; \ if [ x"$$MISSING" = x0 ] ; then echo "$@: SUCCESS ($$TOTAL files are all present)" >&2 ; else echo "$@: FAILED ($$MISSING files of $$TOTAL are missing, see above)" >&2 ; exit 1 ; fi ; \ ) if KNOWN_UNABLE_MANS FAKE_PAGES_BUMP_SRC = false else !KNOWN_UNABLE_MANS if DOC_INSTALL_DISTED_MANS FAKE_PAGES_BUMP_SRC = false else !DOC_INSTALL_DISTED_MANS FAKE_PAGES_BUMP_SRC = true endif !DOC_INSTALL_DISTED_MANS endif !KNOWN_UNABLE_MANS FAKE_FILES = ( \ echo " HELPER $@" >&2 ; \ MISSING=0; \ TOTAL=0; \ for P in $${FILENAMES} ; do \ TOTAL="`expr $$TOTAL + 1`" ; \ F="`basename "$$P"`" ; \ if [ ! -s "$(abs_builddir)/$$F" ] && [ ! -s "$(abs_srcdir)/$$F" ] ; then \ echo "PLACEHOLDER" > "$(abs_builddir)/$$F" ; \ MISSING="`expr $$MISSING + 1`" ; \ fi ; \ done ; \ if [ x"$$MISSING" = x0 ] ; then echo "$@: SUCCESS ($$TOTAL files are all present)" >&2 ; else echo "$@: FAKED SOME FILES ($$MISSING files of $$TOTAL were missing)" >&2 ; exit 1 ; fi ; \ ) # Unlike helpers above, does not fail if placeholders were seen FAKE_FILES_RM = ( \ echo " HELPER $@" >&2 ; \ MISSING=0; \ TOTAL=0; \ for P in $${FILENAMES} ; do \ TOTAL="`expr $$TOTAL + 1`" ; \ F="`basename "$$P"`" ; \ if [ -s "$(abs_builddir)/$$F" ] \ && [ x"PLACEHOLDER" = x"`cat "$(abs_builddir)/$$F"`" ] ; then \ rm -f "$(abs_builddir)/$$F" ; \ MISSING="`expr $$MISSING + 1`" ; \ fi ; \ done ; \ if [ x"$$MISSING" = x0 ] ; then echo "$@: SUCCESS ($$TOTAL files were all real or already absent)" >&2 ; else echo "$@: REMOVED SOME FAKED FILES ($$MISSING files of $$TOTAL were placeholders)" >&2 ; fi ; \ ) # List man pages we intend to deliver (depending on chosen build products) print-MAN_MANS: @echo "$(MAN_MANS)" check-list-MAN_MANS: @FILENAMES='$(MAN_MANS)' ; $(LIST_FILES) # List all (man page) file names we know we should distribute in a tarball # (whether built right now or inherited from a tarball build by itself) print-DIST_ALL_PAGES: @echo "$(DIST_ALL_PAGES)" check-list-DIST_ALL_PAGES: @FILENAMES='$(DIST_ALL_PAGES)' ; $(LIST_FILES) # If any pages are missing, fake them distcheck-light-DIST_ALL_PAGES: @FILENAMES='$(DIST_ALL_PAGES)' ; $(FAKE_FILES) || ( \ if [ x"$(FAKE_PAGES_BUMP_SRC)" = xtrue ] ; then \ cd "$(abs_srcdir)" && touch $(SRC_ALL_PAGES) || echo "$@: Well we tried" >&2 ; \ fi ; ) print-DIST_ALL_MAN_PAGES: @echo "$(DIST_ALL_MAN_PAGES)" check-list-DIST_ALL_MAN_PAGES: @FILENAMES='$(DIST_ALL_MAN_PAGES)' ; $(LIST_FILES) # If any pages are missing, fake them distcheck-light-DIST_ALL_MAN_PAGES: @FILENAMES='$(DIST_ALL_MAN_PAGES)' ; $(FAKE_FILES) || ( \ if [ x"$(FAKE_PAGES_BUMP_SRC)" = xtrue ] ; then \ cd "$(abs_srcdir)" && touch $(SRC_ALL_PAGES) || echo "$@: Well we tried" >&2 ; \ fi ; ) # Likewise for HTML renders (but no fake pages made/needed for dist) print-HTML_MANS: @echo "$(HTML_MANS)" check-list-HTML_MANS: @FILENAMES='$(HTML_MANS)' ; $(LIST_FILES) print-DIST_ALL_HTML_PAGES: @echo "$(DIST_ALL_HTML_PAGES)" check-list-DIST_ALL_HTML_PAGES: @FILENAMES='$(DIST_ALL_HTML_PAGES)' ; $(LIST_FILES) # Likewise for plaintext sources print-SRC_ALL_PAGES: @echo "$(SRC_ALL_PAGES)" check-list-SRC_ALL_PAGES: @FILENAMES='$(SRC_ALL_PAGES)' ; $(LIST_FILES) # Base configuration and client manpages, always installed SRC_CONF_PAGES = \ nut.conf.txt \ ups.conf.txt \ upsd.conf.txt \ upsd.users.txt \ upsmon.conf.txt \ upssched.conf.txt INST_MAN_CONF_PAGES = \ nut.conf.$(MAN_SECTION_CFG) \ ups.conf.$(MAN_SECTION_CFG) \ upsd.conf.$(MAN_SECTION_CFG) \ upsd.users.$(MAN_SECTION_CFG) \ upsmon.conf.$(MAN_SECTION_CFG) \ upssched.conf.$(MAN_SECTION_CFG) DIST_ALL_MAN_PAGES += $(INST_MAN_CONF_PAGES) if WITH_MANS MAN_CONF_PAGES = $(INST_MAN_CONF_PAGES) endif WITH_MANS mancfg_DATA += $(MAN_CONF_PAGES) INST_HTML_CONF_MANS = \ nut.conf.html \ ups.conf.html \ upsd.conf.html \ upsd.users.html \ upsmon.conf.html \ upssched.conf.html DIST_ALL_HTML_PAGES += $(INST_HTML_CONF_MANS) HTML_CONF_MANS = $(INST_HTML_CONF_MANS) # NOTE: Currently SRC_DRIVERTOOL_PAGES are a separate list to generate # a linkman-drivertool-names.txt file, but historically remain part of # MAN/HTML_CLIENT_PAGES in the bigger picture. SRC_DRIVERTOOL_PAGES = \ nut-driver-enumerator.txt \ upsdrvctl.txt \ upsdrvsvcctl.txt SRC_CLIENT_PAGES = \ $(SRC_DRIVERTOOL_PAGES) \ nutupsdrv.txt \ upsc.txt \ upscmd.txt \ upsd.txt \ upslog.txt \ upsmon.txt \ upsrw.txt \ upssched.txt INST_MAN_CLIENT_PAGES = \ nutupsdrv.$(MAN_SECTION_CMD_SYS) \ nut-driver-enumerator.$(MAN_SECTION_CMD_SYS) \ upsc.$(MAN_SECTION_CMD_SYS) \ upscmd.$(MAN_SECTION_CMD_SYS) \ upsd.$(MAN_SECTION_CMD_SYS) \ upsdrvctl.$(MAN_SECTION_CMD_SYS) \ upsdrvsvcctl.$(MAN_SECTION_CMD_SYS) \ upslog.$(MAN_SECTION_CMD_SYS) \ upsmon.$(MAN_SECTION_CMD_SYS) \ upsrw.$(MAN_SECTION_CMD_SYS) \ upssched.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_CLIENT_PAGES) if WITH_MANS MAN_CLIENT_PAGES = $(INST_MAN_CLIENT_PAGES) endif WITH_MANS MAN_CLIENT_PAGES_ADDON_NUT_EXE = nut.exe.$(MAN_SECTION_CMD_SYS) if HAVE_WINDOWS SRC_CLIENT_PAGES += nut.exe.txt if WITH_MANS INST_MAN_CLIENT_PAGES += $(MAN_CLIENT_PAGES_ADDON_NUT_EXE) else !WITH_MANS DIST_ALL_MAN_PAGES += $(MAN_CLIENT_PAGES_ADDON_NUT_EXE) endif !WITH_MANS else !HAVE_WINDOWS SRC_ALL_PAGES += nut.exe.txt DIST_ALL_MAN_PAGES += $(MAN_CLIENT_PAGES_ADDON_NUT_EXE) endif !HAVE_WINDOWS MAN_CLIENT_PAGES_ADDON_NUT_MONITOR = \ NUT-Monitor-py2gtk2.$(MAN_SECTION_CMD_SYS) \ NUT-Monitor-py3qt5.$(MAN_SECTION_CMD_SYS) \ NUT-Monitor.$(MAN_SECTION_CMD_SYS) # Alias page for one text describing two commands: NUT-Monitor-py2gtk2.$(MAN_SECTION_CMD_SYS): NUT-Monitor.$(MAN_SECTION_CMD_SYS) touch $@ NUT-Monitor-py3qt5.$(MAN_SECTION_CMD_SYS): NUT-Monitor.$(MAN_SECTION_CMD_SYS) touch $@ if WITH_NUT_MONITOR SRC_CLIENT_PAGES += NUT-Monitor.txt if WITH_MANS INST_MAN_CLIENT_PAGES += $(MAN_CLIENT_PAGES_ADDON_NUT_MONITOR) else !WITH_MANS DIST_ALL_MAN_PAGES += $(MAN_CLIENT_PAGES_ADDON_NUT_MONITOR) endif !WITH_MANS else !WITH_NUT_MONITOR SRC_ALL_PAGES += NUT-Monitor.txt DIST_ALL_MAN_PAGES += $(MAN_CLIENT_PAGES_ADDON_NUT_MONITOR) endif !WITH_NUT_MONITOR mansys_DATA += $(MAN_CLIENT_PAGES) INST_HTML_CLIENT_MANS = \ nutupsdrv.html \ nut-driver-enumerator.html \ upsc.html \ upscmd.html \ upsd.html \ upsdrvctl.html \ upsdrvsvcctl.html \ upslog.html \ upsmon.html \ upsrw.html \ upssched.html if HAVE_WINDOWS INST_HTML_CLIENT_MANS += nut.exe.html else !HAVE_WINDOWS DIST_ALL_HTML_PAGES += nut.exe.html endif !HAVE_WINDOWS if WITH_NUT_MONITOR INST_HTML_CLIENT_MANS += NUT-Monitor.html # Can't make this work on all make implementations at once, so disabled for now # Anyway it would be the same man-like page for several functions INST_HTML_CLIENT_MANS_FICTION = \ NUT-Monitor-py2gtk2.html \ NUT-Monitor-py3qt5.html NUT-Monitor-py2gtk2.html: NUT-Monitor.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ NUT-Monitor-py3qt5.html: NUT-Monitor.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ else !WITH_NUT_MONITOR DIST_ALL_HTML_PAGES += NUT-Monitor.html endif !WITH_NUT_MONITOR DIST_ALL_HTML_PAGES += $(INST_HTML_CLIENT_MANS) HTML_CLIENT_MANS = $(INST_HTML_CLIENT_MANS) SRC_TOOL_PAGES = \ nut-scanner.txt \ nut-recorder.txt \ nutconf.txt # FIXME: Make nut-scanner and nut-conf pages optional (if tool is enabled)? INST_MAN_TOOL_PAGES = \ nut-scanner.$(MAN_SECTION_CMD_SYS) \ nut-recorder.$(MAN_SECTION_CMD_SYS) \ nutconf.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_TOOL_PAGES) if WITH_MANS MAN_TOOL_PAGES = $(INST_MAN_TOOL_PAGES) endif WITH_MANS mansys_DATA += $(MAN_TOOL_PAGES) # FIXME: Make nut-scanner and nut-conf pages optional (if tool is enabled)? INST_HTML_TOOL_MANS = \ nut-scanner.html \ nut-recorder.html \ nutconf.html DIST_ALL_HTML_PAGES += $(INST_HTML_TOOL_MANS) HTML_TOOL_MANS = $(INST_HTML_TOOL_MANS) # CGI (--with-cgi) related manpages SRC_CGI_PAGES = \ hosts.conf.txt \ upsset.conf.txt \ upsstats.html.txt \ upsset.cgi.txt \ upsstats.cgi.txt \ upsimage.cgi.txt INST_MAN_CGI_CFG_PAGES = \ hosts.conf.$(MAN_SECTION_CFG) \ upsset.conf.$(MAN_SECTION_CFG) \ upsstats.html.$(MAN_SECTION_CFG) INST_MAN_CGI_CMD_SYS_PAGES = \ upsset.cgi.$(MAN_SECTION_CMD_SYS) \ upsstats.cgi.$(MAN_SECTION_CMD_SYS) \ upsimage.cgi.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_CGI_CFG_PAGES) $(INST_MAN_CGI_CMD_SYS_PAGES) if WITH_MANS MAN_CGI_CFG_PAGES = $(INST_MAN_CGI_CFG_PAGES) MAN_CGI_CMD_SYS_PAGES = $(INST_MAN_CGI_CMD_SYS_PAGES) endif WITH_MANS if WITH_CGI mancfg_DATA += $(MAN_CGI_CFG_PAGES) mansys_DATA += $(MAN_CGI_CMD_SYS_PAGES) endif WITH_CGI INST_HTML_CGI_MANS = \ hosts.conf.html \ upsset.conf.html \ upsstats.html.html \ upsset.cgi.html \ upsstats.cgi.html \ upsimage.cgi.html DIST_ALL_HTML_PAGES += $(INST_HTML_CGI_MANS) HTML_CGI_MANS = $(INST_HTML_CGI_MANS) # Development (--with-dev) related manpages SRC_DEV_PAGES = \ upsclient.txt \ upscli_add_host_cert.txt \ upscli_cleanup.txt \ upscli_connect.txt \ upscli_disconnect.txt \ upscli_fd.txt \ upscli_get.txt \ upscli_init.txt \ upscli_set_default_connect_timeout.txt \ upscli_get_default_connect_timeout.txt \ upscli_init_default_connect_timeout.txt \ upscli_list_next.txt \ upscli_list_start.txt \ upscli_readline.txt \ upscli_sendline.txt \ upscli_splitaddr.txt \ upscli_splitname.txt \ upscli_ssl.txt \ upscli_strerror.txt \ upscli_upserror.txt \ upscli_str_add_unique_token.txt \ upscli_str_contains_token.txt \ libnutclient.txt \ libnutclient_commands.txt \ libnutclient_devices.txt \ libnutclient_general.txt \ libnutclient_misc.txt \ libnutclient_tcp.txt \ libnutclient_variables.txt \ nutscan.txt \ nutscan_scan_snmp.txt \ nutscan_scan_usb.txt \ nutscan_scan_xml_http_range.txt \ nutscan_scan_nut.txt \ nutscan_scan_nut_simulation.txt \ nutscan_scan_avahi.txt \ nutscan_scan_ipmi.txt \ nutscan_scan_eaton_serial.txt \ nutscan_display_sanity_check.txt \ nutscan_display_sanity_check_serial.txt \ nutscan_display_ups_conf_with_sanity_check.txt \ nutscan_display_ups_conf.txt \ nutscan_display_parsable.txt \ nutscan_init_ip_ranges.txt \ nutscan_free_ip_ranges.txt \ nutscan_stringify_ip_ranges.txt \ nutscan_add_ip_range.txt \ nutscan_ip_ranges_iter_init.txt \ nutscan_ip_ranges_iter_inc.txt \ nutscan_cidr_to_ip.txt \ nutscan_new_device.txt \ nutscan_free_device.txt \ nutscan_add_option_to_device.txt \ nutscan_add_device_to_device.txt \ nutscan_init.txt \ nutscan_get_serial_ports_list.txt \ libupsclient-config.txt \ sockdebug.txt \ skel.txt # NOTE: nutclient_*.$(MAN_SECTION_API) has no source counterpart (libnutclient_*.txt) LIBNUTCLIENT_MISC_DEPS = \ nutclient_authenticate.$(MAN_SECTION_API) \ nutclient_logout.$(MAN_SECTION_API) \ nutclient_device_login.$(MAN_SECTION_API) \ nutclient_get_device_num_logins.$(MAN_SECTION_API) \ nutclient_device_master.$(MAN_SECTION_API) \ nutclient_device_forced_shutdown.$(MAN_SECTION_API) $(LIBNUTCLIENT_MISC_DEPS): libnutclient_misc.$(MAN_SECTION_API) touch $@ LIBNUTCLIENT_TCP_DEPS = \ nutclient_tcp_create_client.$(MAN_SECTION_API) \ nutclient_tcp_disconnect.$(MAN_SECTION_API) \ nutclient_tcp_get_timeout.$(MAN_SECTION_API) \ nutclient_tcp_is_connected.$(MAN_SECTION_API) \ nutclient_tcp_reconnect.$(MAN_SECTION_API) \ nutclient_tcp_set_timeout.$(MAN_SECTION_API) $(LIBNUTCLIENT_TCP_DEPS): libnutclient_tcp.$(MAN_SECTION_API) touch $@ LIBNUTCLIENT_GENERAL_DEPS = \ nutclient_destroy.$(MAN_SECTION_API) $(LIBNUTCLIENT_GENERAL_DEPS): libnutclient_general.$(MAN_SECTION_API) touch $@ LIBNUTCLIENT_VARIABLES_DEPS = \ nutclient_get_device_rw_variables.$(MAN_SECTION_API) \ nutclient_get_device_variable_description.$(MAN_SECTION_API) \ nutclient_get_device_variables.$(MAN_SECTION_API) \ nutclient_get_device_variable_values.$(MAN_SECTION_API) \ nutclient_has_device_variable.$(MAN_SECTION_API) \ nutclient_set_device_variable_value.$(MAN_SECTION_API) \ nutclient_set_device_variable_values.$(MAN_SECTION_API) $(LIBNUTCLIENT_VARIABLES_DEPS): libnutclient_variables.$(MAN_SECTION_API) touch $@ LIBNUTCLIENT_COMMANDS_DEPS = \ nutclient_execute_device_command.$(MAN_SECTION_API) \ nutclient_get_device_command_description.$(MAN_SECTION_API) \ nutclient_get_device_commands.$(MAN_SECTION_API) \ nutclient_has_device_command.$(MAN_SECTION_API) $(LIBNUTCLIENT_COMMANDS_DEPS): libnutclient_commands.$(MAN_SECTION_API) touch $@ LIBNUTCLIENT_DEVICES_DEPS = \ nutclient_get_device_description.$(MAN_SECTION_API) \ nutclient_get_devices.$(MAN_SECTION_API) \ nutclient_has_device.$(MAN_SECTION_API) $(LIBNUTCLIENT_DEVICES_DEPS): libnutclient_devices.$(MAN_SECTION_API) touch $@ INST_MAN_DEV_API_PAGES = \ upsclient.$(MAN_SECTION_API) \ upscli_add_host_cert.$(MAN_SECTION_API) \ upscli_cleanup.$(MAN_SECTION_API) \ upscli_connect.$(MAN_SECTION_API) \ upscli_tryconnect.$(MAN_SECTION_API) \ upscli_disconnect.$(MAN_SECTION_API) \ upscli_fd.$(MAN_SECTION_API) \ upscli_get.$(MAN_SECTION_API) \ upscli_init.$(MAN_SECTION_API) \ upscli_set_default_connect_timeout.$(MAN_SECTION_API) \ upscli_get_default_connect_timeout.$(MAN_SECTION_API) \ upscli_init_default_connect_timeout.$(MAN_SECTION_API) \ upscli_list_next.$(MAN_SECTION_API) \ upscli_list_start.$(MAN_SECTION_API) \ upscli_readline.$(MAN_SECTION_API) \ upscli_readline_timeout.$(MAN_SECTION_API) \ upscli_sendline.$(MAN_SECTION_API) \ upscli_sendline_timeout.$(MAN_SECTION_API) \ upscli_splitaddr.$(MAN_SECTION_API) \ upscli_splitname.$(MAN_SECTION_API) \ upscli_ssl.$(MAN_SECTION_API) \ upscli_strerror.$(MAN_SECTION_API) \ upscli_upserror.$(MAN_SECTION_API) \ upscli_str_add_unique_token.$(MAN_SECTION_API) \ upscli_str_contains_token.$(MAN_SECTION_API) \ libnutclient.$(MAN_SECTION_API) \ libnutclient_commands.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_COMMANDS_DEPS) \ libnutclient_devices.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_DEVICES_DEPS) \ libnutclient_general.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_GENERAL_DEPS) \ libnutclient_misc.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_MISC_DEPS) \ libnutclient_tcp.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_TCP_DEPS) \ libnutclient_variables.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_VARIABLES_DEPS) \ nutscan.$(MAN_SECTION_API) \ nutscan_scan_snmp.$(MAN_SECTION_API) \ nutscan_scan_usb.$(MAN_SECTION_API) \ nutscan_scan_xml_http_range.$(MAN_SECTION_API) \ nutscan_scan_nut.$(MAN_SECTION_API) \ nutscan_scan_nut_simulation.$(MAN_SECTION_API) \ nutscan_scan_avahi.$(MAN_SECTION_API) \ nutscan_scan_ipmi.$(MAN_SECTION_API) \ nutscan_scan_eaton_serial.$(MAN_SECTION_API) \ nutscan_display_sanity_check.$(MAN_SECTION_API) \ nutscan_display_sanity_check_serial.$(MAN_SECTION_API) \ nutscan_display_ups_conf_with_sanity_check.$(MAN_SECTION_API) \ nutscan_display_ups_conf.$(MAN_SECTION_API) \ nutscan_display_parsable.$(MAN_SECTION_API) \ nutscan_init_ip_ranges.$(MAN_SECTION_API) \ nutscan_free_ip_ranges.$(MAN_SECTION_API) \ nutscan_stringify_ip_ranges.$(MAN_SECTION_API) \ nutscan_add_ip_range.$(MAN_SECTION_API) \ nutscan_ip_ranges_iter_init.$(MAN_SECTION_API) \ nutscan_ip_ranges_iter_inc.$(MAN_SECTION_API) \ nutscan_cidr_to_ip.$(MAN_SECTION_API) \ nutscan_new_device.$(MAN_SECTION_API) \ nutscan_free_device.$(MAN_SECTION_API) \ nutscan_add_option_to_device.$(MAN_SECTION_API) \ nutscan_add_commented_option_to_device.$(MAN_SECTION_API) \ nutscan_add_device_to_device.$(MAN_SECTION_API) \ nutscan_get_serial_ports_list.$(MAN_SECTION_API) \ nutscan_init.$(MAN_SECTION_API) # Alias page for one text describing two commands: upscli_readline_timeout.$(MAN_SECTION_API): upscli_readline.$(MAN_SECTION_API) touch $@ upscli_sendline_timeout.$(MAN_SECTION_API): upscli_sendline.$(MAN_SECTION_API) touch $@ upscli_tryconnect.$(MAN_SECTION_API): upscli_connect.$(MAN_SECTION_API) touch $@ nutscan_scan_ip_range_snmp.$(MAN_SECTION_API): nutscan_scan_snmp.$(MAN_SECTION_API) touch $@ nutscan_scan_ip_range_xml_http.$(MAN_SECTION_API): nutscan_scan_xml_http_range.$(MAN_SECTION_API) touch $@ nutscan_scan_ip_range_nut.$(MAN_SECTION_API): nutscan_scan_nut.$(MAN_SECTION_API) touch $@ nutscan_scan_ip_range_ipmi.$(MAN_SECTION_API): nutscan_scan_ipmi.$(MAN_SECTION_API) touch $@ nutscan_add_commented_option_to_device.$(MAN_SECTION_API): nutscan_add_option_to_device.$(MAN_SECTION_API) touch $@ INST_MAN_DEV_CMD_USR_PAGES = \ libupsclient-config.$(MAN_SECTION_CMD_USR) INST_MAN_DEV_CMD_SYS_PAGES = \ sockdebug.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_DEV_API_PAGES) $(INST_MAN_DEV_CMD_USR_PAGES) $(INST_MAN_DEV_CMD_SYS_PAGES) if WITH_MANS MAN_DEV_API_PAGES = $(INST_MAN_DEV_API_PAGES) MAN_DEV_CMD_USR_PAGES = $(INST_MAN_DEV_CMD_USR_PAGES) MAN_DEV_CMD_SYS_PAGES = $(INST_MAN_DEV_CMD_SYS_PAGES) endif WITH_MANS if WITH_DEV manapi_DATA += $(MAN_DEV_API_PAGES) mansys_DATA += $(MAN_DEV_CMD_SYS_PAGES) if !WITH_PKG_CONFIG manusr_DATA += $(MAN_DEV_CMD_USR_PAGES) endif !WITH_PKG_CONFIG endif WITH_DEV INST_HTML_DEV_MANS = \ upsclient.html \ upscli_add_host_cert.html \ upscli_cleanup.html \ upscli_connect.html \ upscli_disconnect.html \ upscli_fd.html \ upscli_get.html \ upscli_init.html \ upscli_set_default_connect_timeout.html \ upscli_get_default_connect_timeout.html \ upscli_init_default_connect_timeout.html \ upscli_list_next.html \ upscli_list_start.html \ upscli_readline.html \ upscli_sendline.html \ upscli_splitaddr.html \ upscli_splitname.html \ upscli_ssl.html \ upscli_strerror.html \ upscli_upserror.html \ upscli_str_add_unique_token.html \ upscli_str_contains_token.html \ libnutclient.html \ libnutclient_commands.html \ libnutclient_devices.html \ libnutclient_general.html \ libnutclient_misc.html \ libnutclient_tcp.html \ libnutclient_variables.html \ nutscan.html \ nutscan_scan_snmp.html \ nutscan_scan_usb.html \ nutscan_scan_xml_http_range.html \ nutscan_scan_nut.html \ nutscan_scan_nut_simulation.html \ nutscan_scan_avahi.html \ nutscan_scan_ipmi.html \ nutscan_scan_eaton_serial.html \ nutscan_display_sanity_check.html \ nutscan_display_sanity_check_serial.html \ nutscan_display_ups_conf_with_sanity_check.html \ nutscan_display_ups_conf.html \ nutscan_display_parsable.html \ nutscan_init_ip_ranges.html \ nutscan_free_ip_ranges.html \ nutscan_stringify_ip_ranges.html \ nutscan_add_ip_range.html \ nutscan_ip_ranges_iter_init.html \ nutscan_ip_ranges_iter_inc.html \ nutscan_cidr_to_ip.html \ nutscan_new_device.html \ nutscan_free_device.html \ nutscan_add_option_to_device.html \ nutscan_add_device_to_device.html \ nutscan_get_serial_ports_list.html \ nutscan_init.html \ libupsclient-config.html \ sockdebug.html \ skel.html DIST_ALL_HTML_PAGES += $(INST_HTML_DEV_MANS) HTML_DEV_MANS = $(INST_HTML_DEV_MANS) # Can't make this work on all make implementations at once, so disabled for now # Anyway it would be the same man-like page for several functions HTML_DEV_MANS_FICTION = \ upscli_readline_timeout.html \ upscli_sendline_timeout.html \ upscli_tryconnect.html \ nutscan_scan_ip_range_snmp.html \ nutscan_scan_ip_range_xml_http.html \ nutscan_scan_ip_range_nut.html \ nutscan_scan_ip_range_ipmi.html \ nutscan_add_commented_option_to_device.html upscli_readline_timeout.html: upscli_readline.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ upscli_sendline_timeout.html: upscli_sendline.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ upscli_tryconnect.html: upscli_connect.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_scan_ip_range_snmp.html: nutscan_scan_snmp.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_scan_ip_range_xml_http.html: nutscan_scan_xml_http_range.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_scan_ip_range_nut.html: nutscan_scan_nut.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_scan_ip_range_ipmi.html: nutscan_scan_ipmi.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_add_commented_option_to_device.html: nutscan_add_option_to_device.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ # Drivers related manpages # If (--with-drivers=...) then we only build specific documents, however # still do track (and EXTRA_DIST, and spellcheck) all available sources. if SOME_DRIVERS mansys_DATA += $(DRIVER_MAN_LIST) endif # (--with-serial) SRC_SERIAL_PAGES = \ al175.txt \ apcsmart.txt \ apcsmart-old.txt \ bcmxcp.txt \ belkin.txt \ belkinunv.txt \ bestfortress.txt \ bestuferrups.txt \ bestups.txt \ bestfcom.txt \ bicker_ser.txt \ blazer-common.txt \ blazer_ser.txt \ clone.txt \ clone-outlet.txt \ dummy-ups.txt \ etapro.txt \ everups.txt \ gamatronic.txt \ genericups.txt \ isbmex.txt \ ivtscd.txt \ liebert.txt \ liebert-gxe.txt \ liebert-esp2.txt \ masterguard.txt \ metasys.txt \ mge-shut.txt \ mge-utalk.txt \ nhs_ser.txt \ oneac.txt \ microdowell.txt \ microsol-apc.txt \ nutdrv_siemens_sitop.txt \ optiups.txt \ powercom.txt \ powerpanel.txt \ rhino.txt \ riello_ser.txt \ sms_ser.txt \ safenet.txt \ solis.txt \ tripplite.txt \ tripplitesu.txt \ upscode2.txt \ victronups.txt \ apcupsd-ups.txt INST_MAN_SERIAL_PAGES = \ al175.$(MAN_SECTION_CMD_SYS) \ apcsmart.$(MAN_SECTION_CMD_SYS) \ apcsmart-old.$(MAN_SECTION_CMD_SYS) \ bcmxcp.$(MAN_SECTION_CMD_SYS) \ belkin.$(MAN_SECTION_CMD_SYS) \ belkinunv.$(MAN_SECTION_CMD_SYS) \ bestfortress.$(MAN_SECTION_CMD_SYS) \ bestuferrups.$(MAN_SECTION_CMD_SYS) \ bestups.$(MAN_SECTION_CMD_SYS) \ bestfcom.$(MAN_SECTION_CMD_SYS) \ bicker_ser.$(MAN_SECTION_CMD_SYS) \ blazer_ser.$(MAN_SECTION_CMD_SYS) \ clone.$(MAN_SECTION_CMD_SYS) \ clone-outlet.$(MAN_SECTION_CMD_SYS) \ dummy-ups.$(MAN_SECTION_CMD_SYS) \ etapro.$(MAN_SECTION_CMD_SYS) \ everups.$(MAN_SECTION_CMD_SYS) \ gamatronic.$(MAN_SECTION_CMD_SYS) \ genericups.$(MAN_SECTION_CMD_SYS) \ isbmex.$(MAN_SECTION_CMD_SYS) \ ivtscd.$(MAN_SECTION_CMD_SYS) \ liebert.$(MAN_SECTION_CMD_SYS) \ liebert-gxe.$(MAN_SECTION_CMD_SYS) \ liebert-esp2.$(MAN_SECTION_CMD_SYS) \ masterguard.$(MAN_SECTION_CMD_SYS) \ metasys.$(MAN_SECTION_CMD_SYS) \ mge-shut.$(MAN_SECTION_CMD_SYS) \ mge-utalk.$(MAN_SECTION_CMD_SYS) \ oneac.$(MAN_SECTION_CMD_SYS) \ microdowell.$(MAN_SECTION_CMD_SYS) \ microsol-apc.$(MAN_SECTION_CMD_SYS) \ nutdrv_siemens_sitop.$(MAN_SECTION_CMD_SYS) \ optiups.$(MAN_SECTION_CMD_SYS) \ powercom.$(MAN_SECTION_CMD_SYS) \ powerpanel.$(MAN_SECTION_CMD_SYS) \ rhino.$(MAN_SECTION_CMD_SYS) \ riello_ser.$(MAN_SECTION_CMD_SYS) \ sms_ser.$(MAN_SECTION_CMD_SYS) \ safenet.$(MAN_SECTION_CMD_SYS) \ solis.$(MAN_SECTION_CMD_SYS) \ tripplite.$(MAN_SECTION_CMD_SYS) \ tripplitesu.$(MAN_SECTION_CMD_SYS) \ upscode2.$(MAN_SECTION_CMD_SYS) \ victronups.$(MAN_SECTION_CMD_SYS) \ apcupsd-ups.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_SERIAL_PAGES) DIST_ALL_MAN_PAGES += nhs_ser.$(MAN_SECTION_CMD_SYS) if ! SOME_DRIVERS if WITH_MANS MAN_SERIAL_PAGES = $(INST_MAN_SERIAL_PAGES) if HAVE_LINUX_SERIAL_H # Temporary, until ported to more OSes MAN_SERIAL_PAGES += \ nhs_ser.$(MAN_SECTION_CMD_SYS) endif HAVE_LINUX_SERIAL_H endif WITH_MANS if WITH_SERIAL mansys_DATA += $(MAN_SERIAL_PAGES) endif WITH_SERIAL endif ! SOME_DRIVERS INST_HTML_SERIAL_MANS = \ al175.html \ apcsmart.html \ apcsmart-old.html \ bcmxcp.html \ belkin.html \ belkinunv.html \ bestfortress.html \ bestuferrups.html \ bestups.html \ bestfcom.html \ bicker_ser.html \ blazer_ser.html \ clone.html \ clone-outlet.html \ dummy-ups.html \ etapro.html \ everups.html \ gamatronic.html \ genericups.html \ isbmex.html \ ivtscd.html \ liebert.html \ liebert-gxe.html\ liebert-esp2.html \ masterguard.html \ metasys.html \ mge-shut.html \ mge-utalk.html \ oneac.html \ microdowell.html \ microsol-apc.html \ nutdrv_siemens_sitop.html \ optiups.html \ powercom.html \ powerpanel.html \ rhino.html \ riello_ser.html \ sms_ser.html \ safenet.html \ solis.html \ tripplite.html \ tripplitesu.html \ upscode2.html \ victronups.html \ apcupsd-ups.html if HAVE_LINUX_SERIAL_H # Temporary, until ported to more OSes INST_HTML_SERIAL_MANS += \ nhs_ser.html else !HAVE_LINUX_SERIAL_H DIST_ALL_HTML_PAGES += \ nhs_ser.html endif !HAVE_LINUX_SERIAL_H DIST_ALL_HTML_PAGES += $(INST_HTML_SERIAL_MANS) if ! SOME_DRIVERS HTML_SERIAL_MANS = $(INST_HTML_SERIAL_MANS) endif ! SOME_DRIVERS # (--with-snmp) SRC_SNMP_PAGES = snmp-ups.txt INST_MAN_SNMP_PAGES = snmp-ups.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_SNMP_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_SNMP_PAGES = $(INST_MAN_SNMP_PAGES) endif WITH_MANS if WITH_SNMP mansys_DATA += $(MAN_SNMP_PAGES) endif WITH_SNMP endif ! SOME_DRIVERS INST_HTML_SNMP_MANS = snmp-ups.html DIST_ALL_HTML_PAGES += $(INST_HTML_SNMP_MANS) if ! SOME_DRIVERS HTML_SNMP_MANS = $(INST_HTML_SNMP_MANS) endif ! SOME_DRIVERS # (--with-usb) SRC_USB_LIBUSB_PAGES = \ bcmxcp_usb.txt \ blazer-common.txt \ blazer_usb.txt \ nutdrv_atcl_usb.txt \ nut_usb_addvars.txt \ richcomm_usb.txt \ riello_usb.txt \ tripplite_usb.txt \ usbhid-ups.txt INST_MAN_USB_LIBUSB_PAGES = \ bcmxcp_usb.$(MAN_SECTION_CMD_SYS) \ blazer_usb.$(MAN_SECTION_CMD_SYS) \ nutdrv_atcl_usb.$(MAN_SECTION_CMD_SYS) \ richcomm_usb.$(MAN_SECTION_CMD_SYS) \ riello_usb.$(MAN_SECTION_CMD_SYS) \ tripplite_usb.$(MAN_SECTION_CMD_SYS) \ usbhid-ups.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_USB_LIBUSB_PAGES) if ! SOME_DRIVERS # NOTE: nut_usb_addvars and blazer-common are not standalone man pages if WITH_MANS MAN_USB_LIBUSB_PAGES = $(INST_MAN_USB_LIBUSB_PAGES) endif WITH_MANS if WITH_USB mansys_DATA += $(MAN_USB_LIBUSB_PAGES) endif WITH_USB endif ! SOME_DRIVERS INST_HTML_USB_LIBUSB_MANS = \ bcmxcp_usb.html \ blazer_usb.html \ nutdrv_atcl_usb.html \ richcomm_usb.html \ riello_usb.html \ tripplite_usb.html \ usbhid-ups.html DIST_ALL_HTML_PAGES += $(INST_HTML_USB_LIBUSB_MANS) if ! SOME_DRIVERS HTML_USB_LIBUSB_MANS = $(INST_HTML_USB_LIBUSB_MANS) endif ! SOME_DRIVERS # (--with-serial / --with-usb) SRC_SERIAL_USB_PAGES = \ nutdrv_qx.txt INST_MAN_SERIAL_USB_PAGES = \ nutdrv_qx.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_SERIAL_USB_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_SERIAL_USB_PAGES = $(INST_MAN_SERIAL_USB_PAGES) endif WITH_MANS if WITH_SERIAL mansys_DATA += $(MAN_SERIAL_USB_PAGES) else !WITH_SERIAL if WITH_USB mansys_DATA += $(MAN_SERIAL_USB_PAGES) endif WITH_USB endif !WITH_SERIAL endif ! SOME_DRIVERS INST_HTML_SERIAL_USB_MANS = \ nutdrv_qx.html DIST_ALL_HTML_PAGES += $(INST_HTML_SERIAL_USB_MANS) if ! SOME_DRIVERS HTML_SERIAL_USB_MANS = $(INST_HTML_SERIAL_USB_MANS) endif ! SOME_DRIVERS # (--with-neon) SRC_NETXML_PAGES = netxml-ups.txt INST_MAN_NETXML_PAGES = netxml-ups.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_NETXML_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_NETXML_PAGES = $(INST_MAN_NETXML_PAGES) endif WITH_MANS if WITH_NEON mansys_DATA += $(MAN_NETXML_PAGES) endif WITH_NEON endif ! SOME_DRIVERS INST_HTML_NETXML_MANS = netxml-ups.html DIST_ALL_HTML_PAGES += $(INST_HTML_NETXML_MANS) if ! SOME_DRIVERS HTML_NETXML_MANS = $(INST_HTML_NETXML_MANS) endif ! SOME_DRIVERS # (--with-powerman) SRC_POWERMAN_PAGES = powerman-pdu.txt INST_MAN_POWERMAN_PAGES = powerman-pdu.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_POWERMAN_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_POWERMAN_PAGES = $(INST_MAN_POWERMAN_PAGES) endif WITH_MANS if WITH_LIBPOWERMAN mansys_DATA += $(MAN_POWERMAN_PAGES) endif WITH_LIBPOWERMAN endif ! SOME_DRIVERS INST_HTML_POWERMAN_MANS = powerman-pdu.html DIST_ALL_HTML_PAGES += $(INST_HTML_POWERMAN_MANS) if ! SOME_DRIVERS HTML_POWERMAN_MANS = $(INST_HTML_POWERMAN_MANS) endif ! SOME_DRIVERS # (--with-ipmi) SRC_IPMIPSU_PAGES = nut-ipmipsu.txt INST_MAN_IPMIPSU_PAGES = nut-ipmipsu.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_IPMIPSU_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_IPMIPSU_PAGES = $(INST_MAN_IPMIPSU_PAGES) endif WITH_MANS if WITH_IPMI mansys_DATA += $(MAN_IPMIPSU_PAGES) endif WITH_IPMI endif ! SOME_DRIVERS INST_HTML_IPMIPSU_MANS = nut-ipmipsu.html DIST_ALL_HTML_PAGES += $(INST_HTML_IPMIPSU_MANS) if ! SOME_DRIVERS HTML_IPMIPSU_MANS = $(INST_HTML_IPMIPSU_MANS) endif ! SOME_DRIVERS # (--with-macosx_ups) SRC_MACOSX_PAGES = macosx-ups.txt INST_MAN_MACOSX_PAGES = macosx-ups.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_MACOSX_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_MACOSX_PAGES = $(INST_MAN_MACOSX_PAGES) endif WITH_MANS if WITH_MACOSX mansys_DATA += $(MAN_MACOSX_PAGES) endif WITH_MACOSX endif ! SOME_DRIVERS INST_HTML_MACOSX_MANS = macosx-ups.html DIST_ALL_HTML_PAGES += $(INST_HTML_MACOSX_MANS) if ! SOME_DRIVERS HTML_MACOSX_MANS = $(INST_HTML_MACOSX_MANS) endif ! SOME_DRIVERS # (--with-modbus) SRC_MODBUS_PAGES = \ phoenixcontact_modbus.txt \ generic_modbus.txt \ huawei-ups2000.txt \ socomec_jbus.txt \ adelsystem_cbi.txt \ apc_modbus.txt INST_MAN_MODBUS_PAGES = \ phoenixcontact_modbus.$(MAN_SECTION_CMD_SYS) \ generic_modbus.$(MAN_SECTION_CMD_SYS) \ huawei-ups2000.$(MAN_SECTION_CMD_SYS) \ socomec_jbus.$(MAN_SECTION_CMD_SYS) \ adelsystem_cbi.$(MAN_SECTION_CMD_SYS) \ apc_modbus.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_MODBUS_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_MODBUS_PAGES = $(INST_MAN_MODBUS_PAGES) endif WITH_MANS if WITH_MODBUS mansys_DATA += $(MAN_MODBUS_PAGES) endif WITH_MODBUS endif ! SOME_DRIVERS INST_HTML_MODBUS_MANS = \ phoenixcontact_modbus.html \ generic_modbus.html \ huawei-ups2000.html \ socomec_jbus.html \ adelsystem_cbi.html \ apc_modbus.html DIST_ALL_HTML_PAGES += $(INST_HTML_MODBUS_MANS) if ! SOME_DRIVERS HTML_MODBUS_MANS = $(INST_HTML_MODBUS_MANS) endif ! SOME_DRIVERS # (--with-linux_i2c) SRC_LINUX_I2C_PAGES = \ asem.txt \ pijuice.txt \ hwmon_ina219.txt INST_MAN_LINUX_I2C_PAGES = \ asem.$(MAN_SECTION_CMD_SYS) \ pijuice.$(MAN_SECTION_CMD_SYS) \ hwmon_ina219.$(MAN_SECTION_CMD_SYS) DIST_ALL_MAN_PAGES += $(INST_MAN_LINUX_I2C_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_LINUX_I2C_PAGES = $(INST_MAN_LINUX_I2C_PAGES) endif WITH_MANS if WITH_LINUX_I2C mansys_DATA += $(MAN_LINUX_I2C_PAGES) endif WITH_LINUX_I2C endif ! SOME_DRIVERS INST_HTML_LINUX_I2C_MANS = \ asem.html \ pijuice.html \ hwmon_ina219.html DIST_ALL_HTML_PAGES += $(INST_HTML_LINUX_I2C_MANS) if ! SOME_DRIVERS HTML_LINUX_I2C_MANS = $(INST_HTML_LINUX_I2C_MANS) endif ! SOME_DRIVERS # (--with-gpio) SRC_GPIO_PAGES = generic_gpio.txt INST_MAN_GPIO_PAGES = generic_gpio.$(MAN_SECTION_CMD_SYS) DIST_ALL_PAGES += $(INST_MAN_GPIO_PAGES) if ! SOME_DRIVERS if WITH_MANS MAN_GPIO_PAGES = $(INST_MAN_GPIO_PAGES) endif WITH_MANS if WITH_GPIO mansys_DATA += $(MAN_GPIO_PAGES) endif WITH_GPIO endif ! SOME_DRIVERS INST_HTML_GPIO_MANS = \ generic_gpio.html DIST_ALL_HTML_PAGES += $(INST_HTML_GPIO_MANS) if ! SOME_DRIVERS HTML_GPIO_MANS = $(INST_HTML_GPIO_MANS) endif ! SOME_DRIVERS MAN_MANS = if WITH_MANS MAN_MANS += \ $(MAN_CONF_PAGES) \ $(MAN_CLIENT_PAGES) \ $(MAN_TOOL_PAGES) \ $(MAN_CGI_CFG_PAGES) \ $(MAN_CGI_CMD_SYS_PAGES) \ $(MAN_DEV_CMD_USR_PAGES) \ $(MAN_DEV_API_PAGES) \ $(MAN_DEV_CMD_SYS_PAGES) \ $(MAN_SERIAL_PAGES) \ $(MAN_SNMP_PAGES) \ $(MAN_USB_LIBUSB_PAGES) \ $(MAN_SERIAL_USB_PAGES) \ $(MAN_NETXML_PAGES) \ $(MAN_POWERMAN_PAGES) \ $(MAN_IPMIPSU_PAGES) \ $(MAN_MACOSX_PAGES) \ $(MAN_MODBUS_PAGES) \ $(MAN_LINUX_I2C_PAGES) \ $(MAN_GPIO_PAGES) endif WITH_MANS SRC_DRIVERS_PAGES = \ $(SRC_SERIAL_PAGES) \ $(SRC_SNMP_PAGES) \ $(SRC_USB_LIBUSB_PAGES) \ $(SRC_SERIAL_USB_PAGES) \ $(SRC_NETXML_PAGES) \ $(SRC_POWERMAN_PAGES) \ $(SRC_IPMIPSU_PAGES) \ $(SRC_MACOSX_PAGES) \ $(SRC_MODBUS_PAGES) \ $(SRC_LINUX_I2C_PAGES) \ $(SRC_GPIO_PAGES) if SOME_DRIVERS # (Legacy note) The list above probably came up empty in this case, so make sure # that the drivers requested by configure script are documented in the build; # notably in the linkman-driver-names.txt file. SRC_DRIVERS_PAGES += \ $(DRIVER_MAN_LIST_PAGES) endif # distribute everything, even those not installed by default # Note that 'dist' target requires AsciiDoc! SRC_ALL_PAGES += \ $(SRC_CONF_PAGES) \ $(SRC_CLIENT_PAGES) \ $(SRC_TOOL_PAGES) \ $(SRC_CGI_PAGES) \ $(SRC_DEV_PAGES) \ $(SRC_DRIVERS_PAGES) \ index.txt # DIST_ALL_PAGES: Make sure pages are built for the archive (or # inherited from earlier tarball this release is being built from); # caller may have to fake them if we are in a situation we know we can # not provide them (see `make distcheck-ci` in top-level Makefile.am). EXTRA_DIST = \ $(SRC_ALL_PAGES) \ $(DIST_ALL_PAGES) \ $(MAN_MANS) \ asciidoc.conf if ! WITH_MANS # We may be here because tools are missing, or because caller ran # ./configure --without-doc (but the tools were present and AC_PROG # caused the needed variables to resolve, so pages can in fact get # built, or are present in the release tarball we are building). if ! SKIP_MANS # Absense of pages can cause "make dist" to fail, unless caller # (like `make distcheck-light`) runs ./configure --with-doc=skip # (or --with-doc=man=skip specifically). # FIXME: See also HAVE_ASCIIDOC (covers several tools in fact) # and DOC_INSTALL_DISTED_MANS for a more granular approach. dist-warning: @echo "WARNING: Manpage building was disabled by configure script, and these pages are required for our proper 'make dist'" >&2 dist: dist-warning endif ! SKIP_MANS endif ! WITH_MANS # For builds done from dist'ed sources, there may be a conflict of timestamps # between original *.txt files and pre-built manpages etc. leading to skipping # of manpage re-generation even if that activity is possible and requested. # Possibly a cleaner, but less portable, solution would be to touch the # generated files to long ago. Current solution assumes good valid clocks :) dist-hook: @echo "Fix up manpage source timestamps" && cd $(distdir) && touch $(SRC_ALL_PAGES) HTML_MANS = \ index.html \ $(HTML_CONF_MANS) \ $(HTML_CLIENT_MANS) \ $(HTML_TOOL_MANS) \ $(HTML_CGI_MANS) \ $(HTML_DEV_MANS) \ $(HTML_SERIAL_MANS) \ $(HTML_SNMP_MANS) \ $(HTML_USB_LIBUSB_MANS) \ $(HTML_SERIAL_USB_MANS) \ $(HTML_NETXML_MANS) \ $(HTML_POWERMAN_MANS) \ $(HTML_IPMIPSU_MANS) \ $(HTML_MACOSX_MANS) \ $(HTML_MODBUS_MANS) \ $(HTML_LINUX_I2C_MANS) \ $(HTML_GPIO_MANS) # htmlmandir is set by autoconf/automake htmlman_DATA = if WITH_HTML_SINGLE htmlman_DATA += $(HTML_MANS) else !WITH_HTML_SINGLE if WITH_HTML_CHUNKED htmlman_DATA += $(HTML_MANS) endif WITH_HTML_CHUNKED endif !WITH_HTML_SINGLE # Note: target documents, except nutupsdrv.txt itself, start the # list of drivers with `- linkman:nutupsdrv[$(MAN_SECTION_CMD_SYS)]` entry # To regenerate these files, do `make distclean` first LINKMAN_INCLUDE_GENERATED = linkman-driver-names.txt linkman-drivertool-names.txt LINKMAN_INCLUDE_CONSUMERS = index.txt upsd.txt nutupsdrv.txt linkman-driver-names.txt: @if test x"$(abs_srcdir)" != x"$(abs_builddir)" ; then \ if ! test -s "$(builddir)/$@" && test -s "$(srcdir)/$(@F)" ; then \ ln -fs "$(srcdir)/$(@F)" "$(builddir)/" ; \ fi ; \ fi @if test -s "$@" ; then exit 0 ; fi ; \ (LC_ALL=C; LANG=C; export LC_ALL LANG; \ for F in $(SRC_DRIVERS_PAGES) ; do echo "$$F" ; done \ | grep -vE '^nutupsdrv\.txt$$' \ | sort -n | uniq \ | sed 's,^\(.*\)\.txt$$,- linkman:\1[$(MAN_SECTION_CMD_SYS)],' ; \ ) > "$@" @if test ! -s "$@" ; then echo "- No NUT drivers were built" > "$@" ; fi linkman-drivertool-names.txt: @if test x"$(abs_srcdir)" != x"$(abs_builddir)" ; then \ if ! test -s "$(builddir)/$@" && test -s "$(srcdir)/$(@F)" ; then \ ln -fs "$(srcdir)/$(@F)" "$(builddir)/" ; \ fi ; \ fi @if test -s "$@" ; then exit 0 ; fi ; \ (LC_ALL=C; LANG=C; export LC_ALL LANG; \ for F in $(SRC_DRIVERTOOL_PAGES) ; do echo "$$F" ; done \ | sort -n | uniq \ | sed 's,^\(.*\)\.txt$$,- linkman:\1[$(MAN_SECTION_CMD_SYS)],' ; \ ) > "$@" @if test ! -s "$@" ; then echo "- No NUT driver tools were built" > "$@" ; fi # Dependencies are about particular filenames, since over time # we might have several use-cases for LINKMAN_INCLUDE_GENERATED: $(LINKMAN_INCLUDE_CONSUMERS): linkman-driver-names.txt linkman-drivertool-names.txt # These files are generated when we build from git source so not tracked in # git, and not part of tarball (to be in builddir) - so not in EXTRA_DIST. DISTCLEANFILES = $(LINKMAN_INCLUDE_GENERATED) # Make sure sources are there for out-of-tree builds: $(HTML_MANS) $(MAN_MANS): $(abs_top_builddir)/docs/man/.prep-src-docs all-html html-man: $(HTML_MANS) # Have a way to build all man pages, not just those that fit currently # configured drivers, daemons, developer aspect, etc. all-man man-man: $(MAN_MANS) dist-html: $(DIST_ALL_HTML_PAGES) dist-man: $(DIST_ALL_MAN_PAGES) # This list is defined by configure script choices and options: CHECK_LOCAL_TARGETS = @DOC_CHECK_LIST@ if WITH_MANS if ! SKIP_MANS check-local: check-man else SKIP_MANS check-local: check-man-txt check-man-pages @echo "Man-page generation was SKIPPED per user request, so pregenerated pages were sanity-checked (if any)" >&2 endif SKIP_MANS else ! WITH_MANS check-local: check-man-txt check-man-pages @echo "Man-page generation was not done, so pregenerated pages were sanity-checked (if any)" >&2 endif ! WITH_MANS TGT_REQUIRE_CHECK_HTML = if WITH_HTML_SINGLE TGT_REQUIRE_CHECK_HTML += check-html-man else !WITH_HTML_SINGLE if WITH_HTML_CHUNKED TGT_REQUIRE_CHECK_HTML += check-html-man endif WITH_HTML_CHUNKED endif !WITH_HTML_SINGLE check-man check-man-man: check-man-txt check-man-pages $(TGT_REQUIRE_CHECK_HTML) # the "for" loops might better use $^ but it might be not portable check-man-html: check-html-man check-html-man: .check-html-man .check-html-man: $(HTML_MANS) Makefile @FAILED=""; CHECKED=0; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(HTML_MANS) ; do \ CHECKED="`expr $$CHECKED + 1`"; \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(XML|HTML.*document|symbolic link)' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED HTML-man sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED HTML-man sanity check (checked $$CHECKED files)"; exit 0 @touch $@ # Note: many man-pages here have code samples and are mis-identified as C code check-man-page: check-man-pages # Man-pages may be pre-generated (srcdir), or re-built (builddir) check-man-pages: .check-man-pages .check-man-pages: $(MAN_MANS) Makefile @FAILED=""; CHECKED=0; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(MAN_MANS) ; do \ CHECKED="`expr $$CHECKED + 1`"; \ ( test -s "$(abs_srcdir)/$$F" && { file "$(abs_srcdir)/$$F" | $(EGREP) -i '(roff.* input|C source|ASCII text)' > /dev/null ; } ) || \ ( test -s "$(abs_builddir)/$$F" && { file "$(abs_builddir)/$$F" | $(EGREP) -i '(roff.* input|C source|ASCII text)' > /dev/null ; } ) || \ FAILED="$$FAILED $$F" ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED man-page sanity check for:$$FAILED" >&2 ; \ ( echo "SRCDIR:"; cd "$(abs_srcdir)/" && file $$FAILED ; \ echo "BUILDDIR:"; cd "$(abs_builddir)/" && file $$FAILED ; \ ) >&2 ; exit 1; \ fi; echo "PASSED man-page sanity check (checked $$CHECKED files)"; exit 0 @touch $@ check-man-source: check-man-txt # Note: (GNU) make can helpfully add VPATH to the short source filenames # which we had listed above, so the "case" below handles two possibilities check-man-txt: .check-man-txt .check-man-txt: $(SRC_ALL_PAGES) Makefile @FAILED=""; CHECKED=0; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ ( cd $(abs_srcdir) ) || exit; \ for F in $(SRC_ALL_PAGES) ; do \ CHECKED="`expr $$CHECKED + 1`"; \ case "$$F" in \ */*) ;; \ *) F="$(abs_srcdir)/$$F" ;; \ esac ; \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(ASCII|UTF-8|Unicode|ISO-8859|English).* text' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED man-source sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED man-source sanity check (checked $$CHECKED files)"; exit 0 @touch $@ CLEANFILES = *-spellchecked .prep-src-docs *-prepped .check-* SUFFIXES = .txt-prepped .txt .html .$(MAN_SECTION_CMD_USR) .$(MAN_SECTION_API) .$(MAN_SECTION_CFG) .$(MAN_SECTION_CMD_SYS) # For builds with allowed installation of prebuilt man pages, check that # they exist in sources (make would pull them automatically as a fallback # from failed lookup in build products). For builds that require rebuild # of man pages, abort with error if build product is missing. if DOC_INSTALL_DISTED_MANS SRC_PREBUILT_CLAUSE=|| [ -r "$(srcdir)/`basename $@`" ] else SRC_PREBUILT_CLAUSE= endif # Only clean away build products if we can reproduce them # including cases where we generate placeholders if WITH_MANS CLEANFILES += *.$(MAN_SECTION_CMD_USR) *.$(MAN_SECTION_API) *.$(MAN_SECTION_CFG) *.$(MAN_SECTION_CMD_SYS) clean-man-pages: else !WITH_MANS if HAVE_ASCIIDOC CLEANFILES += *.$(MAN_SECTION_CMD_USR) *.$(MAN_SECTION_API) *.$(MAN_SECTION_CFG) *.$(MAN_SECTION_CMD_SYS) clean-man-pages: else !HAVE_ASCIIDOC clean-man-pages: @FILENAMES='$(DIST_ALL_MAN_PAGES)' ; $(FAKE_FILES_RM) endif !HAVE_ASCIIDOC endif !WITH_MANS if HAVE_ASCIIDOC # Only clean away build products if we can reproduce them CLEANFILES += *.xml *.html *.pdf # Working around a2x not friendly to parallelized runs. # See more details in the main NUT docs/Makefile.am # NOTE: MKDIR_P may be defined via expanded $(top_builddir)/install-sh # so should be run from $(abs_builddir) to be safe, as we jump around # the build workspace DOCBUILD_BEGIN = { \ if test -n "$${A2X_OUTDIR}" && test "$${A2X_OUTDIR}" != '.' ; then \ rm -rf "./$${A2X_OUTDIR}" || true ; \ test -d "$@" && rm -rf "$@" || true ; \ _CWD="`pwd`" && (cd '$(abs_builddir)' && $(MKDIR_P) "$${_CWD}/$${A2X_OUTDIR}") || exit ; \ for F in $(LINKMAN_INCLUDE_GENERATED) ; do \ if [ -s "./$$F" ] ; then ln -f -s "../../$$F" "./$${A2X_OUTDIR}/" ; else \ if [ -s "$(abs_srcdir)/$$F" ] ; then ln -f -s "$(abs_srcdir)/$$F" "./$${A2X_OUTDIR}/" ; fi ; fi ; \ done ; \ else A2X_OUTDIR='.' ; fi; \ if test -s "${builddir}/docbook-xsl.css" \ && test -r "${builddir}/docbook-xsl.css" \ && ! test -w "${builddir}/docbook-xsl.css" \ ; then chmod u+w "${builddir}/docbook-xsl.css" ; fi ; \ chmod -R u+w "./$${A2X_OUTDIR}" || true ; \ A2X_VERBOSE="$(ASCIIDOC_VERBOSE)"; if [ "$(V)" = 1 ]; then A2X_VERBOSE="--verbose"; fi; \ } # Note that documents with sub-pages (see LIBNUTCLIENT_*_DEPS above) # may generate multiple files in one go... so we move "*" and hope # for no required hidden files (or would have to `find` them all). DOCBUILD_END = { \ if test -n "$${A2X_OUTDIR}" && test "$${A2X_OUTDIR}" != '.' ; then \ chmod -R u+w "./$${A2X_OUTDIR}" || true ; \ test -d "$@" && rm -rf "$@" || true ; \ for F in $(LINKMAN_INCLUDE_GENERATED) ; do \ rm -f "./$${A2X_OUTDIR}/$$F" || true ; \ done ; \ mv -f "./$${A2X_OUTDIR}/$(@F)" ./ || exit ; \ mv -f "./$${A2X_OUTDIR}/"*.* ./ 2>/dev/null || true ; \ rm -rf "./$${A2X_OUTDIR}" ; \ fi ; \ } ### Call the prep step consistently to create symlinks (out-of-tree) ### or just touch-files for peace of mind (in-tree builds). Then we ### use these path names (truncated "-prepped") now surely located ### in the builddir as the sources for rendered docs. *.txt-prepped: $(abs_top_builddir)/docs/man/.prep-src-docs #.txt.txt-prepped: $(abs_top_builddir)/docs/man/.prep-src-docs ### Regarding absolute paths in attributes below: by default asciidoc ### resolves include paths relative to the main document, so while we ### see the relative builddir as "." in the makefile, for included ### data it would mean the source directory where the .txt resides. ### Note: `(top_)srcdir` and `(top_)builddir` must end with a path ### separator, or be empty -- so in all cases letting the resulting ### string resolve meaningfully in the filesystem during docs build. .txt-prepped.html: @A2X_OUTDIR="tmp/man-html.$(@F).$$$$" ; \ echo " DOC-MAN-HTML Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(ASCIIDOC) --backend=xhtml11 $${A2X_VERBOSE} \ --attribute=localdate="`TZ=UTC date +%Y-%m-%d`" \ --attribute=localtime="`TZ=UTC date +%H:%M:%S`" \ --attribute=nutversion="$(PACKAGE_VERSION)" \ --attribute=srcdir="$(abs_srcdir)/" \ --attribute=builddir="$(abs_builddir)/" \ --attribute=top_srcdir="$(abs_top_srcdir)/" \ --attribute=top_builddir="$(abs_top_builddir)/" \ --attribute=MAN_SECTION_API_BASE='$(MAN_SECTION_API_BASE)' \ --attribute=MAN_SECTION_CFG_BASE='$(MAN_SECTION_CFG_BASE)' \ --attribute=MAN_SECTION_CMD_SYS_BASE='$(MAN_SECTION_CMD_SYS_BASE)' \ --attribute=MAN_SECTION_CMD_USR_BASE='$(MAN_SECTION_CMD_USR_BASE)' \ --attribute=NUT_WEBSITE_BASE='$(NUT_WEBSITE_BASE)' \ -o "$${A2X_OUTDIR}/$(@F)" '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES ### Prior to Asciidoc ~8.6.8, the --destination-dir flag didn't seem to affect the location of the intermediate .xml file. ### This parameter is currently required; see docs/Makefile.am for more detail. A2X_MANPAGE_OPTS = --doctype manpage --format manpage $${A2X_VERBOSE} \ --xsltproc-opts="--nonet" \ --attribute=mansource="Network UPS Tools" \ --attribute=manversion="$(PACKAGE_VERSION)" \ --attribute=manmanual="NUT Manual" \ --attribute=srcdir="$(abs_srcdir)/" \ --attribute=builddir="$(abs_builddir)/" \ --attribute=top_srcdir="$(abs_top_srcdir)/" \ --attribute=top_builddir="$(abs_top_builddir)/" \ --destination-dir="$${A2X_OUTDIR}" if KNOWN_UNABLE_MANS .txt.$(MAN_SECTION_API) .txt-prepped.$(MAN_SECTION_API) \ .txt.$(MAN_SECTION_CFG) .txt-prepped.$(MAN_SECTION_CFG) \ .txt.$(MAN_SECTION_CMD_SYS) .txt-prepped.$(MAN_SECTION_CMD_SYS) \ .txt.$(MAN_SECTION_CMD_USR) .txt-prepped.$(MAN_SECTION_CMD_USR) : @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not functional (even though found)." ; \ else \ echo "Could not find prebuilt $@ manual page." ; \ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed and functional?"; \ exit 1; \ fi else !KNOWN_UNABLE_MANS .txt-prepped.$(MAN_SECTION_CMD_USR): @A2X_OUTDIR="tmp/man$(MAN_SECTION_CMD_USR).$(@F).$$$$" ; \ echo " DOC-MAN Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(A2X) $(A2X_MANPAGE_OPTS) '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES .txt-prepped.$(MAN_SECTION_API): @A2X_OUTDIR="tmp/man$(MAN_SECTION_API).$(@F).$$$$" ; \ echo " DOC-MAN Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(A2X) $(A2X_MANPAGE_OPTS) '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES .txt-prepped.$(MAN_SECTION_CFG): @A2X_OUTDIR="tmp/man$(MAN_SECTION_CFG).$(@F).$$$$" ; \ echo " DOC-MAN Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(A2X) $(A2X_MANPAGE_OPTS) '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES .txt-prepped.$(MAN_SECTION_CMD_SYS): @A2X_OUTDIR="tmp/man$(MAN_SECTION_CMD_SYS).$(@F).$$$$" ; \ echo " DOC-MAN Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(A2X) $(A2X_MANPAGE_OPTS) '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES endif !KNOWN_UNABLE_MANS else !HAVE_ASCIIDOC .txt.html: @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ echo "Not (re)building $@ manual page (as HTML), since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ else \ echo "Could not find prebuilt $@ manual page (as HTML)." ; \ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ exit 1; \ fi .txt.$(MAN_SECTION_CMD_USR): @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ else \ echo "Could not find prebuilt $@ manual page." ; \ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ exit 1; \ fi .txt.$(MAN_SECTION_API): @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ else \ echo "Could not find prebuilt $@ manual page." ; \ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ exit 1; \ fi .txt.$(MAN_SECTION_CFG): @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ else \ echo "Could not find prebuilt $@ manual page." ; \ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ exit 1; \ fi .txt.$(MAN_SECTION_CMD_SYS): @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ else \ echo "Could not find prebuilt $@ manual page." ; \ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ exit 1; \ fi endif !HAVE_ASCIIDOC # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *.txt-spellchecked: Makefile.am $(abs_top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .txt.txt-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SRC_ALL_PAGES)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # When building out-of-tree, be sure to have all asciidoc resources # under the same dir structure (tool limitation) # NOTE: Not including *all* of EXTRA_DIST here, because we also "dist" # the built man pages in the tarball for end-users without an asciidoc # stack (causing a dependency loop)! PREP_SRC = $(LINKMAN_INCLUDE_GENERATED) $(SRC_ALL_PAGES) asciidoc.conf # NOTE: Some "make" implementations prefix a relative or absent path to # the filenames in PREP_SRC, others (e.g. Sun make) prepend the absolute # path to locate the sources, so we end up with bogus trees under docs/. # Code below tries to detect and truncate this mess, including possible # source texts located in/under parent dirs. # We also handle man page links (section-aware) and titles for platforms # where they differ from common defaults. NOTE: Page titles are a line # with the title, followed by another with a sequence of "===" characters # of same length, give or take one (or so). Currently we do not bother to # adjust the second line, as we expect minor length changes like "8"=>"1m". # NOTE: MKDIR_P may be defined via expanded $(top_builddir)/install-sh # so should be run from $(abs_builddir) to be safe, as we jump around # the build workspace # NOTE: For DOCS_NO_MAN case we expect that the top-level Makefile caused # parallel runs of several directories, so we can reasonably wait some # time for the target file to just appear. MAINTAINER_DOCS_PREP_MAN_DELAY = 60 prep-src-docs: $(abs_top_builddir)/docs/man/.prep-src-docs $(abs_top_builddir)/docs/man/.prep-src-docs: $(PREP_SRC) Makefile @cd "$(@D)" || exit ; \ if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then \ if [ "$(MAINTAINER_DOCS_PREP_MAN_DELAY)" -gt 0 ] 2>/dev/null ; then \ echo " DOCS_NO_MAN BLOCK: $@ called in docs/man/Makefile : waiting for other thread to complete this target" ; \ W=0 ; while [ "$${W}" -lt "$(MAINTAINER_DOCS_PREP_MAN_DELAY)" ] && ( [ \! -e '$@' ] || [ x"`find $(PREP_SRC) \! -newer '$@' 2>/dev/null`" = x ] ) ; do sleep 1 ; W="`expr $$W + 1`"; done ; \ echo " DOCS_NO_MAN SKIP: $@ called in docs/man/Makefile : waited $$W seconds" ; \ fi ; \ exit 0 ; \ fi ; \ linkroot="$(abs_builddir)" ; \ MAN_SECTIONS_DEFAULT=false ; \ if [ x"$(MAN_SECTION_API)$(MAN_SECTION_CFG)$(MAN_SECTION_CMD_SYS)$(MAN_SECTION_CMD_USR)" = x3581 ] ; then \ MAN_SECTIONS_DEFAULT=true ; \ fi ; \ if test x"$(abs_srcdir)" = x"$(abs_builddir)" ; then \ COUNT=0; \ for F in $(PREP_SRC) ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed "s#^$(abs_top_srcdir)/*#./#"`"; \ if test x"$${linkroot}" = x"$(abs_builddir)" ; then \ linkroot="$(abs_top_builddir)" ; \ cd "$(abs_top_builddir)" ; \ fi ;; \ esac ; \ if $$MAN_SECTIONS_DEFAULT ; then \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' ; \ else \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' \ -e 's,\(linkman:[^ []*\[\)3\],\1$(MAN_SECTION_API)],g' \ -e 's,\(linkman:[^ []*\[\)5\],\1$(MAN_SECTION_CFG)],g' \ -e 's,\(linkman:[^ []*\[\)8\],\1$(MAN_SECTION_CMD_SYS)],g' \ -e 's,\(linkman:[^ []*\[\)1\],\1$(MAN_SECTION_CMD_USR)],g' \ -e '1 s,\(^.*(\)3)$$,\1$(MAN_SECTION_API)),g' \ -e '1 s,\(^.*(\)5)$$,\1$(MAN_SECTION_CFG)),g' \ -e '1 s,\(^.*(\)8)$$,\1$(MAN_SECTION_CMD_SYS)),g' \ -e '1 s,\(^.*(\)1)$$,\1$(MAN_SECTION_CMD_USR)),g' ; \ fi < "$${F}" > "$${F}-prepped" || exit ; \ COUNT="`expr $$COUNT + 1`" ; \ done ; \ else \ COUNT=30 ; \ touch "$@.$$$$" ; \ while test -e "$@.working" -a "$$COUNT" -gt 0 ; do sleep 1; COUNT="`expr $$COUNT - 1`"; done ; \ touch "$@.working" ; \ if test -n "`find "$@" -newer "$@.$$$$" 2>/dev/null`" ; then \ rm -f "$@.$$$$" "$@.working" ; \ exit 0; \ fi ; \ rm -f "$@.$$$$" ; \ COUNT=0; \ linksrcroot="$(abs_srcdir)" ; \ for F in `echo $(PREP_SRC) | tr ' ' '\n' | sort -n | uniq` ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed "s#^$(abs_top_srcdir)/*#./#"`"; \ if test x"$${linkroot}" = x"$(abs_builddir)" ; then \ linkroot="$(abs_top_builddir)" ; \ linksrcroot="$(abs_top_srcdir)" ; \ cd "$(abs_top_builddir)" ; \ fi ;; \ "$(srcdir)"/*) F="`echo "$$F" | sed 's#^$(srcdir)/*#./#'`" ;; \ */*) ;; \ *) \ linkroot="$(abs_builddir)" ; \ linksrcroot="$(abs_srcdir)" ; \ cd "$(abs_top_builddir)" ;; \ esac ; \ D="`dirname "$$F"`" ; \ (cd '$(abs_builddir)' && $(MKDIR_P) "$${linkroot}/$$D") || { rm -f "$@.working" ; exit 1 ; } ; \ if ! test -e "$${linkroot}/$$F" && test -s "$${linksrcroot}/$$F" ; then \ echo " LN '$${linksrcroot}/$$F' => '$${linkroot}/$$F' (PWD = '`pwd`')" >&2 ; \ ln -fs "$${linksrcroot}/$$F" "$${linkroot}/$$F" || { rm -f "$@.working" ; exit 1 ; } ; \ COUNT="`expr $$COUNT + 1`" ; \ fi ; \ case "$$F" in \ *.txt|*.adoc) IS_TEXT=true ;; \ *.*) IS_TEXT=false ;; \ *) IS_TEXT=true ;; \ esac; \ if $$IS_TEXT ; then \ grep -w linkman "$${linkroot}/$${F}" > /dev/null || IS_TEXT=false ; \ fi ; \ if $$MAN_SECTIONS_DEFAULT || ! $$IS_TEXT ; then \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' ; \ else \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' \ -e 's,\(linkman:[^ []*\[\)3\],\1$(MAN_SECTION_API)],g' \ -e 's,\(linkman:[^ []*\[\)5\],\1$(MAN_SECTION_CFG)],g' \ -e 's,\(linkman:[^ []*\[\)8\],\1$(MAN_SECTION_CMD_SYS)],g' \ -e 's,\(linkman:[^ []*\[\)1\],\1$(MAN_SECTION_CMD_USR)],g' \ -e '1 s,\(^.*(\)3)$$,\1$(MAN_SECTION_API)),g' \ -e '1 s,\(^.*(\)5)$$,\1$(MAN_SECTION_CFG)),g' \ -e '1 s,\(^.*(\)8)$$,\1$(MAN_SECTION_CMD_SYS)),g' \ -e '1 s,\(^.*(\)1)$$,\1$(MAN_SECTION_CMD_USR)),g' ; \ fi < "$${linkroot}/$${F}" > "$${linkroot}/$${F}-prepped" \ || { rm -f "$@.working" ; exit 1 ; } ; \ COUNT="`expr $$COUNT + 1`" ; \ done ; \ fi ; \ if test "$$COUNT" -gt 0 -o ! -e "$@" ; then touch "$@" ; fi @rm -f "$@.working" MAINTAINERCLEANFILES = Makefile.in .dirstamp clean-local: clean-man-pages $(AM_V_at)rm -rf tmp $(AM_V_at)for F in $(PREP_SRC) ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed "s#^$(abs_top_srcdir)/*#./#"`"; cd "$(abs_top_builddir)" ;; \ esac ; \ if test x"$(abs_srcdir)" != x"$(abs_builddir)" ; then \ if test -L "$$F" || test -h "$$F" ; then \ rm -f "$$F" ; \ fi ; \ fi ; \ rm -f "$${F}-prepped" ; \ done ; \ rm -f "$(abs_top_builddir)/docs/man/.prep-src-docs"* nut-2.8.3/docs/man/libnutclient_variables.30000644000200500020050000001166515001555056015565 00000000000000'\" t .\" Title: libnutclient_variables .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIBNUTCLIENT_VARIABL" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libnutclient_variables, nutclient_get_device_variables, nutclient_get_device_rw_variables, nutclient_has_device_variable, nutclient_get_device_variable_description, nutclient_get_device_variable_values, nutclient_set_device_variable_value, nutclient_set_device_variable_values \- Variable related functions in Network UPS Tools high\-level client access library .SH "SYNOPSIS" .sp .nf #include typedef void* NUTCLIENT_t; typedef char** strarr; strarr nutclient_get_device_variables(NUTCLIENT_t client, const char* dev); strarr nutclient_get_device_rw_variables(NUTCLIENT_t client, const char* dev); int nutclient_has_device_variable(NUTCLIENT_t client, const char* dev, const char* var); char* nutclient_get_device_variable_description(NUTCLIENT_t client, const char* dev, const char* var); strarr nutclient_get_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var); void nutclient_set_device_variable_value(NUTCLIENT_t client, const char* dev, const char* var, const char* value); void nutclient_set_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var, const strarr values); .fi .SH "DESCRIPTION" .sp These functions allow to manage variables of devices\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_device_variables()\fR function retrieves the list of variables names for a device\&. .sp The returned strarr must be freed by \fIstrarr_free\fR (see \fBlibnutclient_general\fR(3))\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_device_rw_variables\fR function retrieves the list of read\-write variables names for a device\&. .sp The returned strarr must be freed by \fIstrarr_free\fR (see \fBlibnutclient_general\fR(3))\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_has_device_variable\fR function tests if the specified variable is supported by the device\&. .sp Return \fI1\fR if supported and \fI0\fR if not\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_device_variable_description\fR function retrieves the variable description, if any\&. .sp The returned string must be freed by \fBfree\fR(3)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_device_variable_values\fR returns variable values (generally only one)\&. .sp The returned strarr must be freed by \fIstrarr_free\fR (see \fBlibnutclient_general\fR(3))\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_set_device_variable_value\fR intends to set the value of the specified variable\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_set_device_variable_values\fR intends to set multiple values of the specified variable\&. .RE .sp Common arguments: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIdev\fR is the device name\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIvar\fR is the variable name\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIvalue\fR is the variable value\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIvalues\fR is the variable array of values\&. .RE .SH "SEE ALSO" .sp \fBlibnutclient\fR(3) \fBlibnutclient_devices\fR(3) \fBlibnutclient_general\fR(3) nut-2.8.3/docs/man/usbhid-ups.txt0000644000200500020050000004424615001555412013576 00000000000000USBHID-UPS(8) ============= NAME ---- usbhid-ups - Driver for USB/HID UPS equipment SYNOPSIS -------- *usbhid-ups* -h *usbhid-ups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the usbhid-ups driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ *usbhid-ups* brings USB/HID UPS monitoring to NUT on all platforms supporting USB through libusb. It should detect any UPS that uses the HID Power Device Class, but the amount of data will vary depending on the manufacturer and model. At the present time, usbhid-ups supports: - the newer Eaton USB models, - all MGE USB models, - all Dell USB models, - all AMETEK Powervar UPM models, - some APC models, - some Belkin models, - some Cyber Power Systems models, - some Powercom models, - some PowerWalker models, - some TrippLite models. For a more complete list, refer to the NUT hardware compatibility list, available in the NUT source distribution as `data/driver.list`, or on the NUT website. You may use the `explore` driver option to gather information from HID UPSes which are not yet supported, to help add such support; see below for details. This driver is known to work on: - most Linux systems, - FreeBSD (beta stage) and maybe other *BSD, - Darwin / Mac OS X, - Solaris 10 and illumos-based distributions. EXTRA ARGUMENTS --------------- This driver also supports the following optional settings: include::nut_usb_addvars.txt[] *subdriver*='regex':: Select the USB HID subdriver for the device manually, where automatic match by device attributes alone does not suffice (e.g. new devices for which no `vendorid`/`productid` pair was built into any driver -- but common USB HID support is anticipated, or for different-capability devices with same interface chips, notably "phoenixtec/liebert" and "mge"). + Run the driver program with the `--help` option to see the exact list of `subdriver` values it would currently recognize. + NOTE: This option first checks for exact matches to subdriver identification strings, such as `"TrippLite HID 0.85"` (which are prone to bit-rot), and if there was no exact match -- retries with a case-insensitive extended regular expression. + NOTE: When using this option, it is mandatory to also specify the *vendorid* and *productid* matching parameters. *lowbatt*='num':: Set the percentage at which the UPS will consider the battery charge as critically low, possibly resulting in a forced shutdown (FSD) situation. + This value is typically dictated by the UPS device, although there is a fallback default value of 30 (in percent). Overriding this value can be helpful when the UPS sets this value to a lower percentage than intended. *offdelay*='num':: Set the timer before the UPS is turned off after the kill power command is sent (via the *-k* switch). + The default value is 20 (in seconds), or 60 for CPS devices. Usually this *must be lower* than 'ondelay', but the driver will *not* warn you upon startup if it isn't. + Note that many Cyber Power Systems (CPS) models tend to divide this delay by 60 and round down, so the minimum advisable value is 60 to avoid powering off immediately after NUT sends the shutdown command to the UPS. More details below. *ondelay*='num':: Set the timer for the UPS to switch on in case the power returns after the kill power command had been sent, but before the actual switch off. This ensures the machines connected to the UPS are, in all cases, rebooted after a power failure. + The default value is 30 (in seconds), or 120 for CPS devices. Usually this *must be greater* than offdelay, but the driver will *not* warn you upon startup if it isn't. Some UPSes will restart no matter what, even if the power is (still) out at the moment this timer elapses. In that case, you could see whether setting `ondelay = -1` in *ups.conf* helps. + Note that many CPS models tend to divide this delay by 60 and round down, so the minimum advisable value is 120 to allow a short delay between when the UPS shuts down, and when the power returns. According to support statement (for at least some CPS models), "our UPS systems are unable to set up power on delay". *pollfreq*='num':: Set polling frequency for full updates, in seconds. Compared to the quick updates performed every "pollinterval" (the latter option is described in linkman:ups.conf[5]), the "pollfreq" interval is for polling the less-critical variables. The default value is 30 (in seconds), or 12 sec for CPS devices. *pollonly*:: If this flag is set, the driver will not use Interrupt In transfers during the shorter "pollinterval" cycles (not recommended, but needed if these reports are broken on your UPS). *interrupt_pipe_no_events_tolerance*='num':: Set the tolerance for how many times in a row could we have "Got 0 HID objects" when using USB interrupt mode? This may normally be due to a device having nothing urgent to report, so the default value is `-1` and this situation is not handled in any way specially. However with some devices this was seen in conjunction with a frozen controller, where only a driver reconnection restored the data exchange (e.g. APC BXnnnnMI) -- in such cases you may want to use a reasonable non-negative value here. *onlinedischarge_battery*:: If this flag is set, the driver will treat `OL+DISCHRG` status as offline/on-battery. + For most devices this combination means calibration or similar maintenance; however some UPS models (e.g. CyberPower UT series) emit `OL+DISCHRG` when wall power is lost -- and need this option to handle shutdowns. *onlinedischarge*:: DEPRECATED, old name for `onlinedischarge_battery` described above. *onlinedischarge_calibration*:: If this flag is set, the driver will treat `OL+DISCHRG` status as calibration. Some UPS models (e.g. APC were seen to do so) report `OL+DISCHRG` when they are in calibration mode. This usually happens after a few seconds reporting an `OFF` state as well, while the hardware is switching to on-battery mode. + NOTE: If it takes so long on your device that a shutdown gets issued, you may want to look at `upsmon` option `OFFDURATION` used to filter out temporary values of "administrative OFF" as not a loss of a feed for the powered load. *onlinedischarge_log_throttle_sec*='num':: Set the minimum frequency (in seconds) at which warnings would be emitted for an otherwise not handled `OL+DISCHRG` device status combination. Negative values disable sequentially repeated messages (when this state appears and persists). + If the device does not report `battery.charge`, the default value is 30 seconds (fairly frequent, in case the UPS-reported state combination does reflect a bad power condition and so the situation is urgent). + If it does report `battery.charge`, by default the repeated notifications would only be logged if this charge is different from when the message was emitted previously (e.g. when the battery is really discharging). + If both this option is set, and `battery.charge` is correctly reported, either of these rules allow the notification to be logged. *onlinedischarge_log_throttle_hovercharge*='num':: See details in `onlinedischarge_log_throttle_sec` and `battery.charge` based log message throttling description above. This option adds a concept of UPS "hovering" a battery charge at some level deemed safe for its chemistry, and not forcing it to be fully charged all the time. As long as the current value of `battery.charge` remains at or above this threshold percentage (default 100), the `OL+DISCHRG` message logging is not triggered by variations of the charge. *lbrb_log_delay_sec*='num':: Set to delay status-setting (and log messages) about device entering `LB` or `LB+RB` state. + Some APC BXnnnnMI device models or firmware versions (reportedly 2023-2024) frequently report low battery, replace battery, and all ok within a couple of seconds, sometimes but not always preceded by OL+DISCHRG (presumably calibration). This setting lets the driver ignore short-lived states and only pay attention if they persist longer than this setting (and the device power state is `OL`). *lbrb_log_delay_without_calibrating*:: Set to apply `lbrb_log_delay_sec` even if device is not calibrating. *disable_fix_report_desc*:: Set to disable fix-ups for broken USB encoding, etc. which we apply by default on certain models (vendors/products) which were reported as not following the protocol strictly. This flag allows to disable the feature in particular device configurations. + It is always possible that the vendors eventually release fixed firmware, or re-use identifiers by which we match suspected broken devices for unrelated products, so processing these fix-ups would be a waste of time there. + It is also always possible that NUT fix-ups cause issues on some devices, whether due to NUT bugs or because the vendor protocol implementation is broken in more than one place. *powercom_sdcmd_byte_order_fallback*:: Original `PowerCOM HID` subdriver code (until version 0.7) sent UPS `shutdown` and `stayoff` commands in a wrong byte order, than what is needed by actual devices seen in the field in 2024. The byte order is fixed to satisfy new devices by default since version 0.71. Just in case there are different firmwares out there with opposite behaviors, we provide this toggle to use old behavior in a particular deployment. Maybe it was just a bug and nobody needs this fall-back... *explore*:: With this option, the driver will connect to any device, including ones that are not yet supported. This must always be combined with the "vendorid" option. In this mode, the driver will not do anything useful except for printing debugging information (typically used with -DD). *maxreport*:: With this option, the driver activates a tweak to workaround buggy firmware returning invalid HID report length. Some APC Back-UPS units are known to have this bug. *interruptonly*:: If this flag is set, the driver will not poll UPS. This also implies using of INPUT flagged objects. Some Powercom units need this option. *interruptsize*='num':: Limit the number of bytes to read from interrupt pipe. For some Powercom units this option should be equal to 8. *waitbeforereconnect*='num':: The driver automatically tries to reconnect to the UPS on unexpected error. This parameter (in seconds) allows it to wait before attempting the reconnection. The default value is 0. + NOTE: for instance, it was found that Eaton MGE Ellipse Max 1500 FR UPS firmware stops responding every few hours, which causes usbhid-ups driver to detect an libusb insufficient memory error; in this case, when the usbhid-ups driver tries to reconnect too early, the activity sometimes led the UPS firmware to crash and turn off the load immediately! Setting this parameter to 30 seconds solved this problem (while 20 seconds were not enough). INSTALLATION ------------ This driver may be not built by default. You can build it by installing prerequisites and using `configure --with-usb=yes`. Note that it will also install other USB drivers. You also need to install manually the legacy *hotplug* files (`libhidups` and `libhid.usermap`, generally in `/etc/hotplug/usb/`), or the *udev* file (`nut-usbups.rules`, generally in `/etc/udev/rules.d/`) to address the permission settings problem. For more information, refer to the `scripts/hotplug/README.adoc` or `scripts/udev/README.adoc` files in NUT sources. IMPLEMENTATION -------------- Selecting a specific UPS ~~~~~~~~~~~~~~~~~~~~~~~~ As mentioned above, the driver ignores the "port" value in *ups.conf*. Unlike previous versions of this driver, it is now possible to control multiple UPS units simultaneously with instances of this driver running in parallel, provided they can be distinguished by setting some combination of the device-matching options. For example: [mge] driver = usbhid-ups port = auto vendorid = 0463 [tripplite] driver = usbhid-ups port = auto vendorid = 09ae To monitor devices using the same vendor and product identification (e.g. two pieces of the same model), you would need to find a reliable unique matching criteria: * The 'serial' number is the best option, if populated. * Link-level `bus`/`device`/`busport` may be unreliable (due to re-enumeration on a whim by the operating system). * If nothing else helps, `allow_duplicates` may be an option in some cases. USB Polling and Interrupt Transfers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The *usbhid-ups* driver has two polling intervals. The "pollinterval" configuration option controls what can be considered the "inner loop", where the driver polls and waits briefly for "interrupt" reports. The "pollfreq" option is for less frequent updates of a larger set of values, and as such, we recommend setting that interval to several times the value of "pollinterval". Many UPSes will respond to a USB Interrupt In transfer with HID reports corresponding to values which have changed. This saves the driver from having to poll each value individually with USB Control transfers. Since the `OB` and `LB` status flags are important for a clean shutdown, the driver also explicitly polls the HID paths corresponding to those status bits during the inner "pollinterval" time period. The "pollonly" option can be used to skip the Interrupt In transfers if they are known not to work. KNOWN ISSUES AND BUGS --------------------- UPS reports 65535 sec (or 18:12:15) of battery.runtime capability ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From a number of reports, it seems that some devices either can not report more than a 16-bit unsigned value in the standard field for remaining run time (vendor extended fields may exist but be unknown to the mapping tables in your current NUT driver build), or return `-1` for error and that gets treated as an unsigned 16-bit 65535 value. According to some issue discussions, passing a battery test (calibration) can help the UPS re-estimate the time more correctly. This problem may also be linked to a very lightly loaded large-capacity UPS. In some cases vendor documentation explicitly states that runtime calculation is not reliable with loads under e.g. 10%. Repetitive timeout and staleness ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some models tends to be unresponsive with the default polling frequency. The result is that your system log will have lots of messages like: usb 2-1: control timeout on ep0in usb 2-1: usbfs: USBDEVFS_CONTROL failed cmd usbhid-ups rqt 128 rq 6 len 256 ret -110 In this case, simply modify the general parameter "pollinterval" to a higher value (such as 10 seconds). This should solve the issue. Note that if you increase "pollinterval" beyond 10 or 15 seconds, you might also want to increase "pollfreq" by the same factor. With certain devices and operating systems, notably MGE/Eaton USB Vendor ID (`0x0463`) on some versions of the Linux kernel, you might encounter poor interaction with the "USB HID quirk" mechanism, which precludes Linux from seeing the device as a `hid-generic` first, to hand it over to a NUT driver later. For more details, see the NUT FAQ document. This particular quirk can be tuned with a kernel boot parameter (via GRUB etc.): usbhid.quirks=0x0463:0xffff:0x08 Conversely, some hardware controllers may "fall asleep" when not contacted for too long; CPS devices are commonly associated with such behaviour. In this case, consider enabling `pollonly` flag and/or keeping `pollfreq` and/or `pollinterval` small. Got EPERM: Operation not permitted upon driver startup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You have forgotten to install the hotplug files, as explained in the INSTALLATION section above. Don't forget to restart hotplug so that it applies these changes. Unattended shutdowns ~~~~~~~~~~~~~~~~~~~~ The hardware which was used for development of this driver is almost certainly different from what you have, and not all manufacturers follow the USB HID Power Device Class specifications to the letter. You don't want to find out that yours has issues here when a power failure hits your server room and you're not around to manually restart your servers. If you rely on the UPS to shutdown your systems in case of mains failure and to restart them when the power returns, you *must* test this. You can do so by running 'upsmon -c fsd'. With the mains present, this should bring your systems down and then cycle the power to restart them again. If you do the same without mains present, it should do the same, but in this case, the outputs shall remain off until mains power is applied again. UPS cuts power too soon ~~~~~~~~~~~~~~~~~~~~~~~ Note that many Cyber Power Systems (CPS) models tend to divide `offdelay` by 60 and round down, so the minimum advisable value is 60 (seconds) to avoid powering off immediately after NUT sends the shutdown command to the UPS. For many Cyberpower UPSs, `offdelay` must be set to `0` for normal behavior (the load is restored when AC power returns). Setting `offdelay` above `0` will restart the UPS load *regardless of whether or not power has returned*, and setting `offdelay` below `0` will disable the auto-power-on function of the UPS, keeping the load off even when power returns. UPS does not set battery.charge.low but says OK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Note that many Cyber Power Systems (CPS) models tend to allow only certain values for `battery.charge.low` and anything outside of the set of allowed values are rounded or ignored. A shell loop like this can help you map out the allowed values: ==== for i in `seq 90 -1 0`; do echo "set to $i"; \ upsrw -s battery.charge.low=$i -u * -p * cps-big; \ sleep 1; upsc cps-big battery.charge.low; echo ""; \ done ==== For example, for CPS PR1000LCDRTXL2U model, the only allowed values are `[60,55,50,45,40,35,30,25,20]` and in some cases, your UPS may effectively not support a value of 10 for the `battery.charge.low` setting. HISTORY ------- This driver, formerly called 'newhidups', replaces the legacy 'hidups' driver, which only supported Linux systems. AUTHORS ------- Originally sponsored by MGE UPS SYSTEMS. Now sponsored by Eaton * Arnaud Quette * Peter Selinger * Arjen de Korte SEE ALSO -------- The core driver ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upslog.txt0000644000200500020050000001474715001555412013027 00000000000000UPSLOG(8) ========= NAME ---- upslog - UPS status logger SYNOPSIS -------- *upslog -h* *upslog* ['OPTIONS'] DESCRIPTION ----------- *upslog* is a daemon that will poll a UPS at periodic intervals, fetch the variables that interest you, format them, and write them to a file. The default format string includes variables that are supported by many common UPS models. See the description below to make your own. OPTIONS ------- *-f* 'format':: Monitor the UPS using this format string. Be sure to enclose 'format' in quotes so your shell doesn't split it up. Valid escapes within this string are: + -- %%;; Insert a single "%" %t;; Insert a single TAB character (like `printf("\t")`) %TIME format%;; Insert the time with `strftime` formatting %ETIME%;; Insert the number of seconds since the start of "Epoch", ala `time_t`. This is now a 10-digit number. %HOST%;; Insert the local hostname %UPSHOST%;; Insert the host of the UPS being monitored (the `` part of your logging specification, e.g. `ups[@host[:port]]`) %PID%;; Insert the PID of `upslog` itself %VAR varname%;; Insert the value of variable varname (see NUT developer documentation chapter "Variables" on-line or in the `docs/nut-names.txt` file in sources of the NUT version you have installed for more details) -- + The default format string is: %TIME @Y@m@d @H@M@S% %VAR battery.charge% %VAR input.voltage% %VAR ups.load% [%VAR ups.status%] %VAR ups.temperature% %VAR input.frequency% *-N*:: Prefix `%UPSHOST%%t` before the format string (whether default or custom). Useful when logging many systems into same target. + NOTE: This option DOES NOT currently check if you already have `%UPSHOST%` in the formatting string (e.g. specified explicitly). *-i* 'interval':: Wait this many seconds between polls. This defaults to '30' seconds. + If you require tighter timing, consider writing your own logger using the linkman:upsclient[3] library. *-d* 'count':: Exit after specified amount of updates. Default is '0' for infinite loop (until interrupted otherwise). *-l* 'logfile':: Store the results in this file. + You can use `-` for stdout, but `upslog` will remain in the foreground by default. + Requires that the `-s ` option is also used for the single-system logging. + Can be used with the `-m `, will be added to the list. *-D*:: Raise debugging verbosity level by one; `upslog` will remain in the foreground by default. *-F*:: upslog will run in the foreground, regardless of logging target. *-B*:: upslog will run in the background, regardless of logging target or debugging. *-s* 'ups':: Monitor this UPS. The format for this option is +upsname[@hostname[:port]]+. The default hostname is "localhost". + The 'upsname' may be an asterisk `*` to query UPSes currently served by 'hostname', and monitor each of them (into the same logging destination). + Requires that the `-l ` option is also used for the single-system logging. + Can be used with the `-m `, will be added to the list. *-m* 'tuple':: Monitor multiple UPSs (provided several instances of such option). + The format for this option is a tuple of UPS system and log file specification, separated by commas. An example would be: + ---- upsname@hostname:9999,/var/log/nut/cps.log ---- + The 'upsname' may be an asterisk `*` to query UPSes currently served by 'hostname', and monitor each of them (into the same logging destination). + Tuples may specify `-` as the logfile, to emit messages on `stdout` (e.g. to be collected by the system journal for services). + Use of `stdout` via tuple-based logging specifications also implies that upslog will remain in the foreground by default. *-u* 'username':: If started as 'root', `upslog` will linkmanext:setuid[2] to the user id associated with 'username' for security. + If 'username' is not defined, it will use the value that was compiled into the program. This defaults to 'nobody' (if not otherwise configured), which is far from ideal. COMMON OPTIONS -------------- *-h*:: Show the command-line help message. *-V*:: Show NUT version banner. More details may be available if you also `export NUT_DEBUG_LEVEL=1` or greater verbosity level. *-W* 'secs':: Set the timeout for initial network connections (by default they are indefinitely non-blocking, or until the system interrupts the attempt). Overrides the optional `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable. SERVICE DELAYS -------------- The interval value is merely the number given to linkmanext:sleep[3] after running through the format string. Therefore, a query will actually take slightly longer than the interval, depending on the speed of your system. ON-DEMAND LOGGING ----------------- Sending a `SIGUSR1` to a running *upslog* process makes it wake from the current sleep and log immediately. This is useful when triggered from a *upssched* event trigger (e.g. `AT ONBATT` or `AT ONLINE`) to ensure that an entry always exists, even if the power goes away for a period of time shorter than that specified by the `-i` argument. LOG CO-LOCATION --------------- It is possible and safe to specify the same log file (including `-` for stdout) in several tuples, and it would only be opened or closed once without conflict. Consider adding `%UPSHOST%` to your custom formatting string (e.g. by using the *-N* command-line option), in order to easily differentiate lines corresponding to different systems, when logging them to the same target. LOG ROTATION ------------ *upslog* writes its PID to `upslog.pid`, and will reopen the log file if you send it a `SIGHUP`. This allows it to keep running when the log is rotated by an external program. CAVEATS ------- Historically this daemon supported logging of data for one UPS system per run (specified by the `-s` option) into one log file name or `stdout` (specified by the `-l` option). Since NUT v2.8.1 it allowed to log several devices (each logged into its individual destination file or common `stdout`) as specified by multiple `-m tuple` options. But the two modes were effectively exclusive of each other (single-UPS options were ignored if tuples are also provided). Since NUT v2.8.3, the single-UPS options are added to the list of tuples, so both legacy and new options can be reliably used to monitor multiple devices in the same run. SEE ALSO -------- Server: ~~~~~~~ linkman:upsd[8] Clients: ~~~~~~~~ linkman:upsc[8], linkman:upscmd[8], linkman:upsrw[8], linkman:upsmon[8], linkman:upssched[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/socomec_jbus.80000644000200500020050000001735415001555100013510 00000000000000'\" t .\" Title: socomec_jbus .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "SOCOMEC_JBUS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" socomec_jbus \- Driver for Socomec JBUS UPS with RS\-232 serial Modbus connection\&. .SH "SYNOPSIS" .sp \fBsocomec_jbus\fR \-h .sp \fBsocomec_jbus\fR \-a \fIDEVICE_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the socomec_jbus driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports Socomec JBUS series, online (double conversion) UPS with the following characteristics\&. .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} Single phase and 3\-phase UPS .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} Connection: RS\-232 .RE .sp These are typically provided with a Netvision WEB/SNMP management card / external box that would be better served by the \fBsnmp-ups\fR(8) driver\&. In case netvision isn\(cqt available, you can hook up the UPS directly via the serial port and use this driver\&. .sp Currently, it has only been tested on the following model\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} DIGYS 3/3 15kVA .RE .sp In theory, any Socomec JBUS model should work\&. It should be discovered as \(lqUnknown Socomec JBUS\(rq with a numeric id that I\(cqll need to add it to the list of supported UPSs\&. .sp Sadly, Socomec document only mentions DELPHYS MX and DELPHYS MX elite and I have the id of my own DIGYS, so chances are, your model will not be recognized but will probably mostly work\&. Please report successful or unsuccessful results to the bug tracker or the mailing list\&. Make sure to include the full model number of your UPS manually in your report\&. .sp socomec_jbus uses the libmodbus project, for Modbus implementation\&. .SH "CABLING" .sp The UPS has an RS\-232 port which should be connected with a NULL\-modem cable to a PC serial port\&. The UPS tested has a female DB9 connector, so if you construct the cable yourself, make note of the connector type to avoid using gender changers\&. .sp RS\-232 is supported on all operating systems, either via a built\-in serial port on your computer, or by using an external USB\-to\-RS\-232 converter\&. If you plan to use an USB\-to\-RS\-232 converter, make sure it\(cqs supported by your operating system\&. .SH "INSTALLATION" .sp This driver should be built by default if libmodbus and development headers are available\&. You can force the configure script to build it with the following arguments: .sp .if n \{\ .RS 4 .\} .nf :; \&./configure \-\-with\-serial=yes \-\-with\-modbus=yes .fi .if n \{\ .RE .\} .sp You also need to give proper (R/W) permissions on the local serial device file to allow the NUT driver run\-time user to access it\&. This may need additional setup for start\-up scripting, udev or upower rules, to apply the rights on every boot \(em especially if your device nodes are tracked by a virtual filesystem\&. .sp For example, a USB\-to\-serial converter can be identified as /dev/ttyACM0 or /dev/ttyUSB0 on Linux, or /dev/ttyU0 on FreeBSD (note the capital "U")\&. A built\-in serial port can be identified as /dev/ttyS0 on Linux or one of /dev/cua* names on FreeBSD\&. .SH "INSTANT COMMANDS" .sp This driver does not (yet?) support sending commands to the UPS\&. .SH "VARIABLES" .sp This driver does not support writable runtime variables (see \fBupsrw\fR(8)): for the same reasons\&. Both should be trivial to implement, but since I\(cqve already found one or two inconsistencies in the documentation, I\(cqm withholding from trying them\&. .SH "KNOWN ISSUES AND BUGS" .sp Well, it is an alpha release at best, but so far appears to report the UPS status reliably\&. Mostly based on the work of Yifeng Li on the \fBhuawei-ups2000\fR(8) in that very same source tree\&. .SS "Read failure on some JBUS addresses" .sp The driver polls all documented JBUS addresses, and it is quite possible that your UPS model does not support one of them (e\&.g\&. the Digys does not support address \fI0x1020\fR which should provide the current UPS status)\&. This should be logged with LOG_ERR from modbus_read_input_registers() along with the address that produced the error\&. .SS "Data stale" .sp Under certain circumstances, some registers can return invalid values and trigger a "data stale" error\&. Once a data stale error has occurred, you should see error messages similar to the example below in the system log\&. .sp .if n \{\ .RS 4 .\} .nf socomec_jbus: modbus_read_input_registers(addr:XXXX, count:Z): Illegal data address upsd: Data for UPS [socomec] is stale \- check driver upsd: UPS [socomec] data is no longer stale .fi .if n \{\ .RE .\} .sp So far all known problems have been fixed by the author, but an unknown one cannot be ruled out\&. If you have encountered "data stale" problems during normal uses, please file a bug report with full logs attached\&. .sp Before troubleshooting or reporting a problem, it\(cqs important to check your \fBdmesg\fR log for USB connect and disconnect events to avoid wasting time on the NUT driver when the actual problem is USB\&. For example, if someone yanks the cable out of the USB port, or if a new USB device is plugged into a USB host/hub that is struggling to power its ports (common on single\-board computers like Raspberry Pi), or if you have flaky cabling or EMI noise, the serial converter can get disconnected from USB, at least briefly\&. This creates a permanent data stale, the driver must be restarted (plugging the USB back won\(cqt fix it, since the driver is still using the nonexistent serial device)\&. These USB problems usually have nothing to do with NUT\&. If it\(cqs the case, you should solve the underlying USB problem \(em check the cable, check the converter, try a powered USB hub, try a full\-speed USB isolator, etc\&. .SH "AUTHOR" .sp Thanos Chatziathanassiou .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Socomec JBUS/Modbus Reference Guide: https://www\&.socomec\&.com/files/live/sites/systemsite/files/GB\-JBUS\-MODBUS\-for\-Delphys\-MP\-and\-Delphys\-MX\-operating\-manual\&.pdf .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} libmodbus home page: http://libmodbus\&.org .RE nut-2.8.3/docs/man/bestfortress.txt0000644000200500020050000000227715001555412014236 00000000000000BESTFORTRESS(8) =============== NAME ---- bestfortress - Driver for old Best Fortress UPS equipment SYNOPSIS -------- *bestfortress* -h *bestfortress* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the bestfortress driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports old Best Fortress UPS equipment using a serial connection. One example is the "Fortress LI660", sold in (at least) 1995. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *baudrate*='num':: Set the speed of the serial connection -- 1200, 2400, 4800 or 9600. *max_load*='VA':: Set the full-scale value of the *ups.load* variable. AUTHORS ------- * Holger Dietze * Stuart D. Gathman SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] The newer Best Power drivers: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ linkman:bestups[8], linkman:bestuferrups[8], linkman:bestfcom[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_upserror.txt0000644000200500020050000000172015001555412014741 00000000000000UPSCLI_UPSERROR(3) ================== NAME ---- upscli_upserror - Get current error number for connection SYNOPSIS -------- ------ #include int upscli_upserror(UPSCONN_t *ups); ------ DESCRIPTION ----------- The *upscli_upserror*() function takes the pointer 'ups' to a `UPSCONN_t` state structure and returns the value of the internal error number, if any. This is typically used to check for certain error values like `UPSCLI_ERR_UNKCOMMAND`. That specific error can be used for detecting older versions of linkman:upsd[8] which might not support a given command. Some error messages have additional meanings, so you should use linkman:upscli_strerror[3] to obtain readable error messages. RETURN VALUE ------------ The *upscli_upserror*() function returns one of the `UPSCLI_ERR_*` values from `upsclient.h`, or '0' if no error has occurred. SEE ALSO -------- linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_strerror[3] nut-2.8.3/docs/man/upssched.80000644000200500020050000001444115001555047012657 00000000000000'\" t .\" Title: upssched .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSSCHED" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upssched \- Timer helper for scheduling events from upsmon .SH "SYNOPSIS" .sp \fBupssched\fR .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp \fBupssched\fR should be run from \fBupsmon\fR(8) via the NOTIFYCMD\&. You should never run it directly during normal operations\&. .sp .5v .RE .SH "DESCRIPTION" .sp \fBupssched\fR was created to allow users to execute programs at times relative to events being monitored by \fBupsmon\fR(8)\&. The original purpose was to allow for a shutdown to occur after some fixed period on battery, but there are other uses that are possible\&. .SH "INTEGRATION" .sp upssched needs to be called as the NOTIFYCMD in your \fBupsmon.conf\fR(5)\&. It determines what is happening based on the UPSNAME and NOTIFYTYPE environment variables\&. You should never have to deal with them directly\&. .sp Set the EXEC flag on the events that you want to see in upssched\&. For example, to make sure that upssched hears about ONLINE, ONBATT and LOWBATT events, the flags would look like this: .sp .if n \{\ .RS 4 .\} .nf NOTIFYFLAG ONLINE EXEC NOTIFYFLAG ONBATT EXEC NOTIFYFLAG LOWBATT EXEC .fi .if n \{\ .RE .\} .sp If you also want to continue writing to the syslog, just add it in: .sp .if n \{\ .RS 4 .\} .nf NOTIFYFLAG ONLINE SYSLOG+EXEC NOTIFYFLAG ONBATT SYSLOG+EXEC NOTIFYFLAG LOWBATT SYSLOG+EXEC .fi .if n \{\ .RE .\} .sp For a full list of notify flags, see the \fBupsmon\fR(8) documentation\&. .SH "CONFIGURATION" .sp See \fBupssched.conf\fR(5) for information on configuring this program\&. .SH "EARLY SHUTDOWNS" .sp To shut down the system early, define a timer that starts due to an ONBATT condition\&. When it triggers, make your CMDSCRIPT call your shutdown routine\&. It should finish by calling upsmon \-c fsd so that upsmon gets to shut down the slaves in a controlled manner\&. .sp Be sure you cancel the timer if power returns (ONLINE)\&. .SH "DEBOUNCING EVENTS" .sp If your UPS goes on and off battery frequently, you can use this program to reduce the number of pager messages that are sent out\&. Rather than sending pages directly from \fBupsmon\fR(8), use a short timer here\&. If the timer triggers with the UPS still on battery, then send the page\&. If the power returns before then, the timer can be cancelled and no page is necessary\&. .SH "BACKGROUND" .sp This program was written primarily to fulfill the requests of users for the early shutdown scenario\&. The "outboard" design of the program (relative to upsmon) was intended to reduce the load on the average system\&. Most people don\(cqt have the requirement of shutting down after \fIN\fR seconds on battery, since the usual OB+LB testing is sufficient\&. .sp This program was created separately so those people don\(cqt have to spend CPU time and RAM on something that will never be used in their environments\&. .sp The design of the timer handler is also geared towards minimizing impact\&. It will come and go from the process list as necessary\&. When a new timer is started, a process will be forked to actually watch the clock and eventually start the CMDSCRIPT\&. When a timer triggers, it is removed from the queue\&. Cancelling a timer will also remove it from the queue\&. When no timers are present in the queue, the background process exits\&. .sp This means that you will only see upssched running when one of two things is happening: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} There\(cqs a timer of some sort currently running .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} upsmon just called it, and you managed to catch the brief instance .RE .sp The final optimization handles the possibility of trying to cancel a timer when there are none running\&. If the timer daemon isn\(cqt running, there are no timers to cancel, and furthermore there is no need to start a clock\-watcher\&. So, it skips that step and exits sooner\&. .SH "ENVIRONMENT VARIABLES" .sp \fBNUT_DEBUG_LEVEL\fR sets default debug verbosity if no \fB\-D\fR arguments were provided on command line, but does not request that the daemon runs in foreground mode\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Unlike some other NUT daemons, upssched with enabled debug does not stop reporting on stderr! It forks a background process with the first call as an event handler, which exits soon after all tracked timers have elapsed and were handled (if needed)\&. .sp .5v .RE .sp \fBUPSNAME\fR and \fBNOTIFYTYPE\fR are required, as detailed above\&. They are set by upsmon when it calls upssched as its choice of NOTIFYCMD\&. .sp \fBNUT_CONFPATH\fR is the path name of the directory that contains upssched\&.conf and other configuration files\&. If this variable is not set, \fBupssched\fR uses a built\-in default, which is often /usr/local/ups/etc\&. .SH "FILES" .sp \fBupssched.conf\fR(5) .SH "SEE ALSO" .sp \fBupsmon\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nhs_ser.80000644000200500020050000000724015001555076012503 00000000000000'\" t .\" Title: nhs_ser .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NHS_SER" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nhs_ser \- Driver for NHS Nobreaks, senoidal line, with serial port .SH "SYNOPSIS" .sp \fBnhs_ser\fR \-h .sp \fBnhs_ser\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBnhs_ser\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp \fBnhs_ser\fR supports numerous UPS models made by NHS Sistemas Eletronicos LTDA and marketed in Brazil\&. They feature a serial port and a binary wire protocol\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Currently this driver only builds on Linux\&. This is expected to change in future revisions of the code\&. .sp .5v .RE .SH "EXTRA ARGUMENTS" .sp This driver also supports the following optional settings: .PP \fBbaud\fR=\fInum\fR .RS 4 Set the value of serial port baud rate (default: 2400) .RE .PP \fBah\fR=\fInum\fR .RS 4 Battery discharge capacity in Ampere/hour\&. .RE .PP \fBva\fR=\fInum\fR .RS 4 Nobreak NOMINAL POWER in VA\&. .RE .PP \fBpf\fR=\fInum\fR .RS 4 Power Factor to use in calculations of battery time (default: 0\&.90)\&. .RE .PP \fBvin_low_warn_perc\fR=\fInum\fR .RS 4 Voltage In Percentage to calculate warning low level (default: 2\&.00)\&. .RE .PP \fBvin_low_crit_perc\fR=\fInum\fR .RS 4 Voltage In Percentage to calculate critical low level (default: 2\&.00)\&. .RE .PP \fBvin_high_warn_perc\fR=\fInum\fR .RS 4 Voltage In Percentage to calculate warning high level (default: 2\&.00)\&. .RE .PP \fBvin_high_crit_perc\fR=\fInum\fR .RS 4 Voltage In Percentage to calculate critical high level (default: 2\&.00)\&. .RE .PP \fBnumbatteries\fR=\fInum\fR .RS 4 Num Batteries (override value from nobreak)\&. .RE .PP \fBvbat\fR=\fInum\fR .RS 4 Battery Voltage (default: 12\&.00)\&. .RE .PP \fBdebug_pkt_raw\fR .RS 4 Optional flag to enable debug logging of packet bytes\&. .RE .PP \fBdebug_pkt_data\fR .RS 4 Optional flag to enable debug logging of data packet decoding\&. .RE .PP \fBdebug_pkt_hwinfo\fR .RS 4 Optional flag to enable debug logging of hwinfo packet decoding\&. .RE .SH "AUTHORS" .sp Lucas Willian Bocchi .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upscmd.80000644000200500020050000001321415001555047012331 00000000000000'\" t .\" Title: upscmd .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCMD" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscmd \- Network UPS Tools device/driver instant commands administration tool .SH "SYNOPSIS" .sp \fBupscmd\fR \-h .sp \fBupscmd\fR \-l \fIups\fR .sp \fBupscmd\fR [\-u \fIusername\fR] [\-p \fIpassword\fR] [\-w] [\-t ] \fIups\fR \fIcommand\fR .SH "DESCRIPTION" .sp \fBupscmd\fR allows you to invoke "instant commands" in your UPS hardware\&. It sends commands via the server \fBupsd\fR(8) to your driver, which manages the hardware for you\&. You must use credentials defined in \fBupsd.users\fR(5) file on that data server with appropriate permissions\&. .sp Not all hardware supports this, so check the list with \-l to see if anything will work on your equipment\&. .sp On hardware that supports it, you can use this program to start and stop battery tests, invoke a front panel test (beep!), turn the load on or off, and more\&. .SH "OPTIONS" .PP \fB\-l\fR \fIups\fR .RS 4 Show the list of supported instant commands on that UPS\&. Some hardware may not support any of them\&. .RE .PP \fB\-u\fR \fIusername\fR .RS 4 Set the username for the connection to the server\&. This is optional, and you will be prompted for this when invoking a command if \-u is not used\&. .RE .PP \fB\-p\fR \fIpassword\fR .RS 4 Set the password to authenticate to the server\&. This is also optional like \-u, and you will be prompted for it if necessary\&. .RE .PP \fB\-w\fR .RS 4 Wait for the completion of command execution by the driver and return its actual result from the device\&. Note that this feature requires that both \fBupsd\fR(8) and the driver support TRACKING (NUT version 2\&.8\&.0 or higher), or it will otherwise fail\&. .sp The command will also block until an actual result is provided from the driver, or the timeout is reached (see \fB\-t\fR)\&. .RE .PP \fB\-t\fR \fIseconds\fR .RS 4 Set a timeout when using \fB\-w\fR\&. Defaults to 10 seconds\&. .RE .PP \fIups\fR .RS 4 Connect to this UPS\&. The format is upsname[@hostname[:port]]\&. The default hostname is "localhost"\&. .RE .SH "COMMON OPTIONS" .PP \fB\-h\fR .RS 4 Show the command\-line help message\&. .RE .PP \fB\-V\fR .RS 4 Show NUT version banner\&. More details may be available if you also export NUT_DEBUG_LEVEL=1 or greater verbosity level\&. .RE .PP \fB\-W\fR \fIsecs\fR .RS 4 Set the timeout for initial network connections (by default they are indefinitely non\-blocking, or until the system interrupts the attempt)\&. Overrides the optional NUT_DEFAULT_CONNECT_TIMEOUT environment variable\&. .RE .SH "UNATTENDED MODE" .sp If you run this program inside a shell script or similar to invoke a command, you will need to specify all of the information on the command line\&. This means using \-u and \-p\&. Otherwise it will put up a prompt and your program will hang\&. .sp This is not necessary when displaying the list, as the username and password are not required for read\-only mode\&. .sp Moreover, if you run this program inside a shell script or similar, you should only consider using output from stdout, not stderr\&. .SH "DANGEROUS COMMANDS" .sp Some drivers like \fBapcsmart\fR(8) have built\-in paranoia for the dangerous commands like load\&.off\&. To make them actually turn off the load, you will have to send the command twice within a short window\&. That is, you will have to send it once, then send it again after 3 seconds elapse but before 15 seconds pass\&. .sp This paranoia is entirely defined within the driver\&. upsd and upscmd have no control over the timing\&. .SH "DIAGNOSTICS" .sp \fBupscmd\fR won\(cqt work unless you provide a valid username and password\&. If you get "access denied" errors, make sure that your \fBupsd.users\fR(5) has an entry for you, and that the username you are using has permissions to SET variables\&. .sp \fBupscmd\fR without \fI\-w\fR would somewhat confusingly show "OK" meaning just that the data server connection was established, and the server did not immediately reject the request due to e\&.g\&. unknown instant command name\&. If you care to know the actual results, do use the \-w (\-t NUM) option(s) to wait for them\&. .SH "BUGS" .sp There is currently no way to tell the user when the driver requires confirmation to invoke a command such as load\&.off\&. .sp This is on the list of things to fix in the future, so don\(cqt despair\&. It involves magic cookies\&. .SH "SEE ALSO" .sp \fBupsd\fR(8), \fBupsrw\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan_free_ip_ranges.txt0000644000200500020050000000232415001555412016205 00000000000000NUTSCAN_FREE_IP_RANGES(3) ========================= NAME ---- nutscan_free_ip_ranges - Free contents of a `nutscan_ip_range_list_t` structure populated (and optionally created) by `nutscan_init_ip_ranges()` and, more importantly, filled by a series of `nutscan_add_ip_range()` calls. SYNOPSIS -------- ------ #include void nutscan_free_ip_ranges(nutscan_ip_range_list_t *irl); ------ DESCRIPTION ----------- The *nutscan_free_ip_ranges()* function can free a `nutscan_ip_range_list_t` structure. Doing so, it frees the whole linked list of `nutscan_ip_range_t` entries, and zeroes out helper properties. The structure itself is not freed (as it can be a statically allocated variable on the stack), and can be re-used for a new list if needed. The caller must ultimately free the structure object if it was allocated dynamically (e.g. by originally calling `nutscan_init_ip_ranges(NULL)`). NOTES ----- Technically, the function is currently defined in 'nutscan-ip.h' file. SEE ALSO -------- linkman:nutscan_init_ip_ranges[3], linkman:nutscan_add_ip_range[3], linkman:nutscan_stringify_ip_ranges[3], linkman:nutscan_cidr_to_ip[3], linkman:nutscan_ip_ranges_iter_init[3], linkman:nutscan_ip_ranges_iter_inc[3] nut-2.8.3/docs/man/bcmxcp.txt0000644000200500020050000000434415001555412012762 00000000000000BCMXCP(8) ========= NAME ---- bcmxcp - Driver for UPSes supporting the serial BCM/XCP protocol SYNOPSIS -------- *bcmxcp* -h *bcmxcp* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the bcmxcp driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver should recognize all serial BCM/XCP-compatible UPSes. It has been developed and tested on Powerware PW5115 and PW9120 hardware. If your UPS has a USB connection, you may also consult the linkman:bcmxcp_usb[8] driver documentation. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]. *shutdown_delay=*'delay':: The number of seconds that the UPS should wait between receiving the shutdown command (`upsdrvctl shutdown`) and actually shutting off. *baud_rate=*'rate':: Communication speed for the UPS. If this is set to 9600, it tries to connect to the UPS at 9600bps. If it fails to communicate, it will go into baud-hunting. It starts at 1200 and goes up to 19200. If it succeeds, it tell you the speed it connected with. If not included in the config, it defaults to baud-hunting. DEFAULT VALUES FOR THE EXTRA ARGUMENTS -------------------------------------- - *shutdown_delay =* '120' - *baud_rate =* 'none' INSTANT COMMANDS ---------------- This driver supports the following Instant Commands: *shutdown.return*:: Turn off the load and return when power is back. *shutdown.stayoff*:: Turn off the load and remain off. *test.battery.start*:: Start a battery test. *outlet.n.shutdown.return*:: Turn off the load on outlet 'n' and return when power is back. ('n' is the outlet number reported by the upsc command) TODO LIST --------- Report UPS statistics information:: BCM/XCP supports reporting of UPS statistics data. Change settings:: Access the config register to change settings. BUGS ---- None known. AUTHOR ------ Tore Ørpetveit SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] The USB BCM/XCP driver: ~~~~~~~~~~~~~~~~~~~~~~~ linkman:bcmxcp_usb[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/tripplitesu.txt0000644000200500020050000000230615001555412014066 00000000000000TRIPPLITESU(8) ============== NAME ---- tripplitesu - Driver for Tripp-Lite SmartOnline (SU) UPS equipment SYNOPSIS -------- *tripplitesu* -h *tripplitesu* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the tripplitesu driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports the Tripp Lite SmartOnline family (via the serial port). EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *lowbatt*='num':: Set the low battery warning threshold in percent at which shutdown is initiated by linkman:upsmon[8]. By default, the UPS may not report low battery until there are only a few seconds left. Common values are around 25--30. AUTHOR ------ Allan N. Hessenflow SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Other drivers for Tripp-Lite hardware: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ linkman:tripplite[8], linkman:tripplite_usb[8], linkman:usbhid-ups[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/pijuice.80000644000200500020050000001020715001555101012454 00000000000000'\" t .\" Title: pijuice .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "PIJUICE" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" pijuice \- Driver for UPS in PiJuice HAT .SH "SYNOPSIS" .sp \fBpijuice\fR \-h .sp \fBpijuice\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBpijuice\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This manual page was hastily adapted from related asem driver man page based on information from the original pull request, and so may not fully apply to PiJuice HAT, patches from experts are welcome\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The \fBpijuice\fR driver supports the portable PiJuice HAT UPS for Raspberry Pi embedded PCs\&. .SH "EXTRA ARGUMENTS" .sp The required parameter for this driver is the I2C bus name: .PP \fBport\fR=\fIdev\-node\fR .RS 4 On the PiJuice HAT, this should be /dev/i2c\-1\&. .RE .SH "INSTALLATION" .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This section was copied from asem driver man page and may not fully apply to PiJuice HAT, patches are welcome\&. .sp .5v .RE .sp This driver is specific to the Linux I2C API, and requires the lm_sensors libi2c\-dev or its equivalent to compile\&. .sp Beware that the SystemIO memory used by the I2C controller is reserved by ACPI\&. If only a native I2C driver (e\&.g\&. i2c_i801, as of 3\&.5\&.X Linux kernels) is available, then you\(cqll need to relax the ACPI resources check\&. For example, you can boot with the acpi_enforce_resources=lax option\&. .SH "KNOWN ISSUES AND BUGS" .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This section was copied from asem driver man page and may not fully apply to PiJuice HAT, patches are welcome\&. .sp .5v .RE .sp The driver shutdown function is not implemented, so other arrangements must be made to turn off the UPS\&. .SH "AUTHORS" .sp Andrew Anderson .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Initial pull requests adding this driver: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://github\&.com/networkupstools/nut/pull/730 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://github\&.com/PiSupply/PiJuice/issues/124 .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Product home page: https://uk\&.pi\-supply\&.com/products/pijuice\-standard .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE nut-2.8.3/docs/man/upsimage.cgi.txt0000644000200500020050000000216015001555412014053 00000000000000UPSIMAGE.CGI(8) =============== NAME ---- upsimage.cgi - Image-generating helper for upsstats.cgi SYNOPSIS -------- *upsimage.cgi* NOTE: As a CGI program, this should be invoked through your web server. If you run it from the command line, it will either complain about unauthorized access or spew a PNG at you. DESCRIPTION ----------- *upsimage.cgi* generates the graphical bars that make up the right side of the page generated by linkman:upsstats.cgi[8]. These represent the current battery charge, utility voltage, and UPS load where available. The images are in PNG format, and are created by linking to Boutell's excellent 'gd' library. ACCESS CONTROL -------------- upsstats will only talk to linkman:upsd[8] servers that have been defined in your linkman:hosts.conf[5]. If it complains about "Access to that host is not authorized", check that file first. FILES ----- linkman:hosts.conf[5] SEE ALSO -------- linkman:upsd[8], linkman:upsstats.cgi[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * The gd home page: http://libgd.bitbucket.org nut-2.8.3/docs/man/liebert-esp2.txt0000644000200500020050000000330515001555412013777 00000000000000LIEBERT-ESP2(8) =============== NAME ---- liebert-esp2 - Driver for Liebert UPS, using the ESP-II serial protocol SYNOPSIS -------- *liebert-esp2* -h *liebert-esp2* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the liebert-esp2 driver. For information about the core driver, see linkman:nutupsdrv[8]. SPECIAL CABLING NOTE -------------------- Be aware that an RS-232 cable with ONLY the RX, TX and ground pin must be used when interfacing with GXT2 series UPS units (and possibly others), since the handshaking lines are used for purposes other than RS-232 flow control. Use of a standard RS-232 cable with full handshaking may result in undesired operation and/or shutdown. It is therefore advisable to confirm the proper cable/wiring with the diagram provided in the manual with your UPS. SUPPORTED HARDWARE ------------------ Tested to work on the following units: * Liebert GXT2-6000RT208 This is an experimental driver. You have been warned. This driver currently does not support modification of configuration parameters, such as the low battery warning time and automatic restart policy. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in linkman:ups.conf[5]: *baudrate=*'num':: Set the speed of the serial connection -- 1200, 2400 (default), 4800, 9600 or 19200. AUTHORS ------- * Richard Gregory * Arjen de Korte * Nash Kaminski SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_scan_avahi.txt0000644000200500020050000000307615001555412015336 00000000000000NUTSCAN_SCAN_AVAHI(3) ===================== NAME ---- nutscan_scan_avahi - Scan network for NUT services via mDNS SYNOPSIS -------- ------ #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout); ------ DESCRIPTION ----------- The *nutscan_scan_avahi()* function tries to detect the NUT service via mDNS, and its associated devices. It uses the Avahi library to do so. You MUST call linkman:nutscan_init[3] before using this function. This function can query perspective IP addresses using NUT protocol, and in this case it waits up to 'usec_timeout' microseconds before considering an IP address to be unresponsive. RETURN VALUE ------------ The *nutscan_scan_avahi()* function returns a pointer to a `nutscan_device_t` structure containing all found devices. It returns NULL if an error occurs, or if no device is found. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3], linkman:nutscan_scan_eaton_serial[3] Internet resources: ~~~~~~~~~~~~~~~~~~~ http://avahi.org/ nut-2.8.3/docs/man/upsd.users.txt0000644000200500020050000000765415001555412013630 00000000000000UPSD.USERS(5) ============= NAME ---- upsd.users - Administrative user definitions for NUT upsd data server DESCRIPTION ----------- Administrative commands such as setting variables and the instant commands are powerful, and access to them needs to be restricted. This file defines who may access them, and what is available. IMPORTANT NOTES --------------- * Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message). * Balance the run-time user permissions to access the file (and perhaps the directory it is in) for only `upsd` to be able to read it; write access is not needed. It is common to use `chown root:nut` and `chmod 640` to set up acceptable file permissions. - Packages (and build recipes) typically prepare one set of user and group accounts for NUT. Custom builds with minimal configuration might even use `nobody:nogroup` or similar, which is inherently insecure. - On systems with extra security concerns, NUT drivers and data server should run as separate user accounts which would be members of one same group for shared access to local Unix socket files and the directory they are in, but different groups for configuration file access. This would need some daemons to use customized `user`, `group`, `RUN_AS_USER` and/or `RUN_AS_GROUP` settings to override the single built-in value. - Note that the monitoring, logging, etc. clients are networked-only. They do not need access to these files and directories, and can run as an independent user and group altogether. - Keep in mind the security of also any backup copies of this file, e.g. the archive files it might end up in. SECTIONS -------- Each user gets its own section. The fields in that section set the parameters associated with that user's privileges. The section begins with the name of the user in brackets, and continues until the next user name in brackets or EOF. These users are independent of `/etc/passwd` or other OS account databases. Here are some examples to get you started: [admin] password = mypass actions = set actions = fsd instcmds = all [pfy] password = duh instcmds = test.panel.start instcmds = test.panel.stop [upswired] password = blah upsmon primary [observer] password = abcd upsmon secondary FIELDS ------ *password*:: Set the password for this user. *actions*:: Allow the user to do certain things with `upsd`. To specify multiple actions, use multiple instances of the *actions* field. Valid actions are: + -- SET;; change the value of certain variables in the UPS FSD;; set the forced shutdown flag in the UPS. This is equivalent to an "on battery + low battery" situation for the purposes of monitoring. -- + The list of actions is expected to grow in the future. *instcmds*:: Let a user initiate specific instant commands. Use "ALL" to grant all commands automatically. To specify multiple commands, use multiple instances of the *instcmds* field. For the full list of what your UPS supports, use `upscmd -l`. + The +cmdvartab+ file supplied with the NUT distribution contains a list of most of the generally known command names. *upsmon*:: Add the necessary actions for an `upsmon` process, and can be viewed as a role of a particular client instance to work with this data server instance. This is either set to 'primary' (may request FSD) or 'secondary' (follows critical situations to shut down when needed). + Do not attempt to assign actions to `upsmon` by hand, as you may miss something important. This method of designating a "upsmon user" was created so internal capabilities could be changed later on without breaking existing installations (potentially using actions that are not exposed for direct assignment). SEE ALSO -------- linkman:upsd[8], linkman:upsd.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/ivtscd.80000644000200500020050000000404315001555071012327 00000000000000'\" t .\" Title: ivtscd .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "IVTSCD" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ivtscd \- Driver for the IVT Solar Controller Device .SH "SYNOPSIS" .sp \fBivtscd\fR \-h .sp \fBivtscd\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBivtscd\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "DESCRIPTION" .sp This driver allows to access the IVT SCD\-series devices\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra argument\&. .SH "AUTHOR" .sp Arjen de Korte .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/blazer-common.txt0000644000200500020050000002464315001555412014257 00000000000000NOTE ---- This man page only documents the hardware-specific features of the blazer driver. For information about the core driver, see linkman:nutupsdrv[8]. NOTE ---- Please note that this driver is deprecated and will not receive new development. If it works for managing your devices -- fine, but if you are running it to try setting up a new device, please consider the newer linkman:nutdrv_qx[8] instead, which should handle all 'Q*' protocol variants for NUT. Please do also report if your device works with this driver, but linkman:nutdrv_qx[8] would not actually support it with any subdriver! SUPPORTED HARDWARE ------------------ The blazer driver is known to work with various UPSes from Blazer, Energy Sistem, Fenton Technologies, General Electric, Mustek and many others. The NUT compatibility table lists all the known supported models. Keep in mind, however, that other models not listed there may also be supported, but haven't been tested. All devices with a serial interface (use the *blazer_ser* driver) and many with a USB interface (use the *blazer_usb* driver) are supported. EXTRA ARGUMENTS --------------- You may need to override or provide defaults for some values, depending on the make and model of your UPS. The following are the ones that most likely will need changing (see linkman:ups.conf[5]): *default.battery.voltage.high =* 'value':: Maximum battery voltage that is reached after about 12 to 24 hours charging. If you want the driver to report a guesstimated *battery.charge*, you need to specify this (see <<_battery_charge_guesstimation,BATTERY CHARGE GUESSTIMATION>>). *default.battery.voltage.low =* 'value':: Minimum battery voltage just before the UPS automatically shuts down. If you want the driver to report a guesstimated *battery.charge*, you need to specify this (see <<_battery_charge_guesstimation,BATTERY CHARGE GUESSTIMATION>>). *default.battery.voltage.nominal =* 'value':: *override.battery.voltage.nominal =* 'value':: Some devices show a wrong nominal battery voltage (or none at all), so you may need to override or set a default value. *override.battery.packs =* 'value':: Some devices report a part of the total battery voltage. For instance, if *battery.voltage.nominal* is 24 V, but it reports a *battery.voltage* of around 2 V, the number of *battery.packs* to correct this reading would be 12. The driver will attempt to detect this automatically, but if this fails somehow, you may want to override this value. *ondelay =* 'value':: Time to wait before switching on the UPS (minutes). Note that a value below 3 minutes, may cause earlier firmware versions to not switch on automatically, so it defaults to 3 minutes. The acceptable range is +0..9999+ minutes. *offdelay =* 'value':: Time to wait before shutting down the UPS (seconds). This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds). Defaults to 30 seconds. The acceptable range is +12..600+ seconds. *norating*:: Some UPSes will lock up if you attempt to read rating information from them. Setting this flag will make the driver skip this step. *novendor*:: Some UPSes will lock up if you attempt to read vendor information from them. Setting this flag will make the driver skip this step. *protocol =* 'string':: Skip autodetection of the protocol to use and only use the one specified. Supported values are 'megatec', 'megatec/old', 'mustek' and 'zinto'. *runtimecal =* 'value,value,value,value':: Parameter used in the (optional) runtime estimation. This takes two runtimes at different loads. Typically, this uses the runtime at full load and the runtime at half load. For instance, if your UPS has a rated runtime of 240 seconds at full load and 720 seconds at half load, you would enter + runtimecal = 240,100,720,50 + The first load should always be higher than the second. If you have values available for loads other than 100 and 50 % respectively, you can use those too, but keep them spaced apart as far as reasonably possible. Just don't get too close to no load (prediction of runtime depends more on idle load for the battery then). *chargetime =* 'value':: The time needed to fully recharge the battery after being fully discharged. If not specified, the driver defaults to 43200 seconds (12 hours). Only used if *runtimecal* is also specified. *idleload =* 'value':: Minimum battery load used by the driver to estimate the runtime. If not specified, the driver defaults to 10%. Only used if *runtimecal* is also specified. ifndef::blazer_usb[] SERIAL INTERFACE ONLY ~~~~~~~~~~~~~~~~~~~~~ *cablepower =* 'string':: By default the driver will set DTR and clear RTS ('normal'). If you find that your UPS isn't detected or the communication with the UPS is unreliable, you may try if clear DTR and set RTS ('reverse'), set DTR and RTS ('both') or clear DTR and RTS ('none') improves this situation. endif::blazer_usb[] ifdef::blazer_usb[] USB INTERFACE ONLY ~~~~~~~~~~~~~~~~~~ include::nut_usb_addvars.txt[] *subdriver =* 'string':: Select a serial-over-USB subdriver to use. You have a choice between *phoenix*, *ippon*, *cypress*, and *krauler*. When using this option, it is mandatory to also specify the *vendorid* and *productid*. *langid_fix =* 'value':: Apply the language ID workaround to the krauler subdriver. This is mandatory for some devices to work (LDLC, Dynamix and others). You must to provide *value* (0x409 or 0x4095), according to your device entry in NUT hardware compatibility list (HCL). endif::blazer_usb[] UPS COMMANDS ------------ This driver supports some instant commands (see linkman:upscmd[8]): *beeper.toggle*:: Toggle the UPS beeper. (Not available on some hardware.) *load.on*:: Turn on the load immediately. *load.off*:: Turn off the load immediately (see <<_known_problems,KNOWN PROBLEMS>>). *shutdown.return*:: Turn off the load and return when power is back. Uses the timers defined by *ondelay* and *offdelay*. *shutdown.stayoff*:: Turn off the load and remain off (see <<_known_problems,KNOWN PROBLEMS>>). Uses the timer defined by *offdelay*. *shutdown.stop*:: Stop a shutdown in progress. *test.battery.start.deep*:: Perform a long battery test (Not available on some hardware.) *test.battery.start.quick*:: Perform a (10 second) battery test. *test.battery.start* 'value':: Perform a battery test for the duration of 'value' minutes. *test.battery.stop*:: Stop a running battery test (not available on some hardware.) BATTERY CHARGE GUESSTIMATION ---------------------------- Due to popular demand, this driver will report a guesstimated *battery.charge* value and optionally *battery.runtime*, provided you specified a couple of the <<_extra_arguments,EXTRA ARGUMENTS>> listed above. If you specify both *battery.voltage.high* and *battery.voltage.low* in linkman:ups.conf[5], but don't enter *runtimecal*, it will guesstimate the state of charge by looking at the battery voltage alone. This is not reliable under load, as this only gives reasonably accurate readings if you disconnect the load, let the battery rest for a couple of minutes and then measure the open cell voltage. This just isn't practical if the power went out and the UPS is providing power for your systems. battery.voltage - battery.voltage.low battery.charge = ------------------------------------------ x 100 % battery.voltage.high - battery.voltage.low There is a way to get better readings without disconnecting the load, but this requires one to keep track on how much (and how fast) current is going in- and out of the battery. If you specified the *runtimecal*, the driver will attempt to do this. Note however, that this heavily relies on the values you enter and that the UPS must be able to report the load as well. There are quite a couple of devices that report 0% (or any other fixed value) at all times, in which case this obviously doesn't work. The driver also has no way of determining the degradation of the battery capacity over time, so you'll have to deal with this yourself (by adjusting the values in *runtimecal*). Also note that the driver guesses the initial state of charge based on the battery voltage, so this may be less than 100%, even when you are certain that they are full. There is just no way to reliably measure this between 0 and 100% full charge. This is better than nothing (but not by much). If any of the above calculations are giving you incorrect readings, remember that you are the one who put in the values in linkman:ups.conf[5], so don't complain to the author. If you need something better, consider buy an UPS that reports *battery.charge* and *battery.runtime* all by itself without the help of a NUT driver. NOTES FOR THE PREVIOUS USER OF MEGATEC DRIVERS ---------------------------------------------- The blazer drivers having replaced the megatec ones, some configuration changes may be required by users switching to blazer. Part of this, the following megatec options, in ups.conf, have to be changed: *battvolts*:: You need to use 'default.battery.voltage.high' and 'default.battery.voltage.low' *dtr and rts*:: You need to use 'cablepower' *ignoreoff*:: This parameter can simply be discarded, since it was a wrong understanding of the specification. KNOWN PROBLEMS -------------- Some UPS commands aren't supported by all models. In most cases, the driver will send a message to the system log when the user tries to execute an unsupported command. Unfortunately, some models don't even provide a way for the driver to check for this, so the unsupported commands will silently fail. Both the *load.off* and *shutdown.stayoff* instant commands are meant to turn the load off indefinitely. However, some UPS models don't allow this. Some models report a bogus value for the beeper status (will always be 'enabled' or 'disabled'). So, the *beeper.toggle* command may appear to have no effect in the status reported by the driver when, in fact, it is working fine. The temperature and load value is known to be bogus in some models. AUTHORS ------- * Arjen de Korte * Alexander Gordeev SEE ALSO -------- ifdef::blazer_usb[] linkman:blazer_ser[8], endif::blazer_usb[] ifndef::blazer_usb[] linkman:blazer_usb[8], endif::blazer_usb[] linkman:nutupsdrv[8], linkman:upsc[8], linkman:upscmd[8], linkman:upsrw[8] Internet Resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * The NUT HCL: https://www.networkupstools.org/stable-hcl.html nut-2.8.3/docs/man/nutclient_get_device_commands.30000644000200500020050000000004115001555117017065 00000000000000.so man3/libnutclient_commands.3 nut-2.8.3/docs/man/upsdrvctl.80000644000200500020050000003244115001555047013067 00000000000000'\" t .\" Title: upsdrvctl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSDRVCTL" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsdrvctl \- Network UPS Tools driver controller .SH "SYNOPSIS" .sp \fBupsdrvctl\fR \-h .sp \fBupsdrvctl\fR [\fIOPTIONS\fR] {start | stop | shutdown | status} [\fIups\fR] .sp \fBupsdrvctl\fR [\fIOPTIONS\fR] {list | \-l} [\fIups\fR] .sp \fBupsdrvctl\fR [\fIOPTIONS\fR] \-c COMMAND [\fIups\fR] .SH "DESCRIPTION" .sp \fBupsdrvctl\fR provides a uniform interface for controlling your UPS drivers\&. You should use upsdrvctl command instead of direct calls to the drivers whenever possible\&. .sp When used properly, upsdrvctl lets you maintain identical startup scripts across multiple systems with different UPS configurations\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br .sp For operating systems with service management frameworks, such as Solaris/illumos SMF or Linux systemd, the \fBupsdrvsvcctl\fR(8) may be a better choice\&. .sp In fact, service instances prepared by \fBnut-driver-enumerator\fR(8) based on contents of your \fBups.conf\fR(5) file and automatically maintained by the respective framework can conflict with manual execution of drivers\&. In this case, upsdrvctl would emit a warning in NUT builds with that capability (can be silenced by exporting a NUT_QUIET_INIT_NDE_WARNING environment variable with any value)\&. .sp .5v .RE .sp You may be required to stop service units (if used) and run driver programs directly rather than via upsdrvctl for troubleshooting, e\&.g\&. to facilitate debug log collection or test any custom builds of drivers without conflict with a normally running packaged instance\&. .SH "OPTIONS" .PP \fB\-h\fR .RS 4 Display the help text\&. .RE .PP \fB\-r\fR \fIdirectory\fR .RS 4 If starting a driver, this value will direct it to \fBchroot\fR(2) into \fIdirectory\fR\&. This can be useful when securing systems\&. .sp This may be set in the \fBups.conf\fR(5) with the chroot directive in the global section\&. .RE .PP \fB\-t\fR .RS 4 Enable testing mode\&. This also enables debug mode\&. Testing mode makes upsdrvctl display the actions it would execute without actually doing them\&. Use this to test out your configuration without actually doing anything to your UPS drivers\&. .sp This may be helpful when defining the sdorder directive in your \fBups.conf\fR(5) section for the device\&. .RE .PP \fB\-u\fR \fIusername\fR .RS 4 If starting a driver, this value will direct it to \fBsetuid\fR(2) to the user id associated with \fIusername\fR\&. .sp If the driver is started as \fIroot\fR without specifying this value, it will use the username that was compiled into the binary\&. This defaults to \fInobody\fR (if not otherwise configured), which is far from ideal\&. .sp This may be set in \fBups.conf\fR(5) with the user directive in the global section\&. .RE .PP \fB\-D\fR .RS 4 Raise the debug level\&. Use this multiple times for additional details\&. .sp Note that this does not preclude the upsdrvctl tool from exiting after its job is done (however an explicit \fB\-F\fR option does)\&. .sp Also note that this option alone modifies the debug verbosity of the tool, but not of the drivers it launches\&. See the additional \fB\-d\fR option for that\&. .RE .PP \fB\-d\fR .RS 4 Pass the selected debug level from upsdrvctl to launched drivers\&. .sp Note that by default for NUT daemons, enabled debugging means running in foreground mode; you can specify \fB\-B\fR additionally to avoid that\&. .RE .PP \fB\-F\fR .RS 4 Driver will run in the foreground (not fork away from the upsdrvctl process), regardless of debugging settings\&. It would also keep the tool program itself foregrounded with driver daemons running as its children (in case of a single driver startup, it would not even fork)\&. .sp It would also not wait for drivers to complete initialization, so upsdrvctl will warn about such situations\&. .sp Specify twice (\-FF or \-F \-F) to save the driver PID file even in this mode (not saved by default when staying in foreground)\&. .RE .PP \fB\-B\fR .RS 4 Drivers will run in the background, regardless of debugging settings, as set by \fB\-D\fR and passed\-through by \fB\-d\fR options\&. .RE .PP \fB\-l\fR .RS 4 Alias for list command\&. .RE .SH "COMMANDS" .sp upsdrvctl supports three active commands \(em start, stop and shutdown\&. It also supports passing requests to running drivers using \-c COMMAND syntax, similar to that in some other daemons\&. A couple of helper commands are also available \(em list and status\&. .sp They all can take an optional argument which is a UPS name from \fBups.conf\fR(5)\&. Without that argument, they operate on every UPS that is currently configured\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp upsdrvctl can not manage devices not listed in ups\&.conf (such as test drivers started with \-s TMP option)\&. .sp .5v .RE .PP \fBstart\fR .RS 4 Start the UPS driver(s)\&. In case of failure to start within \fImaxstartdelay\fR time\-frame, further attempts may be executed by using the \fImaxretry\fR and \fIretrydelay\fR values\&. Conversely, the \fInowait\fR global option can be used, especially to speed up parallel start of many drivers\&. .sp See \fBups.conf\fR(5) about these options\&. Built\-in defaults are: \fImaxstartdelay=75\fR (sec), \fImaxretry=1\fR (meaning one attempt at starting), \fIretrydelay=5\fR (sec)\&. .RE .PP \fBstop\fR .RS 4 Stop the UPS driver(s)\&. This does not send commands to the UPS\&. .RE .PP \fBshutdown\fR .RS 4 Command the UPS driver(s) to run their shutdown sequence\&. This assumes that the driver is no longer running, and starts a fresh instance via drivername \-k\&. It is intended to be used as the last step in system shutdown, after the filesystems are no longer mounted \fIrw\fR\&. Drivers are stopped according to their sdorder value \(em see \fBups.conf\fR(5)\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br .sp This will probably power off your computers, so don\(cqt play around with this option\&. Only use it when your systems are prepared to lose power\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Refer to \fBups.conf\fR(5) for using the \fBnowait\fR parameter\&. It can be overridden by NUT_IGNORE_NOWAIT environment variable (e\&.g\&. used to work around certain issues with systemd otherwise)\&. .sp .5v .RE .PP \fBlist\fR .RS 4 Without a further argument, report all currently known device configuration names to stdout, one per line\&. With an argument, also try to report that name, but exit with an error code if that name is not known\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The tool would exit with an error if ups\&.conf file is not found, readable, or does not define any device sections (whose names are reported here and managed in other commands)\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The tool name and NUT version banner line is also printed to stdout before any other processing\&. This can be suppressed by NUT_QUIET_INIT_BANNER environment variable (exported by caller and empty or "true"): .sp .5v .RE .sp .if n \{\ .RS 4 .\} .nf :; NUT_QUIET_INIT_BANNER=true upsdrvctl list dummy UPS1 UPS2 .fi .if n \{\ .RE .\} .PP \fBstatus\fR .RS 4 Similar to list, but reports more information \(em also the driver name, the PID if it is running, and result of a signal probe to check it is responding\&. The NUT_QUIET_INIT_BANNER suppression can be helpful for scripted parsing\&. If there is anything to print (at least one device is known), the first line of status report would be the heading with column names: .sp .if n \{\ .RS 4 .\} .nf :; NUT_QUIET_INIT_BANNER=true upsdrvctl status UPSNAME UPSDRV RUNNING PF_PID S_RESPONSIVE S_PID S_STATUS dummy dummy\-ups N/A \-3 NOT_RESPONSIVE N/A eco650 usbhid\-ups RUNNING 3559207 RESPONSIVE 3559207 "OL" UPS2 dummy\-ups RUNNING 31455 RESPONSIVE 31455 "OL BOOST" .fi .if n \{\ .RE .\} .sp Values are TAB\-separated, but UPSNAME and UPSDRV may be padded by spaces on the right and on the left respectively\&. Any complex string values would be encased in double\-quotes\&. .sp Fields reported (PF_* = according to PID file, if any; S_* = via socket protocol): .PP \fBUPSNAME\fR .RS 4 driver section configuration name .RE .PP \fBUPSDRV\fR .RS 4 driver program name per ups\&.conf .RE .PP \fBRUNNING\fR .RS 4 RUNNING if PF_PID or S_PID is valid, STOPPED if at least one PID value was parsed but none was found running with a correct program name; N/A if no PID file/socket reply or failed to parse\&. First the PID file is consulted, but it may be absent either due to command\-line parameters of daemons, or due to platform (WIN32)\&. If no PID value was found and confirmed this way, we fall back to checking the PID reported via protocol (if available and different)\&. .RE .PP \fBPF_PID\fR .RS 4 PID of driver according to PID file (if any), or some negative values upon errors (as defined in common\&.c) including an absent PID file, invalid contents, or unsupported platform for this mechanism (e\&.g\&. WIN32) .RE .PP \fBS_RESPONSIVE\fR .RS 4 RESPONSIVE if PING/PONG during socket protocol session setup succeeded; NOT_RESPONSIVE otherwise .RE .PP \fBS_PID\fR .RS 4 PID of driver according to GETPID active query, or N/A if the query failed .RE .PP \fBS_STATUS\fR .RS 4 Quoted value of ups\&.status variable .RE .sp This mode does not discover drivers that are not in ups\&.conf (e\&.g\&. started manually for experiments with many \-x CLI options)\&. .RE .PP \fB\-c\fR \fIcommand\fR .RS 4 Send \fIcommand\fR to the background process as a signal\&. Valid commands are: .PP \fBdump\fR .RS 4 tell the driver(s) to dump currently known state information to their stdout (if attached anywhere) .RE .PP \fBreload\fR .RS 4 reread configuration files, ignoring modified settings which can not be applied "on the fly" .RE .PP \fBreload\-or\-error\fR .RS 4 reread configuration files, ignoring but counting changed values which require a driver restart (can not be changed on the fly), and return a success/fail code based on that count, so the caller can decide the fate of the currently running driver instance .RE .PP \fBreload\-or\-exit\fR .RS 4 reread configuration files, exiting the old driver process if it encounters modified settings which can not be applied "on the fly" (so caller like systemd can launch another copy of the driver) .RE .PP \fBexit\fR .RS 4 tell the currently running driver instance to just exit (so an external caller like the new driver instance, or the systemd or SMF frameworks would start another copy) .RE .RE .sp If the upsdrvctl was launched to remain in memory and manage NUT driver processes, it can receive supported signals and pass them to those drivers\&. .SH "ENVIRONMENT VARIABLES" .sp \fBNUT_DEBUG_LEVEL\fR sets default debug verbosity if no \fB\-D\fR arguments were provided on command line, but does not request that the daemon runs in foreground mode\&. .sp \fBNUT_CONFPATH\fR is the path name of the directory that contains ups\&.conf and other configuration files\&. If this variable is not set, \fBupsdrvctl\fR (and the drivers) use a built\-in default, which is often /usr/local/ups/etc\&. .sp \fBNUT_ALTPIDPATH\fR is the path name of the directory in which \fBupsd\fR and drivers store \&.pid files\&. If this variable is not set, \fBupsd\fR and drivers use either \fBNUT_STATEPATH\fR if set, or ALTPIDPATH if set, or otherwise the built\-in default \fBSTATEPATH\fR\&. .SH "DIAGNOSTICS" .sp upsdrvctl will return a nonzero exit code if it encounters an error while performing the desired operation\&. This will also happen if a driver takes longer than the \fImaxstartdelay\fR period to enter the background\&. .SH "SEE ALSO" .sp \fBupsdrvsvcctl\fR(8), \fBnut-driver-enumerator\fR(8), \fBnutupsdrv\fR(8), \fBupsd\fR(8), \fBups.conf\fR(5) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/libnutclient_commands.txt0000644000200500020050000000330515001555412016057 00000000000000LIBNUTCLIENT_COMMANDS(3) ======================== NAME ---- libnutclient_commands, nutclient_get_device_commands, nutclient_has_device_command, nutclient_get_device_command_description, nutclient_execute_device_command - Instant command related functions in Network UPS Tools high-level client access library SYNOPSIS -------- ------ #include typedef void* NUTCLIENT_t; typedef char** strarr; strarr nutclient_get_device_commands( NUTCLIENT_t client, const char* dev); int nutclient_has_device_command( NUTCLIENT_t client, const char* dev, const char* cmd); char* nutclient_get_device_command_description( NUTCLIENT_t client, const char* dev, const char* cmd); void nutclient_execute_device_command( NUTCLIENT_t client, const char* dev, const char* cmd, const char* param=""); ------ DESCRIPTION ----------- These functions allow to manage instant commands of devices. * The *nutclient_get_device_commands()* function retrieves the list of command names for a device. + The returned strarr must be freed by 'strarr_free'. * The *nutclient_has_device_command* function tests if the specified command is supported by the device. + Return '1' if supported and '0' if not. * The *nutclient_get_device_command_description* function retrieves the command description, if any. + The returned string must be freed by linkmanext:free[3] (see linkman:libnutclient_general[3]). * The *nutclient_execute_device_command* intends to execute the instant command, with an optional parameter. Common arguments: * 'dev' is the device name. * 'cmd' is the instant command name. SEE ALSO -------- linkman:libnutclient[3] linkman:libnutclient_devices[3] linkman:libnutclient_general[3] nut-2.8.3/docs/man/nutdrv_siemens_sitop.80000644000200500020050000002153715001555074015330 00000000000000'\" t .\" Title: nutdrv_siemens_sitop .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTDRV_SIEMENS_SITOP" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutdrv_siemens_sitop \- Driver for the Siemens SITOP UPS500 series UPS .SH "SYNOPSIS" .sp \fBnutdrv_siemens_sitop\fR \-h .sp \fBnutdrv_siemens_sitop\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBnutdrv_siemens_sitop\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp \fBnutdrv_siemens_sitop\fR supports Siemens UPS models from the SITOP UPS500 series\&. Some models have a serial port, others have a USB port\&. The models with USB port actually contain a serial\-over\-USB chip, so as far as this driver is concerned, all models are serial models\&. This driver should work with all models in the SITOP UPS500 series, as long as your kernel has support for the serial port device (see section \fBUSB driver\fR below)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This driver has only been tested with the SITOP UPS500S\-2\&.5 with USB port (Siemens product number 6EP1933\-2EC41)\&. .sp .5v .RE .SH "DEVICE SETTINGS" .sp The UPS is configured via DIP\-switches\&. For correct functioning in combination with NUT, set the DIP\-switches to the following: .PP \fBswitch 1\-4\fR .RS 4 Choose whatever suits your situation\&. Any combination will work with NUT\&. .RE .PP \fBswitch 5\fR (⇒ / t) .RS 4 Set to OFF (t)\&. This ensures that the UPS will not cut power unless NUT tells it to do so (or unless the batteries are exhausted)\&. .RE .PP \fBswitch 6\-10\fR (delay) .RS 4 Set to OFF (minimum delay)\&. Setting a higher delay will actually also work, but any command from NUT will be delayed as well before being executed by the UPS\&. With the minimum setting, it will already take 5 seconds before a command from NUT is executed\&. .RE .PP \fBswitch 11\fR (INTERR\&.) .RS 4 Set to ON (interrupt the output after the timer expires)\&. This ensures that the UPS briefly interrupts the output power in response to the shutdown\&.return command\&. See the section \fBInstant Commands\fR below\&. .RE .PP \fBswitch 12\fR (ON/OFF) .RS 4 set to ON (enable the UPS functionality)\&. Without this, the UPS will never supply power from its batteries\&. .RE .SH "USB DRIVER" .sp The USB\-versions of the UPS contain an FTDI USB\-to\-serial converter chip\&. It is programmed with a non\-standard product ID (for example \fI0403:e0e3\fR), but can still be used with the normal ftdi_sio driver\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The following hints may be specific to GNU/Linux\&. .sp .5v .RE .sp Use \fBlsusb\fR to figure out which product ID is used in your model, and replace all occurrences of \fIe0e3\fR in the following examples with the actual Product ID\&. .sp .if n \{\ .RS 4 .\} .nf modprobe ftdi_sio echo 0403 e0e3 > /sys/bus/usb\-serial/drivers/ftdi_sio/new_id .fi .if n \{\ .RE .\} .sp If your system uses \fBudev\fR, this can be automated via an \fBudev\fR rule: .sp .if n \{\ .RS 4 .\} .nf ACTION=="add", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="e0e3", \e RUN+="/sbin/modprobe ftdi_sio", \e RUN+="/bin/sh \-c \*(Aqecho 0403 e0e3 > /sys/bus/usb\-serial/drivers/ftdi_sio/new_id\*(Aq" .fi .if n \{\ .RE .\} .sp You can use the following udev rule to obtain a predictable device name, for example /dev/ttyUPS: .sp .if n \{\ .RS 4 .\} .nf SUBSYSTEM=="tty" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="e0e3" SYMLINK+="ttyUPS" .fi .if n \{\ .RE .\} .SH "POLLING" .sp The UPS does not have a special \fIget status\fR command\&. Instead, it continuously sends out status update messages (tens of messages per second)\&. Every \fBpollinterval\fR, these messages are read from the serial port buffer\&. .sp In order to react quickly on status changes from the UPS, and to prevent the serial buffer from overflowing, \fBpollinterval\fR should be set to a relatively low value\&. The recommended value is 1 (second)\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings: .PP \fBmax_polls_without_data\fR=\fInum\fR .RS 4 The serial port is polled periodically for new data (see \fBPolling\fR)\&. If there is no valid new data after \fInum\fR polls, it is assumed that communication with the UPS is lost\&. .sp The default value is \fI2\fR\&. Lower values may cause spurious \fIData stale\fR messages, especially at startup\&. .RE .SH "INSTANT COMMANDS" .PP \fBshutdown\&.return\fR .RS 4 The behavior of this command depends on the line state: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBon line\fR: after 5 seconds (or longer, if DIP switches 6\-10 are not OFF), the UPS will shut off its output\&. After another 5 seconds, the output is activated again\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBon battery\fR: after 5 seconds (or longer, if DIP switches 6\-10 are not OFF), the UPS will shut off its output\&. The output will stay off, until the line voltage has returned\&. .RE .RE .PP \fBshutdown\&.stayoff\fR .RS 4 The behavior of this command depends on the line state: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBon line\fR: after 5 seconds (or longer, if DIP switches 6\-10 are not OFF), the UPS will shut off its output\&. The output stays off, until the line voltage has been removed for at least 1 second, and has been re\-applied\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBon battery\fR: this command behaves the same as \fBshutdown\&.return\fR\&. .RE .RE .SH "INSTALLATION" .sp Make sure that your operating system has created a serial device for the UPS\&. See the section \fBUSB driver\fR for more information\&. .sp Next, make sure that NUT has access rights to this device file\&. For example, by creating an udev rule that grants permission to the NUT user, or by adding the NUT user to a user group that can access serial devices (e\&.g\&. the \fBdialout\fR group on Debian\-based systems)\&. .SH "DIAGNOSTICS" .sp You can verify the correct functioning of the hardware, by monitoring the serial port with a terminal program, for example picocom: .sp .if n \{\ .RS 4 .\} .nf :; picocom \-b 9600 \-d 8 \-p n /dev/ttyUPS .fi .if n \{\ .RE .\} .sp NUT must not be running when you do this\&. You should now see a continuous stream of 5\-character texts coming in, for example: .sp .if n \{\ .RS 4 .\} .nf BUFRD BA>85 DC_OK .fi .if n \{\ .RE .\} .sp To exit picocom, use Ctrl\-A Ctrl\-X\&. .SH "KNOWN ISSUES AND BUGS" .PP \fBUntested models\fR .RS 4 As mentioned under \fBSupported hardware\fR, this driver has not been tested with all models in the SITOP UPS500 series\&. .RE .PP \fBData stale messages\fR .RS 4 The firmware in these UPSes is quite buggy\&. After sending data to the UPS, it sometimes stops sending status updates\&. This driver tries to prevent this (e\&.g\&. by sending commands twice, and by sending additional LF characters after each command)\&. .sp Once the UPS is in this state, communication can only be restored by rebooting the UPS, or by unplugging and reconnecting the USB cable\&. .sp During normal operation, no commands are sent to the UPS at all (only at shutdown), so this issue is expected to have little impact on usability\&. .sp It is not certain if the serial models are affected by this issue as well\&. .RE .SH "AUTHOR" .sp Matthijs H\&. ten Berge .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/powercom.80000644000200500020050000002455315001555074012701 00000000000000'\" t .\" Title: powercom .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "POWERCOM" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" powercom \- UPS driver for serial Powercom/Trust/Advice UPS equipment .SH "SYNOPSIS" .sp \fBpowercom\fR \-h .sp \fBpowercom\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the powercom driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports many similar kinds of serial UPS hardware (as well as a few USB UPS models with USB\-to\-serial adapters)\&. The most common ones are the Trust 425/625, Powercom, and Advice Partner/King PR750\&. Others using the same protocol may also work\&. For USB connections, you might need \fBusbhid-ups\fR(8)\&. .sp For more specific guidance on which driver is applicable for a USB connection, see the NUT Hardware Compatibility List (HCL)\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file: .PP \fBlinevoltage\fR=\fIvalue\fR .RS 4 An integer specifying the line voltage\&. It can\(cqt be auto detected\&. Acceptable values are in the range of 110\-120 or 220\-240\&. The default is \fI230\fR\&. .RE .PP \fBmanufacturer\fR=\fIname\fR .RS 4 Specify the manufacturer name, which also can\(cqt be auto detected\&. This is a user defined string, so any name is acceptable\&. The default is \fIPowerCom\fR\&. .RE .PP \fBmodelname\fR=\fIname\fR .RS 4 Specify the model name, which also can\(cqt be auto detected\&. This is a user defined string, so any name is acceptable\&. The default is \fIUnknown\fR\&. .RE .PP \fBserialnumber\fR=\fIvalue\fR .RS 4 Like modelname above, but for the serial number\&. The default is \fIUnknown\fR\&. .RE .PP \fBtype\fR=\fIname\fR .RS 4 The exact type of the communication protocol within the powercom family, that will be used to communicate with the UPS\&. The type is named after the first modelname that was coded with that protocol\&. The acceptable names are \fITrust\fR, \fIEgys\fR, \fIKP625AP\fR, \fIIMP\fR, \fIKIN\fR, \fIBNT\fR, \fIBNT\-other\fR and \fIOPTI\fR\&. The default is \fITrust\fR\&. .sp \fIBNT\-other\fR is a special type for other BNT models (such as the 1500A at 120V and can be used to override ALL models using ALL of the following values\&. .RE .PP \fBshutdownArguments\fR={{\fIminutes\fR,\fIseconds\fR},\fIwhether_minutes_should_be_used\fR} .RS 4 The minutes and seconds that the UPS should wait between receiving the shutdown command and actually shutting off\&. The other argument should be set to the character \fIn\fR only when the minutes value should be skipped and not sent to the UPS\&. The default is type\-dependent and is given below\&. The braces and commas are mandatory\&. Note that there should be no whitespace characters\&. .RE .PP \fBnumOfBytesFromUPS\fR=\fIvalue\fR .RS 4 The number of bytes in a UPS frame: 16 is common, 11 for \fITrust\fR\&. The default is type\-dependent and is given below\&. .RE .PP \fBmethodOfFlowControl\fR=\fIname\fR .RS 4 The method of serial communication flow control that is engaged by the UPS\&. The default is type\-dependent and is given below\&. Acceptable names are \fIdtr0rts1\fR, \fIdtr1\fR or \fIno_flow_control\fR\&. .RE .PP \fBvalidationSequence\fR={{\fIindex1\fR,\fIvalue1\fR},{\fIindex2\fR,\fIvalue2\fR},{\fIindex3\fR,\fIvalue3\fR}} .RS 4 (Only for types KP625AP, Trust, Egys\&.) 3 pairs to be used for validating the UPS by comparing bytes of the raw data with constant values\&. The index selects the byte from the UPS (see numOfBytesFromUPS) and the value is for matching to the byte\&. The default is type\-dependent and is given below\&. The braces and commas are mandatory, as the lack of white space characters\&. .RE .PP \fBfrequency\fR={\fIA\fR,\fIB\fR} .RS 4 (Only for types KP625AP, Trust, Egys\&.) A pair to convert the raw frequency data to a human\-readable frequency reading using the function 1/(A*x+B)\&. If the raw value x IS the frequency, then set A=1/(x^2) and B=0\&. The default is type\-dependent and is given below\&. Do note that the braces and commas are mandatory as well, as the lack of whitespace characters\&. .RE .PP \fBloadPercentage\fR={\fIBatteryA\fR,\fIBatteryB\fR,\fILineA\fR,\fILineB\fR} .RS 4 (Only for types KP625AP, Trust, Egys\&.) A quad to convert the raw load data to human readable load percentage reading using the function A*x+B\&. If the raw value x IS the Load Percent, then set A=1 and B=0\&. The default is type\-dependent and is given below\&. Do note that the braces and commas are mandatory, as the lack of white space characters\&. .RE .PP \fBbatteryPercentage\fR={\fIBattery1\fR,\fIBattery2\fR,\fIBattery3\fR,\fILine4\fR,\fILine5\fR} .RS 4 (Only for KP625AP, Trust, Egys\&.) A 5 tuple to convert the raw battery and line data to a human\-readable battery and line percentage reading using the functions (Battery) A*x+B*y+C and (Line) D*x+E\&. If the raw value x IS the Battery Percent, then set A=1, B=0, C=0, D=1, E=0\&. The default is type\-dependent and is given below\&. Do note that the braces and commas are mandatory, as the lack of white space characters\&. .RE .PP \fBvoltage\fR={\fI240A\fR,\fI240B\fR,\fI120A\fR,\fI120B\fR} .RS 4 (Only for types KP625AP, Trust, Egys\&.) A quad that is used convert the raw voltage data to a human\-readable voltage reading using the function A*x+B\&. If the raw value x IS HALF the Voltage, then set A=2, B=0\&. The default is type\-dependent and is given below\&. Do note that the braces and commas are mandatory, as well as the lack of whitespace characters\&. .RE .PP \fBnobt\fR .RS 4 If this flag is present, the battery check on startup is skipped\&. This is useful for systems that tend to overload the UPS when testing the battery on system startup \(em just when the power consumption tends to be high\&. .RE .SH "DEFAULT VALUES FOR THE EXTRA ARGUMENTS" .sp .if n \{\ .RS 4 .\} .nf linevoltage = 230 manufacturer = PowerCom modelname = Unknown serialnumber = Unknown type = Trust .fi .if n \{\ .RE .\} .sp The rest of the default values for the extra arguments are type\-dependent\&. However, \fIBNT\-other\fR is a special type that can be used to override ALL values for ALL models\&. .SS "Trust" .sp .if n \{\ .RS 4 .\} .nf numOfBytesFromUPS = 11 methodOfFlowControl = dtr0rts1 validationSequence = {{5,0},{7,0},{8,0}} shutdownArguments = {{0,10},n} frequency = {0\&.00020997,0\&.00020928} loadPercentage = {6\&.1343,\-0\&.3808,4\&.3110,0\&.1811} batteryPercentage = {5\&.0000,0\&.3268,\-825\&.00,4\&.5639,\-835\&.82} voltage = {1\&.9216,\-0\&.0977,0\&.9545,0\&.0000} .fi .if n \{\ .RE .\} .SS "KP625AP" .sp .if n \{\ .RS 4 .\} .nf numOfBytesFromUPS = 16 methodOfFlowControl = dtr0rts1 validationSequence = {{5,0x80},{7,0},{8,0}} shutdownArguments = {{0,10},n} frequency = {0\&.00020997,0\&.00020928} loadPercentage = {6\&.1343,\-0\&.3808,4\&.3110,0\&.1811} batteryPercentage = {5\&.0000,0\&.3268,\-825\&.00,4\&.5639,\-835\&.82} voltage = {1\&.9216,\-0\&.0977,0\&.9545,0\&.0000} .fi .if n \{\ .RE .\} .SS "Egys" .sp .if n \{\ .RS 4 .\} .nf numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{5,0x80},{7,0},{8,0}} shutdownArguments = {{0,10},n} frequency = {0\&.00020997,0\&.00020928} loadPercentage = {6\&.1343,\-0\&.3808,1\&.3333,0\&.6667} batteryPercentage = {5\&.0000,0\&.3268,\-825\&.00,2\&.2105,\-355\&.37} voltage = {1\&.9216,\-0\&.0977,0\&.9545,0\&.0000} .fi .if n \{\ .RE .\} .SS "IMP" .sp .if n \{\ .RS 4 .\} .nf numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{5,0xFF},{7,0},{8,0}} shutdownArguments = {{1,30},y} .fi .if n \{\ .RE .\} .SS "KIN" .sp .if n \{\ .RS 4 .\} .nf numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{11,0x4b},{8,0},{8,0}} shutdownArguments = {{1,30},y} .fi .if n \{\ .RE .\} .SS "BNT" .sp .if n \{\ .RS 4 .\} .nf numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{11,0x42},{8,0},{8,0}} shutdownArguments = {{1,30},y} .fi .if n \{\ .RE .\} .SS "BNT\-other" .sp .if n \{\ .RS 4 .\} .nf numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{8,0},{8,0},{8,0}} shutdownArguments = {{1,30},y} frequency = {0\&.00027778,0\&.0000} loadPercentage = {1\&.0000,0\&.0,1\&.0000,0\&.0} batteryPercentage = {1\&.0000,0\&.0000,0\&.0000,1\&.0000,0\&.0000} voltage = {2\&.0000,0\&.0000,2\&.0000,0\&.0000} .fi .if n \{\ .RE .\} .SS "OPTI" .sp .if n \{\ .RS 4 .\} .nf numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{5,0xFF},{7,0},{8,0}} shutdownArguments = {{1,30},y} .fi .if n \{\ .RE .\} .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Peter Bieringer .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Alexey Sidorov .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Keven L\&. Ates .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Rouben Tchakhmakhtchian .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/oneac.txt0000644000200500020050000000611715001555412012573 00000000000000ONEAC(8) ======== NAME ---- oneac - Driver for Oneac UPS equipment SYNOPSIS -------- *oneac* -h *oneac* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the oneac driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports various Oneac UPS families: - EG (late 80s, early 90s, plug-in serial interface card) - ON (early and mid-90s, plug-in serial interface card) - OZ (mid-90s on, DB-25 std., interface slot) - OB (early 2000's on, big cabinet, DB-25 std., interface slot) If your UPS is equipped with the Basic Interface card, use the linkman:genericups[8] driver. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file: *testtime*='num':: Change battery test time from the 2 minute default. *offdelay*='num':: Change shutdown delay time from 0 second default. INSTANT COMMANDS ---------------- This driver supports the following Instant Commands. (See linkman:upscmd[8]) All UPS units ~~~~~~~~~~~~~ *shutdown.return*:: Turn off the load possibly after a delay and return when power is back. *shutdown.stop*:: Stop a shutdown in progress. *shutdown.reboot*:: Shut down the load briefly while rebooting the UPS. *test.failure.start*:: Starts a 15 second long simulation of an input power failure. *test.battery.start.quick*:: Start a "quick" battery test. The default time is 2 minutes. This time can be set in the *ups.conf* file. See *testime* above. *test.battery.stop*:: Stops a battery test that is in progress. All ON UPS units ~~~~~~~~~~~~~~~~ *reset.input.minmax*:: Reset the minimum and maximum input line voltage values seen since the last reset or power on. Newer ON UPS units ~~~~~~~~~~~~~~~~~~ *test.panel.start*:: Start testing the UPS panel. *test.battery.start.deep*:: Start a "deep" battery test. This test runs the UPS until the low battery point and then returns to the AC line. *reset.input.minmax*:: Reset the minimum and maximum input line voltage values seen since the last reset or power on. *beeper.enable*:: Enable UPS beeper/buzzer. *beeper.disable*:: Disable UPS beeper/buzzer. *beeper.mute*:: Mutes the UPS beeper/buzzer for the current alarm condition(s). Writable Variables ------------------ See linkman:upsrw[8] to see what variables are writable for the UPS. NOTE: If your UPS supports writing `battery.runtime.low`, the new set value is to be entered in minutes (up to '99') but the reported value is reported in seconds (set 'value * 60'). NOTE: If your UPS supports `input.transfer.low` and `input.transfer.high`, those values are used to create an allowable output range. The UPS will do what it can to keep the output voltage value within the defined range (for example: tap change or switch to inverter). AUTHORS ------- * Bill Elliot * Eric Lawson SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_splitaddr.txt0000644000200500020050000000217215001555412015050 00000000000000UPSCLI_SPLITADDR(3) =================== NAME ---- upscli_splitaddr - Split a listening address into its components SYNOPSIS -------- ------ #include int upscli_splitaddr(const char *buf, char **hostname, int *port) ------ DESCRIPTION ----------- The *upscli_splitaddr()* function takes a pointer to the listening address definition 'buf' and returns the pointer to dynamically allocated memory in 'hostname'. It also copies the port number into 'port'. FORMATTING ---------- A listening address definition is specified according to this format: [:] Definitions without an explicit port value receive the default value of '3493'. MEMORY USAGE ------------ You must linkmanext:free[3] the pointer 'hostname' when you are done with it to avoid memory leaks. RETURN VALUE ------------ The *upscli_splitaddr()* function returns '0' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_fd[3], linkman:upscli_get[3], linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_splitname[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/nutclient_get_device_rw_variables.30000644000200500020050000000004215001555117017745 00000000000000.so man3/libnutclient_variables.3 nut-2.8.3/docs/man/blazer_usb.80000644000200500020050000004521015001555077013172 00000000000000'\" t .\" Title: blazer_usb .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BLAZER_USB" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" blazer_usb \- Driver for Megatec/Q1 protocol USB based UPS equipment .SH "SYNOPSIS" .sp \fBblazer_usb\fR \-h .sp \fBblazer_usb\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .SH "NOTE" .sp This man page only documents the hardware\-specific features of the blazer driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .SH "NOTE" .sp Please note that this driver is deprecated and will not receive new development\&. If it works for managing your devices \(em fine, but if you are running it to try setting up a new device, please consider the newer \fBnutdrv_qx\fR(8) instead, which should handle all \fIQ*\fR protocol variants for NUT\&. .sp Please do also report if your device works with this driver, but \fBnutdrv_qx\fR(8) would not actually support it with any subdriver! .SH "SUPPORTED HARDWARE" .sp The blazer driver is known to work with various UPSes from Blazer, Energy Sistem, Fenton Technologies, General Electric, Mustek and many others\&. The NUT compatibility table lists all the known supported models\&. Keep in mind, however, that other models not listed there may also be supported, but haven\(cqt been tested\&. .sp All devices with a serial interface (use the \fBblazer_ser\fR driver) and many with a USB interface (use the \fBblazer_usb\fR driver) are supported\&. .SH "EXTRA ARGUMENTS" .sp You may need to override or provide defaults for some values, depending on the make and model of your UPS\&. The following are the ones that most likely will need changing (see \fBups.conf\fR(5)): .PP \fBdefault\&.battery\&.voltage\&.high =\fR \fIvalue\fR .RS 4 Maximum battery voltage that is reached after about 12 to 24 hours charging\&. If you want the driver to report a guesstimated \fBbattery\&.charge\fR, you need to specify this (see BATTERY CHARGE GUESSTIMATION)\&. .RE .PP \fBdefault\&.battery\&.voltage\&.low =\fR \fIvalue\fR .RS 4 Minimum battery voltage just before the UPS automatically shuts down\&. If you want the driver to report a guesstimated \fBbattery\&.charge\fR, you need to specify this (see BATTERY CHARGE GUESSTIMATION)\&. .RE .PP \fBdefault\&.battery\&.voltage\&.nominal =\fR \fIvalue\fR, \fBoverride\&.battery\&.voltage\&.nominal =\fR \fIvalue\fR .RS 4 Some devices show a wrong nominal battery voltage (or none at all), so you may need to override or set a default value\&. .RE .PP \fBoverride\&.battery\&.packs =\fR \fIvalue\fR .RS 4 Some devices report a part of the total battery voltage\&. For instance, if \fBbattery\&.voltage\&.nominal\fR is 24 V, but it reports a \fBbattery\&.voltage\fR of around 2 V, the number of \fBbattery\&.packs\fR to correct this reading would be 12\&. The driver will attempt to detect this automatically, but if this fails somehow, you may want to override this value\&. .RE .PP \fBondelay =\fR \fIvalue\fR .RS 4 Time to wait before switching on the UPS (minutes)\&. Note that a value below 3 minutes, may cause earlier firmware versions to not switch on automatically, so it defaults to 3 minutes\&. The acceptable range is 0\&.\&.9999 minutes\&. .RE .PP \fBoffdelay =\fR \fIvalue\fR .RS 4 Time to wait before shutting down the UPS (seconds)\&. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds)\&. Defaults to 30 seconds\&. The acceptable range is 12\&.\&.600 seconds\&. .RE .PP \fBnorating\fR .RS 4 Some UPSes will lock up if you attempt to read rating information from them\&. Setting this flag will make the driver skip this step\&. .RE .PP \fBnovendor\fR .RS 4 Some UPSes will lock up if you attempt to read vendor information from them\&. Setting this flag will make the driver skip this step\&. .RE .PP \fBprotocol =\fR \fIstring\fR .RS 4 Skip autodetection of the protocol to use and only use the one specified\&. Supported values are \fImegatec\fR, \fImegatec/old\fR, \fImustek\fR and \fIzinto\fR\&. .RE .PP \fBruntimecal =\fR \fIvalue,value,value,value\fR .RS 4 Parameter used in the (optional) runtime estimation\&. This takes two runtimes at different loads\&. Typically, this uses the runtime at full load and the runtime at half load\&. For instance, if your UPS has a rated runtime of 240 seconds at full load and 720 seconds at half load, you would enter .sp .if n \{\ .RS 4 .\} .nf runtimecal = 240,100,720,50 .fi .if n \{\ .RE .\} .sp The first load should always be higher than the second\&. If you have values available for loads other than 100 and 50 % respectively, you can use those too, but keep them spaced apart as far as reasonably possible\&. Just don\(cqt get too close to no load (prediction of runtime depends more on idle load for the battery then)\&. .RE .PP \fBchargetime =\fR \fIvalue\fR .RS 4 The time needed to fully recharge the battery after being fully discharged\&. If not specified, the driver defaults to 43200 seconds (12 hours)\&. Only used if \fBruntimecal\fR is also specified\&. .RE .PP \fBidleload =\fR \fIvalue\fR .RS 4 Minimum battery load used by the driver to estimate the runtime\&. If not specified, the driver defaults to 10%\&. Only used if \fBruntimecal\fR is also specified\&. .RE .SS "USB INTERFACE ONLY" .PP \fBport =\fR \fIstring\fR .RS 4 Some \fIvalue\fR must be set, typically \fBauto\fR\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This could be a device filesystem path like /dev/usb/hiddev0 but current use of libusb API precludes knowing and matching by such identifiers\&. They may also be inherently unreliable (dependent on re\-plugging and enumeration order)\&. At this time the actual \fIvalue\fR is ignored, but syntactically some \fIport\fR configuration must still be there\&. .sp .5v .RE .RE .sp It is possible to control multiple UPS units simultaneously by running several instances of this driver, provided they can be uniquely distinguished by setting some combination of the \fBvendor\fR, \fBproduct\fR, \fBvendorid\fR, \fBproductid\fR, \fBserial\fR, \fBbus\fR and/or \fBdevice\fR options detailed below\&. For devices or operating systems that do not provide sufficient information, the \fBallow_duplicates\fR option can be of use (limited and risky!) .PP \fBvendorid =\fR \fIregex\fR, \fBproductid =\fR \fIregex\fR, \fBvendor =\fR \fIregex\fR, \fBproduct =\fR \fIregex\fR, \fBserial =\fR \fIregex\fR .RS 4 Select a specific UPS, in case there is more than one connected via USB\&. Each option specifies an extended regular expression (see \fBregex\fR(7) for more information on regular expressions), which must match the UPS\(cqs entire respective vendor/product/serial string values (minus any surrounding whitespace), or the whole 4\-digit hexadecimal code for vendorid and productid\&. .sp Try \fBlsusb\fR(8) or running this NUT driver with \-DD command\-line argument for finding out the strings to match\&. .sp Examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendor="Foo\&.Corporation\&.*" .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendorid="051d*" (APC) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x product="\&.*(Smart|Back)\-?UPS\&.*" .RE .RE .PP \fBbus =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB bus or group of buses\&. The argument is a regular expression that must match the bus name where the UPS is connected (e\&.g\&. bus="002" or bus="00[2\-3]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .RE .PP \fBdevice =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB device or group of devices\&. The argument is a regular expression that must match the device name where the UPS is connected (e\&.g\&. device="001" or device="00[1\-2]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br device numbers are not guaranteed by the OS to be stable across re\-boots or device re\-plugging\&. .sp .5v .RE .RE .PP \fBbusport =\fR \fIregex\fR .RS 4 If supported by the hardware, OS and libusb on the particular deployment, this option should allow to specify physical port numbers on an USB hub, rather than logical device enumeration values, and in turn \(em this should be less volatile across reboots or re\-plugging\&. The value may be seen in the USB topology output of lsusb \-tv on systems with that tool, for example\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br this option is not practically supported by some NUT builds (it should be ignored with a warning then), and not by all systems that NUT can run on\&. .sp .5v .RE .RE .PP \fBallow_duplicates\fR .RS 4 If you have several UPS devices which may not be uniquely identified by the options above (e\&.g\&. only \fIVID:PID\fR can be discovered there), this flag allows each driver instance where it is set to take the first match if available, or proceed to try another\&. .sp Normally the driver initialization would abort at this point claiming "Resource busy" or similar error, assuming that the otherwise properly matched device is unique \(em and some other process already handles it\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This feature is inherently non\-deterministic! The association of driver instance name to actual device may vary between runs! .sp If you only care to know that \fBat least\fR one of your no\-name UPSes is online, this option can help\&. .sp If you must really know \fBwhich\fR one, it will not! .sp .5v .RE .RE .PP \fBusb_set_altinterface =\fR \fIbAlternateSetting\fR .RS 4 Force redundant call to usb_set_altinterface(), especially if needed for devices serving multiple USB roles where the UPS is not represented by the interface number 0 (default)\&. .RE .PP \fBusb_config_index\fR, \fBusb_hid_rep_index\fR, \fBusb_hid_desc_index\fR, \fBusb_hid_ep_in\fR, \fBusb_hid_ep_out\fR .RS 4 Force use of specific interface, endpoint, descriptor index etc\&. numbers, rather than defaulting to \fI0\fR (rarely other values in certain drivers for some devices known to use non\-zero numbers)\&. Specified as a hexadecimal number\&. .sp As a rule of thumb for usb_hid_desc_index discovery, you can see larger wDescriptorLength values (roughly 600+ bytes) in reports of lsusb or similar tools\&. .RE .PP \fBLIBUSB_DEBUG =\fR \fIINTEGER\fR .RS 4 Run\-time troubleshooting of USB\-capable NUT drivers can involve not only raising the common NUT debug verbosity (e\&.g\&. using the DEBUG_MIN setting in \fBups.conf\fR(5) or protocol commands to change the driver\&.debug value), but may also benefit from LibUSB specific debugging\&. .sp For the latter, you can set the LIBUSB_DEBUG driver option; alternatively you can classically export the environment variable LIBUSB_DEBUG before starting a NUT driver program (may be set and "exported" in driver init script or service method, perhaps via \fBnut.conf\fR(5)), to a numeric value such as 4 ("All messages are emitted")\&. .sp For more details, including the currently supported values for your version of the library, see e\&.g\&.: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/group__libusb__lib\&.html .RE .RE .PP \fBsubdriver =\fR \fIstring\fR .RS 4 Select a serial\-over\-USB subdriver to use\&. You have a choice between \fBphoenix\fR, \fBippon\fR, \fBcypress\fR, and \fBkrauler\fR\&. When using this option, it is mandatory to also specify the \fBvendorid\fR and \fBproductid\fR\&. .RE .PP \fBlangid_fix =\fR \fIvalue\fR .RS 4 Apply the language ID workaround to the krauler subdriver\&. This is mandatory for some devices to work (LDLC, Dynamix and others)\&. You must to provide \fBvalue\fR (0x409 or 0x4095), according to your device entry in NUT hardware compatibility list (HCL)\&. .RE .SH "UPS COMMANDS" .sp This driver supports some instant commands (see \fBupscmd\fR(8)): .PP \fBbeeper\&.toggle\fR .RS 4 Toggle the UPS beeper\&. (Not available on some hardware\&.) .RE .PP \fBload\&.on\fR .RS 4 Turn on the load immediately\&. .RE .PP \fBload\&.off\fR .RS 4 Turn off the load immediately (see KNOWN PROBLEMS)\&. .RE .PP \fBshutdown\&.return\fR .RS 4 Turn off the load and return when power is back\&. Uses the timers defined by \fBondelay\fR and \fBoffdelay\fR\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Turn off the load and remain off (see KNOWN PROBLEMS)\&. Uses the timer defined by \fBoffdelay\fR\&. .RE .PP \fBshutdown\&.stop\fR .RS 4 Stop a shutdown in progress\&. .RE .PP \fBtest\&.battery\&.start\&.deep\fR .RS 4 Perform a long battery test (Not available on some hardware\&.) .RE .PP \fBtest\&.battery\&.start\&.quick\fR .RS 4 Perform a (10 second) battery test\&. .RE .PP \fBtest\&.battery\&.start\fR \fIvalue\fR .RS 4 Perform a battery test for the duration of \fIvalue\fR minutes\&. .RE .PP \fBtest\&.battery\&.stop\fR .RS 4 Stop a running battery test (not available on some hardware\&.) .RE .SH "BATTERY CHARGE GUESSTIMATION" .sp Due to popular demand, this driver will report a guesstimated \fBbattery\&.charge\fR value and optionally \fBbattery\&.runtime\fR, provided you specified a couple of the EXTRA ARGUMENTS listed above\&. .sp If you specify both \fBbattery\&.voltage\&.high\fR and \fBbattery\&.voltage\&.low\fR in \fBups.conf\fR(5), but don\(cqt enter \fBruntimecal\fR, it will guesstimate the state of charge by looking at the battery voltage alone\&. This is not reliable under load, as this only gives reasonably accurate readings if you disconnect the load, let the battery rest for a couple of minutes and then measure the open cell voltage\&. This just isn\(cqt practical if the power went out and the UPS is providing power for your systems\&. .sp .if n \{\ .RS 4 .\} .nf battery\&.voltage \- battery\&.voltage\&.low battery\&.charge = \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- x 100 % battery\&.voltage\&.high \- battery\&.voltage\&.low .fi .if n \{\ .RE .\} .sp There is a way to get better readings without disconnecting the load, but this requires one to keep track on how much (and how fast) current is going in\- and out of the battery\&. If you specified the \fBruntimecal\fR, the driver will attempt to do this\&. Note however, that this heavily relies on the values you enter and that the UPS must be able to report the load as well\&. There are quite a couple of devices that report 0% (or any other fixed value) at all times, in which case this obviously doesn\(cqt work\&. .sp The driver also has no way of determining the degradation of the battery capacity over time, so you\(cqll have to deal with this yourself (by adjusting the values in \fBruntimecal\fR)\&. Also note that the driver guesses the initial state of charge based on the battery voltage, so this may be less than 100%, even when you are certain that they are full\&. There is just no way to reliably measure this between 0 and 100% full charge\&. .sp This is better than nothing (but not by much)\&. If any of the above calculations are giving you incorrect readings, remember that you are the one who put in the values in \fBups.conf\fR(5), so don\(cqt complain to the author\&. If you need something better, consider buy an UPS that reports \fBbattery\&.charge\fR and \fBbattery\&.runtime\fR all by itself without the help of a NUT driver\&. .SH "NOTES FOR THE PREVIOUS USER OF MEGATEC DRIVERS" .sp The blazer drivers having replaced the megatec ones, some configuration changes may be required by users switching to blazer\&. .sp Part of this, the following megatec options, in ups\&.conf, have to be changed: .PP \fBbattvolts\fR .RS 4 You need to use \fIdefault\&.battery\&.voltage\&.high\fR and \fIdefault\&.battery\&.voltage\&.low\fR .RE .PP \fBdtr and rts\fR .RS 4 You need to use \fIcablepower\fR .RE .PP \fBignoreoff\fR .RS 4 This parameter can simply be discarded, since it was a wrong understanding of the specification\&. .RE .SH "KNOWN PROBLEMS" .sp Some UPS commands aren\(cqt supported by all models\&. In most cases, the driver will send a message to the system log when the user tries to execute an unsupported command\&. Unfortunately, some models don\(cqt even provide a way for the driver to check for this, so the unsupported commands will silently fail\&. .sp Both the \fBload\&.off\fR and \fBshutdown\&.stayoff\fR instant commands are meant to turn the load off indefinitely\&. However, some UPS models don\(cqt allow this\&. .sp Some models report a bogus value for the beeper status (will always be \fIenabled\fR or \fIdisabled\fR)\&. So, the \fBbeeper\&.toggle\fR command may appear to have no effect in the status reported by the driver when, in fact, it is working fine\&. .sp The temperature and load value is known to be bogus in some models\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arjen de Korte .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Alexander Gordeev .RE .SH "SEE ALSO" .sp \fBblazer_ser\fR(8), \fBnutupsdrv\fR(8), \fBupsc\fR(8), \fBupscmd\fR(8), \fBupsrw\fR(8) .SS "Internet Resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT HCL: https://www\&.networkupstools\&.org/stable\-hcl\&.html .RE nut-2.8.3/docs/man/mge-shut.txt0000644000200500020050000000531615001555412013237 00000000000000MGE-SHUT(8) =========== NAME ---- mge-shut - Driver for SHUT Protocol UPS equipment SYNOPSIS -------- *mge-shut* -h *mge-shut* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the mge-shut driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ mge-shut supports all recent Eaton, MGE and Dell UPS models which use the SHUT (Serial HID UPS Transfer) protocol. Older MGE models, such as Pulsar ESV+, Pulsar EX and Pulsar ES+, use the U-Talk protocol and should use the mge-utalk driver. EXTRA ARGUMENTS --------------- This driver also supports the following optional settings: *lowbatt*='num':: Set the low battery warning threshold at which shutdown is initiated by linkman:upsmon[8]. + The factory default value is 30 (in percent), and can be settable depending on the exact model. *offdelay*='num':: Set the timer before the UPS is turned off after the kill power command is sent (via the `-k` switch). + The default value is 20 (in seconds). Usually this *must be lower* than 'ondelay', but the driver will *not* warn you upon startup if it isn't. *ondelay*='num':: Set the timer for the UPS to switch on in case the power returns after the kill power command had been sent but before the actual switch off. This ensures the machines connected to the UPS are, in all cases, rebooted after a power failure. + The default value is 30 (in seconds). Usually this *must be greater* than offdelay, but the driver will *not* warn you upon startup if it isn't. Some UPSes will restart no matter what, even if the power is (still) out at the moment this timer elapses. In that case, you could try if setting 'ondelay = -1' in *ups.conf* helps. + WARNING: ondelay parameter was set in ten seconds unit in the legacy mge-shut driver ( 3 for 30 seconds) . It is now set in seconds ( 30 for 30 seconds). Make sure you use the correct unit in your configuration. *notification*='num':: Set notification type to '1' (no), '2' (light) or '3' (yes). + This argument is ignored. It is only here for backward compatibility. KNOWN ISSUES ------------ Repetitive timeout and staleness ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some models tend to be unresponsive with the default polling frequency. The result is that you have some "data stale" errors in your system log. In this case, simply modify the general parameter `pollinterval` to a higher value (like '10' for 10 seconds). This should solve the issue. Using 'notification=3' might also help. AUTHOR ------ Arnaud Quette SEE ALSO -------- The core driver ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscode2.80000644000200500020050000001207715001555076012572 00000000000000'\" t .\" Title: upscode2 .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCODE2" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscode2 \- Driver for UPScode II compatible UPS equipment .SH "SYNOPSIS" .sp \fBupscode2\fR \-h .sp \fBupscode2\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the upscode2 driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports UPS equipment which can be controlled via the UPScode II protocol\&. This is mainly Fiskars, Powerware equipment, but also some (probably OEM\(cqed) products from Compaq\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBmanufacturer\fR=\fIvalue\fR .RS 4 Autodetection of this parameter is not possible yet (and it probably never will be)\&. Therefore, this user\-defined string accepts any name\&. The default is \fIunknown\fR\&. .RE .PP \fBinput_timeout\fR=\fIvalue\fR .RS 4 The timeout waiting for a response from the UPS\&. Some UPS models have shown to be rather slow, resulting in frequent messages about empty responses from the UPS\&. If you see this, try increasing this value\&. .RE .PP \fBoutput_pace\fR=\fIvalue\fR .RS 4 Delay between characters sent to the UPS\&. This was added for completeness with the above parameter\&. It has not shown to be needed yet\&. .RE .PP \fBbaudrate\fR=\fIvalue\fR .RS 4 The default baudrate is 1200, which is the standard for the UPScode II protocol\&. .RE .PP \fBfull_update_timer\fR=\fIvalue\fR .RS 4 Number of seconds between collection of normative values\&. .RE .PP \fBuse_crlf\fR .RS 4 Flag to set if commands towards to UPS need to be terminated with CR\-LF, and not just CR\&. .RE .PP \fBuse_pre_lf\fR .RS 4 Flag to set if commands towards to UPS need to be introduced with an LF\&. A Compaq T1500h is known to need this\&. .RE .SH "COMMANDS" .sp The driver supports the following commands for those UPSes that support them\&. The available commands are autodetected during initialization, so you should check availability with \fIupscmd \-l\fR\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} test\&.panel\&.start \- Start UPS self test .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} test\&.battery\&.start \- Start battery self test .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} beeper\&.enable \- Enable UPS beeper .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} beeper\&.disable \- Disable UPS beeper .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} shutdown\&.return \- Shut down in 1 second and wait for power to return .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} shutdown\&.stayoff \- Shut down in 1 seconds .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} shutdown\&.reboot \- Shut down in 1 seconds and reboot after 1 minute .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} shutdown\&.reboot\&.graceful \- Shut down in 20 seconds and reboot after 1 minute .RE .SH "NOTES" .sp The Powerware UPS models that this driver has been tested against until now have not returned a value for \fIbattery\&.charge\fR\&. Therefore, the driver will guesstimate a value based on the nominal battery min/max and the current battery voltage\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Håvard Lygre .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Niels Baggesen .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/macosx-ups.80000644000200500020050000001024715001555100013126 00000000000000'\" t .\" Title: macosx-ups .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "MACOSX\-UPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" macosx-ups \- Monitor for Mac OS X built\-in UPS and battery driver .SH "SYNOPSIS" .sp \fBmacosx\-ups\fR \-h .sp \fBmacosx\-ups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBmacosx\-ups\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp \fBmacosx\-ups\fR supports any USB HID Power Device Class (PDC) UPS which is matched by the Mac OS X built\-in drivers\&. It also can monitor a laptop internal battery as though it were an UPS\&. .sp If the UPS is visible in the Energy Saver preferences pane of System Preferences, this driver should be able to monitor it\&. .SH "EXTRA ARGUMENTS" .PP \fBport\fR=auto .RS 4 Due to changes in the way that Mac OS X lists power sources, the \fBport\fR parameter no longer has any effect\&. The rest of NUT still requires a value here, and our traditional "don\(cqt care" value is auto\&. .RE .PP \fBmodel\fR=\fIregex\fR .RS 4 Likewise, if you have more than one UPS, it may be necessary to specify a \fBmodel\fR name to match against\&. This parameter is also a case\-insensitive extended regular expression\&. .RE .SH "DIAGNOSTICS" .sp If the driver cannot find an UPS, first open System Preferences and see if there is an "UPS" tab on the Energy Saver panel\&. If so, re\-run the driver with the \-D flag to list the names of the power sources found\&. .SH "KNOWN ISSUES AND BUGS" .sp This driver is a monitoring\-only driver, and cannot shut down an UPS on its own\&. However, this should not be a problem in practice: it is monitoring the built\-in Mac OS X UPS driver, which has configuration options for several shutdown scenarios\&. Consult the Energy Saver control panel or \fBpmset\fR(8) for more information\&. .sp The default distribution of \fBapcupsd\fR installs a kernel extension which prevents Mac OS X from attaching to the UPS\&. In order to use this driver after installing apcupsd, you must first run the apcupsd\-uninstall script and reboot\&. .sp Note that other UPS monitoring solutions may show more detail than what is provided by the built\-in Mac OS X driver\&. In particular, voltages other than the battery voltage, as well as current and frequency, are typically not shown\&. It may be possible to monitor these values with \fBapcupsd\fR (for APC hardware only) or \fBusbhid-ups\fR(8)\&. .SH "AUTHOR" .sp Charles Lepple .SH "SEE ALSO" .sp \fBusbhid-ups\fR(8), \fBpmset\fR(8), \fBregex\fR(3) .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The apcupsd home page: http://www\&.apcupsd\&.org/ .RE nut-2.8.3/docs/man/upscli_readline.30000644000200500020050000000534115001555053014172 00000000000000'\" t .\" Title: upscli_readline .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_READLINE" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_readline, upscli_readline_timeout \- Read a single response from a UPS .SH "SYNOPSIS" .sp .nf #include #include /* or on some platforms */ int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen); int upscli_readline_timeout(UPSCONN_t *ups, char *buf, size_t buflen, const time_t timeout); .fi .SH "DESCRIPTION" .sp The \fBupscli_readline()\fR and \fBupscli_readline_timeout()\fR functions take the pointer \fIups\fR to a UPSCONN_t state structure, receive a single line from the server, and copy up to \fIbuflen\fR bytes of the response into the buffer \fIbuf\fR\&. .sp Some parsing of the string occurs during reception\&. In particular, ERR messages from \fBupsd\fR(8) are detected and will cause this function to return \fI\-1\fR\&. .sp The difference between the two functions is that \fBupscli_readline_timeout()\fR lets the caller decide the amount of time (\fItimeout\fR seconds) after which it should give up and return, whereas \fBupscli_readline()\fR does not offer this freedom, and uses NUT default network timeout (5 seconds)\&. .SH "RETURN VALUE" .sp The \fBupscli_readline()\fR and \fBupscli_readline_timeout()\fR functions return \fI0\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_fd\fR(3), \fBupscli_get\fR(3), \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/nutclient_get_device_command_description.30000644000200500020050000000004115001555117021305 00000000000000.so man3/libnutclient_commands.3 nut-2.8.3/docs/man/liebert.txt0000644000200500020050000000243415001555412013132 00000000000000LIEBERT(8) ========== NAME ---- liebert - Driver for Liebert contact-closure UPS equipment SYNOPSIS -------- *liebert* -h *liebert* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the liebert driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports some Liebert UPS equipment with a contact-closure interface. This includes the UPStation GXT2 with their contact-closure cable. The smart mode ("Multilink") cable is NOT supported by this driver. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. BUGS ---- This driver does not yet support shutdowns by raising DTR. Be aware that shutdowns are not possible with the stock contact-closure cable. You may have to build another cable with DTR connected through to the UPS for it to work. There is no way for this driver to detect the hardware or cable. It will start up successfully even if no UPS is present. This is a fundamental limitation of any contact-closure driver. SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nut.conf.txt0000644000200500020050000002056315001555412013241 00000000000000NUT.CONF(5) =========== NAME ---- nut.conf - UPS definitions for Network UPS Tools DESCRIPTION ----------- This file attempts to standardize the various files being found in different installations, like `/etc/default/nut` on Debian based systems and `/etc/sysconfig/ups` on RedHat based systems. Distribution's init script should source this file in order to determine which components have to be started. Blank lines are ignored. Lines with a hash (`#`) character at the first position of the line are ignored, too. They can be used to add comments. IMPORTANT NOTES --------------- * This file is intended to be sourced by shell scripts as well as by service management frameworks like systemd on Linux: - There is no guaranteed `export VAR=VAL` syntax - No guaranteed expansion of variables like `VAR1="$VAR2-something"` -- only verbatim assignments - You may need to `export VAR` when sourcing it into init-scripts or other scripts, for eventual propagation of certain settings to NUT programs. Not-exported variables can only be consumed by the script which "sourced" the file (and may choose to `export` them independently). * You MUST NOT use spaces around the equal sign! * Practical support for this file and its settings currently varies between different OS packages and NUT sample scripts, but should converge over time. * Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message). Refer to the EXAMPLE section for illustrations. DIRECTIVES ---------- *MODE*:: Required. Recognized values are 'none', 'standalone', 'netserver' and 'netclient'. Defaults to 'none'. none;; Indicates that NUT should not get started automatically, possibly because it is not configured or that an Integrated Power Management or some external system, is used to startup the NUT components. standalone;; Addresses a local only configuration, with 1 UPS protecting the local system. This implies to start the 3 NUT layers (driver, upsd and upsmon), with the related configuration files. This mode can also address UPS redundancy. netserver;; Like the standalone configuration, but also possibly need one or more specific LISTEN directive(s) in upsd.conf. Since this MODE is open to the network, a special care should be applied to security concerns. netclient;; When only upsmon is required, possibly because there are other hosts that are more closely attached to the UPS, the MODE should be set to netclient. *ALLOW_NO_DEVICE*:: Optional, defaults to `false`. Set this to `true` to allow starting the `upsd` NUT data server service even if `ups.conf` has no device sections configured at the moment. This environment variable overrides the built-in "false" flag value in the `upsd` program, and an optional same-named default flag that can be set in `upsd.conf`. + If you want a data server always running and responding on the network, even if it initially has nothing to serve (may be live-reloaded later, when devices become configured), this option is for you. *ALLOW_NOT_ALL_LISTENERS*:: Optional, defaults to `false`. Set this to `true` to allow starting the `upsd` NUT data server even if not all `LISTEN` directives can be honoured at the moment. This environment variable overrides the built-in "false" flag in the `upsd` program, and an optional same-named default flag that can be set in `upsd.conf`. + If you want a data server always running, even if it would potentially not serve all clients on every uptime, this option is for you (note you would have to restart `upsd` to pick up the `LISTEN`ed IP address if it appears later). + Probably configuring `LISTEN *` is a better choice in such cases. *UPSD_OPTIONS*:: Optional. Set upsd specific options. See linkman:upsd[8] for more details. It is ignored when 'MODE' above indicates that no upsd should be running. *UPSMON_OPTIONS*:: Optional. Set upsmon specific options. See linkman:upsmon[8] for more details. It is ignored when 'MODE' above indicates that no `upsmon` should be running. *POWEROFF_WAIT*:: Optional. At the end of an emergency system halt, the upsmon primary will signal the UPS to switch off. This may fail for a number of reasons. Most notably is the case that mains power returns during the shutdown process. See the section "Power races" in `/usr/share/doc/nut/FAQ.txt.gz`. The system will wait this long for the UPS to cut power, and then reboot. It should be long enough to exhaust the batteries, in case line power continues to be unavailable. On the other hand, it should not be so long that the system remains offline for an unreasonable amount of time if line power has returned. See linkmanext:sleep[1] for compatible time syntax. If you specify the time in seconds, use the "s" suffix. + WARNING: This workaround might be dangerous under some circumstances. Please read http://bugs.debian.org/358696 for more details. *POWEROFF_QUIET*:: Optional, defaults to `false`. This setting controls if the NUT shutdown integration scripts or service units would emit messages about their activity (or lack thereof). By default they may be verbose, to aid in post-mortem troubleshooting via logs or console captures. Set to `true` to avoid that trove of information, if you consider it noise. *NUT_DEBUG_LEVEL*:: Optional, defaults to `0`. This setting controls the default debugging message verbosity passed to NUT daemons. As an environment variable, its priority sits between that of 'DEBUG_MIN' setting of a driver and the command-line options. *NUT_DEBUG_PID*:: Optionally add current process ID to tags with debug-level identifiers. This may be useful when many NUT daemons write to the same console or log file, such as in containers/plugins for Home Assistant, storage appliances... *NUT_DEBUG_SYSLOG*:: Optional, unset by default. Normally NUT can (attempt to) use the syslog or Event Log (WIN32), but the environment variable 'NUT_DEBUG_SYSLOG' allows to bypass it, and perhaps keep the daemons logging to stderr (useful e.g. in NUT Integration Test suite to not pollute the OS logs, or in systemd where stderr and syslog both go into the same journal). Recognized values: + [options="header",cols="1,3a"] |=========================================================================== | Value | Description | `stderr` | Disabled and `background()` keeps `stderr` attached | `none` | Disabled and `background()` detaches `stderr` as usual | `default` | Not disabled | unset/other | Not disabled |=========================================================================== *NUT_IGNORE_CHECKPROCNAME*:: Optional, defaults to `false`. Normally NUT can (attempt to) verify that the program file name matches the name associated with a running process, when using PID files to send signals. + The `NUT_IGNORE_CHECKPROCNAME` boolean toggle allows to quickly skip such verification, in case it causes problems (e.g. NUT programs were renamed and do not match built-in expectations). + This environment variable can also be optionally set in init-scripts or service methods for `upsd`, `upsmon` and NUT drivers/`upsdrvctl`. *NUT_QUIET_INIT_UPSNOTIFY*:: Optional flag to prevent daemons which can notify service management frameworks (such as systemd) about passing their lifecycle milestones, to not report loudly if they could NOT do so (e.g. running on a system without a framework, or misconfigured so they could not report and the OS could eventually restart the false-positively identified "unresponsive" service. + Currently such reports, done by default, help troubleshoot service start-up and highlight that NUT sources (or package build) did not take advantage of tighter OS service management framework integration (if one exists, so that developers could focus on adding that). Reasons to set this flag could include platforms without such a framework and not expecting one, although nagging your favourite OS or contributing development to make it better is also a way. EXAMPLE ------- ------ # /etc/nut/nut.conf. See nut.conf(5) MODE=none UPSD_OPTIONS="" UPSMON_OPTIONS="" # POWEROFF_WAIT=15m ------ INTEGRATION ----------- An init script, such as `/etc/init.d/nut`, is expected to source this file in order to determine which components have to be started. SEE ALSO -------- linkman:ups.conf[5], linkman:upsd.conf[5], linkman:upsd.users[5], linkman:upsmon.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_scan_xml_http_range.30000644000200500020050000000715115001555057016607 00000000000000'\" t .\" Title: nutscan_scan_xml_http_range .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_SCAN_XML_HTT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_scan_xml_http_range \- Scan network for XML/HTTP devices\&. .SH "SYNOPSIS" .sp .nf #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_xml_http_range( const char * start_ip, const char * end_ip, useconds_t usec_timeout, nutscan_xml_t * sec) nutscan_device_t * nutscan_scan_ip_range_xml_http( nutscan_ip_range_list_t * irl, useconds_t usec_timeout, nutscan_xml_t * sec) .fi .SH "DESCRIPTION" .sp The \fBnutscan_scan_xml_http_range()\fR and \fBnutscan_scan_ip_range_xml_http()\fR functions try to detect NUT compatible XML/HTTP devices\&. .sp If \fIstart_ip\fR for the former or \fIirl\fR for the latter are NULL, the respective function does this by issuing a broadcast message on all currently configured network interfaces\&. .sp Otherwise, the former queries every IP ranging from \fIstart_ip\fR to \fIstop_ip\fR, , where \fIstartIP\fR is mandatory and \fIstopIP\fR is optional (one \fIstartIP\fR address is scanned if \fIstopIP\fR is NULL); while the latter can walk several IP address ranges represented by a nutscan_ip_range_list_t structure\&. .sp Those IP arguments may be either IPv4 or IPv6 addresses or host names\&. .sp It waits up to \fIusec_timeout\fR microseconds for a response from potential devices\&. .sp You MUST call \fBnutscan_init\fR(3) before using this function\&. .SH "RETURN VALUE" .sp The \fBnutscan_scan_xml_http_range()\fR function returns a pointer to a nutscan_device_t structure containing all found devices or NULL if an error occurs or no device is found\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_scan_eaton_serial\fR(3), \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_add_ip_range\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/upsd.conf.txt0000644000200500020050000002334015001555412013402 00000000000000UPSD.CONF(5) ============ NAME ---- upsd.conf - Configuration for Network UPS Tools upsd data server DESCRIPTION ----------- linkman:upsd[8] uses this file to control access to the server and set some other miscellaneous configuration values. This file contains details on access controls, so keep it secure. Ideally, only the `upsd` process should be able to read it. IMPORTANT NOTES --------------- * Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message). * Balance the run-time user permissions to access the file (and perhaps the directory it is in) for only `upsd` to be able to read it; write access is not needed. It is common to use `chown root:nut` and `chmod 640` to set up acceptable file permissions. - Packages (and build recipes) typically prepare one set of user and group accounts for NUT. Custom builds with minimal configuration might even use `nobody:nogroup` or similar, which is inherently insecure. - On systems with extra security concerns, NUT drivers and data server should run as separate user accounts which would be members of one same group for shared access to local Unix socket files and the directory they are in, but different groups for configuration file access. This would need some daemons to use customized `user`, `group`, `RUN_AS_USER` and/or `RUN_AS_GROUP` settings to override the single built-in value. - Note that the monitoring, logging, etc. clients are networked-only. They do not need access to these files and directories, and can run as an independent user and group altogether. - Keep in mind the security of also any backup copies of this file, e.g. the archive files it might end up in. CONFIGURATION DIRECTIVES ------------------------ *MAXAGE 'seconds'*:: `upsd` usually allows a driver to stop responding for up to 15 seconds before declaring the data "stale". If your driver takes a very long time to process updates but is otherwise operational, you can use `MAXAGE` to make `upsd` wait longer. + Most users should leave this at the default value. *TRACKINGDELAY 'seconds'*:: When instant commands and variables setting status tracking is enabled, status execution information are kept during this amount of time, and then cleaned up. This defaults to 3600 (1 hour). *ALLOW_NO_DEVICE 'Boolean'*:: Normally upsd requires that at least one device section is defined in ups.conf when the daemon starts, to serve its data. For automatically managed services it may be preferred to have upsd always running, and reload the configuration when power devices become defined. + Boolean values 'true', 'yes', 'on' and '1' mean that the server would not refuse to start with zero device sections found in ups.conf. + Boolean values 'false', 'no', 'off' and '0' mean that the server should refuse to start if zero device sections were found in ups.conf. This is the default, unless the calling environment sets a same-named variable to enforce a value for the current run. One way this can happen is somebody un-commenting it in the 'nut.conf' file used by init-scripts and service unit method scripts. *ALLOW_NOT_ALL_LISTENERS 'Boolean'*:: Normally upsd requires that all `LISTEN` directives can be honoured at the moment the daemon starts. If your LAN IP address (or host name) used in one of the `LISTEN` directives may be not always accessible, and for some reason do not want to just `LISTEN *` on the wildcard interface, but e.g. you still want to use `upsmon` on `localhost`, this option can help. Note you would have to restart `upsd` to pick up the `LISTEN`'ed IP address if it appears later. + Boolean values 'true', 'yes', 'on' and '1' mean that the server would not refuse to start if it can listen on at least one interface. + Boolean values 'false', 'no', 'off' and '0' mean that the server should refuse to start if it can not LISTEN on each and every (non-localhost) interface found in upsd.conf. This is the default, unless the calling environment sets a same-named variable to enforce a value for the current run. One way this can happen is somebody un-commenting it in the 'nut.conf' file used by init-scripts and service unit method scripts. *STATEPATH 'path'*:: Tell `upsd` to look for the driver state sockets in 'path' rather than the default that was compiled into the program. + Note that the drivers must use the same path, so `upsd` would prefer the same-named setting from `ups.conf` global section, if present, over its own. + Environment variable `NUT_STATEPATH` set by caller (e.g. init script or service method) can override this setting. *LISTEN 'interface' 'port'*:: Bind a listening port to the interface specified by its Internet address or name. This may be useful on hosts with multiple interfaces. You should not rely exclusively on this for security, as it can be subverted on many systems. + Optionally listen on TCP port 'port' instead of the default value which was compiled into the code. This overrides any value you may have set with `configure --with-port`. If you don't change it with configure or this value, `upsd` will listen on port '3493' for this interface. + Multiple `LISTEN` addresses may be specified. The default is to bind to `127.0.0.1` if no `LISTEN` addresses are specified (and also `::1` if IPv6 support is compiled in). + To listen on all available interfaces and configured IP addresses of your system, you may also use `::` for IPv6 and `0.0.0.0` for IPv4, respectively. As a special case, a single `LISTEN * ` directive (with an asterisk) will try to listen on both IPv6 (`::0`) and IPv4 (`0.0.0.0`) wild-card IP addresses, subject to `upsd` command-line arguments or system configuration. Note that if the system supports IPv4-mapped IPv6 addressing per RFC-3493, and does not allow to disable this mode, then there may be one listening socket to handle both address families. + LISTEN 127.0.0.1 LISTEN 192.168.50.1 LISTEN myhostname.mydomain LISTEN ::1 LISTEN 2001:0db8:1234:08d3:1319:8a2e:0370:7344 + This parameter will only be read at startup. You'll need to restart (rather than merely reload) `upsd` to apply any changes made here. + Please note that older NUT releases could have been using the IPv4-mapped IPv6 addressing (sometimes also known as "dual-stack") mode, if provided by the system. Current versions (since NUT v2.8.1 release) explicitly try to restrict their listening sockets to only support one address family on each socket, and so avoid IPv4-mapped mode where possible. *MAXCONN 'connections'*:: This defaults to maximum number allowed on your system. Each UPS, each `LISTEN` address and each client count as one connection. If the server runs out of connections, it will no longer accept new incoming client connections. Only set this if you know exactly what you're doing. *CERTFILE 'certificate file'*:: When compiled with SSL support with OpenSSL backend, you can enter the certificate file here. + The certificates must be in PEM format and must be sorted starting with the subject's certificate (server certificate), followed by intermediate CA certificates (if applicable) and the highest level (root) CA. It should end with the server key. See `docs/security.txt` in NUT sources, or the Security chapter of NUT user manual, for more information on the SSL support in NUT. *CERTPATH 'certificate database'*:: When compiled with SSL support with NSS backend, you can enter the certificate path here. + Certificates are stored in a dedicated database (data split in 3 files). Specify the path of the database directory. *CERTIDENT 'certificate name' 'database password'*:: When compiled with SSL support with NSS backend, you can specify the certificate name to retrieve from database to authenticate itself and the password required to access certificate related private key. + NOTE: Be sure to enclose "certificate name" in double-quotes if you are using a value with spaces in it. *CERTREQUEST 'certificate request level'*:: When compiled with SSL support with NSS backend and client certificate validation (disabled by default, see `docs/security.txt` in NUT sources), you can specify if `upsd` requests or requires clients' certificates. + Possible values are: + - '0' to not request to clients to provide any certificate - '1' to require to all clients a certificate - '2' to require to all clients a valid certificate *DISABLE_WEAK_SSL 'BOOLEAN'*:: Tell `upsd` to disable older/weak SSL/TLS protocols and ciphers. With relatively recent versions of OpenSSL or NSS it will be restricted to TLSv1.2 or better. + Unless you have really ancient clients, you probably want to enable this. Currently disabled by default to ensure compatibility with existing setups. *DEBUG_MIN 'INTEGER'*:: Optionally specify a minimum debug level for `upsd` data daemon, e.g. for troubleshooting a deployment, without impacting foreground or background running mode directly. Command-line option `-D` can only increase this verbosity level. + NOTE: If the running daemon receives a `reload` command, presence of the `DEBUG_MIN NUMBER` value in the configuration file can be used to tune debugging verbosity in the running service daemon (it is recommended to comment it away or set the minimum to explicit zero when done, to avoid huge journals and I/O system abuse). Keep in mind that for this run-time tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files is applied instantly and overrides any previously set value, from file or CLI options, regardless of older logging level being higher or lower than the newly found number; a missing (or commented away) value however does not change the previously active logging verbosity. SEE ALSO -------- linkman:upsd[8], linkman:nutupsdrv[8], linkman:upsd.users[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nhs_ser.txt0000644000200500020050000000371615001555412013151 00000000000000NHS_SER(8) ========== NAME ---- nhs_ser - Driver for NHS Nobreaks, senoidal line, with serial port SYNOPSIS -------- *nhs_ser* -h *nhs_ser* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *nhs_ser* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ *nhs_ser* supports numerous UPS models made by NHS Sistemas Eletronicos LTDA and marketed in Brazil. They feature a serial port and a binary wire protocol. NOTE: Currently this driver only builds on Linux. This is expected to change in future revisions of the code. EXTRA ARGUMENTS --------------- This driver also supports the following optional settings: *baud*='num':: Set the value of serial port baud rate (default: 2400) *ah*='num':: Battery discharge capacity in Ampere/hour. *va*='num':: Nobreak NOMINAL POWER in VA. *pf*='num':: Power Factor to use in calculations of battery time (default: 0.90). *vin_low_warn_perc*='num':: Voltage In Percentage to calculate warning low level (default: 2.00). *vin_low_crit_perc*='num':: Voltage In Percentage to calculate critical low level (default: 2.00). *vin_high_warn_perc*='num':: Voltage In Percentage to calculate warning high level (default: 2.00). *vin_high_crit_perc*='num':: Voltage In Percentage to calculate critical high level (default: 2.00). *numbatteries*='num':: Num Batteries (override value from nobreak). *vbat*='num':: Battery Voltage (default: 12.00). *debug_pkt_raw*:: Optional flag to enable debug logging of packet bytes. *debug_pkt_data*:: Optional flag to enable debug logging of data packet decoding. *debug_pkt_hwinfo*:: Optional flag to enable debug logging of hwinfo packet decoding. AUTHORS ------- Lucas Willian Bocchi SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_readline_timeout.30000644000200500020050000000003315001555117015732 00000000000000.so man3/upscli_readline.3 nut-2.8.3/docs/man/nutscan_scan_eaton_serial.txt0000644000200500020050000000272515001555412016713 00000000000000NUTSCAN_SCAN_EATON_SERIAL(3) ============================ NAME ---- nutscan_scan_eaton_serial - Scan serial ports for Eaton devices (XCP, SHUT and Q1). SYNOPSIS -------- ------ #include nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_list); ------ DESCRIPTION ----------- The *nutscan_scan_eaton_serial()* function tries to detect NUT devices which are compatible with Eaton's serial device protocols (SHUT, XCP and Q1 (aka blazer or megatec)). 'ports_list' is a NULL-terminated array of pointers to strings containing serial device name (`/dev/ttyS0`, `COM1`, `/dev/ttya`...) You MUST call linkman:nutscan_init[3] before using this function. RETURN VALUE ------------ The *nutscan_scan_eaton_serial()* function returns a pointer to a `nutscan_device_t` structure containing all found devices or NULL if an error occurs or no device is found. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_get_serial_ports_list[3] nut-2.8.3/docs/man/genericups.txt0000644000200500020050000003017015001555412013646 00000000000000GENERICUPS(8) ============= NAME ---- genericups - Driver for contact-closure UPS equipment SYNOPSIS -------- *genericups* -h *genericups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the genericups driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports hardware from many different manufacturers as it only uses the very simplest of signaling schemes. Contact closure refers to a kind of interface where basic high/low signals are provided to indicate status. This kind of UPS can only report line power and battery status. This means that you will only get the essentials in ups.status: OL, OB, and LB (some UPSes may also support RB and BYPASS). Anything else requires a smarter UPS. CABLING ------- Cabling is different for every kind of UPS. See the table below for information on what is known to work with a given UPS type. EXTRA ARGUMENTS --------------- This driver supports the following settings in the linkman:ups.conf[5]: upstype='type':: Required. Configures the driver for a specific kind of UPS. See the <<_ups_types,UPS Types>> section below for more information on which entries are available. mfr='string':: Optional. The very nature of a generic UPS driver sometimes means that the stock manufacturer data has no relation to the actual hardware that is attached. With the `mfr` setting, you can change the value that is seen by clients that monitor this UPS. model='string':: Optional. This is like `mfr` above, but it overrides the model string instead. serial='string':: Optional. This is like `mfr` above and intended to record the identification string of the UPS. It is titled "serial" because usually this string is referred to as the serial number. sdtime='value':: Optional. The driver will sleep for this many seconds after setting the shutdown signal. This is necessary for some hardware which requires a sustained level to activate the shutdown sequence. + The default behavior of the driver is to exit immediately. If this doesn't reliably trigger a shutdown in your UPS hardware, use this setting to give it more time to react. NOTE: very large values for +sdtime+ may create warnings from upsdrvctl if it gets tired of waiting for the driver to return. CUSTOM CONFIGURATIONS --------------------- You may override the values for `CP`, `OL`, `LB`, and `SD` by defining them in the linkman:ups.conf[5] after the `upstype` setting. For example, to set the cable power to `DTR` and the low battery value to `DCD`, it would look like this: ---- CP = DTR LB = DCD ---- Recognized values for input lines are `CTS`, `DCD`, and `RNG`. Recognized values for output lines are `DTR`, `RTS`, and `ST`. See below for more about what these signals mean. These values may be negated for active low signals. That is, `LB=-DCD` recognizes a low battery condition when `DCD` is not held high. TYPE INFORMATION ---------------- The essence of a UPS definition in this driver is how it uses the serial lines that are available. These are the abbreviations you will see below: OL:: On line (no power failure) (opposite of 'OB' -- on battery) LB:: Low battery RB:: Replace battery BYPASS:: Battery bypass active or no battery installed SD:: Shutdown load CP:: Cable power (must be present for cable to have valid reading) CTS:: Clear to Send. Received from the UPS. RTS:: Ready to Send. Sent by the PC. DCD:: Data Carrier Detect. Received from the UPS. RNG:: Ring indicate. Received from the UPS. DTR:: Data Terminal Ready. Sent by the PC. DSR:: Data Set Ready. Received from the UPS. ST:: Send a BREAK on the transmit data line NULL:: Disable this signal. Disabled signal will always be low except for 'OL' which will always be high. none:: Alias to `NULL` which matches some other documentation. A `-` in front of a signal name (like `-RNG`) means that the indicated condition is signaled with an active low signal. For example, `[LB=-RNG]` means the battery is low when the ring indicate line goes low, and that the battery is OK when that line is held high. UPS TYPES --------- 0 = UPSonic LAN Saver 600 [CP=DTR+RTS] [OL=-CTS] [LB=DCD] [SD=DTR] 1 = APC Back-UPS/Back-UPS Pro/Smart-UPS with 940-0095A/C cable [CP=DTR] [OL=-RNG] [LB=DCD] [SD=RTS] 2 = APC Back-UPS/Back-UPS Pro/Smart-UPS with 940-0020B cable (Note: Type 2 has also been reported to work with the 940-0020C cable). [CP=RTS] [OL=-CTS] [LB=DCD] [SD=DTR+RTS] 3 = PowerTech Comp1000 with DTR cable power [CP=DTR] [OL=CTS] [LB=DCD] [SD=DTR+RTS] 4 = Generic RUPS Model [CP=RTS] [OL=CTS] [LB=-DCD] [SD=-RTS] 5 = Tripp Lite UPS with Lan2.2 interface (black 73-0844 cable) [CP=DTR] [OL=CTS] [LB=-DCD] [SD=DTR+RTS] 6 = Best Patriot with INT51 cable [CP=DTR] [OL=CTS] [LB=-DCD] [SD=RTS] 7 = CyberPower Power99 Also Upsonic Power Guardian PG-500, Belkin Belkin Home Office, F6H350-SER, F6H500-SER, F6H650-SER, Eaton Management Card Contact -- Config3 with cable 66033 (shutdown does not work) [CP=RTS] [OL=CTS] [LB=-DCD] [SD=DTR] 8 = Nitram Elite 500 [CP=DTR] [OL=CTS] [LB=-DCD] [SD=???] 9 = APC Back-UPS/Back-UPS Pro/Smart-UPS with 940-0023A cable [CP=none] [OL=-DCD] [LB=CTS] [SD=RTS] 10 = Victron Lite with crack cable [CP=RTS] [OL=CTS] [LB=-DCD] [SD=DTR] 11 = Powerware 3115 [CP=DTR] [OL=-CTS] [LB=-DCD] [SD=ST] 12 = APC Back-UPS Office with 940-0119A cable [CP=RTS] [OL=-CTS] [LB=DCD] [SD=DTR] 13 = RPT Repoteck RPT-800A/RPT-162A [CP=DTR+RTS] [OL=DCD] [LB=-CTS] [SD=ST] 14 = Online P-series [CP=DTR] [OL=DCD] [LB=-CTS] [SD=RTS] 15 = Powerware 5119, 5125 [CP=DTR] [OL=CTS] [LB=-DCD] [SD=ST] 16 = Nitram Elite 2002 [CP=DTR+RTS] [OL=CTS] [LB=-DCD] [SD=???] 17 = PowerKinetics 9001 [CP=DTR] [OL=CTS] [LB=-DCD] [SD=???] 18 = TrippLite Omni 450LAN with Martin's cabling [CP=DTR] [OL=CTS] [LB=DCD] [SD=none] 19 = Fideltronic Ares Series [CP=DTR] [OL=CTS] [LB=-DCD] [SD=RTS] 20 = Powerware 5119 RM (check `docs/cables/powerware.txt` in NUT sources) [CP=DTR] [OL=-CTS] [LB=DCD] [SD=ST] 21 = Generic RUPS 2000 (Megatec M2501 cable) [CP=RTS] [OL=CTS] [LB=-DCD] [SD=RTS+DTR] 22 = Gamatronic All models with alarm interface (also CyberPower SL series) [CP=RTS] [OL=CTS] [LB=-DCD] [SD=DTR] 23 = Generic FTTx (Fiber to the x) battery backup with 4-wire telemetry interface [CP=RTS] [OL=CTS] [LB=-DCD] [RB=-RNG] [BYPASS=-DSR] [SD=none] SIMILAR MODELS -------------- Many different UPS companies make models with similar interfaces. The RUPS cable seems to be especially popular in the "power strip" variety of UPS found in office supply stores. If your UPS works with an entry in the table above, but the model or manufacturer information don't match, don't despair. You can fix that easily by using the `mfr` and `model` variables documented above in your linkman:ups.conf[5]. TESTING COMPATIBILITY --------------------- If your UPS isn't listed above, you can try going through the list until you find one that works. There is a lot of cable and interface reuse in the UPS world, and you may find a match. To do this, first make sure nothing important is plugged into the outlets on the UPS, as you may inadvertently switch it off. Definitely make sure that the computer you're using is not plugged into that UPS. Plug in something small like a lamp so you know when power is being supplied to the outlets. Now, you can either attempt to make an educated guess based on the documentation your manufacturer has provided (if any), or just start going down the list. Step 1 ~~~~~~ Pick a driver to try from the list (run `genericups -h`) and go to step 2. Step 2 ~~~~~~ Start the driver with the type you want to try, e.g.: genericups -x upstype=n /dev/port Let linkman:upsd[8] sync up (watch the syslog), and then run linkman:upsc[8] to see what it found. If the `STATUS` is correct (should be "OL" for online), continue to <<_step_3,Step 3>>, otherwise go back to step 1. Alternatively, you can run `genericups` in debug mode, e.g.: genericups -DDDDD -x upstype=n /dev/port In this mode it will be running in the foreground and continuously display the line and battery status of the UPS. Step 3 ~~~~~~ Disconnect the UPS from the wall/mains power. This is easiest if you have a switched outlet in between it and the wall, but you can also just pull the plug to test. The lamp should stay lit, and the status should switch to "OB". If the lamp went out or the status didn't go to "OB" within about 15 seconds, go to <<_step_1,Step 1>>. Otherwise, continue to <<_step_4,Step 4>>. Step 4 ~~~~~~ At this point, we know that OL and OB work. If nothing else beyond this point works, you at least know what your OL/OB value should be. Wait for the UPS to start complaining about a low battery. Depending on the size of your UPS battery and the lamp's bulb, this could take awhile. It should start complaining audibly at some point. When this happens, STATUS should show "OB LB" within 15 seconds. If not, go to <<_step_1,Step 1>>, otherwise continue to <<_step_5,Step 5>>. Step 5 ~~~~~~ So far: OL works, OB works, and LB works. With the UPS running on battery, run the genericups driver with the -k switch to shut it down. genericups -x upstype=n -k /dev/port If the UPS turns off the lamp, you're done. At this point, you have verified that the shutdown sequence actually does what you want. You can start using the genericups driver with this type number for normal operations. You should use your findings to add a section to your ups.conf. Here is a quick example: [myups] driver = genericups port = /dev/ttyS0 upstype = 1 Change the port and upstype values to match your system. NEW SUPPORT ----------- If the above testing sequence fails, you will probably need to create a new entry to support your hardware. All UPS types are determined from the table in the `genericups.h` file in the source tree. On a standard 9 pin serial port, there are 6 lines that are used as the standard "high/low" signal levels. 4 of them are incoming (to the PC, from the UPS), and the other 2 are outgoing (to the UPS, from the PC). The other 3 are the receive/transmit lines and the ground. Be aware that many manufacturers remap pins within the cable. If you have any doubts, a quick check with a multimeter should confirm whether the cable is straight-through or not. Another thing to keep in mind is that some cables have electronics in them to do special things. Some have resistors and transistors on board to change behavior depending on what's being supplied by the PC. SPECIFIC MODEL NOTES -------------------- These have been contributed by users of this driver. The Centralion CL series may power down the load if the driver starts up with the UPS running on battery as the default line settings contain the shutdown sequence. - Neil Muller The Tripp-Lite Internet Office 700 must be used with the black 73-0844 cable instead of the gray 73-0743 cable. This entry should work with any of their models with the Lan 2.2 interface -- see the sticker by the DB9 connector on the UPS. - Stephen Brown Type 5 should work with the Tripp-Lite Lan 2.1 interface and the 73-0724 cable. This was tested with the OmniSmart 675 PNP on Red Hat 7.2. - Q Giese Types 7 and 10 should both work with the PhoenixTec A1000. BUGS ---- There is no way to reliably detect a contact-closure UPS. This means the driver will start up happily even if no UPS is detected. It also means that if the connection between the UPS and computer is interrupted, you may not be able to sense this in software. Most contact-closure UPSes will not power down the load if the line power is present. This can create a race when using secondary linkman:upsmon[8] systems. See the linkman:upsmon[8] man page for more information. The solution to both of these problems is to upgrade to a smart protocol UPS of some kind that allows detection and proper load cycling on command. SEE ALSO -------- The core driver ~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/etapro.80000644000200500020050000000407315001555070012327 00000000000000'\" t .\" Title: etapro .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "ETAPRO" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" etapro \- Driver for ETA UPS equipment .SH "SYNOPSIS" .sp \fBetapro\fR \-h .sp \fBetapro\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the etapro driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports ETA UPS equipment with the "PRO" option for smart mode\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "AUTHOR" .sp Marek Michalkiewicz .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/liebert-gxe.80000644000200500020050000000601115001555072013240 00000000000000'\" t .\" Title: liebert-gxe .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIEBERT\-GXE" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" liebert-gxe \- Driver for Liebert GXE series UPS, using the YDN23 serial protocol .SH "SYNOPSIS" .sp \fBliebert\-gxe\fR \-h .sp \fBliebert\-gxe\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the liebert\-gxe driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp Tested to work on the following units: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Liebert GXE 01k00TS1101C00 .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This UPS has an RS\-232 port and a USB port\&. The USB port has an ACM interface which functions as a serial port for the host operating system\&. Both ports can be used managing the device\&. .sp .5v .RE .RE .sp This is an experimental driver\&. You have been warned\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in \fBups.conf\fR(5): .PP \fBaddr=\fR\fInum\fR .RS 4 Set the address of the UPS \(em 01 (default) ~ 99\&. .RE .PP \fBretry=\fR\fInum\fR .RS 4 Set the max times of read failures\&. (UPS sometimes ignores the incoming command and causes driver stales\&. The driver will ignore \fBretry\fR failures if occurred in a row\&. However, this does increase the latency if a real stale happened\&. Default to 3) .RE .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Gong Zhile .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/apcsmart-old.txt0000644000200500020050000000563515001555412014100 00000000000000APCSMART-OLD(8) =============== NAME ---- apcsmart-old - Driver for American Power Conversion Smart Protocol UPS equipment SYNOPSIS -------- *apcsmart-old* -h *apcsmart-old* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the apcsmart-old driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ apcsmart-old should recognize all recent APC models that use a serial protocol at 2400 bps. This is primarily the Smart-UPS, Matrix-UPS and Back-UPS Pro lines. The driver attempts to support every bell and whistle of the APC reporting interface, whether or not this is strictly sensible. Some older hardware may only report a handful of variables. This is usually not a bug--they just don't support anything else. CABLING ------- This driver expects to see a 940-0024C cable or a clone by default. You can switch to the 940-0095B dual-mode cable support with the `cable=` definition described below. If your 940-0024C cable is broken or missing, use this diagram to build a clone: https://www.networkupstools.org/cables/940-0024C.jpg EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *cable=940-0095B*:: Configure the serial port for the APC 940-0095B dual-mode cable. *sdtype=*'num':: Use shutdown type 'num', according to this table: 0;; soft shutdown or powerdown, depending on battery status 1;; soft shutdown followed by powerdown 2;; instant power off 3;; power off with grace period 4;; "force OB" hack method for CS 350 Modes 0 and 1 will power up the load when power returns. Modes 2 and 3 will keep the load turned off when the power returns. Mode 4 exploits an oddity in the CS 350 models since they only seem to support the S command, but then only when running on battery. As a result, the driver will force the UPS to go on battery if necessary before sending the shutdown command. This ensures that the load gets reset. BUGS ---- Some older APC UPS models return bogus data in the status register during a front panel test. This is usually detected and discarded, but some other unexpected values have occasionally slipped through. APC UPS models with both USB and serial ports require a power cycle when switching from USB communication to serial, and perhaps vice versa. AUTHORS AND HISTORY ------------------- Nigel Metheringham (drawing heavily on the original `apcsmart` driver by Russell Kroll). This driver was called `newapc` for a time and was renamed in the 1.5 series. In 2.6.2 the driver was renamed to `apcsmart-old`, being superseded by updated version with new features which currently holds the `apcsmart` name. SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/blazer_usb.txt0000644000200500020050000000034315001555412013631 00000000000000BLAZER_USB(8) ============= :blazer_usb: NAME ---- blazer_usb - Driver for Megatec/Q1 protocol USB based UPS equipment SYNOPSIS -------- *blazer_usb* -h *blazer_usb* -a 'UPS_NAME' ['OPTIONS'] include::blazer-common.txt[] nut-2.8.3/docs/man/nut-ipmipsu.txt0000644000200500020050000000570515001555412014002 00000000000000NUT-IPMIPSU(8) ============== NAME ---- nut-ipmipsu - Driver for IPMI Power Supply Units (PSU) SYNOPSIS -------- *nut-ipmipsu* -h *nut-ipmipsu* -a 'PSU_NAME' ['OPTIONS'] NOTE: This driver is experimental, and still a work-in-progress. Feedback is encouraged. NOTE: This man page only documents the hardware-specific features of the nut-ipmipsu driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver should support a wide range of PSUs through local IPMI interface. nut-ipmipsu currently uses the GNU FreeIPMI project, for IPMI implementation. EXTRA ARGUMENTS --------------- This driver doesn't support any optional settings. INSTALLATION ------------ This driver may be not built by default. You can build it by installing the libfreeipmi-dev dependencies and using `configure --with-ipmi=yes`. You also need to give proper permissions on the local IPMI device file (`/dev/ipmi0` for example) to allow the NUT user to access it. An *udev* rules file (`nut-ipmipsu.rules`) is provided and automatically installed on an *udev* enabled system. This file is generally installed in `/etc/udev/rules.d/`, or `/lib/udev/rules.d/` on newer systems, to address the permission settings problem. For more information, refer to `scripts/udev/README.adoc` in NUT sources. INSTANT COMMANDS ---------------- This driver doesn't support any instant commands. IMPLEMENTATION -------------- The `port` value is used to identify the PSU. For instance, to target FRU '0x2', use the following in *ups.conf*: [pdu] driver = nut-ipmipsu port = id2 This driver will report various information related to a PSU, including: - manufacturer, model, serial and part numbers, - nominal voltage and frequency, - actual current and voltage, - status of the PSU: * 'OL' means that the PSU is present and providing power, * 'OFF' means that the PSU is present but not providing power (power cable removed), * 'stale' (no data) means that the PSU is not present (i.e. physically removed). Here is an example output for a Dell r610 server: device.mfr: DELL device.mfr.date: 01/05/11 - 08:51:00 device.model: PWR SPLY,717W,RDNT device.part: 0RN442A01 device.serial: CN179721130031 device.type: psu driver.name: nut-ipmipsu driver.parameter.pollinterval: 2 driver.parameter.port: id2 driver.version: 2.6.1-3139M driver.version.data: IPMI PSU driver driver.version.internal: 0.01 input.current: 0.20 input.frequency.high: 63 input.frequency.low: 47 input.voltage: 232.00 input.voltage.maximum: 264 input.voltage.minimum: 90 ups.id: 2 ups.realpower.nominal: 717 ups.status: OL ups.voltage: 12 AUTHOR ------ Arnaud Quette SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * GNU FreeIPMI home page: http://www.gnu.org/software/freeipmi/ nut-2.8.3/docs/man/upscli_splitname.30000644000200500020050000000517315001555053014406 00000000000000'\" t .\" Title: upscli_splitname .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_SPLITNAME" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_splitname \- Split a UPS definition into its components .SH "SYNOPSIS" .sp .nf #include int upscli_splitname(const char *buf, char **upsname, char **hostname, int *port) .fi .SH "DESCRIPTION" .sp The \fBupscli_splitname()\fR function takes a pointer to the raw UPS definition \fIbuf\fR and returns pointers to dynamically allocated memory in \fIupsname\fR and \fIhostname\fR\&. It also copies the port number into \fIport\fR\&. .SH "FORMATTING" .sp An UPS definition is specified according to this format: .sp .if n \{\ .RS 4 .\} .nf [@[:]] .fi .if n \{\ .RE .\} .sp When the UPS name is not given, this function will print an error to stderr and return \fI\-1\fR without changing anything\&. .sp Definitions without an explicit port value receive the default value of \fI3493\fR\&. The default hostname is "localhost"\&. .SH "MEMORY USAGE" .sp You must \fBfree\fR(3) the pointers to \fIupsname\fR and \fIhostname\fR when you are done with them to avoid memory leaks\&. .SH "RETURN VALUE" .sp The \fBupscli_splitname()\fR function returns \fI0\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_fd\fR(3), \fBupscli_get\fR(3), \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_splitaddr\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/netxml-ups.80000644000200500020050000001415715001555100013147 00000000000000'\" t .\" Title: netxml-ups .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NETXML\-UPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" netxml-ups \- Driver for Eaton / MGE Network Management Card / Proxy (XML/HTTP Protocol) equipment .SH "SYNOPSIS" .sp \fBnetxml\-ups\fR \-h .sp \fBnetxml\-ups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the netxml\-ups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp netxml\-ups supports all recent Eaton / MGE models which use a Network Management Card or Proxy (MGE XML/HTTP protocol based)\&. This applies to both Eaton (previously MGE Office Protection Systems) and to MGE UPS SYSTEMS\&. Supported card and proxy models are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NMC Minislot (Ref 66102, firmware EA or newer), .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} SNMP/Web Minislot card (Ref 66244) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NMC Transverse (Ref 66074), .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NMC & Modbus/JBus (Ref 66103), .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Network Management Proxy, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} ePDU Monitored (newer version)\&. .RE .sp Older models, such as SNMP card (Ref 66062 and Ref 66045), use the SNMP protocol and should use the \fBsnmp-ups\fR(8) driver with the mibs=mge parameter\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBtimeout\fR=\fIvalue\fR .RS 4 The timeout for connecting to and reading from the UPS\&. Defaults to 5 seconds\&. Don\(cqt change this value unless you know exactly what you\(cqre doing\&. .sp This value \fBmust never\fR be higher than half the MAXAGE value specified in \fBupsd.conf\fR(5), otherwise you run the risk that \fBupsd\fR(8) declares the driver stale while it is waiting for a connection to timeout\&. .RE .PP \fBsubscribe\fR .RS 4 Connect to the NMC in subscribed mode\&. This allows to receive notifications and alarms more quickly, beside from the standard polling requests\&. .RE .PP \fBlogin\fR=\fIvalue\fR .RS 4 Set the login value for authenticated mode\&. This feature also needs the \fBpassword\fR argument, and allows value settings in the card\&. This feature is not used yet\&. .RE .PP \fBpassword\fR=\fIvalue\fR .RS 4 Set the password value, needed with the login for authenticated mode\&. This feature is not used yet\&. .RE .PP \fBshutdown_duration\fR=\fIvalue\fR .RS 4 Set the shutdown duration of the operating system, in seconds\&. This represents the amount of time needed by the system to operate a clean shutdown\&. Defaults to 120 seconds\&. .RE .PP \fBshutdown_timer\fR=\fIvalue\fR .RS 4 Set the shutdown timer, in seconds\&. After \fIvalue\fR seconds running on battery, the local system will receive a notification to shut down\&. Defaults to "none" (disabled)\&. .RE .PP \fBdo_convert_deci\fR .RS 4 If this flag value is present, the driver assumes you have a very old MGE networked UPS (or rather an old network management card firmware) which serves certain measurements spelled 10x too big in the XML markup\&. .sp Originally such measurements were decimated by the driver \(em but this is wrong for newer, more sane, devices \(em so this behavior was deprecated and is now disabled by default\&. Enabling this flag in configuration of a particular driver instance restores the old behavior for those measurements\&. .RE .SH "IMPLEMENTATION" .sp The hostname of the networked UPS is specified with the port value in ups\&.conf, i\&.e\&.: .sp .if n \{\ .RS 4 .\} .nf [mgexml] driver = netxml\-ups port = http://netxml\-ups\&.example\&.com:80 .fi .if n \{\ .RE .\} .sp Specifying the method to connect to the UPS (http, https) is mandatory\&. If the port is equal to the default for the method specified (80 for http, 443 for https) it may be omitted\&. .sp In order not to overload older NMCs by polling them too frequently, it is recommended to increase the "pollinterval" (see \fBnutupsdrv\fR(8)) and \fBups.conf\fR(5)) to at least 5 seconds\&. .SH "KNOWN ISSUES" .sp Don\(cqt connect to the UPS through a proxy\&. Although it would be trivial to add support for proxies, this is not recommended and don\(cqt ask for it\&. Not only because it will prevent the driver to make a persistent connection to the UPS, but also it adds an additional failure mode\&. If the proxy goes down (for whatever reason), the driver will no longer be able to reach the UPS\&. .SH "AUTHORS" .sp Arjen de Korte .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upsmon.80000644000200500020050000007011015001555050012347 00000000000000'\" t .\" Title: upsmon .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSMON" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsmon \- UPS monitor and shutdown controller .SH "SYNOPSIS" .sp \fBupsmon\fR \-h .sp \fBupsmon\fR \-c \fIcommand\fR [\-P \fIpid\fR] .sp \fBupsmon\fR [\-D] [\-F | \-B] [\-K] [\-p] [\-u \fIuser\fR] .SH "DESCRIPTION" .sp \fBupsmon\fR is the client process that is responsible for the most important part of UPS monitoring \(em shutting down the system when the power goes out\&. It can call out to other helper programs for notification purposes during power events\&. .sp upsmon can monitor multiple systems using a single process\&. Every UPS that is defined in the \fBupsmon.conf\fR(5) configuration file is assigned a power value and a type (\fBprimary\fR or \fBsecondary\fR)\&. .SH "OPTIONS" .PP \fB\-c\fR \fIcommand\fR .RS 4 Send the command \fIcommand\fR to the existing upsmon process\&. Valid commands are: .PP \fBfsd\fR .RS 4 shutdown all primary\-mode UPSes (use with caution) .RE .PP \fBstop\fR .RS 4 stop monitoring and exit .RE .PP \fBreload\fR .RS 4 reread \fBupsmon.conf\fR(5) configuration file\&. See "reloading nuances" below if this doesn\(cqt work\&. .RE .RE .PP \fB\-P\fR \fIpid\fR .RS 4 Send the command signal above using specified PID number, rather than consulting the PID file\&. This can help define service units which start main upsmon as a foreground process so it does not have to rely on a PID file\&. .RE .PP \fB\-D\fR .RS 4 Raise the debugging level\&. upsmon will run in the foreground by default, and will print information on stdout about the monitoring process\&. Use this option multiple times for more details\&. .RE .PP \fB\-F\fR .RS 4 upsmon will run in the foreground, regardless of debugging settings\&. .RE .PP \fB\-B\fR .RS 4 upsmon will run in the background, regardless of debugging settings\&. .RE .PP \fB\-K\fR .RS 4 Test for the shutdown flag\&. If it exists and contains the magic string from upsmon, then upsmon will exit with EXIT_SUCCESS\&. Any other condition will make upsmon exit with EXIT_FAILURE\&. .sp You can test for a successful exit from upsmon \-K in your shutdown scripts to know when to call \fBupsdrvctl\fR(8) to shut down the UPS\&. .RE .PP \fB\-p\fR .RS 4 Run privileged all the time\&. Normally upsmon will split into two processes\&. The majority of the code runs as an unprivileged user, and only a tiny stub runs as root\&. This switch will disable that mode, and run the old "all root all the time" system\&. .sp This is not the recommended mode, and you should not use this unless you have a very good reason\&. .RE .PP \fB\-u\fR \fIuser\fR .RS 4 Set the user for the unprivileged monitoring process\&. This has no effect when using \-p\&. .sp The default \fIuser\fR is set at build configuration time with configure \-\-with\-user=\&.\&.\&.\&. Typically this is \fInobody\fR (if not otherwise configured), which is far from ideal, so most packaged distributions will probably have a specific \fInut\fR user for this task\&. If your notification scripts need to run as a specific user, set it here\&. .sp You can also set this in the \fBupsmon.conf\fR(5) file with the RUN_AS_USER directive\&. .RE .SH "COMMON OPTIONS" .PP \fB\-h\fR .RS 4 Show the command\-line help message\&. .RE .PP \fB\-V\fR .RS 4 Show NUT version banner\&. More details may be available if you also export NUT_DEBUG_LEVEL=1 or greater verbosity level\&. .RE .PP \fB\-W\fR \fIsecs\fR .RS 4 Set the timeout for initial network connections (by default they are indefinitely non\-blocking, or until the system interrupts the attempt)\&. Overrides the optional NUT_DEFAULT_CONNECT_TIMEOUT environment variable\&. .RE .SH "UPS DEFINITIONS" .sp In the \fBupsmon.conf\fR(5), you must specify at least one UPS that will be monitored\&. Use the MONITOR directive like this: .sp .if n \{\ .RS 4 .\} .nf MONITOR \*(Aqsystem\*(Aq \*(Aqpowervalue\*(Aq \*(Aqusername\*(Aq \*(Aqpassword\*(Aq \*(Aqtype\*(Aq .fi .if n \{\ .RE .\} .sp The \fIsystem\fR refers to a \fBupsd\fR(8) server, in the form upsname[@hostname[:port]]\&. The default \fIhostname\fR is "localhost", and default \fIport\fR is \fI3493\fR\&. Some examples follow: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} "su700@mybox" means a UPS called "su700" on a system called "mybox"\&. This is the normal form\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} "fenton@bigbox:5678" is a UPS called "fenton" on a system called "bigbox" which runs \fBupsd\fR(8) on port "5678"\&. .RE .sp The \fIpowervalue\fR refers to how many power supplies on this client system are being driven this UPS\&. This is typically set to \fI1\fR, but see the section on power values below\&. .sp The \fIusername\fR is a section in your \fBupsd.users\fR(5) file\&. Whatever password you set in that section must match the \fIpassword\fR set in this file for the corresponding data server instance\&. .sp The type set in that section of the data server configuration must also match the \fItype\fR here \(em \fBprimary\fR or \fBsecondary\fR (consider it an "upsmon role")\&. In general, a "primary" client process is one running on the system with the UPS actually plugged into a serial or USB port, and a "secondary" is drawing power from the UPS but can\(cqt talk to it directly\&. See the section on UPS types for more\&. .SH "NOTIFY EVENTS" .sp \fBupsmon\fR senses several events as it monitors each UPS\&. They are called "notify events", as they can be used to tell the users and admins about the change in status\&. See the additional NOTIFY\-related sections below for information on customizing the delivery of these messages\&. .PP \fBONLINE\fR .RS 4 The UPS is back on line\&. .RE .PP \fBONBATT\fR .RS 4 The UPS is on battery\&. .RE .PP \fBLOWBATT\fR .RS 4 The UPS battery is low (as determined by the driver)\&. .RE .PP \fBFSD\fR .RS 4 The UPS has been commanded into the "forced shutdown" mode\&. .RE .PP \fBCOMMOK\fR .RS 4 Communication with the UPS has been established\&. .RE .PP \fBCOMMBAD\fR .RS 4 Communication with the UPS was just lost\&. .RE .PP \fBSHUTDOWN\fR .RS 4 The local system is being shut down\&. .RE .PP \fBREPLBATT\fR .RS 4 The UPS needs to have its battery replaced\&. .RE .PP \fBNOCOMM\fR .RS 4 The UPS can\(cqt be contacted for monitoring\&. .RE .PP \fBNOPARENT\fR .RS 4 upsmon parent process died \- shutdown impossible\&. .RE .PP \fBCAL\fR .RS 4 UPS calibration in progress\&. .RE .PP \fBNOTCAL\fR .RS 4 UPS calibration finished\&. .RE .PP \fBOFF\fR .RS 4 UPS administratively OFF or asleep\&. .RE .PP \fBNOTOFF\fR .RS 4 UPS no longer administratively OFF or asleep\&. .RE .PP \fBBYPASS\fR .RS 4 UPS on bypass (powered, not protecting)\&. .RE .PP \fBNOTBYPASS\fR .RS 4 UPS no longer on bypass\&. .RE .PP \fBECO\fR .RS 4 UPS in ECO or similar mode (as defined and named by vendor); other names include High Efficiency mode and Energy Saver System\&. .sp For example, Eaton docs define High Efficiency mode as a sort of hardware\-monitored bypass with switch\-over under 10ms into Online mode in case of troubles (so what was known as Line\-Interactive in the older days), which can be \fBchosen\fR instead of always running in a dual\-conversion mode (safer, but more wasteful and with a toll on battery life)\&. Older devices only implemented one or the other\&. .RE .PP \fBNOTECO\fR .RS 4 UPS no longer in ECO mode (see above)\&. .RE .PP \fBALARM\fR .RS 4 UPS has one or more active alarms (look at ups\&.alarm for details)\&. .RE .PP \fBNOTALARM\fR .RS 4 UPS is no longer in an alarm state (no active alarms)\&. .RE .PP \fBOVER\fR .RS 4 UPS is overloaded\&. .RE .PP \fBNOTOVER\fR .RS 4 UPS is no longer overloaded\&. .RE .PP \fBTRIM\fR .RS 4 UPS is trimming incoming voltage\&. .RE .PP \fBNOTTRIM\fR .RS 4 UPS is no longer trimming incoming voltage\&. .RE .PP \fBBOOST\fR .RS 4 UPS is boosting incoming voltage\&. .RE .PP \fBNOTBOOST\fR .RS 4 UPS is no longer boosting incoming voltage\&. .RE .PP \fBOTHER\fR .RS 4 UPS has at least one unclassified status token\&. .RE .PP \fBNOTOTHER\fR .RS 4 UPS has no unclassified status tokens anymore\&. .RE .PP \fBSUSPEND_STARTING\fR .RS 4 OS is entering sleep/suspend/hibernate mode\&. .RE .PP \fBSUSPEND_FINISHED\fR .RS 4 OS just finished sleep/suspend/hibernate mode, de\-activating obsolete UPS readings to avoid an unfortunate shutdown\&. .RE .SH "NOTIFY COMMAND" .sp In \fBupsmon.conf\fR(5), you can configure a program called the NOTIFYCMD that will handle events that occur\&. .sp The syntax is: NOTIFYCMD "\fIpath to program\fR" .sp Example: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NOTIFYCMD "/usr/local/bin/notifyme" .RE .sp Remember to wrap the path in "double quotes" if it contains any spaces\&. It should probably not rely on receiving any command\-line arguments\&. .sp The program you run as your NOTIFYCMD can use the environment variables NOTIFYTYPE and UPSNAME to know what has happened and on which UPS\&. It also receives the notification message (see below) as the first (and only) argument, so you can deliver a pre\-formatted message too\&. .sp Note that the NOTIFYCMD will only be called for a given event when you set the EXEC flag by using the notify flags, as detailed below\&. .SH "NOTIFY FLAGS" .sp By default, all notify events (see above) generate a global message (wall) to all users, plus they are logged via the syslog\&. Except for Windows where upsmon only writes to the syslog by default\&. You can change this with the NOTIFYFLAG directive in the configuration file: .sp The syntax is: NOTIFYFLAG \fInotifytype\fR \fIflags\fR .sp Examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NOTIFYFLAG ONLINE SYSLOG .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NOTIFYFLAG ONBATT SYSLOG+WALL .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC .RE .sp The flags that can be set on a given notify event are: .PP \fBSYSLOG\fR .RS 4 Write this message to the syslog\&. .RE .PP \fBWALL\fR .RS 4 Send this message to all users on the system via \fBwall\fR(1)\&. .RE .PP \fBEXEC\fR .RS 4 Execute the NOTIFYCMD\&. .RE .PP \fBIGNORE\fR .RS 4 Don\(cqt do anything\&. If you use this, don\(cqt use any of the other flags\&. .RE .sp You can mix these flags; for example, SYSLOG+WALL+EXEC does all three for a given event\&. .SH "NOTIFY MESSAGES" .sp upsmon comes with default messages for each of the NOTIFY events\&. These can be changed with the NOTIFYMSG directive\&. .sp The syntax is: NOTIFYMSG \fItype\fR "\fImessage\fR" .sp Examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NOTIFYMSG ONLINE "UPS %s is getting line power" .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NOTIFYMSG ONBATT "Someone pulled the plug on %s" .RE .sp The first instance of %s is replaced with the identifier of the UPS that generated the event\&. These messages are used when sending walls to the users directly from upsmon, and are also passed to the NOTIFYCMD\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Certain notifications, such as NOTIFY_ALARM and NOTIFY_OTHER, can accept a second instance of %s that would be replaced with the alarm text or the unrecognized token, respectively\&. .sp .5v .RE .SH "POWER VALUES" .sp The "current overall power value" is the sum of all UPSes that are currently able to supply power to the system hosting upsmon\&. Any UPS that is either on line or just on battery contributes to this number\&. If a UPS is critical (on battery and low battery) or has been put into "forced shutdown" mode, it no longer contributes\&. .sp The syntax is: MONITOR \fIupsname\fR \fIpowervalue\fR \fIusername\fR \fIpassword\fR \fItype\fR .sp A "power value" on a MONITOR line in the config file is the number of power supplies that the UPS runs on the current system\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Normally, you only have one power supply, so it will be set to \fI1\fR\&. .sp Example: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} MONITOR myups@myhost 1 username mypassword primary .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} On a large server with redundant power supplies, the power value for a UPS may be greater than 1\&. You may also have more than one of them defined\&. .sp Examples for a server with four power supply modules and two UPSes (each feeding two power supplies of that server): .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} MONITOR ups\-alpha@myhost 2 username mypassword primary .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} MONITOR ups\-beta@myhost 2 username mypassword primary .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} You can also set the power value for a UPS to \fI0\fR if it does not supply any power to that system\&. This is generally used when you want to use the upsmon notification features for a UPS even though it\(cqs not actually powering the system that hosts this instance of the upsmon client\&. .sp Don\(cqt set this to "primary" unless you really want to power this UPS off when this instance of upsmon needs to shut down for its own reasons\&. .sp Example: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} MONITOR faraway@anotherbox 0 username mypassword secondary .RE .RE .sp The "minimum power value" is the number of power supplies that must be receiving power in order to keep this upsmon client\(cqs computer running\&. .sp The syntax is: MINSUPPLIES \fIvalue\fR .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Typical PCs only have 1, so most users will leave this at the default\&. .sp Example: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} MINSUPPLIES 1 .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If you have a server or similar system with redundant power, then this value will usually be set higher\&. One that requires three power supplies out of 4 to be running at all times would simply set it to 3\&. .sp Example: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} MINSUPPLIES 3 .RE .sp When the current overall healthy UPS\-protected external power value drops below the minimum required power value, upsmon starts the shutdown sequence\&. This design allows you to lose some of your power supplies in a redundant power environment without bringing down the entire system, while still working properly for smaller systems\&. .RE .SH "UPS TYPES" .sp \fBupsmon\fR and \fBupsd\fR(8) don\(cqt always run on the same system\&. When they do, any UPSes that are directly attached to the upsmon host should be monitored in "primary" mode\&. This makes upsmon take charge of that equipment, and it will wait for the "secondary" systems to disconnect before shutting down the local system\&. This allows the distant systems (monitoring over the network) to shut down cleanly before upsdrvctl shutdown runs locally and turns them all off\&. .sp When upsmon runs as a secondary, it is relying on the distant system to tell it about the state of the UPS\&. When that UPS goes critical (on battery and low battery), it immediately invokes the local shutdown command\&. This needs to happen quickly\&. Once all secondaries disconnect from the distant \fBupsd\fR(8) server, its primary\-mode upsmon will start its own shutdown process\&. Your secondary systems must all quiesce and shut down before the primary turns off the shared power source, or filesystem damage may result\&. .sp upsmon deals with secondaries that get wedged, hang, or otherwise fail to gracefully disconnect from \fBupsd\fR(8) in a timely manner with the HOSTSYNC timer\&. During a shutdown situation, the primary upsmon will give up after this interval and it will shut down anyway\&. This keeps the primary from sitting there forever (which would endanger that host) if a secondary should break somehow\&. This defaults to 15 seconds\&. .sp If your primary system is shutting down too quickly, set the FINALDELAY interval to something greater than the default 15 seconds\&. Don\(cqt set this too high, or your UPS battery may run out of power before the primary upsmon process shuts down that system\&. .SH "TIMED SHUTDOWNS" .sp For those rare situations where the shutdown process can\(cqt be completed between the time that low battery is signalled and the UPS actually powers off the load, use the \fBupssched\fR(8) helper program\&. You can use it along with upsmon to schedule a shutdown based on the "on battery" event\&. upssched can then come back to upsmon to initiate the shutdown once it has run on battery too long\&. .sp This can be complicated and messy, so stick to the default critical UPS handling if you can\&. .SH "REDUNDANT POWER SUPPLIES" .sp If you have more than one power supply for redundant power, you may also have more than one UPS feeding your computer\&. upsmon can handle this\&. Be sure to set the UPS power values appropriately and the MINSUPPLIES value high enough so that it keeps running until it really does need to shut down\&. .sp For example, the HP NetServer LH4 by default has 3 power supplies installed, with one bay empty\&. It has two power cords, one per side of the box\&. This means that one power cord powers two power supply bays, and that you can only have two UPSes supplying power\&. .sp Connect UPS "alpha" to the cord feeding two power supplies, and UPS "beta" to the cord that feeds the third and the empty slot\&. Define alpha as a powervalue of 2, and beta as a powervalue of 1\&. Set the MINSUPPLIES to 2\&. .sp When alpha goes on battery, your current overall power value will stay at 3, as it\(cqs still supplying power\&. However, once it goes critical (on battery and low battery), it will stop contributing to the current overall power value\&. That means the value will be 1 (beta alone), which is less than 2\&. That is insufficient to run the system, and upsmon will invoke the shutdown sequence\&. .sp However, if beta goes critical, subtracting its contribution will take the current overall value from 3 to 2\&. This is just high enough to satisfy the minimum, so the system will continue running as before\&. If beta returns later, it will be re\-added and the current value will go back to 3\&. This allows you to swap out UPSes, change a power configuration, or whatever, as long as you maintain the minimum power value at all times\&. .SH "MIXED OPERATIONS" .sp Besides being able to monitor multiple UPSes, upsmon can also monitor them as different roles\&. If you have a system with multiple power supplies serviced by separate UPS batteries, it\(cqs possible to be a primary on one UPS and a secondary on the other\&. This usually happens when you run out of serial or USB ports and need to do the monitoring through another system nearby\&. .sp This is also complicated, especially when it comes time to power down a UPS that has gone critical but doesn\(cqt supply the local system\&. You can do this with some scripting magic in your notify command script, but it\(cqs beyond the scope of this manual\&. .SH "FORCED SHUTDOWNS" .sp When upsmon is forced to bring down the local system, it sets the "FSD" (forced shutdown) flag on any UPSes that it is running in primary mode\&. This is used to synchronize secondary systems in the event that a primary which is otherwise OK needs to be brought down due to some pressing event on the UPS manager system\&. .sp You can manually invoke this mode on the system with primary\-mode upsmon by starting another copy of the program with \-c fsd command line argument\&. This is useful when you want to initiate a shutdown before the critical stage through some external means, such as \fBupssched\fR(8)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br .sp Please note that by design, since we require power\-cycling the load and don\(cqt want some systems to be powered off while others remain running if the "wall power" returns at the wrong moment as usual, the "FSD" flag can not be removed from the data server unless its daemon is restarted\&. If we do take the first step in critical mode, then we normally intend to go all the way \(em shut down all the servers gracefully, and power down the UPS\&. .sp .5v .RE .sp Keep in mind that some UPS devices and corresponding drivers would also latch or otherwise resurface the "FSD" state again even if "wall power" is available, but the remaining battery charge is below a threshold configured as "safe" in the device (usually if you manually power on the UPS after a long power outage)\&. This is by design of respective UPS vendors, since in such situation they can not guarantee that if a new power outage happens, their UPS would safely shut down your systems again\&. So it is deemed better and safer to stay dark until batteries become sufficiently charged\&. .sp When it is time to shut down, upsmon creates POWERDOWNFLAG to communicate to the operating system that the UPS should be commanded off late in the shutdown sequence\&. This file is removed if present when upsmon starts, so that the next normal shutdown does not cause the UPS to be turned off\&. (The file can\(cqt in general be removed during shutdown because the filesystem might be read only\&. If the file is in a RAM\-backed filesystem, the it won\(cqt be present and the check to remove it won\(cqt fire\&.) .SH "SIMULATING POWER FAILURES" .sp To test a synchronized shutdown without pulling the plug on your UPS(es), you need only set the forced shutdown (FSD) flag on them\&. You can do this by calling upsmon again to set the flag, i\&.e\&.: .sp .if n \{\ .RS 4 .\} .nf :; upsmon \-c fsd .fi .if n \{\ .RE .\} .sp After that, the primary and the secondary will do their usual shutdown sequence as if the battery had gone critical, while you can time how long it takes for them\&. This is much easier on your UPS equipment, and it beats crawling under a desk to find the plug\&. .sp Note you can also use a dummy SHUTDOWNCMD setting to just report that the systems would shut down at this point, without actually disrupting their work\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br .sp After such "dummy" experiments you may have to restart the NUT data server upsd to clear its "FSD" flag for the devices and clients involved, and make sure no files named by POWERDOWNFLAG option (e\&.g\&. /etc/killpower) remain on the upsmon primary systems under test\&. .sp .5v .RE .SH "DEAD UPSES" .sp In the event that upsmon can\(cqt reach \fBupsd\fR(8), it declares that UPS "dead" after some interval controlled by DEADTIME in the \fBupsmon.conf\fR(5)\&. If this happens while that UPS was last known to be on battery, it is assumed to have gone critical and no longer contributes to the overall power value\&. .sp upsmon will alert you to a UPS that can\(cqt be contacted for monitoring with a "NOCOMM" notifier by default every 300 seconds\&. This can be changed with the NOCOMMWARNTIME setting\&. .sp Also upsmon normally reports polling failures for each device that are in place for each POLLFREQ loop (e\&.g\&. "Data stale" or "Driver not connected") to system log as configured\&. If your devices are expected to be AWOL for an extended timeframe, you can use POLLFAIL_LOG_THROTTLE_MAX to reduce the stress on syslog traffic and storage, by posting these messages only once in every several loop cycles, and when the error condition has changed or cleared\&. A negative value means standard behavior (log on every loop, effectively same as when max=1), and a zero value means to never repeat the message (log only on start and end/change of the failure state)\&. .sp Note that this throttle only applies to one latest\-active error state per monitored device\&. .SH "UPS ALARMS" .sp UPS manufacturers and UPS drivers may implement device\-specific alarms to notify the user about potentially severe conditions of the UPS\&. The status "ALARM" will be set on such UPS as a common denominator for the different implementations throughout the various UPS drivers and generally anytime that a "ups\&.alarm" variable is seen reported by the specific UPS driver\&. .sp Alarms can be acted upon by the user using the "ALARM" and "NOTALARM" notifiers, which are reported by the upsmon when the "ALARM" status occurs or disappears\&. .sp As alarms raised by the UPS are usually severe in nature, the upsmon watches a UPS in such a state more closely, bumping up the polling frequency as needed\&. .sp When connection loss occurs in such an alarm state, the upsmon will by default consider the volatile UPS as critical/dead and this may lead to false shutdowns if the actual alarm was in fact mundane in nature (e\&.g\&. caused by a HE/ECO mode)\&. This can be changed by utilizing the ALARMCRITICAL setting within upsmon\&.conf\&. .SH "RELOADING NUANCES" .sp upsmon usually gives up root powers for the process that does most of the work, including handling signals like SIGHUP to reload the configuration file\&. This means your \fBupsmon.conf\fR(8) file must be readable by the non\-root account that upsmon switches to\&. .sp If you want reloads to work, upsmon must run as some user that has permissions to read the configuration file\&. I recommend making a new user just for this purpose, as making the file readable by "nobody" (the default user) would be a bad idea\&. .sp See the RUN_AS_USER section in \fBupsmon.conf\fR(8) for more on this topic\&. .sp Additionally, you can\(cqt change the SHUTDOWNCMD or POWERDOWNFLAG definitions with a reload due to the split\-process model\&. If you change those values, you \fBmust\fR stop upsmon and start it back up\&. upsmon will warn you in the syslog if you make changes to either of those values during a reload\&. .SH "ENVIRONMENT VARIABLES" .sp \fBNUT_DEBUG_LEVEL\fR sets default debug verbosity if no \fB\-D\fR arguments were provided on command line, but does not request that the daemon runs in foreground mode\&. .sp \fBNUT_CONFPATH\fR is the path name of the directory that contains upsmon\&.conf and other configuration files\&. If this variable is not set, \fBupsmon\fR uses a built\-in default, which is often /usr/local/ups/etc\&. .sp \fBNUT_QUIET_INIT_UPSNOTIFY=true\fR can be used to prevent daemons which can notify service management frameworks (such as systemd) about passing their lifecycle milestones from emitting such notifications (including those about lack of system support for such modern features, once per run)\&. .sp \fBNUT_QUIET_INIT_BANNER=true\fR can be used to suppress NUT tool name and version banner\&. NOT recommended for services due to adverse troubleshooting impact, but may be helpful in shell profiles or scripts which process NUT tool outputs\&. .SH "FILES" .sp \fBupsmon.conf\fR(5) .SH "SEE ALSO" .SS "Server:" .sp \fBupsd\fR(8) .SS "Clients:" .sp \fBupsc\fR(8), \fBupscmd\fR(8), \fBupsrw\fR(8), \fBupsmon\fR(8) .SS "CGI programs:" .sp \fBupsset.cgi\fR(8), \fBupsstats.cgi\fR(8), \fBupsimage.cgi\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nut.exe.txt0000644000200500020050000000775415001555412013104 00000000000000NUT.EXE(8) ========== NAME ---- nut.exe - NUT for Windows wrapper for all-in-one service SYNOPSIS -------- *nut.exe* {-h | /?} *nut.exe* ['OPTIONS'] *nut.exe* (as a service implementation) DESCRIPTION ----------- *nut.exe* wraps NUT programs to start and stop as a Windows service. Depending on linkman:nut.conf[5] setting of 'MODE', it would manage the bundle of driver(s), linkman:upsd[8] data server and linkman:upsmon[8] client, as well as attempt an UPS shutdown command in case of FSD handling, or for mere 'netclient' systems it would run just the linkman:upsmon[8] client to monitor remote UPS device(s) and initiate the OS shut down on the local Windows system as applicable. Beside launching or stopping a set of the NUT programs in certain cases, this helper program also allows to register (or un-register) itself as a Windows service. To actually manage the service from command line you can execute the Windows `net` command, e.g.: ---- net stop "Network UPS Tools" net start "Network UPS Tools" ---- You can also execute `nut start` to automatically register the service (if not yet registered) and start it, and `nut stop` to stop the service (if registered and running). Note that for a Windows machine to act as a NUT data server for further clients, you may have to add Windows Firewall rules to allow incoming connections (by default to port `3493/tcp`), e.g. using PowerShell to elevate (alternately right-click a "Command Prompt" shortcut and select "Run as administrator"), and execute `netsh` to actually configure the needed "Advanced Firewall" rule: ---- REM Elevate to administrator status then run netsh to add firewall rule. REM Recommended to adapt "LocalIP" to expected listeners of this server, REM and "RemoteIP" to your single or comma-separated subnet(s) in CIDR REM notation, specific client IP address(es), or ranges of address(es) REM (dash-separated, as IP1-IP2). REM The following goes as one long command line: powershell.exe -Command "Start-Process netsh.exe -ArgumentList \"advfirewall firewall add rule name=NUT-upsd-data-server dir=in action=allow localip=ANY remoteip=ANY program=%ProgramFiles%\NUT\sbin\upsd.exe localport=3493 protocol=tcp\" -Verb RunAs" ---- Keep in mind that by default NUT linkman:upsd[8] only listens on `localhost`, so you would need to add some `LISTEN` directives in linkman:upsd.conf[5] as well in this case. OPTIONS ------- *nut.exe* is currently launched with no arguments when it is intended to run as the implementation of a registered Windows service; it would error out otherwise. */?*:: Display the help text and exit. *-h*:: Display the help text and exit. *-V*:: Display NUT version and exit. *-D*:: Raise the debug level. Use this multiple times for additional details. The non-trivial debug level would be passed down to launched NUT programs. Primarily useful for troubleshooting with the non-service mode. *-I*:: Install as a Windows service called "Network UPS Tools". *-U*:: Uninstall the Windows service. *-N*:: Run once in non-service mode (for troubleshooting). *start*:: Install as a Windows service called "Network UPS Tools" (if not yet done), and try to start this service. *stop*:: Try to stop a Windows service called "Network UPS Tools". DIAGNOSTICS ----------- *nut.exe* should not interact with console message buffers (`stdout`, `stderr`) much, except when explicitly asked to (e.g. displaying help and NUT version, running with verbose debug mode) or when exiting after an attempted service initialization while not running in a service context. Most of normal logging from *nut.exe* goes to the Windows Event Log. Launched NUT programs may emit messages of their own; their fate when no console is attached is questionable. SEE ALSO -------- linkman:nut.conf[5], linkman:ups.conf[5], linkman:nutupsdrv[8], linkman:upsd[8], linkman:upsd.conf[5], linkman:upsd.users[5], linkman:upsmon[8], linkman:upsmon.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/liebert-esp2.80000644000200500020050000000654215001555072013337 00000000000000'\" t .\" Title: liebert-esp2 .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIEBERT\-ESP2" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" liebert-esp2 \- Driver for Liebert UPS, using the ESP\-II serial protocol .SH "SYNOPSIS" .sp \fBliebert\-esp2\fR \-h .sp \fBliebert\-esp2\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the liebert\-esp2 driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SPECIAL CABLING NOTE" .sp Be aware that an RS\-232 cable with ONLY the RX, TX and ground pin must be used when interfacing with GXT2 series UPS units (and possibly others), since the handshaking lines are used for purposes other than RS\-232 flow control\&. .sp Use of a standard RS\-232 cable with full handshaking may result in undesired operation and/or shutdown\&. It is therefore advisable to confirm the proper cable/wiring with the diagram provided in the manual with your UPS\&. .SH "SUPPORTED HARDWARE" .sp Tested to work on the following units: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Liebert GXT2\-6000RT208 .RE .sp This is an experimental driver\&. You have been warned\&. .sp This driver currently does not support modification of configuration parameters, such as the low battery warning time and automatic restart policy\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in \fBups.conf\fR(5): .PP \fBbaudrate=\fR\fInum\fR .RS 4 Set the speed of the serial connection \(em 1200, 2400 (default), 4800, 9600 or 19200\&. .RE .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Richard Gregory .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arjen de Korte .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Nash Kaminski .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutclient_set_device_variable_value.30000644000200500020050000000004215001555117020262 00000000000000.so man3/libnutclient_variables.3 nut-2.8.3/docs/man/nutscan_scan_nut.30000644000200500020050000000700215001555057014375 00000000000000'\" t .\" Title: nutscan_scan_nut .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_SCAN_NUT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_scan_nut \- Scan network for available NUT services\&. .SH "SYNOPSIS" .sp .nf #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_nut( const char * startIP, const char * stopIP, const char * port, useconds_t usec_timeout); nutscan_device_t * nutscan_scan_ip_range_nut( nutscan_ip_range_list_t * irl, const char * port, useconds_t usec_timeout); .fi .SH "DESCRIPTION" .sp The \fBnutscan_scan_nut()\fR and \fBnutscan_scan_ip_range_nut()\fR functions try to detect available NUT services and their associated devices\&. The former issues a NUT request on every IP ranging from \fIstartIP\fR to \fIstopIP\fR, where \fIstartIP\fR is mandatory and \fIstopIP\fR is optional (one \fIstartIP\fR address is scanned if \fIstopIP\fR is NULL); while the latter can walk several IP address ranges represented by a nutscan_ip_range_list_t structure\&. .sp Those IP arguments may be either IPv4 or IPv6 addresses or host names\&. .sp You MUST call \fBnutscan_init\fR(3) before using this function\&. .sp A specific \fIport\fR number may be passed, or NULL to use the default NUT port\&. .sp This function waits up to \fIusec_timeout\fR microseconds before considering an IP address does not respond to NUT queries\&. .SH "RETURN VALUE" .sp The \fBnutscan_scan_nut()\fR function returns a pointer to a nutscan_device_t structure containing all found devices or NULL if an error occurs or no device is found\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_scan_eaton_serial\fR(3), \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_add_ip_range\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/upsmon.txt0000644000200500020050000005727215001555412013037 00000000000000UPSMON(8) ========= NAME ---- upsmon - UPS monitor and shutdown controller SYNOPSIS -------- *upsmon* -h *upsmon* -c 'command' [-P 'pid'] *upsmon* [-D] [-F | -B] [-K] [-p] [-u 'user'] DESCRIPTION ----------- *upsmon* is the client process that is responsible for the most important part of UPS monitoring -- shutting down the system when the power goes out. It can call out to other helper programs for notification purposes during power events. upsmon can monitor multiple systems using a single process. Every UPS that is defined in the linkman:upsmon.conf[5] configuration file is assigned a power value and a type (*primary* or *secondary*). OPTIONS ------- *-c* 'command':: Send the command 'command' to the existing upsmon process. Valid commands are: *fsd*;; shutdown all primary-mode UPSes (use with caution) *stop*;; stop monitoring and exit *reload*;; reread linkman:upsmon.conf[5] configuration file. See "reloading nuances" below if this doesn't work. *-P* 'pid':: Send the command signal above using specified PID number, rather than consulting the PID file. This can help define service units which start main `upsmon` as a foreground process so it does not have to rely on a PID file. *-D*:: Raise the debugging level. upsmon will run in the foreground by default, and will print information on stdout about the monitoring process. Use this option multiple times for more details. *-F*:: upsmon will run in the foreground, regardless of debugging settings. *-B*:: upsmon will run in the background, regardless of debugging settings. *-K*:: Test for the shutdown flag. If it exists and contains the magic string from upsmon, then upsmon will exit with `EXIT_SUCCESS`. Any other condition will make upsmon exit with `EXIT_FAILURE`. + You can test for a successful exit from `upsmon -K` in your shutdown scripts to know when to call linkman:upsdrvctl[8] to shut down the UPS. *-p*:: Run privileged all the time. Normally upsmon will split into two processes. The majority of the code runs as an unprivileged user, and only a tiny stub runs as root. This switch will disable that mode, and run the old "all root all the time" system. + This is not the recommended mode, and you should not use this unless you have a very good reason. *-u* 'user':: Set the user for the unprivileged monitoring process. This has no effect when using -p. + The default 'user' is set at build configuration time with `configure --with-user=...`. Typically this is 'nobody' (if not otherwise configured), which is far from ideal, so most packaged distributions will probably have a specific 'nut' user for this task. If your notification scripts need to run as a specific user, set it here. + You can also set this in the linkman:upsmon.conf[5] file with the `RUN_AS_USER` directive. COMMON OPTIONS -------------- *-h*:: Show the command-line help message. *-V*:: Show NUT version banner. More details may be available if you also `export NUT_DEBUG_LEVEL=1` or greater verbosity level. *-W* 'secs':: Set the timeout for initial network connections (by default they are indefinitely non-blocking, or until the system interrupts the attempt). Overrides the optional `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable. UPS DEFINITIONS --------------- In the linkman:upsmon.conf[5], you must specify at least one UPS that will be monitored. Use the MONITOR directive like this: MONITOR 'system' 'powervalue' 'username' 'password' 'type' The 'system' refers to a linkman:upsd[8] server, in the form +upsname[@hostname[:port]]+. The default 'hostname' is "localhost", and default 'port' is '3493'. Some examples follow: - "su700@mybox" means a UPS called "su700" on a system called "mybox". This is the normal form. - "fenton@bigbox:5678" is a UPS called "fenton" on a system called "bigbox" which runs linkman:upsd[8] on port "5678". The 'powervalue' refers to how many power supplies on this client system are being driven this UPS. This is typically set to '1', but see the section on power values below. The 'username' is a section in your linkman:upsd.users[5] file. Whatever password you set in that section must match the 'password' set in this file for the corresponding data server instance. The type set in that section of the data server configuration must also match the 'type' here -- *primary* or *secondary* (consider it an "upsmon role"). In general, a "primary" client process is one running on the system with the UPS actually plugged into a serial or USB port, and a "secondary" is drawing power from the UPS but can't talk to it directly. See the section on UPS types for more. NOTIFY EVENTS ------------- *upsmon* senses several events as it monitors each UPS. They are called "notify events", as they can be used to tell the users and admins about the change in status. See the additional NOTIFY-related sections below for information on customizing the delivery of these messages. *ONLINE*:: The UPS is back on line. *ONBATT*:: The UPS is on battery. *LOWBATT*:: The UPS battery is low (as determined by the driver). *FSD*:: The UPS has been commanded into the "forced shutdown" mode. *COMMOK*:: Communication with the UPS has been established. *COMMBAD*:: Communication with the UPS was just lost. *SHUTDOWN*:: The local system is being shut down. *REPLBATT*:: The UPS needs to have its battery replaced. *NOCOMM*:: The UPS can't be contacted for monitoring. *NOPARENT*:: `upsmon` parent process died - shutdown impossible. *CAL*:: UPS calibration in progress. *NOTCAL*:: UPS calibration finished. *OFF*:: UPS administratively OFF or asleep. *NOTOFF*:: UPS no longer administratively OFF or asleep. *BYPASS*:: UPS on bypass (powered, not protecting). *NOTBYPASS*:: UPS no longer on bypass. *ECO*:: UPS in ECO or similar mode (as defined and named by vendor); other names include High Efficiency mode and Energy Saver System. + For example, Eaton docs define High Efficiency mode as a sort of hardware-monitored bypass with switch-over under 10ms into Online mode in case of troubles (so what was known as Line-Interactive in the older days), which can be *chosen* instead of always running in a dual-conversion mode (safer, but more wasteful and with a toll on battery life). Older devices only implemented one or the other. *NOTECO*:: UPS no longer in ECO mode (see above). *ALARM*:: UPS has one or more active alarms (look at `ups.alarm` for details). *NOTALARM*:: UPS is no longer in an alarm state (no active alarms). *OVER*:: UPS is overloaded. *NOTOVER*:: UPS is no longer overloaded. *TRIM*:: UPS is trimming incoming voltage. *NOTTRIM*:: UPS is no longer trimming incoming voltage. *BOOST*:: UPS is boosting incoming voltage. *NOTBOOST*:: UPS is no longer boosting incoming voltage. *OTHER*:: UPS has at least one unclassified status token. *NOTOTHER*:: UPS has no unclassified status tokens anymore. *SUSPEND_STARTING*:: OS is entering sleep/suspend/hibernate mode. *SUSPEND_FINISHED*:: OS just finished sleep/suspend/hibernate mode, de-activating obsolete UPS readings to avoid an unfortunate shutdown. NOTIFY COMMAND -------------- In linkman:upsmon.conf[5], you can configure a program called the NOTIFYCMD that will handle events that occur. The syntax is: +NOTIFYCMD+ "'path to program'" Example: - `NOTIFYCMD "/usr/local/bin/notifyme"` Remember to wrap the path in "double quotes" if it contains any spaces. It should probably not rely on receiving any command-line arguments. The program you run as your NOTIFYCMD can use the environment variables NOTIFYTYPE and UPSNAME to know what has happened and on which UPS. It also receives the notification message (see below) as the first (and only) argument, so you can deliver a pre-formatted message too. Note that the NOTIFYCMD will only be called for a given event when you set the EXEC flag by using the notify flags, as detailed below. NOTIFY FLAGS ------------ By default, all notify events (see above) generate a global message (wall) to all users, plus they are logged via the syslog. Except for Windows where upsmon only writes to the syslog by default. You can change this with the NOTIFYFLAG directive in the configuration file: The syntax is: +NOTIFYFLAG+ 'notifytype' 'flags' Examples: - `NOTIFYFLAG ONLINE SYSLOG` - `NOTIFYFLAG ONBATT SYSLOG+WALL` - `NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC` The flags that can be set on a given notify event are: *SYSLOG*:: Write this message to the syslog. *WALL*:: Send this message to all users on the system via linkmanext:wall[1]. *EXEC*:: Execute the NOTIFYCMD. *IGNORE*:: Don't do anything. If you use this, don't use any of the other flags. You can mix these flags; for example, `SYSLOG+WALL+EXEC` does all three for a given event. NOTIFY MESSAGES --------------- upsmon comes with default messages for each of the NOTIFY events. These can be changed with the NOTIFYMSG directive. The syntax is: +NOTIFYMSG+ 'type' "'message'" Examples: - `NOTIFYMSG ONLINE "UPS %s is getting line power"` - `NOTIFYMSG ONBATT "Someone pulled the plug on %s"` The first instance of `%s` is replaced with the identifier of the UPS that generated the event. These messages are used when sending walls to the users directly from upsmon, and are also passed to the NOTIFYCMD. NOTE: Certain notifications, such as `NOTIFY_ALARM` and `NOTIFY_OTHER`, can accept a second instance of `%s` that would be replaced with the alarm text or the unrecognized token, respectively. POWER VALUES ------------ The "current overall power value" is the sum of all UPSes that are currently able to supply power to the system hosting upsmon. Any UPS that is either on line or just on battery contributes to this number. If a UPS is critical (on battery and low battery) or has been put into "forced shutdown" mode, it no longer contributes. The syntax is: +MONITOR+ 'upsname' 'powervalue' 'username' 'password' 'type' A "power value" on a MONITOR line in the config file is the number of power supplies that the UPS runs on the current system. * Normally, you only have one power supply, so it will be set to '1'. + Example: - `MONITOR myups@myhost 1 username mypassword primary` * On a large server with redundant power supplies, the power value for a UPS may be greater than 1. You may also have more than one of them defined. + Examples for a server with four power supply modules and two UPSes (each feeding two power supplies of that server): - `MONITOR ups-alpha@myhost 2 username mypassword primary` - `MONITOR ups-beta@myhost 2 username mypassword primary` * You can also set the power value for a UPS to '0' if it does not supply any power to that system. This is generally used when you want to use the upsmon notification features for a UPS even though it's not actually powering the system that hosts this instance of the upsmon client. + Don't set this to "primary" unless you really want to power this UPS off when this instance of upsmon needs to shut down for its own reasons. + Example: - `MONITOR faraway@anotherbox 0 username mypassword secondary` The "minimum power value" is the number of power supplies that must be receiving power in order to keep this `upsmon` client's computer running. The syntax is: +MINSUPPLIES+ 'value' * Typical PCs only have 1, so most users will leave this at the default. + Example: - `MINSUPPLIES 1` * If you have a server or similar system with redundant power, then this value will usually be set higher. One that requires three power supplies out of 4 to be running at all times would simply set it to 3. + -- Example: - `MINSUPPLIES 3` -- + When the current overall healthy UPS-protected external power value drops below the minimum required power value, `upsmon` starts the shutdown sequence. This design allows you to lose some of your power supplies in a redundant power environment without bringing down the entire system, while still working properly for smaller systems. UPS TYPES --------- *upsmon* and linkman:upsd[8] don't always run on the same system. When they do, any UPSes that are directly attached to the upsmon host should be monitored in "primary" mode. This makes upsmon take charge of that equipment, and it will wait for the "secondary" systems to disconnect before shutting down the local system. This allows the distant systems (monitoring over the network) to shut down cleanly before `upsdrvctl shutdown` runs locally and turns them all off. When upsmon runs as a secondary, it is relying on the distant system to tell it about the state of the UPS. When that UPS goes critical (on battery and low battery), it immediately invokes the local shutdown command. This needs to happen quickly. Once all secondaries disconnect from the distant linkman:upsd[8] server, its primary-mode upsmon will start its own shutdown process. Your secondary systems must all quiesce and shut down before the primary turns off the shared power source, or filesystem damage may result. upsmon deals with secondaries that get wedged, hang, or otherwise fail to gracefully disconnect from linkman:upsd[8] in a timely manner with the HOSTSYNC timer. During a shutdown situation, the primary upsmon will give up after this interval and it will shut down anyway. This keeps the primary from sitting there forever (which would endanger that host) if a secondary should break somehow. This defaults to 15 seconds. If your primary system is shutting down too quickly, set the FINALDELAY interval to something greater than the default 15 seconds. Don't set this too high, or your UPS battery may run out of power before the primary upsmon process shuts down that system. TIMED SHUTDOWNS --------------- For those rare situations where the shutdown process can't be completed between the time that low battery is signalled and the UPS actually powers off the load, use the linkman:upssched[8] helper program. You can use it along with upsmon to schedule a shutdown based on the "on battery" event. upssched can then come back to upsmon to initiate the shutdown once it has run on battery too long. This can be complicated and messy, so stick to the default critical UPS handling if you can. REDUNDANT POWER SUPPLIES ------------------------ If you have more than one power supply for redundant power, you may also have more than one UPS feeding your computer. upsmon can handle this. Be sure to set the UPS power values appropriately and the MINSUPPLIES value high enough so that it keeps running until it really does need to shut down. For example, the HP NetServer LH4 by default has 3 power supplies installed, with one bay empty. It has two power cords, one per side of the box. This means that one power cord powers two power supply bays, and that you can only have two UPSes supplying power. Connect UPS "alpha" to the cord feeding two power supplies, and UPS "beta" to the cord that feeds the third and the empty slot. Define alpha as a powervalue of 2, and beta as a powervalue of 1. Set the MINSUPPLIES to 2. When alpha goes on battery, your current overall power value will stay at 3, as it's still supplying power. However, once it goes critical (on battery and low battery), it will stop contributing to the current overall power value. That means the value will be 1 (beta alone), which is less than 2. That is insufficient to run the system, and upsmon will invoke the shutdown sequence. However, if beta goes critical, subtracting its contribution will take the current overall value from 3 to 2. This is just high enough to satisfy the minimum, so the system will continue running as before. If beta returns later, it will be re-added and the current value will go back to 3. This allows you to swap out UPSes, change a power configuration, or whatever, as long as you maintain the minimum power value at all times. MIXED OPERATIONS ---------------- Besides being able to monitor multiple UPSes, upsmon can also monitor them as different roles. If you have a system with multiple power supplies serviced by separate UPS batteries, it's possible to be a primary on one UPS and a secondary on the other. This usually happens when you run out of serial or USB ports and need to do the monitoring through another system nearby. This is also complicated, especially when it comes time to power down a UPS that has gone critical but doesn't supply the local system. You can do this with some scripting magic in your notify command script, but it's beyond the scope of this manual. FORCED SHUTDOWNS ---------------- When upsmon is forced to bring down the local system, it sets the "FSD" (forced shutdown) flag on any UPSes that it is running in primary mode. This is used to synchronize secondary systems in the event that a primary which is otherwise OK needs to be brought down due to some pressing event on the UPS manager system. You can manually invoke this mode on the system with primary-mode upsmon by starting another copy of the program with `-c fsd` command line argument. This is useful when you want to initiate a shutdown before the critical stage through some external means, such as linkman:upssched[8]. WARNING: Please note that by design, since we require power-cycling the load and don't want some systems to be powered off while others remain running if the "wall power" returns at the wrong moment as usual, the "FSD" flag can not be removed from the data server unless its daemon is restarted. If we do take the first step in critical mode, then we normally intend to go all the way -- shut down all the servers gracefully, and power down the UPS. Keep in mind that some UPS devices and corresponding drivers would also latch or otherwise resurface the "FSD" state again even if "wall power" is available, but the remaining battery charge is below a threshold configured as "safe" in the device (usually if you manually power on the UPS after a long power outage). This is by design of respective UPS vendors, since in such situation they can not guarantee that if a new power outage happens, their UPS would safely shut down your systems again. So it is deemed better and safer to stay dark until batteries become sufficiently charged. When it is time to shut down, upsmon creates POWERDOWNFLAG to communicate to the operating system that the UPS should be commanded off late in the shutdown sequence. This file is removed if present when upsmon starts, so that the next normal shutdown does not cause the UPS to be turned off. (The file can't in general be removed during shutdown because the filesystem might be read only. If the file is in a RAM-backed filesystem, the it won't be present and the check to remove it won't fire.) SIMULATING POWER FAILURES ------------------------- To test a synchronized shutdown without pulling the plug on your UPS(es), you need only set the forced shutdown (FSD) flag on them. You can do this by calling upsmon again to set the flag, i.e.: :; upsmon -c fsd After that, the primary and the secondary will do their usual shutdown sequence as if the battery had gone critical, while you can time how long it takes for them. This is much easier on your UPS equipment, and it beats crawling under a desk to find the plug. Note you can also use a dummy SHUTDOWNCMD setting to just report that the systems would shut down at this point, without actually disrupting their work. WARNING: After such "dummy" experiments you may have to restart the NUT data server `upsd` to clear its "FSD" flag for the devices and clients involved, and make sure no files named by `POWERDOWNFLAG` option (e.g. `/etc/killpower`) remain on the `upsmon primary` systems under test. DEAD UPSES ---------- In the event that upsmon can't reach linkman:upsd[8], it declares that UPS "dead" after some interval controlled by DEADTIME in the linkman:upsmon.conf[5]. If this happens while that UPS was last known to be on battery, it is assumed to have gone critical and no longer contributes to the overall power value. upsmon will alert you to a UPS that can't be contacted for monitoring with a "NOCOMM" notifier by default every 300 seconds. This can be changed with the NOCOMMWARNTIME setting. Also upsmon normally reports polling failures for each device that are in place for each POLLFREQ loop (e.g. "Data stale" or "Driver not connected") to system log as configured. If your devices are expected to be AWOL for an extended timeframe, you can use POLLFAIL_LOG_THROTTLE_MAX to reduce the stress on syslog traffic and storage, by posting these messages only once in every several loop cycles, and when the error condition has changed or cleared. A negative value means standard behavior (log on every loop, effectively same as when `max=1`), and a zero value means to never repeat the message (log only on start and end/change of the failure state). Note that this throttle only applies to one latest-active error state per monitored device. UPS ALARMS ---------- UPS manufacturers and UPS drivers may implement device-specific alarms to notify the user about potentially severe conditions of the UPS. The status "ALARM" will be set on such UPS as a common denominator for the different implementations throughout the various UPS drivers and generally anytime that a "ups.alarm" variable is seen reported by the specific UPS driver. Alarms can be acted upon by the user using the "ALARM" and "NOTALARM" notifiers, which are reported by the `upsmon` when the "ALARM" status occurs or disappears. As alarms raised by the UPS are usually severe in nature, the `upsmon` watches a UPS in such a state more closely, bumping up the polling frequency as needed. When connection loss occurs in such an alarm state, the `upsmon` will by default consider the volatile UPS as critical/dead and this may lead to false shutdowns if the actual alarm was in fact mundane in nature (e.g. caused by a HE/ECO mode). This can be changed by utilizing the `ALARMCRITICAL` setting within `upsmon.conf`. RELOADING NUANCES ----------------- upsmon usually gives up root powers for the process that does most of the work, including handling signals like SIGHUP to reload the configuration file. This means your linkman:upsmon.conf[8] file must be readable by the non-root account that upsmon switches to. If you want reloads to work, upsmon must run as some user that has permissions to read the configuration file. I recommend making a new user just for this purpose, as making the file readable by "nobody" (the default user) would be a bad idea. See the RUN_AS_USER section in linkman:upsmon.conf[8] for more on this topic. Additionally, you can't change the SHUTDOWNCMD or POWERDOWNFLAG definitions with a reload due to the split-process model. If you change those values, you *must* stop upsmon and start it back up. upsmon will warn you in the syslog if you make changes to either of those values during a reload. ENVIRONMENT VARIABLES --------------------- *NUT_DEBUG_LEVEL* sets default debug verbosity if no *-D* arguments were provided on command line, but does not request that the daemon runs in foreground mode. *NUT_CONFPATH* is the path name of the directory that contains `upsmon.conf` and other configuration files. If this variable is not set, *upsmon* uses a built-in default, which is often `/usr/local/ups/etc`. *NUT_QUIET_INIT_UPSNOTIFY=true* can be used to prevent daemons which can notify service management frameworks (such as systemd) about passing their lifecycle milestones from emitting such notifications (including those about lack of system support for such modern features, once per run). *NUT_QUIET_INIT_BANNER=true* can be used to suppress NUT tool name and version banner. NOT recommended for services due to adverse troubleshooting impact, but may be helpful in shell profiles or scripts which process NUT tool outputs. FILES ----- linkman:upsmon.conf[5] SEE ALSO -------- Server: ~~~~~~~ linkman:upsd[8] Clients: ~~~~~~~~ linkman:upsc[8], linkman:upscmd[8], linkman:upsrw[8], linkman:upsmon[8] CGI programs: ~~~~~~~~~~~~~ linkman:upsset.cgi[8], linkman:upsstats.cgi[8], linkman:upsimage.cgi[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_scan_avahi.30000644000200500020050000000542615001555060014661 00000000000000'\" t .\" Title: nutscan_scan_avahi .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_SCAN_AVAHI" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_scan_avahi \- Scan network for NUT services via mDNS .SH "SYNOPSIS" .sp .nf #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_avahi(useconds_t usec_timeout); .fi .SH "DESCRIPTION" .sp The \fBnutscan_scan_avahi()\fR function tries to detect the NUT service via mDNS, and its associated devices\&. It uses the Avahi library to do so\&. .sp You MUST call \fBnutscan_init\fR(3) before using this function\&. .sp This function can query perspective IP addresses using NUT protocol, and in this case it waits up to \fIusec_timeout\fR microseconds before considering an IP address to be unresponsive\&. .SH "RETURN VALUE" .sp The \fBnutscan_scan_avahi()\fR function returns a pointer to a nutscan_device_t structure containing all found devices\&. .sp It returns NULL if an error occurs, or if no device is found\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_cidr_to_ip\fR(3), \fBnutscan_scan_eaton_serial\fR(3) .SS "Internet resources:" .sp http://avahi\&.org/ nut-2.8.3/docs/man/nutscan_ip_ranges_iter_inc.30000644000200500020050000000534015001555062016405 00000000000000'\" t .\" Title: nutscan_ip_ranges_iter_inc .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_IP_RANGES_IT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_ip_ranges_iter_inc \- Proceed with iteration of an IP address range using a `nutscan_ip_range_list_iter_t` structure\&. .SH "SYNOPSIS" .sp .nf #include char * nutscan_ip_ranges_iter_inc(nutscan_ip_range_list_iter_t *irliter); .fi .SH "DESCRIPTION" .sp The \fBnutscan_ip_ranges_iter_inc()\fR function can walk an iterator from the specified nutscan_ip_range_list_iter_t helper object, prepared by \fBnutscan_ip_ranges_iter_init\fR(3) from a nutscan_ip_range_list_t structure\&. .sp This function skips work if: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the structure pointer is NULL (NULL is returned); .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the structure pointer\(cqs ip_range list is NULL (NULL is returned), .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the structure pointer\(cqs ip_range_iter pointer is NULL (NULL is returned)\&. .RE .sp Returns the next IP address from the currently iterated registered IP address range, or switches iteration to the next range if no addresses remained in the current one\&. The caller SHOULD NOT free this string while iterating\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-ip\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_cidr_to_ip\fR(3), \fBnutscan_ip_ranges_iter_init\fR(3) nut-2.8.3/docs/man/clone-outlet.txt0000644000200500020050000001672415001555412014125 00000000000000CLONE-OUTLET(8) =============== NAME ---- clone-outlet - Clone an UPS, treating its outlet as if it were an UPS (monitoring only) SYNOPSIS -------- *clone-outlet* -h *clone-outlet* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the clone-outlet driver. For information about the core driver, see linkman:nutupsdrv[8]. DESCRIPTION ----------- This driver, which sits on top of another driver's local UNIX socket file (or Windows named pipe), allows users to group clients to a particular outlet of a device and deal with this output as if it were a normal UPS. Unlike the linkman:clone[8] driver or linkman:dummy-ups[8] driver running in repeater mode, this driver represents a read-only device for monitoring and shutdowns (it does not accept setting any values or sending instant commands during run time). Unlike linkman:dummy-ups[8] generally, this driver does not require a running `upsd` data server nor use the networked NUT protocol to talk to the "real" driver (which may be remote in case of `dummy-ups` repeater mode). This driver does not create a completely new virtual device, but replaces or extends some of the original readings reported by the "real" driver using information from the specified outlet, and relays all other readings as they were. Remote clients like `upsmon` can `MONITOR` the device entry presented by the data server with this driver (and the "real" driver) running and published. A larger deployment with one or more lower-priority devices collected on a manageable outlet of an UPS or ePDU would likely see several drivers set up on the system actually capable of interactions with the UPS and running the NUT data server linkman:upsd[8] (and likely powered by another outlet): * a "real" driver talking to the UPS; * a `clone` driver talking to the "real" driver and issuing outlet power-off (or power-cycle) based on relatively high thresholds for remaining battery charge and/or runtime of the actual UPS (or explicit instant commands), with such operations first setting the respective timers for the outlet on the "real" driver, and the "FSD" flag among states of the virtual UPS status; * possibly a `clone-outlet` driver which is read-only and interprets the outlet timer values as triggers for "FSD" or "OFF" flags reported among states of the virtual UPS status. With this approach, the lower-priority systems collected on such outlet would run the NUT linkman:upsmon[8] client to `MONITOR` the virtual UPS presented by the read-only `clone-outlet` driver and shut down as soon as the "FSD" flag is raised (fairly early, based on charge and/or runtime thresholds configured for that driver) allowing the higher-priority devices (likely including the NUT server) to enjoy a longer on-battery life. The `clone` driver responsible for outlet power state changes would not normally be monitored directly (e.g. to avoid unfortunate direct shutdown requests from those clients), although it can be (instead of `clone-outlet`) in sufficiently trusted networks. EXTRA ARGUMENTS --------------- This driver supports the following settings: *port*='drivername-devicename':: Required. The standard NUT driver `port` setting, here it provides the name of the local Unix socket (or named Windows pipe) for connection to the "real" driver. *prefix*='outlet.N':: Required. Specify the outlet prefix as known on the original driver. The subset of data points reported by the "real" UPS driver for the actual device on this prefix would be reported as data points of the virtual UPS maintained by this driver. IMPLEMENTATION -------------- The port specification in the linkman:ups.conf[5] should reference the local driver socket (or Windows named pipe) that the "real" UPS driver is using. For example: ------ [realups] driver = usbhid-ups port = auto [clone-outlet-1] driver = clone-outlet port = usbhid-ups-realups prefix = outlet.1 desc = "Outlet 1 of the Real UPS" [...] ------ The driver internally interprets "real" driver's information about shutdown delay and shutdown timer, whole UPS status and this outlet's status, and relays other data points as they were. If the outlet supports and reports a delayed power-off, the virtual UPS would issue an FSD via `ups.status` for its clients to shut down safely. In more detail: Given the (required) `prefix` value such as `outlet.1`, the driver would specifically keep track of `.status`, `.delay.shutdown`, and `.timer.shutdown` data points reported by the "real" driver. Numeric values of the `*.shutdown` readings would be noted by this driver, and the boolean outlet status ("off" or otherwise) will be remembered. These values will also be re-published by this driver "as is". The `ups.status` from the "real" driver would be remembered, but not re-published by this driver immediately. Instead, it would be published during regular "update info" loop cycles either: * with the "OFF" state added (if `.status` indicates the outlet is "off"), * or with the "FSD" state prepended (if `.timer.shutdown` is non-negative and does not exceed the `.delay.shutdown` value), * or "as is" if the outlet power state is "not critical". IMPORTANT --------- Unlike a real UPS, you should *not* configure a upsmon primary mode for this driver. When a linkman:upsmon[8] primary sees the OB LB flags and tells the linkman:upsd[8] server it is OK to initiate the shutdown sequence, the server will latch the FSD status, and it will not be possible to restart the systems connected without restarting the `upsd` server. This will be a problem if the power returns after the clone UPS initiated the shutdown sequence on its outlet, but returns before the real UPS begins shutting down. The solution is in the `clone` driver, that will insert the FSD flag if needed without the help of an `upsmon` primary. CAVEATS ------- The clone UPS will follow the status on the real UPS driver. You can only make the clone UPS shutdown earlier than the real UPS driver, not later. If the real UPS driver initiates a shutdown, the clone-outlet UPS driver will immediately follow. Be aware that the commands to shutdown/restart an outlet on the real UPS drivers are not affected, so if you tell the real UPS driver to shutdown the outlet of the clone UPS driver immediately, your clients will lose power without warning. A delayed outlet power-off should propagate as FSD, and the delay should be sufficiently long to allow for client shutdowns. If you use service management frameworks like systemd or SMF to manage the dependencies between driver instances and other units, then you may have to set up special dependencies (e.g. with systemd "drop-in" snippet files) to queue your `clone` drivers to start after the "real" device drivers. ////////////////////////////////////// TODO later: declare the driver as "optional", see https://github.com/networkupstools/nut/issues/1389 ////////////////////////////////////// AUTHOR ------ Arjen de Korte SEE ALSO -------- linkman:upscmd[1], linkman:upsrw[1], linkman:ups.conf[5], linkman:clone[8], linkman:nutupsdrv[8] Dummy driver: ~~~~~~~~~~~~~ The "repeater" mode of 'dummy-ups' driver is in some ways similar to the 'clone' and 'clone-outlet' drivers, by relaying information from a locally or remotely running "real" device driver (and NUT data server). linkman:dummy-ups[8] Internet Resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_display_parsable.txt0000644000200500020050000000307615001555412016560 00000000000000NUTSCAN_DISPLAY_PARSABLE(3) =========================== NAME ---- nutscan_display_parsable - Display the specified `nutscan_device_t` structure on stdout. SYNOPSIS -------- ------ #include void nutscan_display_parsable(nutscan_device_t * device); ------ DESCRIPTION ----------- The *nutscan_display_parsable()* function displays all NUT devices in 'device' to `stdout`. It displays them in a way that can be easily parsed, which is: :driver="",port=""[,="",="",...] * may be one of USB, SNMP, XML, NUT, IPMI or AVAHI. * is the name of the driver's binary corresponding to this device. * and depend on , see the corresponding driver's man page. Note that this format is for machine consumption, so is not associated with sanity checks that may be used along with display method for the `ups.conf` file format. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/masterguard.80000644000200500020050000000507115001555072013354 00000000000000'\" t .\" Title: masterguard .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "MASTERGUARD" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" masterguard \- Driver for Masterguard UPS equipment .SH "SYNOPSIS" .sp \fBmasterguard\fR \-h .sp \fBmasterguard\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the masterguard driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "NOTE" .sp Please note that this driver is deprecated and will not receive new development\&. If it works for managing your devices \(em fine, but if you are running it to try setting up a new device, please consider the newer \fBnutdrv_qx\fR(8) instead, which should handle all \fIQ*\fR protocol variants for NUT\&. .sp Please do also report if your device works with this driver, but \fBnutdrv_qx\fR(8) would not actually support it with any subdriver! .SH "SUPPORTED HARDWARE" .sp This driver supports Masterguard UPS equipment (serial connection only)\&. .SH "EXTRA ARGUMENTS" .PP \fBCS\fR .RS 4 Cancel the shutdown procedure\&. .RE .SH "AUTHOR" .sp Michael Spanier .SH "SEE ALSO" .SS "Newer driver:" .sp \fBnutdrv_qx\fR(8) .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutupsdrv.80000644000200500020050000005165715001555047013125 00000000000000'\" t .\" Title: nutupsdrv .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTUPSDRV" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutupsdrv \- Generic manual for unified NUT drivers .SH "SYNOPSIS" .sp \fBnutupsdrv\fR \fI\-h\fR .sp \fBnutupsdrv\fR [OPTIONS] .SH "DESCRIPTION" .sp \fBnutupsdrv\fR is not actually a driver\&. This is a combined man page for the shared code that is the core of many drivers within the Network UPS Tools package\&. .sp For information on the specific drivers, see their individual man pages\&. .sp UPS drivers provide a communication channel between the physical UPS hardware and the \fBupsd\fR(8) server\&. The driver is responsible for translating the native protocol of the UPS to the common format used by the rest of this package\&. .sp The core has three modes of operation which are determined by the command line switches\&. In the normal mode, the driver will periodically poll the UPS for its state and parameters, as per the \fBpollinterval\fR parameter in \fBups.conf\fR(5)\&. The results of this command are presented to upsd\&. The driver will also handle setting variables and instant commands if available\&. .sp In the second mode, using \fB\-k\fR, the driver can instruct the UPS to shut down the load, possibly after some delay\&. This mode of operation is intended for cases when it is known that the UPS is running out of battery power and the systems attached must be turned off to ensure a proper reboot when power returns\&. .sp In the third mode, using \fB\-d\fR, the driver will exit after some update loops, dumping the data tree (in \fBupsc\fR(8)\-like format) to stdout\&. This can be useful to complement the \fBnut-scanner\fR(8) to discover devices, along with in\-depth data\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp You probably don\(cqt want to use any of these options directly\&. You should use \fBupsdrvctl\fR(8) (or \fBupsdrvsvcctl\fR(8) on systems with a service management framework like systemd or SMF) to control your drivers, and \fBups.conf\fR(5) to configure them\&. The rest of this manual describes options and parameters that generally are not needed by normal users\&. .sp .5v .RE .SH "OPTIONS" .PP \fB\-h\fR .RS 4 Display a help message without doing anything else\&. This will also list possible values for \fI\-x\fR in that driver, and other help text that the driver\(cqs author may have provided\&. .RE .PP \fB\-a\fR \fIid\fR .RS 4 Autoconfigure this driver using the \fIid\fR section of \fBups.conf\fR(5)\&. \fBThis argument is mandatory when calling the driver directly\&.\fR .RE .PP \fB\-s\fR \fIid\fR .RS 4 Configure this driver only with command line arguments instead of reading \fBups.conf\fR(5)\&. To be used instead of \fB\-a\fR option when need to run a driver not present in driver configuration file\&. Instead, driver configuration have to be set with \fB\-x\fR options directly in the command line\&. As such driver instance cannot be controlled by \fBupsdrvctl\fR(8) or \fBupsdrvsvcctl\fR(8), this option should be used for specific needs only\&. .RE .PP \fB\-D\fR .RS 4 Raise the debugging level\&. Use this multiple times to see more details\&. Running a driver in debug mode will (by default) prevent it from backgrounding after startup\&. It will keep on logging information to the console until it receives a \fBSIGINT\fR (usually Ctrl\-C) or \fBSIGTERM\fR signal\&. .sp The level of debugging needed depends both on the driver and the problem you\(cqre trying to diagnose\&. Therefore, first explain the problem you have with a driver to a developer/maintainer, before sending them debugging output\&. More often than not, if you just pick a level, the output may be either too limited or too verbose to be of any use\&. .RE .PP \fB\-d\fR \fIupdate_count\fR .RS 4 Dump the data tree (in \fBupsc\fR(8)\-like format) to stdout after running the driver update loop for the specified \fIupdate_count\fR times and exit\&. .sp By default this prevents the driver process from backgrounding after startup\&. Note that the driver banner will be printed too, so when using this option in scripts, don\(cqt forget to trim the first line, or use the NUT_QUIET_INIT_BANNER environment variable\&. .RE .PP \fB\-q\fR .RS 4 Raise log level threshold\&. Use this multiple times to log more details\&. .sp The debugging comment above also applies here\&. .RE .PP \fB\-c\fR \fIcommand\fR .RS 4 Send \fIcommand\fR to the background process as a signal\&. Valid commands are: .PP \fBreload\fR .RS 4 reread configuration files, ignoring modified settings which can not be applied "on the fly" .RE .PP \fBreload\-or\-error\fR .RS 4 reread configuration files, ignoring but counting changed values which require a driver restart (can not be changed on the fly), and return a success/fail code based on that count, so the caller can decide the fate of the currently running driver instance .RE .PP \fBreload\-or\-exit\fR .RS 4 reread configuration files, exiting the old driver process if it encounters modified settings which can not be applied "on the fly" (so caller like systemd can launch another copy of the driver) .RE .RE .PP \fBexit\fR .RS 4 tell the currently running driver instance to just exit (so an external caller like the new driver instance, or the systemd or SMF frameworks would start another copy) .RE .sp With recent NUT v2\&.8\&.x releases, such commands can be sent using the Unix socket for driver\-server interaction\&. As a fallback, like older releases, signals can be sent to the old driver instance\(cqs PID (where possible)\&. .PP \fB\-P\fR \fIpid\fR .RS 4 Send the command signal above using specified PID number, rather than consulting the PID file\&. This can help define service units which start each NUT driver as a foreground process so it does not create a PID file\&. See also \-FF option as an alternative\&. .RE .PP \fB\-F\fR .RS 4 Enforce running the driver as a foreground process, regardless of debugging or data\-dumping settings\&. Specify twice (\-FF or \-F \-F) to save the PID file even in this mode\&. .RE .PP \fB\-B\fR .RS 4 Enforce running the driver as a background process, regardless of debugging or data\-dumping settings\&. .RE .PP \fB\-i\fR \fIinterval\fR .RS 4 Set the poll interval for the device\&. The default value is 2 (in seconds)\&. .RE .PP \fB\-V\fR .RS 4 Print only version information, then exit\&. .RE .PP \fB\-L\fR .RS 4 Print a parsable list of driver variables\&. Mostly useful for configuration wizard programs\&. .RE .PP \fB\-k\fR .RS 4 ("Kill" power) Forced shutdown mode\&. The UPS will power off the attached load, if possible\&. .sp You should use upsdrvctl shutdown whenever possible instead of calling this directly\&. Note that the constrained operating system context for shutdown typically rules out use of upsdrvsvcctl shutdown\&. .RE .PP \fB\-r\fR \fIdirectory\fR .RS 4 The driver will \fBchroot\fR(2) to \fIdirectory\fR during initialization\&. This can be useful when securing systems\&. .sp In addition to the state path, many systems will require /dev/null to exist within \fIdirectory\fR for this to work\&. The serial ports are opened before the chroot call, so you do not need to create them inside the jail\&. In fact, it is somewhat safer if you do not (but reconnection to devices may be no longer possible and could require a full restart of the driver)\&. .RE .PP \fB\-u\fR \fIusername\fR .RS 4 Override the unprivileged username that the driver may use after startup\&. If started as root, after opening configuration files (and optionally calling \fBchroot\fR(2), as described in the previous option), the driver will look up \fIusername\fR in the passwd database, then change to the user and group identities associated with \fIusername\fR\&. (If started with a nonzero UID or effective UID, the driver will silently ignore this option\&.) .sp When compiling NUT from source, the default username is typically nobody, and this may cause permission errors when the driver opens the UPS device node\&. You can use this option to temporarily override the defaults\&. For testing purposes, you can set this option to root to bypass permission errors, especially with USB\-based drivers\&. However, you will want to remove this option later in order to avoid permission conflicts between the driver and the unprivileged copy of \fBupsd\fR(8)\&. .RE .PP \fB\-g\fR \fIgroupname\fR .RS 4 Override the unprivileged group name that the driver may use after startup to set permissions for the filesystem socket so upsd may still access it if the run\-time user of the driver normally would deny that access\&. .RE .PP \fB\-x\fR \fIvar\fR=\fIval\fR .RS 4 Define a variable called \fIvar\fR with the value of \fIvar\fR in the driver\&. This varies from driver to driver \(em see their specific man pages for more information\&. .sp This is like setting \fIvar\fR=\fIval\fR in \fBups.conf\fR(5), but \fB\-x\fR overrides any settings from that file\&. .RE .SH "DIAGNOSTICS" .sp Information about the startup process is printed to stdout and/or stderr\&. Additional messages after that point are only available in the syslog, unless the driver remains in foreground (e\&.g\&. due to raised debugging verbosity)\&. .sp After \fBupsd\fR(8) starts, the UPS clients such as \fBupsc\fR(8) can be used to query the status of an UPS\&. .SH "PROGRAM CONTROL" .sp You should always use \fBupsdrvctl\fR(8) (or \fBupsdrvsvcctl\fR(8) on systems with a service management framework like systemd or SMF) to control the drivers\&. While drivers can be started by hand for testing purposes, it is not recommended for production use\&. .SH "FILES" .PP ups\&.conf .RS 4 Required configuration file\&. This contains all details on which drivers to start and where the hardware is attached\&. .RE .SH "ENVIRONMENT VARIABLES" .sp \fBNUT_DEBUG_LEVEL\fR sets default debug verbosity if no \fB\-D\fR arguments were provided on command line, but does not request that the daemon runs in foreground mode\&. .sp \fBNUT_CONFPATH\fR is the path name of the directory that contains ups\&.conf and other configuration files\&. If this variable is not set, drivers use a built\-in default, which is often /usr/local/ups/etc\&. .sp \fBNUT_STATEPATH\fR is the path name of the directory in which \fBupsd\fR and drivers keep shared state information\&. If this variable is not set, \fBupsd\fR and drivers use a built\-in default, which is often /var/state/ups\&. The \fBSTATEPATH\fR directive in \fBupsd.conf\fR(5) overrides this variable\&. .sp \fBNUT_ALTPIDPATH\fR is the path name of the directory in which \fBupsd\fR and drivers store \&.pid files\&. If this variable is not set, \fBupsd\fR and drivers use either \fBNUT_STATEPATH\fR if set, or ALTPIDPATH if set, or otherwise the built\-in default \fBSTATEPATH\fR\&. .sp \fBNUT_QUIET_INIT_UPSNOTIFY=true\fR can be used to prevent daemons which can notify service management frameworks (such as systemd) about passing their lifecycle milestones from emitting such notifications (including those about lack of system support for such modern features, once per run)\&. .sp \fBNUT_QUIET_INIT_BANNER=true\fR can be used to suppress NUT tool name and version banner\&. NOT recommended for services due to adverse troubleshooting impact, but may be helpful in shell profiles or scripts which process NUT tool outputs\&. .SH "BUGS" .sp Some of the drivers may have bugs\&. See their manuals for more information\&. .SH "SEE ALSO" .SS "Configuration:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBups.conf\fR(5) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnut.conf\fR(5) .RE .SS "Server:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsd\fR(8) .RE .SS "Clients:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsc\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupscmd\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsrw\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupslog\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsmon\fR(8) .RE .SS "CGI programs:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsset.cgi\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsstats.cgi\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsimage.cgi\fR(8) .RE .SS "Driver control:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnut-driver-enumerator\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsdrvctl\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupsdrvsvcctl\fR(8) .RE .SS "Drivers:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBadelsystem_cbi\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBal175\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBapc_modbus\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBapcsmart-old\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBapcsmart\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBapcupsd-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBasem\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbcmxcp\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbcmxcp_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbelkin\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbelkinunv\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbestfcom\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbestfortress\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbestuferrups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbestups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbicker_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBblazer-common\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBblazer_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBblazer_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBclone-outlet\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBclone\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBdummy-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBetapro\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBeverups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBgamatronic\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBgeneric_gpio\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBgeneric_modbus\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBgenericups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBhuawei-ups2000\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBhwmon_ina219\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBisbmex\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBivtscd\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBliebert-esp2\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBliebert-gxe\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBliebert\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmacosx-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmasterguard\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmetasys\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmge-shut\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmge-utalk\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmicrodowell\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBmicrosol-apc\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnetxml-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnhs_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnut-ipmipsu\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnut_usb_addvars\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutdrv_atcl_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutdrv_qx\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutdrv_siemens_sitop\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBoneac\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBoptiups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBphoenixcontact_modbus\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpijuice\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpowercom\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpowerman-pdu\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBpowerpanel\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBrhino\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBrichcomm_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBriello_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBriello_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsafenet\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsms_ser\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsnmp-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsocomec_jbus\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBsolis\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtripplite\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtripplite_usb\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBtripplitesu\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBupscode2\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBusbhid-ups\fR(8) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBvictronups\fR(8) .RE .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/gamatronic.txt0000644000200500020050000000151215001555412013624 00000000000000GAMATRONIC(8) ============= NAME ---- gamatronic - Driver for Gamatronic UPS equipment SYNOPSIS -------- *gamatronic* -h *gamatronic* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the gamatronic driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ Various -- Rebuilt to work with Gamatronic UPS Units, but should recognize any UPS that speaks the SEC protocol at 1200-19200 bps. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. AUTHOR ------ Nadav Moskovitch SEE ALSO -------- The core driver ~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_scan_usb.30000644000200500020050000000710015001555057014357 00000000000000'\" t .\" Title: nutscan_scan_usb .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_SCAN_USB" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_scan_usb \- Scan NUT compatible USB devices\&. .SH "SYNOPSIS" .sp .nf #include nutscan_device_t * nutscan_scan_usb(nutscan_usb_t * scanopts); .fi .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Before libnutscan version 2\&.5\&.0 there was no argument: .sp .nf nutscan_device_t * nutscan_scan_usb(void); .fi .sp After the API update to have an argument, equivalent default activity can be achieved by passing NULL value for the argument\&. .sp .5v .RE .SH "DESCRIPTION" .sp The \fBnutscan_scan_usb()\fR function tries to detect NUT compatible USB devices\&. .sp The scanopts argument contains toggles about values that would be reported into the generated device section\&. Currently they regard physical link details which can change over time (e\&.g\&. USB re\-enumeration due to software or hardware re\-connections); see nut\-scan\&.h for current details: .sp .if n \{\ .RS 4 .\} .nf /* USB scan options structure */ typedef struct nutscan_usb { /* Hardware link related values below are not reliable for run\-time * matching (they can change over time) but can be useful if e\&.g\&. * "serial" is not available or unique */ int report_bus; int report_busport; int report_device; /* The value is not currently used for device matching, but might be * used later, and it is available from discovery */ int report_bcdDevice; } nutscan_usb_t; .fi .if n \{\ .RE .\} .sp You MUST call \fBnutscan_init\fR(3) before using this function\&. .SH "RETURN VALUE" .sp The \fBnutscan_scan_usb()\fR function returns a pointer to a nutscan_device_t structure containing all found devices or NULL if an error occurs or no device is found\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_scan_eaton_serial\fR(3) nut-2.8.3/docs/man/libnutclient_variables.txt0000644000200500020050000000521715001555412016232 00000000000000LIBNUTCLIENT_VARIABLES(3) ========================= NAME ---- libnutclient_variables, nutclient_get_device_variables, nutclient_get_device_rw_variables, nutclient_has_device_variable, nutclient_get_device_variable_description, nutclient_get_device_variable_values, nutclient_set_device_variable_value, nutclient_set_device_variable_values - Variable related functions in Network UPS Tools high-level client access library SYNOPSIS -------- ------ #include typedef void* NUTCLIENT_t; typedef char** strarr; strarr nutclient_get_device_variables(NUTCLIENT_t client, const char* dev); strarr nutclient_get_device_rw_variables(NUTCLIENT_t client, const char* dev); int nutclient_has_device_variable(NUTCLIENT_t client, const char* dev, const char* var); char* nutclient_get_device_variable_description(NUTCLIENT_t client, const char* dev, const char* var); strarr nutclient_get_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var); void nutclient_set_device_variable_value(NUTCLIENT_t client, const char* dev, const char* var, const char* value); void nutclient_set_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var, const strarr values); ------ DESCRIPTION ----------- These functions allow to manage variables of devices. * The *nutclient_get_device_variables()* function retrieves the list of variables names for a device. + The returned strarr must be freed by 'strarr_free' (see linkman:libnutclient_general[3]). * The *nutclient_get_device_rw_variables* function retrieves the list of read-write variables names for a device. + The returned strarr must be freed by 'strarr_free' (see linkman:libnutclient_general[3]). * The *nutclient_has_device_variable* function tests if the specified variable is supported by the device. + Return '1' if supported and '0' if not. * The *nutclient_get_device_variable_description* function retrieves the variable description, if any. + The returned string must be freed by linkmanext:free[3]. * The *nutclient_get_device_variable_values* returns variable values (generally only one). + The returned strarr must be freed by 'strarr_free' (see linkman:libnutclient_general[3]). * The *nutclient_set_device_variable_value* intends to set the value of the specified variable. * The *nutclient_set_device_variable_values* intends to set multiple values of the specified variable. Common arguments: * 'dev' is the device name. * 'var' is the variable name. * 'value' is the variable value. * 'values' is the variable array of values. SEE ALSO -------- linkman:libnutclient[3] linkman:libnutclient_devices[3] linkman:libnutclient_general[3] nut-2.8.3/docs/man/upscli_str_contains_token.txt0000644000200500020050000000173615001555412016775 00000000000000UPSCLI_STR_CONTAINS_TOKEN(3) ============================ NAME ---- upscli_str_contains_token - Verify that an unique token is present in the string SYNOPSIS -------- ------ #include int upscli_str_contains_token(const char *string, const char *token); ------ DESCRIPTION ----------- The *upscli_str_contains_token*() function takes the pointer 'tgt' to a caller-provided `const char *` buffer, comprised of unique tokens separated by single space characters (ASCII '0x20'), and the pointer 'token' to a presumed-contiguous token value that should be found in the 'tgt' buffer. RETURN VALUE ------------ The *upscli_str_contains_token*() function returns a numeric code: * 'non-zero' if the 'token' value was found in 'tgt' buffer (possibly surrounded by space characters, or being at start/end of the string); * '0' if 'token' was not found, or if either 'token' or 'tgt' string was `NULL` or empty. SEE ALSO -------- linkman:upscli_str_add_unique_token[3] nut-2.8.3/docs/man/upslog.80000644000200500020050000002055515001555047012355 00000000000000'\" t .\" Title: upslog .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSLOG" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upslog \- UPS status logger .SH "SYNOPSIS" .sp \fBupslog \-h\fR .sp \fBupslog\fR [\fIOPTIONS\fR] .SH "DESCRIPTION" .sp \fBupslog\fR is a daemon that will poll a UPS at periodic intervals, fetch the variables that interest you, format them, and write them to a file\&. .sp The default format string includes variables that are supported by many common UPS models\&. See the description below to make your own\&. .SH "OPTIONS" .PP \fB\-f\fR \fIformat\fR .RS 4 Monitor the UPS using this format string\&. Be sure to enclose \fIformat\fR in quotes so your shell doesn\(cqt split it up\&. Valid escapes within this string are: .PP %% .RS 4 Insert a single "%" .RE .PP %t .RS 4 Insert a single TAB character (like printf("\et")) .RE .PP %TIME format% .RS 4 Insert the time with strftime formatting .RE .PP %ETIME% .RS 4 Insert the number of seconds since the start of "Epoch", ala time_t\&. This is now a 10\-digit number\&. .RE .PP %HOST% .RS 4 Insert the local hostname .RE .PP %UPSHOST% .RS 4 Insert the host of the UPS being monitored (the part of your logging specification, e\&.g\&. ups[@host[:port]]) .RE .PP %PID% .RS 4 Insert the PID of upslog itself .RE .PP %VAR varname% .RS 4 Insert the value of variable varname (see NUT developer documentation chapter "Variables" on\-line or in the docs/nut\-names\&.txt file in sources of the NUT version you have installed for more details) .RE .sp The default format string is: .sp .if n \{\ .RS 4 .\} .nf %TIME @Y@m@d @H@M@S% %VAR battery\&.charge% %VAR input\&.voltage% %VAR ups\&.load% [%VAR ups\&.status%] %VAR ups\&.temperature% %VAR input\&.frequency% .fi .if n \{\ .RE .\} .RE .PP \fB\-N\fR .RS 4 Prefix %UPSHOST%%t before the format string (whether default or custom)\&. Useful when logging many systems into same target\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This option DOES NOT currently check if you already have %UPSHOST% in the formatting string (e\&.g\&. specified explicitly)\&. .sp .5v .RE .RE .PP \fB\-i\fR \fIinterval\fR .RS 4 Wait this many seconds between polls\&. This defaults to \fI30\fR seconds\&. .sp If you require tighter timing, consider writing your own logger using the \fBupsclient\fR(3) library\&. .RE .PP \fB\-d\fR \fIcount\fR .RS 4 Exit after specified amount of updates\&. Default is \fI0\fR for infinite loop (until interrupted otherwise)\&. .RE .PP \fB\-l\fR \fIlogfile\fR .RS 4 Store the results in this file\&. .sp You can use \- for stdout, but upslog will remain in the foreground by default\&. .sp Requires that the \-s option is also used for the single\-system logging\&. .sp Can be used with the \-m , will be added to the list\&. .RE .PP \fB\-D\fR .RS 4 Raise debugging verbosity level by one; upslog will remain in the foreground by default\&. .RE .PP \fB\-F\fR .RS 4 upslog will run in the foreground, regardless of logging target\&. .RE .PP \fB\-B\fR .RS 4 upslog will run in the background, regardless of logging target or debugging\&. .RE .PP \fB\-s\fR \fIups\fR .RS 4 Monitor this UPS\&. The format for this option is upsname[@hostname[:port]]\&. The default hostname is "localhost"\&. .sp The \fIupsname\fR may be an asterisk * to query UPSes currently served by \fIhostname\fR, and monitor each of them (into the same logging destination)\&. .sp Requires that the \-l option is also used for the single\-system logging\&. .sp Can be used with the \-m , will be added to the list\&. .RE .PP \fB\-m\fR \fItuple\fR .RS 4 Monitor multiple UPSs (provided several instances of such option)\&. .sp The format for this option is a tuple of UPS system and log file specification, separated by commas\&. An example would be: .sp .if n \{\ .RS 4 .\} .nf upsname@hostname:9999,/var/log/nut/cps\&.log .fi .if n \{\ .RE .\} .sp The \fIupsname\fR may be an asterisk * to query UPSes currently served by \fIhostname\fR, and monitor each of them (into the same logging destination)\&. .sp Tuples may specify \- as the logfile, to emit messages on stdout (e\&.g\&. to be collected by the system journal for services)\&. .sp Use of stdout via tuple\-based logging specifications also implies that upslog will remain in the foreground by default\&. .RE .PP \fB\-u\fR \fIusername\fR .RS 4 If started as \fIroot\fR, upslog will \fBsetuid\fR(2) to the user id associated with \fIusername\fR for security\&. .sp If \fIusername\fR is not defined, it will use the value that was compiled into the program\&. This defaults to \fInobody\fR (if not otherwise configured), which is far from ideal\&. .RE .SH "COMMON OPTIONS" .PP \fB\-h\fR .RS 4 Show the command\-line help message\&. .RE .PP \fB\-V\fR .RS 4 Show NUT version banner\&. More details may be available if you also export NUT_DEBUG_LEVEL=1 or greater verbosity level\&. .RE .PP \fB\-W\fR \fIsecs\fR .RS 4 Set the timeout for initial network connections (by default they are indefinitely non\-blocking, or until the system interrupts the attempt)\&. Overrides the optional NUT_DEFAULT_CONNECT_TIMEOUT environment variable\&. .RE .SH "SERVICE DELAYS" .sp The interval value is merely the number given to \fBsleep\fR(3) after running through the format string\&. Therefore, a query will actually take slightly longer than the interval, depending on the speed of your system\&. .SH "ON\-DEMAND LOGGING" .sp Sending a SIGUSR1 to a running \fBupslog\fR process makes it wake from the current sleep and log immediately\&. This is useful when triggered from a \fBupssched\fR event trigger (e\&.g\&. AT ONBATT or AT ONLINE) to ensure that an entry always exists, even if the power goes away for a period of time shorter than that specified by the \-i argument\&. .SH "LOG CO\-LOCATION" .sp It is possible and safe to specify the same log file (including \- for stdout) in several tuples, and it would only be opened or closed once without conflict\&. .sp Consider adding %UPSHOST% to your custom formatting string (e\&.g\&. by using the \fB\-N\fR command\-line option), in order to easily differentiate lines corresponding to different systems, when logging them to the same target\&. .SH "LOG ROTATION" .sp \fBupslog\fR writes its PID to upslog\&.pid, and will reopen the log file if you send it a SIGHUP\&. This allows it to keep running when the log is rotated by an external program\&. .SH "CAVEATS" .sp Historically this daemon supported logging of data for one UPS system per run (specified by the \-s option) into one log file name or stdout (specified by the \-l option)\&. .sp Since NUT v2\&.8\&.1 it allowed to log several devices (each logged into its individual destination file or common stdout) as specified by multiple \-m tuple options\&. But the two modes were effectively exclusive of each other (single\-UPS options were ignored if tuples are also provided)\&. .sp Since NUT v2\&.8\&.3, the single\-UPS options are added to the list of tuples, so both legacy and new options can be reliably used to monitor multiple devices in the same run\&. .SH "SEE ALSO" .SS "Server:" .sp \fBupsd\fR(8) .SS "Clients:" .sp \fBupsc\fR(8), \fBupscmd\fR(8), \fBupsrw\fR(8), \fBupsmon\fR(8), \fBupssched\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/belkinunv.80000644000200500020050000003372115001555066013041 00000000000000'\" t .\" Title: belkinunv .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BELKINUNV" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" belkinunv \- Driver for Belkin "Universal UPS" and compatible .SH "SYNOPSIS" .sp \fBbelkinunv\fR \-h .sp \fBbelkinunv\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the belkin driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This driver only supports serial connections\&. If your UPS has a USB port, please consult the Hardware Compatibility List (HCL) to see which of the USB drivers you should use\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The belkinunv driver is known to work with the Belkin Universal UPS models F6C800\-UNV and F6C120\-UNV, and is expected to work with other Belkin Universal UPS models\&. The driver only supports serial communication, not USB\&. .sp The Trust UPS and older Belkin units are not supported by this driver, and neither are the Belkin Home Office models (F6H500\-SER and so forth)\&. However, some Belkin models, such as the Regulator Pro, are supported by the \fBbelkin\fR(8) driver, and the Home Office models are supported using the \fBgenericups\fR(8) driver with upstype=7\&. .SH "SOFT SHUTDOWN WORKAROUND" .sp One problem with the Belkin Universal UPS is that it cannot enter a soft shutdown (shut down the load until AC power returns) unless the batteries are completely depleted\&. Thus, one cannot just shut off the UPS after operating system shutdown; it will not come back on when the power comes back on\&. Therefore, the \fBbelkinunv\fR driver should never be used with the \fB\-k\fR option\&. Instead, the \fB\-x wait\fR option is provided as a workaround\&. .sp When called with the \fB\-x wait\fR option, \fBbelkinunv\fR behaves as a standalone program (i\&.e\&., it does not fork into the background)\&. It performs one simple task: it connects to the UPS, waits for AC power to return, and then exits with status 0\&. .sp This is meant to be used in a shutdown script as follows: during a shutdown, after all filesystems have been remounted read\-only, and just before the system would normally be halted: check /etc/killpower (or similar) to see if this shutdown was caused by \fBupsmon\fR(8), and if yes, call \fBbelkinunv \-x wait\fR\&. If AC power comes back on, \fBbelkinunv\fR exits, and things should be arranged so that the system reboots in this case\&. If AC power does not come back on, the UPS will eventually run out of batteries, kill the computer\(cqs power supply, and go into soft shutdown mode, which means everything will reboot properly when the power returns\&. In either case, a deadlock is avoided\&. .sp In addition, if an optional integer argument is given to the \fB\-x wait\fR option, this causes \fBbelkinunv\fR to wait not only for AC power to be present, but also for the battery charge to reach the given level\&. I use this as part of my startup scripts, to ensure that the batteries are sufficiently charged before the computer continues booting\&. This should be put very early in the startup script, before any filesystems are mounted read/write, and before any filesystem checks are performed\&. .sp Several other \fB\-x\fR options are provided to fine\-tune this behavior\&. See the options below for detailed descriptions\&. See the examples below for examples of how to use \fBbelkinunv\fR in shutdown and startup scripts\&. .SH "OPTIONS" .sp See also \fBnutupsdrv\fR(8) for generic options\&. Never use the \fB\-k\fR option with this driver; it does not work properly\&. .PP \fB\-x wait\fR[=\fIlevel\fR] .RS 4 When this option is used, \fBbelkinunv\fR does not fork into the background, but behaves as a standalone program\&. It connects to the UPS and waits until AC power is present\&. If \fIlevel\fR is specified, it also waits until the battery charge reaches at least the given level in percent\&. Then, and only then, \fBbelkinunv\fR exits\&. In addition, while \fBbelkinunv\fR runs in this mode, it displays a status line with information on the UPS status and battery level\&. This is intended for use in the computer\(cqs shutdown and startup scripts, as described under Soft Shutdown Workaround above\&. .RE .PP \fB\-x nohang\fR .RS 4 This option only has an effect when used in conjunction with the \fB\-x wait\fR option\&. It causes \fBbelkinunv\fR to exit if a connection with the UPS cannot be established or is lost, instead of retrying forever, which is the default behavior\&. The \fB\-x nohang\fR option should be used in a startup script, to ensure the computer remains bootable even if the UPS has been disconnected during the power failure (for instance, you attached your computer to a generator, carried it to a neighbor\(cqs house, or whatever)\&. .RE .PP \fB\-x flash\fR .RS 4 This option only has an effect when used in conjunction with the \fB\-x wait\fR option\&. It causes the UPS load to be shut off for a short time ("flashed") just after the AC power has returned and the requested battery level (if any) has been attained\&. This is useful if slaves are attached to this UPS; the flash will cause all of them to reboot\&. Note that, due to the design of the Belkin UPS hardware, the load shutdown lasts ca\&. 1\(em2 minutes; a shorter flash cannot be performed reliably\&. Also, the computers will reboot at the scheduled time, on battery power if necessary, even if AC power fails again in the meantime\&. This should not be a problem, as your startup scripts can catch this situation\&. .RE .PP \fB\-x silent\fR .RS 4 This option only has an effect when used in conjunction with the \fB\-x wait\fR option\&. It suppresses the status line which \fBbelkinunv\fR would normally print\&. .RE .PP \fB\-x dumbterm\fR .RS 4 This option only has an effect when used in conjunction with the \fB\-x wait\fR option\&. It changes the way in which \fBbelkinunv\fR prints its status line\&. Normally, terminal control sequences are used to overwrite the same line with new status information, each time the status is updated\&. This may not work on all terminals\&. If the \fB\-x dumbterm\fR option is given, each status update is written on a new line\&. .RE .SH "VARIABLES" .PP \fBbattery\&.charge\fR, \fBbattery\&.runtime\fR .RS 4 not supported by all hardware\&. .RE .PP \fBbattery\&.voltage\fR, \fBbattery\&.voltage\&.nominal\fR, \fBinput\&.frequency\fR, \fBinput\&.frequency\&.nominal\fR .RS 4 e\&.g\&. 60 for 60Hz .RE .PP \fBinput\&.sensitivity\fR .RS 4 writable: normal/medium/low .RE .PP \fBinput\&.transfer\&.high\fR .RS 4 writable: high transfer voltage point in V .RE .PP \fBinput\&.transfer\&.low\fR .RS 4 writable: low transfer voltage point in V .RE .PP \fBinput\&.voltage\fR, \fBinput\&.voltage\&.maximum\fR, \fBinput\&.voltage\&.minimum\fR, \fBinput\&.voltage\&.nominal\fR, \fBoutput\&.frequency\fR, \fBoutput\&.voltage\fR, \fBups\&.beeper\&.status\fR .RS 4 writable\&. Values: enabled/disabled/muted\&. This variable controls the state of the panel beeper\&. Enabled means sound when the alarm is present, disabled means never sound, and muted means the sound is temporarily disabled until the alarm would normally stop sounding\&. In the muted state, the beeper is automatically turned back on at the next event (AC failure, battery test, etc)\&. Also, the beeper can\(cqt be turned off during a critical event (low battery)\&. Note that not all UPS models support the "disabled" state\&. .RE .PP \fBups\&.firmware\fR, \fBups\&.load\fR, \fBups\&.model\fR, \fBups\&.power\&.nominal\fR .RS 4 e\&.g\&. 800 for an 800VA system .RE .PP \fBups\&.status\fR .RS 4 a list of flags; see the status flags below\&. .RE .PP \fBups\&.temperature\fR .RS 4 not supported by all hardware\&. .RE .PP \fBups\&.test\&.result\fR, \fBups\&.delay\&.restart\fR .RS 4 time to restart (read only) .RE .PP \fBups\&.delay\&.shutdown\fR .RS 4 time to shutdown (read only)\&. This is always a multiple of 60 seconds\&. .RE .PP \fBups\&.type\fR .RS 4 ONLINE/OFFLINE/LINEINT\&. This describes the basic layout of this UPS (for GUI clients which want to draw an animated picture of power flow)\&. An offline UPS has a direct connection from AC input to AC output, and also a connection from AC input to the battery, and from the battery to AC output\&. An online UPS lacks the direct connection from AC input to AC output, whereas a line interactive UPS lacks the connection from AC input to the battery\&. .RE .SH "COMMANDS" .PP \fBbeeper\&.enable, beeper\&.disable, beeper\&.mute\fR .RS 4 Enable, disable or mute the panel beeper\&. Note that if the beeper is muted, it is automatically turned back on at the next event (AC failure, battery test, etc)\&. Also, the beeper can\(cqt be turned muted during a critical event (low battery)\&. .RE .PP \fBreset\&.input\&.minmax\fR .RS 4 Reset the variables \fBinput\&.voltage\&.minimum\fR and \fBinput\&.voltage\&.maximum\fR\&. .RE .PP \fBshutdown\&.reboot\fR .RS 4 Shut down load immediately for about 1\(em2 minutes\&. .RE .PP \fBshutdown\&.reboot\&.graceful\fR .RS 4 After 40 second delay, shut down load for about 1\(em2 minutes\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Shut down load immediately and stay off\&. The only way it can be turned back on is by manually pressing the front panel button\&. .RE .PP \fBtest\&.battery\&.start, test\&.battery\&.stop\fR .RS 4 Start/stop 10 second battery test\&. .RE .PP \fBtest\&.failure\&.start, test\&.failure\&.stop\fR .RS 4 Start/stop "deep" battery test\&. .RE .SH "STATUS FLAGS" .PP \fBOB\fR .RS 4 load is on battery, including during tests .RE .PP \fBOFF\fR .RS 4 load is off .RE .PP \fBOL\fR .RS 4 load is online .RE .PP \fBACFAIL\fR .RS 4 AC failure\&. Note that this refers to the AC input, and thus it is not the same as "OB"\&. An AC failure can occur at any time, for instance, during a battery test, or when the UPS load is off\&. .RE .PP \fBOVER\fR .RS 4 overload .RE .PP \fBOVERHEAT\fR .RS 4 overheat .RE .PP \fBCOMMFAULT\fR .RS 4 UPS fault .RE .PP \fBLB\fR .RS 4 low battery .RE .PP \fBCHRG\fR .RS 4 charging .RE .PP \fBDEPLETED\fR .RS 4 the battery is depleted\&. When the UPS raises this flag, it simultaneously switches off the load\&. .RE .PP \fBRB\fR .RS 4 replace battery .RE .SH "EXAMPLES" .sp Here is an example for how \fBbelkinunv\fR should be used in a computer\(cqs shutdown script\&. These commands should go in the very last part of the shutdown script, after all file systems have been mounted read\-only, and just before the computer halts\&. Note that \fBbelkinunv\fR must be installed in a directory which is still readable at that point\&. .sp .if n \{\ .RS 4 .\} .nf # NEAR END OF SHUTDOWN SCRIPT: # if shutdown was caused by UPS, perform Belkin UPS workaround\&. if [ \-f /etc/killpower ] || /usr/sbin/upsmon \-K ; then echo "Waiting for AC power, or for UPS batteries to run out\&.\&.\&." /usr/bin/belkinunv \-x wait /dev/ttyS1 # we get here if the power came back on\&. Reboot\&. echo "Power is back\&. Rebooting\&.\&.\&." reboot fi .fi .if n \{\ .RE .\} .sp And here is an example of how to use \fBbelkinunv\fR in the startup script\&. These commands should go near the beginning of the startup script, before any file systems are mounted read/write, and before any file system integrity checks are done\&. .sp .if n \{\ .RS 4 .\} .nf # NEAR BEGINNING OF STARTUP SCRIPT: # if we are recovering from a power failure, wait for the UPS to # charge to a comfortable level before writing anything to disk if [ \-f /etc/killpower ] || /usr/sbin/upsmon \-K ; then echo "Waiting for UPS battery charge to reach 60%\&.\&.\&." /usr/bin/belkinunv \-x wait=60 \-x nohang /dev/ttyS1 fi .fi .if n \{\ .RE .\} .SH "EXIT STATUS" .sp When used normally, \fBbelkinunv\fR forks into the background and its diagnostics are the same as for all NUT drivers, see \fBnutupsdrv\fR(8)\&. .sp When used with the \fB\-x wait\fR option, the exit status is normally \fB0\fR\&. If the \fB\-x nohang\fR option has also been specified, an exit status of \fB1\fR indicates that communication with the UPS was lost\&. If the \fB\-x flash\fR option has been specified, an exit status of \fB2\fR indicates that the timed shutdown has failed\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in \fBups.conf\fR(5)\&. .SH "AUTHOR" .sp Peter Selinger .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Other Belkin drivers:" .sp \fBbelkinunv\fR(8), \fBblazer_ser\fR(8), \fBblazer_usb\fR(8), \fBusbhid-ups\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The documentation for the protocol used by this UPS: belkin\-universal\-ups\&.html (replica on NUT site) .RE nut-2.8.3/docs/man/nutscan_scan_xml_http_range.txt0000644000200500020050000000437715001555412017266 00000000000000NUTSCAN_SCAN_XML_HTTP_RANGE(3) ============================== NAME ---- nutscan_scan_xml_http_range - Scan network for XML/HTTP devices. SYNOPSIS -------- ------ #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_xml_http_range( const char * start_ip, const char * end_ip, useconds_t usec_timeout, nutscan_xml_t * sec) nutscan_device_t * nutscan_scan_ip_range_xml_http( nutscan_ip_range_list_t * irl, useconds_t usec_timeout, nutscan_xml_t * sec) ------ DESCRIPTION ----------- The *nutscan_scan_xml_http_range()* and *nutscan_scan_ip_range_xml_http()* functions try to detect NUT compatible XML/HTTP devices. If 'start_ip' for the former or 'irl' for the latter are NULL, the respective function does this by issuing a broadcast message on all currently configured network interfaces. Otherwise, the former queries every IP ranging from 'start_ip' to 'stop_ip', , where 'startIP' is mandatory and 'stopIP' is optional (one 'startIP' address is scanned if 'stopIP' is NULL); while the latter can walk several IP address ranges represented by a `nutscan_ip_range_list_t` structure. Those IP arguments may be either IPv4 or IPv6 addresses or host names. It waits up to 'usec_timeout' microseconds for a response from potential devices. You MUST call linkman:nutscan_init[3] before using this function. RETURN VALUE ------------ The *nutscan_scan_xml_http_range()* function returns a pointer to a `nutscan_device_t` structure containing all found devices or NULL if an error occurs or no device is found. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], linkman:nutscan_init_ip_ranges[3], linkman:nutscan_free_ip_ranges[3], linkman:nutscan_add_ip_range[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/nut.exe.80000644000200500020050000001304115001555211012413 00000000000000'\" t .\" Title: nut.exe .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUT\&.EXE" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nut.exe \- NUT for Windows wrapper for all\-in\-one service .SH "SYNOPSIS" .sp \fBnut\&.exe\fR {\-h | /?} .sp \fBnut\&.exe\fR [\fIOPTIONS\fR] .sp \fBnut\&.exe\fR (as a service implementation) .SH "DESCRIPTION" .sp \fBnut\&.exe\fR wraps NUT programs to start and stop as a Windows service\&. .sp Depending on \fBnut.conf\fR(5) setting of \fIMODE\fR, it would manage the bundle of driver(s), \fBupsd\fR(8) data server and \fBupsmon\fR(8) client, as well as attempt an UPS shutdown command in case of FSD handling, or for mere \fInetclient\fR systems it would run just the \fBupsmon\fR(8) client to monitor remote UPS device(s) and initiate the OS shut down on the local Windows system as applicable\&. .sp Beside launching or stopping a set of the NUT programs in certain cases, this helper program also allows to register (or un\-register) itself as a Windows service\&. To actually manage the service from command line you can execute the Windows net command, e\&.g\&.: .sp .if n \{\ .RS 4 .\} .nf net stop "Network UPS Tools" net start "Network UPS Tools" .fi .if n \{\ .RE .\} .sp You can also execute nut start to automatically register the service (if not yet registered) and start it, and nut stop to stop the service (if registered and running)\&. .sp Note that for a Windows machine to act as a NUT data server for further clients, you may have to add Windows Firewall rules to allow incoming connections (by default to port 3493/tcp), e\&.g\&. using PowerShell to elevate (alternately right\-click a "Command Prompt" shortcut and select "Run as administrator"), and execute netsh to actually configure the needed "Advanced Firewall" rule: .sp .if n \{\ .RS 4 .\} .nf REM Elevate to administrator status then run netsh to add firewall rule\&. REM Recommended to adapt "LocalIP" to expected listeners of this server, REM and "RemoteIP" to your single or comma\-separated subnet(s) in CIDR REM notation, specific client IP address(es), or ranges of address(es) REM (dash\-separated, as IP1\-IP2)\&. REM The following goes as one long command line: powershell\&.exe \-Command "Start\-Process netsh\&.exe \-ArgumentList \e"advfirewall firewall add rule name=NUT\-upsd\-data\-server dir=in action=allow localip=ANY remoteip=ANY program=%ProgramFiles%\eNUT\esbin\eupsd\&.exe localport=3493 protocol=tcp\e" \-Verb RunAs" .fi .if n \{\ .RE .\} .sp Keep in mind that by default NUT \fBupsd\fR(8) only listens on localhost, so you would need to add some LISTEN directives in \fBupsd.conf\fR(5) as well in this case\&. .SH "OPTIONS" .sp \fBnut\&.exe\fR is currently launched with no arguments when it is intended to run as the implementation of a registered Windows service; it would error out otherwise\&. .PP \fB/?\fR .RS 4 Display the help text and exit\&. .RE .PP \fB\-h\fR .RS 4 Display the help text and exit\&. .RE .PP \fB\-V\fR .RS 4 Display NUT version and exit\&. .RE .PP \fB\-D\fR .RS 4 Raise the debug level\&. Use this multiple times for additional details\&. The non\-trivial debug level would be passed down to launched NUT programs\&. Primarily useful for troubleshooting with the non\-service mode\&. .RE .PP \fB\-I\fR .RS 4 Install as a Windows service called "Network UPS Tools"\&. .RE .PP \fB\-U\fR .RS 4 Uninstall the Windows service\&. .RE .PP \fB\-N\fR .RS 4 Run once in non\-service mode (for troubleshooting)\&. .RE .PP \fBstart\fR .RS 4 Install as a Windows service called "Network UPS Tools" (if not yet done), and try to start this service\&. .RE .PP \fBstop\fR .RS 4 Try to stop a Windows service called "Network UPS Tools"\&. .RE .SH "DIAGNOSTICS" .sp \fBnut\&.exe\fR should not interact with console message buffers (stdout, stderr) much, except when explicitly asked to (e\&.g\&. displaying help and NUT version, running with verbose debug mode) or when exiting after an attempted service initialization while not running in a service context\&. .sp Most of normal logging from \fBnut\&.exe\fR goes to the Windows Event Log\&. .sp Launched NUT programs may emit messages of their own; their fate when no console is attached is questionable\&. .SH "SEE ALSO" .sp \fBnut.conf\fR(5), \fBups.conf\fR(5), \fBnutupsdrv\fR(8), \fBupsd\fR(8), \fBupsd.conf\fR(5), \fBupsd.users\fR(5), \fBupsmon\fR(8), \fBupsmon.conf\fR(5) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/dummy-ups.txt0000644000200500020050000002742215001555412013450 00000000000000DUMMY-UPS(8) ============ NAME ---- dummy-ups - Driver for multi-purpose UPS emulation or relay SYNOPSIS -------- *dummy-ups* -h *dummy-ups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the *dummy-ups* driver. For information about the core driver, see linkman:nutupsdrv[8]. DESCRIPTION ----------- This program is a multi-purpose UPS emulation tool. Its general behavior depends on the running mode: "dummy" ("dummy-once" or "dummy-loop"), or "repeater". //////////////////////////////////////// ...or "meta" eventually. //////////////////////////////////////// Dummy Mode ~~~~~~~~~~ In this mode, *dummy-ups* looks like a standard NUT device driver to linkman:upsd[8] and allows one to change any value for testing purposes. It is both interactive, controllable through the linkman:upsrw[1] and linkman:upscmd[1] commands (or equivalent graphical tool), and batchable through script files. It can be configured, launched and used as any other "real" NUT driver. This mode is mostly useful for development and testing purposes. NOTE: See below about the differences of `dummy-once` vs. `dummy-loop` modes -- the former may be more suitable for "interactive" uses and tests. Repeater Mode ~~~~~~~~~~~~~ In this mode, *dummy-ups* acts as a NUT client, simply forwarding data. This can be useful for supervision purposes. This mode can also allow some load sharing between several `upsd` instances communicating with ultimate NUT clients, with a "central" one using a point-to-point communication with the actual UPS or ePDU device. This arrangement can also help with networked UPSes, whose network management cards can be overwhelmed with a whole farm of servers directly polling SNMP or other networked protocols every few seconds. //////////////////////////////////////// Future intention: Meta mode to aggregate several drivers as one device e.g. to represent same UPS with Serial + USB + SNMP links, and/or cover an SNMP UPS that supports different data in different MIBs. //////////////////////////////////////// IMPLEMENTATION -------------- The `port` specification in `ups.conf` depends on the running mode, and allows the driver to select the right mode of operation. Since NUT v2.8.0, the `mode` specification in `ups.conf` allows users to override the mode of operation which would be otherwise guessed by the driver. Dummy Mode ~~~~~~~~~~ In this context, `port` in the `ups.conf` block specifies a "definition file" name for the *dummy-ups* to read data from. This can either be an absolute or a relative path name. In the latter case the NUT sysconfig directory (i.e. `/etc/nut`, `/usr/local/ups/etc`, ...) is prepended. NOTE: The "sysconfig" location is built-in according to `configure` script arguments, but can be tuned at run time by `NUT_CONFPATH` environment variable. See the `tests/NIT/nit.sh` script in NUT sources, which heavily relies on this driver, for more examples. Since NUT v2.8.0 two aspects of this mode are differentiated: * `dummy-once` reads the specified file once to the end (interrupting for `TIMER` lines, etc.) and does not re-process it until the filesystem timestamp of the data file is changed; this reduces run-time stress if you test with a lot of dummy devices, and allows use/test cases to `upsrw` variables into the driver instance -- and they remain in memory until the driver is restarted (or the file is touched or modified); + Since NUT v2.8.0 `dummy-once` is assigned by default to files with a `*.dev` naming pattern. * `dummy-loop` reads the specified file again and again, with a short sleep between the processing cycles; for sequence files using a `TIMER` keyword (see below), or for use/test cases which modify file contents with external means, this allows an impression of a device whose state changes over time. + Before NUT v2.8.0 this was the only aspect, so a simple `dummy` mode value maps to this behavior for backwards compatibility. + Since NUT v2.8.0 `dummy-loop` is assigned by default to files with a `*.seq` naming pattern, and `dummy` is assigned by default to files with other naming patterns that the driver could not classify. [NOTE] ====== Said defaulting based on filename pattern can break third-party test scripts which earlier expected `*.dev` files to work as a looping sequence with a `TIMER` keywords to change values slowly. Now such files should get processed to the end once. Specify `mode=dummy-loop` driver option or rename the data file used in the `port` option for legacy behavior. Use/Test-cases which modified such files content externally should not be impacted. ====== For instance: ---- [dummy1] driver = dummy-ups port = evolution500.seq desc = "dummy-ups in dummy-loop mode" [dummy2] driver = dummy-ups port = epdu-managed.dev desc = "dummy-ups in dummy-once mode" ---- This definition file, specified by the `port` argument in the example above, is generally named `something.dev` or `something.seq`. It contains a list of all valid variables and associated values (you can later use `upsrw` only to modify values of these variables), and has the same format as an linkman:upsc[8] data dump (`: `). This means you can easily create definition files from an existing UPS using `upsc > file.dev`. Note that the Network UPS project provides an extensive link:https://www.networkupstools.org/ddl/index.html[DDL (Devices Dumps Library)] with files which can be used for modelling real devices. Entries for the DDL library are best prepared with the link:https://raw.githubusercontent.com/networkupstools/nut/master/tools/nut-ddl-dump.sh[`tools/nut-ddl-dump.sh`] script from NUT sources instead of plain `upsc`, to provide some additional data points from other NUT clients as well. The file can also be empty, in which case only a basic set of data is available: `device.*`, `driver.*`, `ups.mfr`, `ups.model`, `ups.status` as filled by the driver itself. Some sample definition files are available in the `data` directory of the NUT source tree, and generally in the "sysconfig" or "share" directory of your system distribution. Since *dummy-ups* will usually loop on reading this file, you can dynamically modify it with some external process to "interact" with the driver. This will avoid message spam into your system log files, if you are using NUT default configuration. NOTE: By default since NUT v2.8.0, it will not loop on files in `dummy-once` mode, e.g. those with a `.dev` extension, unless their timestamp changes. You can also use the `TIMER ` instruction to create scheduled event sequences (such files are traditionally named with the `.seq` extension). For example, the following sequence will loop on switching `ups.status` between "OL", "OB" and "OB LB" every minute: ups.status: OL TIMER 60 ups.status: OB TIMER 60 ups.status: OB LB TIMER 60 It is wise to end the script for `dummy-loop` mode with a `TIMER` keyword. Otherwise `dummy-ups` will directly go back to the beginning of the file and, in particular, forget any values you could have just set with `upsrw`. Note that to avoid CPU overload with an infinite loop, the driver "sleeps" a bit between file-reading cycles (currently this delay is hardcoded to one second), independently of (and/or in addition to) any `TIMER` keywords and possibly the common `pollinterval` setting. Repeater Mode ~~~~~~~~~~~~~ In this context, `port` in the `ups.conf` block is the name of the target UPS, using the NUT format, i.e.: @[:] For instance: [repeater] driver = dummy-ups port = ups1@remotehost desc = "dummy-ups in repeater mode" Unlike UPS specifications in the rest of NUT, the `@hostname` portion is not optional -- it is the `@` character which enables Repeater Mode. To refer to an UPS on the same host as *dummy-ups*, use `port = upsname@localhost`. Note that to avoid CPU overload with an infinite loop, the driver "sleeps" a bit between data-requesting cycles (currently this delay is hardcoded to one second), so propagation of data updates available to a remote `upsd` may lag by this much. Beware that any error encountered at repeater mode startup (e.g. when not all target UPS to be repeated or their `upsd` instances are connectable yet) will by default cause the *dummy-ups* driver to terminate prematurely. This behaviour can be changed by setting the `repeater_disable_strict_start` flag, making such errors non-fatal. INTERACTION ----------- Once the driver is loaded in dummy mode, you can change any variables, except those of the `driver.*` and `server.*` collections. You can do this by either editing the definition file, or use the linkman:upsrw[1] and linkman:upscmd[1] commands. Note that in simulation mode, new variables can be added on the fly, but only by adding these to the definition file (and waiting for it to be re-read). That is, the driver should not allow to define a new variable via `upsrw`. Conversely, if you need to remove a variable (such as transient ones, like `ups.alarm`), simply update these by setting an empty value. As a result, they will get removed from the data. In repeater mode, the driver acts according to the capabilities of the UPS, and so supports the same instant commands and settable values. BACKGROUND ---------- Dummy Mode was originally written in one evening to replace the previous 'dummycons' testing driver, which was too limited, and required a terminal for interaction. *dummy-ups* is useful for NUT client development, and other testing purposes. It also helps the NUT Quality Assurance effort, by automating some tests on the NUT framework and the NIT (NUT Integration Test suite). See the `tests/NIT/nit.sh` script in NUT sources, which heavily relies on this driver, for more examples. It now offers a repeater mode. This will help in building the Meta UPS approach, which allows one to build a virtual device, composed of several other devices (either UPS, PDUs), or perhaps represent the same device which supports several communication protocols and different media (Serial, USB, SNMP...) BUGS ---- Instant commands are not yet supported in Dummy Mode, and data need name/value checking enforcement, as well as boundaries or enumeration definition. CAVEATS ------- If you use service management frameworks like systemd or SMF to manage the dependencies between driver instances and the data server, and some of these drivers are `dummy-ups` in repeater mode representing data from another driver running on the same system, then you may have to set up special dependencies (e.g. with systemd "drop-in" snippet files) to allow your `nut-server` to start after the "real" device drivers and before such repeater drivers (without a responding server, they would fail to start anyway). This may also need special care in `upsd.conf` and/or `ups.conf` files to not block the system start-up for too long while the repeater driver has not started. ////////////////////////////////////// TODO later: declare the driver as "optional", see https://github.com/networkupstools/nut/issues/1389 ////////////////////////////////////// AUTHOR ------ Arnaud Quette SEE ALSO -------- linkman:upscmd[1], linkman:upsrw[1], linkman:ups.conf[5], linkman:nutupsdrv[8] Clone drivers: ~~~~~~~~~~~~~~ The "repeater" mode of 'dummy-ups' driver is in some ways similar to the 'clone' and 'clone-outlet' drivers, which sit on top of another driver socket (or named Windows pipe) locally, and allow users to group clients to a particular outlet of a device and deal with this output as if it were a normal UPS. Notably, in this mode the 'dummy-ups' driver is a client to the networked NUT protocol and can relay information of local or remotely served devices, and requires a running NUT data server 'upsd' to represent the "real" device for this to work. linkman:clone[8], linkman:clone-outlet[8] Internet Resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/belkinunv.txt0000644000200500020050000002700215001555412013477 00000000000000BELKINUNV(8) ============ NAME ---- belkinunv - Driver for Belkin "Universal UPS" and compatible SYNOPSIS -------- *belkinunv* -h *belkinunv* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the belkin driver. For information about the core driver, see linkman:nutupsdrv[8]. NOTE: This driver only supports serial connections. If your UPS has a USB port, please consult the Hardware Compatibility List (HCL) to see which of the USB drivers you should use. SUPPORTED HARDWARE ------------------ The belkinunv driver is known to work with the Belkin Universal UPS models F6C800-UNV and F6C120-UNV, and is expected to work with other Belkin Universal UPS models. The driver only supports serial communication, not USB. The Trust UPS and older Belkin units are not supported by this driver, and neither are the Belkin Home Office models (F6H500-SER and so forth). However, some Belkin models, such as the Regulator Pro, are supported by the linkman:belkin[8] driver, and the Home Office models are supported using the linkman:genericups[8] driver with `upstype=7`. SOFT SHUTDOWN WORKAROUND ------------------------ One problem with the Belkin Universal UPS is that it cannot enter a soft shutdown (shut down the load until AC power returns) unless the batteries are completely depleted. Thus, one cannot just shut off the UPS after operating system shutdown; it will not come back on when the power comes back on. Therefore, the *belkinunv* driver should never be used with the *-k* option. Instead, the *-x wait* option is provided as a workaround. When called with the *-x wait* option, *belkinunv* behaves as a standalone program (i.e., it does not fork into the background). It performs one simple task: it connects to the UPS, waits for AC power to return, and then exits with status 0. This is meant to be used in a shutdown script as follows: during a shutdown, after all filesystems have been remounted read-only, and just before the system would normally be halted: check `/etc/killpower` (or similar) to see if this shutdown was caused by linkman:upsmon[8], and if yes, call *belkinunv -x wait*. If AC power comes back on, *belkinunv* exits, and things should be arranged so that the system reboots in this case. If AC power does not come back on, the UPS will eventually run out of batteries, kill the computer's power supply, and go into soft shutdown mode, which means everything will reboot properly when the power returns. In either case, a deadlock is avoided. In addition, if an optional integer argument is given to the *-x wait* option, this causes *belkinunv* to wait not only for AC power to be present, but also for the battery charge to reach the given level. I use this as part of my startup scripts, to ensure that the batteries are sufficiently charged before the computer continues booting. This should be put very early in the startup script, before any filesystems are mounted read/write, and before any filesystem checks are performed. Several other *-x* options are provided to fine-tune this behavior. See the <<_options,options>> below for detailed descriptions. See the <<_examples,examples>> below for examples of how to use *belkinunv* in shutdown and startup scripts. OPTIONS ------- See also linkman:nutupsdrv[8] for generic options. Never use the *-k* option with this driver; it does not work properly. *-x wait*[='level']:: When this option is used, *belkinunv* does not fork into the background, but behaves as a standalone program. It connects to the UPS and waits until AC power is present. If 'level' is specified, it also waits until the battery charge reaches at least the given level in percent. Then, and only then, *belkinunv* exits. In addition, while *belkinunv* runs in this mode, it displays a status line with information on the UPS status and battery level. This is intended for use in the computer's shutdown and startup scripts, as described under <<_soft_shutdown_workaround,Soft Shutdown Workaround>> above. *-x nohang*:: This option only has an effect when used in conjunction with the *-x wait* option. It causes *belkinunv* to exit if a connection with the UPS cannot be established or is lost, instead of retrying forever, which is the default behavior. The *-x nohang* option should be used in a startup script, to ensure the computer remains bootable even if the UPS has been disconnected during the power failure (for instance, you attached your computer to a generator, carried it to a neighbor's house, or whatever). *-x flash*:: This option only has an effect when used in conjunction with the *-x wait* option. It causes the UPS load to be shut off for a short time ("flashed") just after the AC power has returned and the requested battery level (if any) has been attained. This is useful if slaves are attached to this UPS; the flash will cause all of them to reboot. Note that, due to the design of the Belkin UPS hardware, the load shutdown lasts ca. 1--2 minutes; a shorter flash cannot be performed reliably. Also, the computers will reboot at the scheduled time, on battery power if necessary, even if AC power fails again in the meantime. This should not be a problem, as your startup scripts can catch this situation. *-x silent*:: This option only has an effect when used in conjunction with the *-x wait* option. It suppresses the status line which *belkinunv* would normally print. *-x dumbterm*:: This option only has an effect when used in conjunction with the *-x wait* option. It changes the way in which *belkinunv* prints its status line. Normally, terminal control sequences are used to overwrite the same line with new status information, each time the status is updated. This may not work on all terminals. If the *-x dumbterm* option is given, each status update is written on a new line. VARIABLES --------- *battery.charge*:: *battery.runtime*:: not supported by all hardware. *battery.voltage*:: *battery.voltage.nominal*:: *input.frequency*:: *input.frequency.nominal*:: e.g. 60 for 60Hz *input.sensitivity*:: writable: normal/medium/low *input.transfer.high*:: writable: high transfer voltage point in V *input.transfer.low*:: writable: low transfer voltage point in V *input.voltage*:: *input.voltage.maximum*:: *input.voltage.minimum*:: *input.voltage.nominal*:: *output.frequency*:: *output.voltage*:: *ups.beeper.status*:: writable. Values: enabled/disabled/muted. This variable controls the state of the panel beeper. Enabled means sound when the alarm is present, disabled means never sound, and muted means the sound is temporarily disabled until the alarm would normally stop sounding. In the muted state, the beeper is automatically turned back on at the next event (AC failure, battery test, etc). Also, the beeper can't be turned off during a critical event (low battery). Note that not all UPS models support the "disabled" state. *ups.firmware*:: *ups.load*:: *ups.model*:: *ups.power.nominal*:: e.g. 800 for an 800VA system *ups.status*:: a list of flags; see the <<_status_flags,status flags>> below. *ups.temperature*:: not supported by all hardware. *ups.test.result*:: *ups.delay.restart*:: time to restart (read only) *ups.delay.shutdown*:: time to shutdown (read only). This is always a multiple of 60 seconds. *ups.type*:: ONLINE/OFFLINE/LINEINT. This describes the basic layout of this UPS (for GUI clients which want to draw an animated picture of power flow). An offline UPS has a direct connection from AC input to AC output, and also a connection from AC input to the battery, and from the battery to AC output. An online UPS lacks the direct connection from AC input to AC output, whereas a line interactive UPS lacks the connection from AC input to the battery. COMMANDS -------- *beeper.enable, beeper.disable, beeper.mute*:: Enable, disable or mute the panel beeper. Note that if the beeper is muted, it is automatically turned back on at the next event (AC failure, battery test, etc). Also, the beeper can't be turned muted during a critical event (low battery). *reset.input.minmax*:: Reset the variables *input.voltage.minimum* and *input.voltage.maximum*. *shutdown.reboot*:: Shut down load immediately for about 1--2 minutes. *shutdown.reboot.graceful*:: After 40 second delay, shut down load for about 1--2 minutes. *shutdown.stayoff*:: Shut down load immediately and stay off. The only way it can be turned back on is by manually pressing the front panel button. *test.battery.start, test.battery.stop*:: Start/stop 10 second battery test. *test.failure.start, test.failure.stop*:: Start/stop "deep" battery test. STATUS FLAGS ------------ *OB*:: load is on battery, including during tests *OFF*:: load is off *OL*:: load is online *ACFAIL*:: AC failure. Note that this refers to the AC input, and thus it is not the same as "OB". An AC failure can occur at any time, for instance, during a battery test, or when the UPS load is off. *OVER*:: overload *OVERHEAT*:: overheat *COMMFAULT*:: UPS fault *LB*:: low battery *CHRG*:: charging *DEPLETED*:: the battery is depleted. When the UPS raises this flag, it simultaneously switches off the load. *RB*:: replace battery EXAMPLES -------- Here is an example for how *belkinunv* should be used in a computer's shutdown script. These commands should go in the very last part of the shutdown script, after all file systems have been mounted read-only, and just before the computer halts. Note that *belkinunv* must be installed in a directory which is still readable at that point. ---- # NEAR END OF SHUTDOWN SCRIPT: # if shutdown was caused by UPS, perform Belkin UPS workaround. if [ -f /etc/killpower ] || /usr/sbin/upsmon -K ; then echo "Waiting for AC power, or for UPS batteries to run out..." /usr/bin/belkinunv -x wait /dev/ttyS1 # we get here if the power came back on. Reboot. echo "Power is back. Rebooting..." reboot fi ---- And here is an example of how to use *belkinunv* in the startup script. These commands should go near the beginning of the startup script, before any file systems are mounted read/write, and before any file system integrity checks are done. ---- # NEAR BEGINNING OF STARTUP SCRIPT: # if we are recovering from a power failure, wait for the UPS to # charge to a comfortable level before writing anything to disk if [ -f /etc/killpower ] || /usr/sbin/upsmon -K ; then echo "Waiting for UPS battery charge to reach 60%..." /usr/bin/belkinunv -x wait=60 -x nohang /dev/ttyS1 fi ---- EXIT STATUS ----------- When used normally, *belkinunv* forks into the background and its diagnostics are the same as for all NUT drivers, see linkman:nutupsdrv[8]. When used with the *-x wait* option, the exit status is normally *0*. If the *-x nohang* option has also been specified, an exit status of *1* indicates that communication with the UPS was lost. If the *-x flash* option has been specified, an exit status of *2* indicates that the timed shutdown has failed. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in linkman:ups.conf[5]. AUTHOR ------ Peter Selinger SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Other Belkin drivers: ~~~~~~~~~~~~~~~~~~~~~ linkman:belkinunv[8], linkman:blazer_ser[8], linkman:blazer_usb[8], linkman:usbhid-ups[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * The documentation for the protocol used by this UPS: link:http://www.mscs.dal.ca/~selinger/ups/belkin-universal-ups.html[belkin-universal-ups.html] (link:https://www.networkupstools.org/protocols/belkin-universal.html[replica on NUT site]) nut-2.8.3/docs/man/nutscan_scan_eaton_serial.30000644000200500020050000000524415001555060016234 00000000000000'\" t .\" Title: nutscan_scan_eaton_serial .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_SCAN_EATON_S" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_scan_eaton_serial \- Scan serial ports for Eaton devices (XCP, SHUT and Q1)\&. .SH "SYNOPSIS" .sp .nf #include nutscan_device_t * nutscan_scan_eaton_serial(const char* ports_list); .fi .SH "DESCRIPTION" .sp The \fBnutscan_scan_eaton_serial()\fR function tries to detect NUT devices which are compatible with Eaton\(cqs serial device protocols (SHUT, XCP and Q1 (aka blazer or megatec))\&. .sp \fIports_list\fR is a NULL\-terminated array of pointers to strings containing serial device name (/dev/ttyS0, COM1, /dev/ttya\&...) .sp You MUST call \fBnutscan_init\fR(3) before using this function\&. .SH "RETURN VALUE" .sp The \fBnutscan_scan_eaton_serial()\fR function returns a pointer to a nutscan_device_t structure containing all found devices or NULL if an error occurs or no device is found\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_get_serial_ports_list\fR(3) nut-2.8.3/docs/man/bcmxcp_usb.80000644000200500020050000001211515001555076013164 00000000000000'\" t .\" Title: bcmxcp_usb .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BCMXCP_USB" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" bcmxcp_usb \- Experimental driver for UPSes supporting the BCM/XCP protocol over USB .SH "SYNOPSIS" .sp \fBbcmxcp_usb\fR \-h .sp \fBbcmxcp_usb\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the bcmxcp_usb driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This driver is a variant of the serial driver \fBbcmxcp\fR(8) and uses the same core code\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver should recognize all BCM/XCP\-compatible UPSes that are connected via USB\&. It has been developed and tested on Powerware PW3501 hardware\&. It also has been tested on PW5110 hardware\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5)\&. .PP \fBshutdown_delay =\fR \fIdelay\fR .RS 4 The number of seconds that the UPS should wait between receiving the shutdown command and actually shutting off\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This driver does not currently support USB\-matching settings common to other drivers, such as \fBvendor\fR, \fBvendorid\fR, \fBproduct\fR, \fBproductid\fR, \fBserial\fR, \fBdevice\fR or \fBbus\fR\&. .sp .5v .RE .SH "DEFAULT VALUES FOR THE EXTRA ARGUMENTS" .sp \fBshutdown_delay =\fR\fI120\fR .SH "INSTANT COMMANDS" .sp This driver supports the following Instant Commands: .PP \fBshutdown\&.return\fR .RS 4 Turn off the load and return when power is back\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Turn off the load and remain off\&. .RE .PP \fBtest\&.battery\&.start\fR .RS 4 Start a battery test\&. .RE .SH "TODO LIST" .PP \fBReport UPS alarm status\fR .RS 4 BCM/XCP supports reporting a wide range of UPS alarm conditions\&. .RE .PP \fBReport UPS statistics information\fR .RS 4 BCM/XCP supports reporting of UPS statistics data\&. .RE .SH "EXPERIMENTAL DRIVER" .sp This driver has been tagged experimental, even if it has been reported to be stable\&. Thus it is not suitable for production systems and it may be not built by default\&. This is mainly due to the fact that it is a new driver\&. .SH "INSTALLATION" .sp This driver may be not built by default\&. You can require building it by using \&./configure \-\-with\-usb=yes (note that it will also install other USB drivers), or \&./configure \-\-with\-drivers=bcmxcp_usb\&. Either way, you would need libusb\-dev (libraries and headers package) or equivalent for other platforms\&. .sp You also need to install manually the hotplug files (libhidups and libhid\&.usermap), generally in etc/hotplug/usb/, to address the permission settings problem\&. Lastly note that the libhidups file must have execution flag set (ie using chmod +x \&...)\&. .SH "IMPLEMENTATION" .sp bcmxcp_usb only supports 1 UPS at this time\&. You can put the "auto" value for port in ups\&.conf, i\&.e\&.: .sp .if n \{\ .RS 4 .\} .nf [pw3105] driver = bcmxcp_usb port = auto .fi .if n \{\ .RE .\} .SH "KNOWN ISSUES AND BUGS" .SS ""Got EPERM: Operation not permitted upon driver startup"" .sp You have forgotten to install the hotplug files, as explained in the INSTALLATION section above\&. Don\(cqt forget to restart hotplug so that it applies these changes\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Tore Ørpetveit .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Wolfgang Ocker .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutclient_destroy.30000644000200500020050000000004015001555117014576 00000000000000.so man3/libnutclient_general.3 nut-2.8.3/docs/man/libnutclient_commands.30000644000200500020050000000711015001555055015403 00000000000000'\" t .\" Title: libnutclient_commands .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIBNUTCLIENT_COMMAND" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libnutclient_commands, nutclient_get_device_commands, nutclient_has_device_command, nutclient_get_device_command_description, nutclient_execute_device_command \- Instant command related functions in Network UPS Tools high\-level client access library .SH "SYNOPSIS" .sp .nf #include typedef void* NUTCLIENT_t; typedef char** strarr; strarr nutclient_get_device_commands( NUTCLIENT_t client, const char* dev); int nutclient_has_device_command( NUTCLIENT_t client, const char* dev, const char* cmd); char* nutclient_get_device_command_description( NUTCLIENT_t client, const char* dev, const char* cmd); void nutclient_execute_device_command( NUTCLIENT_t client, const char* dev, const char* cmd, const char* param=""); .fi .SH "DESCRIPTION" .sp These functions allow to manage instant commands of devices\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_device_commands()\fR function retrieves the list of command names for a device\&. .sp The returned strarr must be freed by \fIstrarr_free\fR\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_has_device_command\fR function tests if the specified command is supported by the device\&. .sp Return \fI1\fR if supported and \fI0\fR if not\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_device_command_description\fR function retrieves the command description, if any\&. .sp The returned string must be freed by \fBfree\fR(3) (see \fBlibnutclient_general\fR(3))\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_execute_device_command\fR intends to execute the instant command, with an optional parameter\&. .RE .sp Common arguments: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIdev\fR is the device name\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIcmd\fR is the instant command name\&. .RE .SH "SEE ALSO" .sp \fBlibnutclient\fR(3) \fBlibnutclient_devices\fR(3) \fBlibnutclient_general\fR(3) nut-2.8.3/docs/man/libnutclient.txt0000644000200500020050000000276215001555412014204 00000000000000LIBNUTCLIENT(3) =============== NAME ---- libnutclient - Network UPS Tools high-level client access library SYNOPSIS -------- ------ #include ------ Refer to this file for more information. DESCRIPTION ----------- The Network UPS Tools (NUT) *nutclient* library provides a number of useful functions for programs to use when communicating with linkman:upsd[8]. It provides high-level representation of NUT data through client connection, devices, variables and commands. Unlike linkman:upsclient[3] (also known as "upscli" API), here all low-level protocol details are hidden. State is maintained across calls in an opaque structure called `NUTCLIENT_t`. Callers are expected to create one per client connection. These will be provided to most of the *nutclient* functions. The format of this structure is subject to change, and client programs must not reference elements within it directly. `NUTCLIENT_t` represents the common connection information. Derived versions exist for each connection type (`NUTCLIENT_TCP_t` for TCP connection; actually the unique connection type, `NUTCLIENT_TCP_t` can be passed as `NUTCLIENT_t` parameter). See the `nutclient.h` header for more information. ERROR HANDLING -------------- There is currently no specific mechanism around error handling. SEE ALSO -------- linkman:libnutclient_devices[3] linkman:libnutclient_commands[3] linkman:libnutclient_general[3] linkman:libnutclient_misc[3] linkman:libnutclient_tcp[3] linkman:libnutclient_variables[3] nut-2.8.3/docs/man/nutclient_get_devices.30000644000200500020050000000004015001555117015366 00000000000000.so man3/libnutclient_devices.3 nut-2.8.3/docs/man/upscli_disconnect.30000644000200500020050000000404615001555051014537 00000000000000'\" t .\" Title: upscli_disconnect .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_DISCONNECT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_disconnect \- Disconnect from a UPS server .SH "SYNOPSIS" .sp .nf #include int upscli_disconnect(UPSCONN_t *ups); .fi .SH "DESCRIPTION" .sp The \fBupscli_disconnect()\fR function takes the pointer \fIups\fR to a UPSCONN_t state structure, shuts down the connection to the server, and frees dynamic memory used by the state structure\&. .sp The UPSCONN_t structure is no longer valid after this function is called\&. .sp This function must be called, or your program will leak memory and file descriptors\&. .SH "RETURN VALUE" .sp The \fBupscli_disconnect()\fR function returns \fI0\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_connect\fR(3), \fBupscli_fd\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/Makefile.in0000644000200500020050000026761115001555011013015 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: man pages # # Notes: # - sources (.txt) and groff formats are both distributed, # - only sources are versioned ; groff files are generated at worst # during 'make dist' (while preparing a release tarball) # - HTML files are built upon request, if AsciiDoc is available, # - groff update will only happen if AsciiDoc is available too, # - all this can probably (and hopefully) be improved, but I've not # found a way to do pattern replacement on the fly for target deps! # FIXME: investigate an autogen.sh hook # - Ref: http://www.gnu.org/software/hello/manual/automake/Man-pages.html # - WITH_MANS can be enabled if either we are building man-pages, or if # the --with-doc=man=auto detected an inability to build the man-pages # but enabled the DOC_INSTALL_DISTED_MANS toggle so we deliver disted # files from source tree # - Man page lists are collected into several patterns of make variables # (FIXME? to simplify?) : # * INST_MAN_xxx_PAGES, INST_HTML_xxx_PAGES: what we would install # (if building of man/HTML pages, and perhaps an optional tool building, # are enabled); # * MAN_xxx_PAGES: what we actually enable to build and deliver (may be empty); # * HTML_xxx_PAGES: populated most of the time, buildable optionally; # * DIST_ALL_PAGES: all known page file names, to help ensure dist archive # contains everything that any build may want (even if missing tools to # build the docs from scratch, or choosing not to do that for speed). # * DIST_ALL_MAN_PAGES: all known MAN page file names, to help ensure dist archive # * DIST_ALL_HTML_PAGES: all known HTML page file names, to help ensure nut-website VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ # Give it our best shot; do not try if we know we would fail # Do not distcheck-light-DIST_ALL_MAN_PAGES for fake pages either - # this is up to caller and use-case @KNOWN_UNABLE_MANS_FALSE@@WITH_MANS_TRUE@am__append_1 = all-man @WITH_HTML_SINGLE_TRUE@am__append_2 = all-html @WITH_HTML_CHUNKED_TRUE@@WITH_HTML_SINGLE_FALSE@am__append_3 = all-html @HAVE_WINDOWS_TRUE@am__append_4 = nut.exe.txt @HAVE_WINDOWS_TRUE@@WITH_MANS_TRUE@am__append_5 = $(MAN_CLIENT_PAGES_ADDON_NUT_EXE) @HAVE_WINDOWS_TRUE@@WITH_MANS_FALSE@am__append_6 = $(MAN_CLIENT_PAGES_ADDON_NUT_EXE) @HAVE_WINDOWS_FALSE@am__append_7 = nut.exe.txt @HAVE_WINDOWS_FALSE@am__append_8 = $(MAN_CLIENT_PAGES_ADDON_NUT_EXE) @WITH_NUT_MONITOR_TRUE@am__append_9 = NUT-Monitor.txt @WITH_MANS_TRUE@@WITH_NUT_MONITOR_TRUE@am__append_10 = $(MAN_CLIENT_PAGES_ADDON_NUT_MONITOR) @WITH_MANS_FALSE@@WITH_NUT_MONITOR_TRUE@am__append_11 = $(MAN_CLIENT_PAGES_ADDON_NUT_MONITOR) @WITH_NUT_MONITOR_FALSE@am__append_12 = NUT-Monitor.txt @WITH_NUT_MONITOR_FALSE@am__append_13 = $(MAN_CLIENT_PAGES_ADDON_NUT_MONITOR) @HAVE_WINDOWS_TRUE@am__append_14 = nut.exe.html @HAVE_WINDOWS_FALSE@am__append_15 = nut.exe.html @WITH_NUT_MONITOR_TRUE@am__append_16 = NUT-Monitor.html @WITH_NUT_MONITOR_FALSE@am__append_17 = NUT-Monitor.html @WITH_CGI_TRUE@am__append_18 = $(MAN_CGI_CFG_PAGES) @WITH_CGI_TRUE@am__append_19 = $(MAN_CGI_CMD_SYS_PAGES) @WITH_DEV_TRUE@am__append_20 = $(MAN_DEV_API_PAGES) @WITH_DEV_TRUE@am__append_21 = $(MAN_DEV_CMD_SYS_PAGES) @WITH_DEV_TRUE@@WITH_PKG_CONFIG_FALSE@am__append_22 = $(MAN_DEV_CMD_USR_PAGES) # Drivers related manpages # If (--with-drivers=...) then we only build specific documents, however # still do track (and EXTRA_DIST, and spellcheck) all available sources. @SOME_DRIVERS_TRUE@am__append_23 = $(DRIVER_MAN_LIST) # Temporary, until ported to more OSes @HAVE_LINUX_SERIAL_H_TRUE@@SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@am__append_24 = \ @HAVE_LINUX_SERIAL_H_TRUE@@SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@ nhs_ser.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_SERIAL_TRUE@am__append_25 = $(MAN_SERIAL_PAGES) # Temporary, until ported to more OSes @HAVE_LINUX_SERIAL_H_TRUE@am__append_26 = \ @HAVE_LINUX_SERIAL_H_TRUE@ nhs_ser.html @HAVE_LINUX_SERIAL_H_FALSE@am__append_27 = \ @HAVE_LINUX_SERIAL_H_FALSE@ nhs_ser.html @SOME_DRIVERS_FALSE@@WITH_SNMP_TRUE@am__append_28 = $(MAN_SNMP_PAGES) @SOME_DRIVERS_FALSE@@WITH_USB_TRUE@am__append_29 = $(MAN_USB_LIBUSB_PAGES) @SOME_DRIVERS_FALSE@@WITH_SERIAL_TRUE@am__append_30 = $(MAN_SERIAL_USB_PAGES) @SOME_DRIVERS_FALSE@@WITH_SERIAL_FALSE@@WITH_USB_TRUE@am__append_31 = $(MAN_SERIAL_USB_PAGES) @SOME_DRIVERS_FALSE@@WITH_NEON_TRUE@am__append_32 = $(MAN_NETXML_PAGES) @SOME_DRIVERS_FALSE@@WITH_LIBPOWERMAN_TRUE@am__append_33 = $(MAN_POWERMAN_PAGES) @SOME_DRIVERS_FALSE@@WITH_IPMI_TRUE@am__append_34 = $(MAN_IPMIPSU_PAGES) @SOME_DRIVERS_FALSE@@WITH_MACOSX_TRUE@am__append_35 = $(MAN_MACOSX_PAGES) @SOME_DRIVERS_FALSE@@WITH_MODBUS_TRUE@am__append_36 = $(MAN_MODBUS_PAGES) @SOME_DRIVERS_FALSE@@WITH_LINUX_I2C_TRUE@am__append_37 = $(MAN_LINUX_I2C_PAGES) @SOME_DRIVERS_FALSE@@WITH_GPIO_TRUE@am__append_38 = $(MAN_GPIO_PAGES) @WITH_MANS_TRUE@am__append_39 = \ @WITH_MANS_TRUE@ $(MAN_CONF_PAGES) \ @WITH_MANS_TRUE@ $(MAN_CLIENT_PAGES) \ @WITH_MANS_TRUE@ $(MAN_TOOL_PAGES) \ @WITH_MANS_TRUE@ $(MAN_CGI_CFG_PAGES) \ @WITH_MANS_TRUE@ $(MAN_CGI_CMD_SYS_PAGES) \ @WITH_MANS_TRUE@ $(MAN_DEV_CMD_USR_PAGES) \ @WITH_MANS_TRUE@ $(MAN_DEV_API_PAGES) \ @WITH_MANS_TRUE@ $(MAN_DEV_CMD_SYS_PAGES) \ @WITH_MANS_TRUE@ $(MAN_SERIAL_PAGES) \ @WITH_MANS_TRUE@ $(MAN_SNMP_PAGES) \ @WITH_MANS_TRUE@ $(MAN_USB_LIBUSB_PAGES) \ @WITH_MANS_TRUE@ $(MAN_SERIAL_USB_PAGES) \ @WITH_MANS_TRUE@ $(MAN_NETXML_PAGES) \ @WITH_MANS_TRUE@ $(MAN_POWERMAN_PAGES) \ @WITH_MANS_TRUE@ $(MAN_IPMIPSU_PAGES) \ @WITH_MANS_TRUE@ $(MAN_MACOSX_PAGES) \ @WITH_MANS_TRUE@ $(MAN_MODBUS_PAGES) \ @WITH_MANS_TRUE@ $(MAN_LINUX_I2C_PAGES) \ @WITH_MANS_TRUE@ $(MAN_GPIO_PAGES) # (Legacy note) The list above probably came up empty in this case, so make sure # that the drivers requested by configure script are documented in the build; # notably in the linkman-driver-names.txt file. @SOME_DRIVERS_TRUE@am__append_40 = \ @SOME_DRIVERS_TRUE@ $(DRIVER_MAN_LIST_PAGES) @WITH_HTML_SINGLE_TRUE@am__append_41 = $(HTML_MANS) @WITH_HTML_CHUNKED_TRUE@@WITH_HTML_SINGLE_FALSE@am__append_42 = $(HTML_MANS) @WITH_HTML_SINGLE_TRUE@am__append_43 = check-html-man @WITH_HTML_CHUNKED_TRUE@@WITH_HTML_SINGLE_FALSE@am__append_44 = check-html-man # Only clean away build products if we can reproduce them # including cases where we generate placeholders @WITH_MANS_TRUE@am__append_45 = *.$(MAN_SECTION_CMD_USR) *.$(MAN_SECTION_API) *.$(MAN_SECTION_CFG) *.$(MAN_SECTION_CMD_SYS) @HAVE_ASCIIDOC_TRUE@@WITH_MANS_FALSE@am__append_46 = *.$(MAN_SECTION_CMD_USR) *.$(MAN_SECTION_API) *.$(MAN_SECTION_CFG) *.$(MAN_SECTION_CMD_SYS) # Only clean away build products if we can reproduce them @HAVE_ASCIIDOC_TRUE@am__append_47 = *.xml *.html *.pdf subdir = docs/man ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(htmlmandir)" "$(DESTDIR)$(manapidir)" \ "$(DESTDIR)$(mancfgdir)" "$(DESTDIR)$(mansysdir)" \ "$(DESTDIR)$(manusrdir)" DATA = $(htmlman_DATA) $(manapi_DATA) $(mancfg_DATA) $(mansys_DATA) \ $(manusr_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ # Is "egrep == grep -E" always valid? (maybe all a job for configure.ac) #EGREP = egrep EGREP = grep -E EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ # Possible man page section remapping in some distros: MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ # Other rewritable properties: NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ # distribute everything, even those not installed by default # Note that 'dist' target requires AsciiDoc! SRC_ALL_PAGES = index.txt $(am__append_7) $(am__append_12) \ $(SRC_CONF_PAGES) $(SRC_CLIENT_PAGES) $(SRC_TOOL_PAGES) \ $(SRC_CGI_PAGES) $(SRC_DEV_PAGES) $(SRC_DRIVERS_PAGES) \ index.txt # Used for dist completeness checks; the actual build products # (depending on enabled features) are in MAN_MANS and HTML_MANS. # This does not necessarily trigger the build, just allows us # to check if they all exist. DIST_ALL_MAN_PAGES = $(INST_MAN_CONF_PAGES) $(INST_MAN_CLIENT_PAGES) \ $(am__append_6) $(am__append_8) $(am__append_11) \ $(am__append_13) $(INST_MAN_TOOL_PAGES) \ $(INST_MAN_CGI_CFG_PAGES) $(INST_MAN_CGI_CMD_SYS_PAGES) \ $(INST_MAN_DEV_API_PAGES) $(INST_MAN_DEV_CMD_USR_PAGES) \ $(INST_MAN_DEV_CMD_SYS_PAGES) $(INST_MAN_SERIAL_PAGES) \ nhs_ser.$(MAN_SECTION_CMD_SYS) $(INST_MAN_SNMP_PAGES) \ $(INST_MAN_USB_LIBUSB_PAGES) $(INST_MAN_SERIAL_USB_PAGES) \ $(INST_MAN_NETXML_PAGES) $(INST_MAN_POWERMAN_PAGES) \ $(INST_MAN_IPMIPSU_PAGES) $(INST_MAN_MACOSX_PAGES) \ $(INST_MAN_MODBUS_PAGES) $(INST_MAN_LINUX_I2C_PAGES) DIST_ALL_HTML_PAGES = index.html $(INST_HTML_CONF_MANS) \ $(am__append_15) $(am__append_17) $(INST_HTML_CLIENT_MANS) \ $(INST_HTML_TOOL_MANS) $(INST_HTML_CGI_MANS) \ $(INST_HTML_DEV_MANS) $(am__append_27) \ $(INST_HTML_SERIAL_MANS) $(INST_HTML_SNMP_MANS) \ $(INST_HTML_USB_LIBUSB_MANS) $(INST_HTML_SERIAL_USB_MANS) \ $(INST_HTML_NETXML_MANS) $(INST_HTML_POWERMAN_MANS) \ $(INST_HTML_IPMIPSU_MANS) $(INST_HTML_MACOSX_MANS) \ $(INST_HTML_MODBUS_MANS) $(INST_HTML_LINUX_I2C_MANS) \ $(INST_HTML_GPIO_MANS) # HTML collection is for nut-website primarily, not for tarballs... so far... DIST_ALL_PAGES = $(DIST_ALL_MAN_PAGES) $(INST_MAN_GPIO_PAGES) # Groups and locations for man pages manapidir = $(mandir)/man$(MAN_SECTION_API_BASE) manapi_DATA = $(am__append_20) mancfgdir = $(mandir)/man$(MAN_SECTION_CFG_BASE) mancfg_DATA = $(MAN_CONF_PAGES) $(am__append_18) mansysdir = $(mandir)/man$(MAN_SECTION_CMD_SYS_BASE) mansys_DATA = $(MAN_CLIENT_PAGES) $(MAN_TOOL_PAGES) $(am__append_19) \ $(am__append_21) $(am__append_23) $(am__append_25) \ $(am__append_28) $(am__append_29) $(am__append_30) \ $(am__append_31) $(am__append_32) $(am__append_33) \ $(am__append_34) $(am__append_35) $(am__append_36) \ $(am__append_37) $(am__append_38) manusrdir = $(mandir)/man$(MAN_SECTION_CMD_USR_BASE) manusr_DATA = $(am__append_22) ALL_TGT = $(am__append_1) $(am__append_2) $(am__append_3) # Ensure early build by default automake "all" rule, if it gets used. BUILT_SOURCES = $(abs_top_builddir)/docs/man/.prep-src-docs all-optional # Quickly check that we have all needed files (e.g. from configure script) # Do not ensure they are built/valid/etc. LIST_FILES = ( \ echo " HELPER $@" >&2 ; \ MISSING=0; \ TOTAL=0; \ for P in $${FILENAMES} ; do \ TOTAL="`expr $$TOTAL + 1`" ; \ F="`basename "$$P"`" ; \ if [ -s "$(abs_builddir)/$$F" ] ; then \ echo "BUILDDIR: $(builddir)/$$F" ; \ else \ if [ -s "$(abs_srcdir)/$$F" ] ; then \ echo "SRCDIR: $(srcdir)/$$F" ; \ else \ echo "MISSING: $$F" >&2 ; \ MISSING="`expr $$MISSING + 1`" ; \ fi ; \ fi ; \ done ; \ if [ x"$$MISSING" = x0 ] ; then echo "$@: SUCCESS ($$TOTAL files are all present)" >&2 ; else echo "$@: FAILED ($$MISSING files of $$TOTAL are missing, see above)" >&2 ; exit 1 ; fi ; \ ) @DOC_INSTALL_DISTED_MANS_FALSE@@KNOWN_UNABLE_MANS_FALSE@FAKE_PAGES_BUMP_SRC = true @DOC_INSTALL_DISTED_MANS_TRUE@@KNOWN_UNABLE_MANS_FALSE@FAKE_PAGES_BUMP_SRC = false @KNOWN_UNABLE_MANS_TRUE@FAKE_PAGES_BUMP_SRC = false FAKE_FILES = ( \ echo " HELPER $@" >&2 ; \ MISSING=0; \ TOTAL=0; \ for P in $${FILENAMES} ; do \ TOTAL="`expr $$TOTAL + 1`" ; \ F="`basename "$$P"`" ; \ if [ ! -s "$(abs_builddir)/$$F" ] && [ ! -s "$(abs_srcdir)/$$F" ] ; then \ echo "PLACEHOLDER" > "$(abs_builddir)/$$F" ; \ MISSING="`expr $$MISSING + 1`" ; \ fi ; \ done ; \ if [ x"$$MISSING" = x0 ] ; then echo "$@: SUCCESS ($$TOTAL files are all present)" >&2 ; else echo "$@: FAKED SOME FILES ($$MISSING files of $$TOTAL were missing)" >&2 ; exit 1 ; fi ; \ ) # Unlike helpers above, does not fail if placeholders were seen FAKE_FILES_RM = ( \ echo " HELPER $@" >&2 ; \ MISSING=0; \ TOTAL=0; \ for P in $${FILENAMES} ; do \ TOTAL="`expr $$TOTAL + 1`" ; \ F="`basename "$$P"`" ; \ if [ -s "$(abs_builddir)/$$F" ] \ && [ x"PLACEHOLDER" = x"`cat "$(abs_builddir)/$$F"`" ] ; then \ rm -f "$(abs_builddir)/$$F" ; \ MISSING="`expr $$MISSING + 1`" ; \ fi ; \ done ; \ if [ x"$$MISSING" = x0 ] ; then echo "$@: SUCCESS ($$TOTAL files were all real or already absent)" >&2 ; else echo "$@: REMOVED SOME FAKED FILES ($$MISSING files of $$TOTAL were placeholders)" >&2 ; fi ; \ ) # Base configuration and client manpages, always installed SRC_CONF_PAGES = \ nut.conf.txt \ ups.conf.txt \ upsd.conf.txt \ upsd.users.txt \ upsmon.conf.txt \ upssched.conf.txt INST_MAN_CONF_PAGES = \ nut.conf.$(MAN_SECTION_CFG) \ ups.conf.$(MAN_SECTION_CFG) \ upsd.conf.$(MAN_SECTION_CFG) \ upsd.users.$(MAN_SECTION_CFG) \ upsmon.conf.$(MAN_SECTION_CFG) \ upssched.conf.$(MAN_SECTION_CFG) @WITH_MANS_TRUE@MAN_CONF_PAGES = $(INST_MAN_CONF_PAGES) INST_HTML_CONF_MANS = \ nut.conf.html \ ups.conf.html \ upsd.conf.html \ upsd.users.html \ upsmon.conf.html \ upssched.conf.html HTML_CONF_MANS = $(INST_HTML_CONF_MANS) # NOTE: Currently SRC_DRIVERTOOL_PAGES are a separate list to generate # a linkman-drivertool-names.txt file, but historically remain part of # MAN/HTML_CLIENT_PAGES in the bigger picture. SRC_DRIVERTOOL_PAGES = \ nut-driver-enumerator.txt \ upsdrvctl.txt \ upsdrvsvcctl.txt SRC_CLIENT_PAGES = $(SRC_DRIVERTOOL_PAGES) nutupsdrv.txt upsc.txt \ upscmd.txt upsd.txt upslog.txt upsmon.txt upsrw.txt \ upssched.txt $(am__append_4) $(am__append_9) INST_MAN_CLIENT_PAGES = nutupsdrv.$(MAN_SECTION_CMD_SYS) \ nut-driver-enumerator.$(MAN_SECTION_CMD_SYS) \ upsc.$(MAN_SECTION_CMD_SYS) upscmd.$(MAN_SECTION_CMD_SYS) \ upsd.$(MAN_SECTION_CMD_SYS) upsdrvctl.$(MAN_SECTION_CMD_SYS) \ upsdrvsvcctl.$(MAN_SECTION_CMD_SYS) \ upslog.$(MAN_SECTION_CMD_SYS) upsmon.$(MAN_SECTION_CMD_SYS) \ upsrw.$(MAN_SECTION_CMD_SYS) upssched.$(MAN_SECTION_CMD_SYS) \ $(am__append_5) $(am__append_10) @WITH_MANS_TRUE@MAN_CLIENT_PAGES = $(INST_MAN_CLIENT_PAGES) MAN_CLIENT_PAGES_ADDON_NUT_EXE = nut.exe.$(MAN_SECTION_CMD_SYS) MAN_CLIENT_PAGES_ADDON_NUT_MONITOR = \ NUT-Monitor-py2gtk2.$(MAN_SECTION_CMD_SYS) \ NUT-Monitor-py3qt5.$(MAN_SECTION_CMD_SYS) \ NUT-Monitor.$(MAN_SECTION_CMD_SYS) INST_HTML_CLIENT_MANS = nutupsdrv.html nut-driver-enumerator.html \ upsc.html upscmd.html upsd.html upsdrvctl.html \ upsdrvsvcctl.html upslog.html upsmon.html upsrw.html \ upssched.html $(am__append_14) $(am__append_16) # Can't make this work on all make implementations at once, so disabled for now # Anyway it would be the same man-like page for several functions @WITH_NUT_MONITOR_TRUE@INST_HTML_CLIENT_MANS_FICTION = \ @WITH_NUT_MONITOR_TRUE@ NUT-Monitor-py2gtk2.html \ @WITH_NUT_MONITOR_TRUE@ NUT-Monitor-py3qt5.html HTML_CLIENT_MANS = $(INST_HTML_CLIENT_MANS) SRC_TOOL_PAGES = \ nut-scanner.txt \ nut-recorder.txt \ nutconf.txt # FIXME: Make nut-scanner and nut-conf pages optional (if tool is enabled)? INST_MAN_TOOL_PAGES = \ nut-scanner.$(MAN_SECTION_CMD_SYS) \ nut-recorder.$(MAN_SECTION_CMD_SYS) \ nutconf.$(MAN_SECTION_CMD_SYS) @WITH_MANS_TRUE@MAN_TOOL_PAGES = $(INST_MAN_TOOL_PAGES) # FIXME: Make nut-scanner and nut-conf pages optional (if tool is enabled)? INST_HTML_TOOL_MANS = \ nut-scanner.html \ nut-recorder.html \ nutconf.html HTML_TOOL_MANS = $(INST_HTML_TOOL_MANS) # CGI (--with-cgi) related manpages SRC_CGI_PAGES = \ hosts.conf.txt \ upsset.conf.txt \ upsstats.html.txt \ upsset.cgi.txt \ upsstats.cgi.txt \ upsimage.cgi.txt INST_MAN_CGI_CFG_PAGES = \ hosts.conf.$(MAN_SECTION_CFG) \ upsset.conf.$(MAN_SECTION_CFG) \ upsstats.html.$(MAN_SECTION_CFG) INST_MAN_CGI_CMD_SYS_PAGES = \ upsset.cgi.$(MAN_SECTION_CMD_SYS) \ upsstats.cgi.$(MAN_SECTION_CMD_SYS) \ upsimage.cgi.$(MAN_SECTION_CMD_SYS) @WITH_MANS_TRUE@MAN_CGI_CFG_PAGES = $(INST_MAN_CGI_CFG_PAGES) @WITH_MANS_TRUE@MAN_CGI_CMD_SYS_PAGES = $(INST_MAN_CGI_CMD_SYS_PAGES) INST_HTML_CGI_MANS = \ hosts.conf.html \ upsset.conf.html \ upsstats.html.html \ upsset.cgi.html \ upsstats.cgi.html \ upsimage.cgi.html HTML_CGI_MANS = $(INST_HTML_CGI_MANS) # Development (--with-dev) related manpages SRC_DEV_PAGES = \ upsclient.txt \ upscli_add_host_cert.txt \ upscli_cleanup.txt \ upscli_connect.txt \ upscli_disconnect.txt \ upscli_fd.txt \ upscli_get.txt \ upscli_init.txt \ upscli_set_default_connect_timeout.txt \ upscli_get_default_connect_timeout.txt \ upscli_init_default_connect_timeout.txt \ upscli_list_next.txt \ upscli_list_start.txt \ upscli_readline.txt \ upscli_sendline.txt \ upscli_splitaddr.txt \ upscli_splitname.txt \ upscli_ssl.txt \ upscli_strerror.txt \ upscli_upserror.txt \ upscli_str_add_unique_token.txt \ upscli_str_contains_token.txt \ libnutclient.txt \ libnutclient_commands.txt \ libnutclient_devices.txt \ libnutclient_general.txt \ libnutclient_misc.txt \ libnutclient_tcp.txt \ libnutclient_variables.txt \ nutscan.txt \ nutscan_scan_snmp.txt \ nutscan_scan_usb.txt \ nutscan_scan_xml_http_range.txt \ nutscan_scan_nut.txt \ nutscan_scan_nut_simulation.txt \ nutscan_scan_avahi.txt \ nutscan_scan_ipmi.txt \ nutscan_scan_eaton_serial.txt \ nutscan_display_sanity_check.txt \ nutscan_display_sanity_check_serial.txt \ nutscan_display_ups_conf_with_sanity_check.txt \ nutscan_display_ups_conf.txt \ nutscan_display_parsable.txt \ nutscan_init_ip_ranges.txt \ nutscan_free_ip_ranges.txt \ nutscan_stringify_ip_ranges.txt \ nutscan_add_ip_range.txt \ nutscan_ip_ranges_iter_init.txt \ nutscan_ip_ranges_iter_inc.txt \ nutscan_cidr_to_ip.txt \ nutscan_new_device.txt \ nutscan_free_device.txt \ nutscan_add_option_to_device.txt \ nutscan_add_device_to_device.txt \ nutscan_init.txt \ nutscan_get_serial_ports_list.txt \ libupsclient-config.txt \ sockdebug.txt \ skel.txt # NOTE: nutclient_*.$(MAN_SECTION_API) has no source counterpart (libnutclient_*.txt) LIBNUTCLIENT_MISC_DEPS = \ nutclient_authenticate.$(MAN_SECTION_API) \ nutclient_logout.$(MAN_SECTION_API) \ nutclient_device_login.$(MAN_SECTION_API) \ nutclient_get_device_num_logins.$(MAN_SECTION_API) \ nutclient_device_master.$(MAN_SECTION_API) \ nutclient_device_forced_shutdown.$(MAN_SECTION_API) LIBNUTCLIENT_TCP_DEPS = \ nutclient_tcp_create_client.$(MAN_SECTION_API) \ nutclient_tcp_disconnect.$(MAN_SECTION_API) \ nutclient_tcp_get_timeout.$(MAN_SECTION_API) \ nutclient_tcp_is_connected.$(MAN_SECTION_API) \ nutclient_tcp_reconnect.$(MAN_SECTION_API) \ nutclient_tcp_set_timeout.$(MAN_SECTION_API) LIBNUTCLIENT_GENERAL_DEPS = \ nutclient_destroy.$(MAN_SECTION_API) LIBNUTCLIENT_VARIABLES_DEPS = \ nutclient_get_device_rw_variables.$(MAN_SECTION_API) \ nutclient_get_device_variable_description.$(MAN_SECTION_API) \ nutclient_get_device_variables.$(MAN_SECTION_API) \ nutclient_get_device_variable_values.$(MAN_SECTION_API) \ nutclient_has_device_variable.$(MAN_SECTION_API) \ nutclient_set_device_variable_value.$(MAN_SECTION_API) \ nutclient_set_device_variable_values.$(MAN_SECTION_API) LIBNUTCLIENT_COMMANDS_DEPS = \ nutclient_execute_device_command.$(MAN_SECTION_API) \ nutclient_get_device_command_description.$(MAN_SECTION_API) \ nutclient_get_device_commands.$(MAN_SECTION_API) \ nutclient_has_device_command.$(MAN_SECTION_API) LIBNUTCLIENT_DEVICES_DEPS = \ nutclient_get_device_description.$(MAN_SECTION_API) \ nutclient_get_devices.$(MAN_SECTION_API) \ nutclient_has_device.$(MAN_SECTION_API) INST_MAN_DEV_API_PAGES = \ upsclient.$(MAN_SECTION_API) \ upscli_add_host_cert.$(MAN_SECTION_API) \ upscli_cleanup.$(MAN_SECTION_API) \ upscli_connect.$(MAN_SECTION_API) \ upscli_tryconnect.$(MAN_SECTION_API) \ upscli_disconnect.$(MAN_SECTION_API) \ upscli_fd.$(MAN_SECTION_API) \ upscli_get.$(MAN_SECTION_API) \ upscli_init.$(MAN_SECTION_API) \ upscli_set_default_connect_timeout.$(MAN_SECTION_API) \ upscli_get_default_connect_timeout.$(MAN_SECTION_API) \ upscli_init_default_connect_timeout.$(MAN_SECTION_API) \ upscli_list_next.$(MAN_SECTION_API) \ upscli_list_start.$(MAN_SECTION_API) \ upscli_readline.$(MAN_SECTION_API) \ upscli_readline_timeout.$(MAN_SECTION_API) \ upscli_sendline.$(MAN_SECTION_API) \ upscli_sendline_timeout.$(MAN_SECTION_API) \ upscli_splitaddr.$(MAN_SECTION_API) \ upscli_splitname.$(MAN_SECTION_API) \ upscli_ssl.$(MAN_SECTION_API) \ upscli_strerror.$(MAN_SECTION_API) \ upscli_upserror.$(MAN_SECTION_API) \ upscli_str_add_unique_token.$(MAN_SECTION_API) \ upscli_str_contains_token.$(MAN_SECTION_API) \ libnutclient.$(MAN_SECTION_API) \ libnutclient_commands.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_COMMANDS_DEPS) \ libnutclient_devices.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_DEVICES_DEPS) \ libnutclient_general.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_GENERAL_DEPS) \ libnutclient_misc.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_MISC_DEPS) \ libnutclient_tcp.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_TCP_DEPS) \ libnutclient_variables.$(MAN_SECTION_API) \ $(LIBNUTCLIENT_VARIABLES_DEPS) \ nutscan.$(MAN_SECTION_API) \ nutscan_scan_snmp.$(MAN_SECTION_API) \ nutscan_scan_usb.$(MAN_SECTION_API) \ nutscan_scan_xml_http_range.$(MAN_SECTION_API) \ nutscan_scan_nut.$(MAN_SECTION_API) \ nutscan_scan_nut_simulation.$(MAN_SECTION_API) \ nutscan_scan_avahi.$(MAN_SECTION_API) \ nutscan_scan_ipmi.$(MAN_SECTION_API) \ nutscan_scan_eaton_serial.$(MAN_SECTION_API) \ nutscan_display_sanity_check.$(MAN_SECTION_API) \ nutscan_display_sanity_check_serial.$(MAN_SECTION_API) \ nutscan_display_ups_conf_with_sanity_check.$(MAN_SECTION_API) \ nutscan_display_ups_conf.$(MAN_SECTION_API) \ nutscan_display_parsable.$(MAN_SECTION_API) \ nutscan_init_ip_ranges.$(MAN_SECTION_API) \ nutscan_free_ip_ranges.$(MAN_SECTION_API) \ nutscan_stringify_ip_ranges.$(MAN_SECTION_API) \ nutscan_add_ip_range.$(MAN_SECTION_API) \ nutscan_ip_ranges_iter_init.$(MAN_SECTION_API) \ nutscan_ip_ranges_iter_inc.$(MAN_SECTION_API) \ nutscan_cidr_to_ip.$(MAN_SECTION_API) \ nutscan_new_device.$(MAN_SECTION_API) \ nutscan_free_device.$(MAN_SECTION_API) \ nutscan_add_option_to_device.$(MAN_SECTION_API) \ nutscan_add_commented_option_to_device.$(MAN_SECTION_API) \ nutscan_add_device_to_device.$(MAN_SECTION_API) \ nutscan_get_serial_ports_list.$(MAN_SECTION_API) \ nutscan_init.$(MAN_SECTION_API) INST_MAN_DEV_CMD_USR_PAGES = \ libupsclient-config.$(MAN_SECTION_CMD_USR) INST_MAN_DEV_CMD_SYS_PAGES = \ sockdebug.$(MAN_SECTION_CMD_SYS) @WITH_MANS_TRUE@MAN_DEV_API_PAGES = $(INST_MAN_DEV_API_PAGES) @WITH_MANS_TRUE@MAN_DEV_CMD_USR_PAGES = $(INST_MAN_DEV_CMD_USR_PAGES) @WITH_MANS_TRUE@MAN_DEV_CMD_SYS_PAGES = $(INST_MAN_DEV_CMD_SYS_PAGES) INST_HTML_DEV_MANS = \ upsclient.html \ upscli_add_host_cert.html \ upscli_cleanup.html \ upscli_connect.html \ upscli_disconnect.html \ upscli_fd.html \ upscli_get.html \ upscli_init.html \ upscli_set_default_connect_timeout.html \ upscli_get_default_connect_timeout.html \ upscli_init_default_connect_timeout.html \ upscli_list_next.html \ upscli_list_start.html \ upscli_readline.html \ upscli_sendline.html \ upscli_splitaddr.html \ upscli_splitname.html \ upscli_ssl.html \ upscli_strerror.html \ upscli_upserror.html \ upscli_str_add_unique_token.html \ upscli_str_contains_token.html \ libnutclient.html \ libnutclient_commands.html \ libnutclient_devices.html \ libnutclient_general.html \ libnutclient_misc.html \ libnutclient_tcp.html \ libnutclient_variables.html \ nutscan.html \ nutscan_scan_snmp.html \ nutscan_scan_usb.html \ nutscan_scan_xml_http_range.html \ nutscan_scan_nut.html \ nutscan_scan_nut_simulation.html \ nutscan_scan_avahi.html \ nutscan_scan_ipmi.html \ nutscan_scan_eaton_serial.html \ nutscan_display_sanity_check.html \ nutscan_display_sanity_check_serial.html \ nutscan_display_ups_conf_with_sanity_check.html \ nutscan_display_ups_conf.html \ nutscan_display_parsable.html \ nutscan_init_ip_ranges.html \ nutscan_free_ip_ranges.html \ nutscan_stringify_ip_ranges.html \ nutscan_add_ip_range.html \ nutscan_ip_ranges_iter_init.html \ nutscan_ip_ranges_iter_inc.html \ nutscan_cidr_to_ip.html \ nutscan_new_device.html \ nutscan_free_device.html \ nutscan_add_option_to_device.html \ nutscan_add_device_to_device.html \ nutscan_get_serial_ports_list.html \ nutscan_init.html \ libupsclient-config.html \ sockdebug.html \ skel.html HTML_DEV_MANS = $(INST_HTML_DEV_MANS) # Can't make this work on all make implementations at once, so disabled for now # Anyway it would be the same man-like page for several functions HTML_DEV_MANS_FICTION = \ upscli_readline_timeout.html \ upscli_sendline_timeout.html \ upscli_tryconnect.html \ nutscan_scan_ip_range_snmp.html \ nutscan_scan_ip_range_xml_http.html \ nutscan_scan_ip_range_nut.html \ nutscan_scan_ip_range_ipmi.html \ nutscan_add_commented_option_to_device.html # (--with-serial) SRC_SERIAL_PAGES = \ al175.txt \ apcsmart.txt \ apcsmart-old.txt \ bcmxcp.txt \ belkin.txt \ belkinunv.txt \ bestfortress.txt \ bestuferrups.txt \ bestups.txt \ bestfcom.txt \ bicker_ser.txt \ blazer-common.txt \ blazer_ser.txt \ clone.txt \ clone-outlet.txt \ dummy-ups.txt \ etapro.txt \ everups.txt \ gamatronic.txt \ genericups.txt \ isbmex.txt \ ivtscd.txt \ liebert.txt \ liebert-gxe.txt \ liebert-esp2.txt \ masterguard.txt \ metasys.txt \ mge-shut.txt \ mge-utalk.txt \ nhs_ser.txt \ oneac.txt \ microdowell.txt \ microsol-apc.txt \ nutdrv_siemens_sitop.txt \ optiups.txt \ powercom.txt \ powerpanel.txt \ rhino.txt \ riello_ser.txt \ sms_ser.txt \ safenet.txt \ solis.txt \ tripplite.txt \ tripplitesu.txt \ upscode2.txt \ victronups.txt \ apcupsd-ups.txt INST_MAN_SERIAL_PAGES = \ al175.$(MAN_SECTION_CMD_SYS) \ apcsmart.$(MAN_SECTION_CMD_SYS) \ apcsmart-old.$(MAN_SECTION_CMD_SYS) \ bcmxcp.$(MAN_SECTION_CMD_SYS) \ belkin.$(MAN_SECTION_CMD_SYS) \ belkinunv.$(MAN_SECTION_CMD_SYS) \ bestfortress.$(MAN_SECTION_CMD_SYS) \ bestuferrups.$(MAN_SECTION_CMD_SYS) \ bestups.$(MAN_SECTION_CMD_SYS) \ bestfcom.$(MAN_SECTION_CMD_SYS) \ bicker_ser.$(MAN_SECTION_CMD_SYS) \ blazer_ser.$(MAN_SECTION_CMD_SYS) \ clone.$(MAN_SECTION_CMD_SYS) \ clone-outlet.$(MAN_SECTION_CMD_SYS) \ dummy-ups.$(MAN_SECTION_CMD_SYS) \ etapro.$(MAN_SECTION_CMD_SYS) \ everups.$(MAN_SECTION_CMD_SYS) \ gamatronic.$(MAN_SECTION_CMD_SYS) \ genericups.$(MAN_SECTION_CMD_SYS) \ isbmex.$(MAN_SECTION_CMD_SYS) \ ivtscd.$(MAN_SECTION_CMD_SYS) \ liebert.$(MAN_SECTION_CMD_SYS) \ liebert-gxe.$(MAN_SECTION_CMD_SYS) \ liebert-esp2.$(MAN_SECTION_CMD_SYS) \ masterguard.$(MAN_SECTION_CMD_SYS) \ metasys.$(MAN_SECTION_CMD_SYS) \ mge-shut.$(MAN_SECTION_CMD_SYS) \ mge-utalk.$(MAN_SECTION_CMD_SYS) \ oneac.$(MAN_SECTION_CMD_SYS) \ microdowell.$(MAN_SECTION_CMD_SYS) \ microsol-apc.$(MAN_SECTION_CMD_SYS) \ nutdrv_siemens_sitop.$(MAN_SECTION_CMD_SYS) \ optiups.$(MAN_SECTION_CMD_SYS) \ powercom.$(MAN_SECTION_CMD_SYS) \ powerpanel.$(MAN_SECTION_CMD_SYS) \ rhino.$(MAN_SECTION_CMD_SYS) \ riello_ser.$(MAN_SECTION_CMD_SYS) \ sms_ser.$(MAN_SECTION_CMD_SYS) \ safenet.$(MAN_SECTION_CMD_SYS) \ solis.$(MAN_SECTION_CMD_SYS) \ tripplite.$(MAN_SECTION_CMD_SYS) \ tripplitesu.$(MAN_SECTION_CMD_SYS) \ upscode2.$(MAN_SECTION_CMD_SYS) \ victronups.$(MAN_SECTION_CMD_SYS) \ apcupsd-ups.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_SERIAL_PAGES = \ @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@ $(INST_MAN_SERIAL_PAGES) \ @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@ $(am__append_24) INST_HTML_SERIAL_MANS = al175.html apcsmart.html apcsmart-old.html \ bcmxcp.html belkin.html belkinunv.html bestfortress.html \ bestuferrups.html bestups.html bestfcom.html bicker_ser.html \ blazer_ser.html clone.html clone-outlet.html dummy-ups.html \ etapro.html everups.html gamatronic.html genericups.html \ isbmex.html ivtscd.html liebert.html liebert-gxe.html \ liebert-esp2.html masterguard.html metasys.html mge-shut.html \ mge-utalk.html oneac.html microdowell.html microsol-apc.html \ nutdrv_siemens_sitop.html optiups.html powercom.html \ powerpanel.html rhino.html riello_ser.html sms_ser.html \ safenet.html solis.html tripplite.html tripplitesu.html \ upscode2.html victronups.html apcupsd-ups.html \ $(am__append_26) @SOME_DRIVERS_FALSE@HTML_SERIAL_MANS = $(INST_HTML_SERIAL_MANS) # (--with-snmp) SRC_SNMP_PAGES = snmp-ups.txt INST_MAN_SNMP_PAGES = snmp-ups.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_SNMP_PAGES = $(INST_MAN_SNMP_PAGES) INST_HTML_SNMP_MANS = snmp-ups.html @SOME_DRIVERS_FALSE@HTML_SNMP_MANS = $(INST_HTML_SNMP_MANS) # (--with-usb) SRC_USB_LIBUSB_PAGES = \ bcmxcp_usb.txt \ blazer-common.txt \ blazer_usb.txt \ nutdrv_atcl_usb.txt \ nut_usb_addvars.txt \ richcomm_usb.txt \ riello_usb.txt \ tripplite_usb.txt \ usbhid-ups.txt INST_MAN_USB_LIBUSB_PAGES = \ bcmxcp_usb.$(MAN_SECTION_CMD_SYS) \ blazer_usb.$(MAN_SECTION_CMD_SYS) \ nutdrv_atcl_usb.$(MAN_SECTION_CMD_SYS) \ richcomm_usb.$(MAN_SECTION_CMD_SYS) \ riello_usb.$(MAN_SECTION_CMD_SYS) \ tripplite_usb.$(MAN_SECTION_CMD_SYS) \ usbhid-ups.$(MAN_SECTION_CMD_SYS) # NOTE: nut_usb_addvars and blazer-common are not standalone man pages @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_USB_LIBUSB_PAGES = $(INST_MAN_USB_LIBUSB_PAGES) INST_HTML_USB_LIBUSB_MANS = \ bcmxcp_usb.html \ blazer_usb.html \ nutdrv_atcl_usb.html \ richcomm_usb.html \ riello_usb.html \ tripplite_usb.html \ usbhid-ups.html @SOME_DRIVERS_FALSE@HTML_USB_LIBUSB_MANS = $(INST_HTML_USB_LIBUSB_MANS) # (--with-serial / --with-usb) SRC_SERIAL_USB_PAGES = \ nutdrv_qx.txt INST_MAN_SERIAL_USB_PAGES = \ nutdrv_qx.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_SERIAL_USB_PAGES = $(INST_MAN_SERIAL_USB_PAGES) INST_HTML_SERIAL_USB_MANS = \ nutdrv_qx.html @SOME_DRIVERS_FALSE@HTML_SERIAL_USB_MANS = $(INST_HTML_SERIAL_USB_MANS) # (--with-neon) SRC_NETXML_PAGES = netxml-ups.txt INST_MAN_NETXML_PAGES = netxml-ups.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_NETXML_PAGES = $(INST_MAN_NETXML_PAGES) INST_HTML_NETXML_MANS = netxml-ups.html @SOME_DRIVERS_FALSE@HTML_NETXML_MANS = $(INST_HTML_NETXML_MANS) # (--with-powerman) SRC_POWERMAN_PAGES = powerman-pdu.txt INST_MAN_POWERMAN_PAGES = powerman-pdu.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_POWERMAN_PAGES = $(INST_MAN_POWERMAN_PAGES) INST_HTML_POWERMAN_MANS = powerman-pdu.html @SOME_DRIVERS_FALSE@HTML_POWERMAN_MANS = $(INST_HTML_POWERMAN_MANS) # (--with-ipmi) SRC_IPMIPSU_PAGES = nut-ipmipsu.txt INST_MAN_IPMIPSU_PAGES = nut-ipmipsu.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_IPMIPSU_PAGES = $(INST_MAN_IPMIPSU_PAGES) INST_HTML_IPMIPSU_MANS = nut-ipmipsu.html @SOME_DRIVERS_FALSE@HTML_IPMIPSU_MANS = $(INST_HTML_IPMIPSU_MANS) # (--with-macosx_ups) SRC_MACOSX_PAGES = macosx-ups.txt INST_MAN_MACOSX_PAGES = macosx-ups.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_MACOSX_PAGES = $(INST_MAN_MACOSX_PAGES) INST_HTML_MACOSX_MANS = macosx-ups.html @SOME_DRIVERS_FALSE@HTML_MACOSX_MANS = $(INST_HTML_MACOSX_MANS) # (--with-modbus) SRC_MODBUS_PAGES = \ phoenixcontact_modbus.txt \ generic_modbus.txt \ huawei-ups2000.txt \ socomec_jbus.txt \ adelsystem_cbi.txt \ apc_modbus.txt INST_MAN_MODBUS_PAGES = \ phoenixcontact_modbus.$(MAN_SECTION_CMD_SYS) \ generic_modbus.$(MAN_SECTION_CMD_SYS) \ huawei-ups2000.$(MAN_SECTION_CMD_SYS) \ socomec_jbus.$(MAN_SECTION_CMD_SYS) \ adelsystem_cbi.$(MAN_SECTION_CMD_SYS) \ apc_modbus.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_MODBUS_PAGES = $(INST_MAN_MODBUS_PAGES) INST_HTML_MODBUS_MANS = \ phoenixcontact_modbus.html \ generic_modbus.html \ huawei-ups2000.html \ socomec_jbus.html \ adelsystem_cbi.html \ apc_modbus.html @SOME_DRIVERS_FALSE@HTML_MODBUS_MANS = $(INST_HTML_MODBUS_MANS) # (--with-linux_i2c) SRC_LINUX_I2C_PAGES = \ asem.txt \ pijuice.txt \ hwmon_ina219.txt INST_MAN_LINUX_I2C_PAGES = \ asem.$(MAN_SECTION_CMD_SYS) \ pijuice.$(MAN_SECTION_CMD_SYS) \ hwmon_ina219.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_LINUX_I2C_PAGES = $(INST_MAN_LINUX_I2C_PAGES) INST_HTML_LINUX_I2C_MANS = \ asem.html \ pijuice.html \ hwmon_ina219.html @SOME_DRIVERS_FALSE@HTML_LINUX_I2C_MANS = $(INST_HTML_LINUX_I2C_MANS) # (--with-gpio) SRC_GPIO_PAGES = generic_gpio.txt INST_MAN_GPIO_PAGES = generic_gpio.$(MAN_SECTION_CMD_SYS) @SOME_DRIVERS_FALSE@@WITH_MANS_TRUE@MAN_GPIO_PAGES = $(INST_MAN_GPIO_PAGES) INST_HTML_GPIO_MANS = \ generic_gpio.html @SOME_DRIVERS_FALSE@HTML_GPIO_MANS = $(INST_HTML_GPIO_MANS) MAN_MANS = $(am__append_39) SRC_DRIVERS_PAGES = $(SRC_SERIAL_PAGES) $(SRC_SNMP_PAGES) \ $(SRC_USB_LIBUSB_PAGES) $(SRC_SERIAL_USB_PAGES) \ $(SRC_NETXML_PAGES) $(SRC_POWERMAN_PAGES) $(SRC_IPMIPSU_PAGES) \ $(SRC_MACOSX_PAGES) $(SRC_MODBUS_PAGES) $(SRC_LINUX_I2C_PAGES) \ $(SRC_GPIO_PAGES) $(am__append_40) # DIST_ALL_PAGES: Make sure pages are built for the archive (or # inherited from earlier tarball this release is being built from); # caller may have to fake them if we are in a situation we know we can # not provide them (see `make distcheck-ci` in top-level Makefile.am). EXTRA_DIST = \ $(SRC_ALL_PAGES) \ $(DIST_ALL_PAGES) \ $(MAN_MANS) \ asciidoc.conf HTML_MANS = \ index.html \ $(HTML_CONF_MANS) \ $(HTML_CLIENT_MANS) \ $(HTML_TOOL_MANS) \ $(HTML_CGI_MANS) \ $(HTML_DEV_MANS) \ $(HTML_SERIAL_MANS) \ $(HTML_SNMP_MANS) \ $(HTML_USB_LIBUSB_MANS) \ $(HTML_SERIAL_USB_MANS) \ $(HTML_NETXML_MANS) \ $(HTML_POWERMAN_MANS) \ $(HTML_IPMIPSU_MANS) \ $(HTML_MACOSX_MANS) \ $(HTML_MODBUS_MANS) \ $(HTML_LINUX_I2C_MANS) \ $(HTML_GPIO_MANS) # htmlmandir is set by autoconf/automake htmlman_DATA = $(am__append_41) $(am__append_42) # Note: target documents, except nutupsdrv.txt itself, start the # list of drivers with `- linkman:nutupsdrv[$(MAN_SECTION_CMD_SYS)]` entry # To regenerate these files, do `make distclean` first LINKMAN_INCLUDE_GENERATED = linkman-driver-names.txt linkman-drivertool-names.txt LINKMAN_INCLUDE_CONSUMERS = index.txt upsd.txt nutupsdrv.txt # These files are generated when we build from git source so not tracked in # git, and not part of tarball (to be in builddir) - so not in EXTRA_DIST. DISTCLEANFILES = $(LINKMAN_INCLUDE_GENERATED) # This list is defined by configure script choices and options: CHECK_LOCAL_TARGETS = @DOC_CHECK_LIST@ TGT_REQUIRE_CHECK_HTML = $(am__append_43) $(am__append_44) CLEANFILES = *-spellchecked .prep-src-docs *-prepped .check-* \ $(am__append_45) $(am__append_46) $(am__append_47) SUFFIXES = .txt-prepped .txt .html .$(MAN_SECTION_CMD_USR) .$(MAN_SECTION_API) .$(MAN_SECTION_CFG) .$(MAN_SECTION_CMD_SYS) @DOC_INSTALL_DISTED_MANS_FALSE@SRC_PREBUILT_CLAUSE = # For builds with allowed installation of prebuilt man pages, check that # they exist in sources (make would pull them automatically as a fallback # from failed lookup in build products). For builds that require rebuild # of man pages, abort with error if build product is missing. @DOC_INSTALL_DISTED_MANS_TRUE@SRC_PREBUILT_CLAUSE = || [ -r "$(srcdir)/`basename $@`" ] # Working around a2x not friendly to parallelized runs. # See more details in the main NUT docs/Makefile.am # NOTE: MKDIR_P may be defined via expanded $(top_builddir)/install-sh # so should be run from $(abs_builddir) to be safe, as we jump around # the build workspace @HAVE_ASCIIDOC_TRUE@DOCBUILD_BEGIN = { \ @HAVE_ASCIIDOC_TRUE@ if test -n "$${A2X_OUTDIR}" && test "$${A2X_OUTDIR}" != '.' ; then \ @HAVE_ASCIIDOC_TRUE@ rm -rf "./$${A2X_OUTDIR}" || true ; \ @HAVE_ASCIIDOC_TRUE@ test -d "$@" && rm -rf "$@" || true ; \ @HAVE_ASCIIDOC_TRUE@ _CWD="`pwd`" && (cd '$(abs_builddir)' && $(MKDIR_P) "$${_CWD}/$${A2X_OUTDIR}") || exit ; \ @HAVE_ASCIIDOC_TRUE@ for F in $(LINKMAN_INCLUDE_GENERATED) ; do \ @HAVE_ASCIIDOC_TRUE@ if [ -s "./$$F" ] ; then ln -f -s "../../$$F" "./$${A2X_OUTDIR}/" ; else \ @HAVE_ASCIIDOC_TRUE@ if [ -s "$(abs_srcdir)/$$F" ] ; then ln -f -s "$(abs_srcdir)/$$F" "./$${A2X_OUTDIR}/" ; fi ; fi ; \ @HAVE_ASCIIDOC_TRUE@ done ; \ @HAVE_ASCIIDOC_TRUE@ else A2X_OUTDIR='.' ; fi; \ @HAVE_ASCIIDOC_TRUE@ if test -s "${builddir}/docbook-xsl.css" \ @HAVE_ASCIIDOC_TRUE@ && test -r "${builddir}/docbook-xsl.css" \ @HAVE_ASCIIDOC_TRUE@ && ! test -w "${builddir}/docbook-xsl.css" \ @HAVE_ASCIIDOC_TRUE@ ; then chmod u+w "${builddir}/docbook-xsl.css" ; fi ; \ @HAVE_ASCIIDOC_TRUE@ chmod -R u+w "./$${A2X_OUTDIR}" || true ; \ @HAVE_ASCIIDOC_TRUE@ A2X_VERBOSE="$(ASCIIDOC_VERBOSE)"; if [ "$(V)" = 1 ]; then A2X_VERBOSE="--verbose"; fi; \ @HAVE_ASCIIDOC_TRUE@} # Note that documents with sub-pages (see LIBNUTCLIENT_*_DEPS above) # may generate multiple files in one go... so we move "*" and hope # for no required hidden files (or would have to `find` them all). @HAVE_ASCIIDOC_TRUE@DOCBUILD_END = { \ @HAVE_ASCIIDOC_TRUE@ if test -n "$${A2X_OUTDIR}" && test "$${A2X_OUTDIR}" != '.' ; then \ @HAVE_ASCIIDOC_TRUE@ chmod -R u+w "./$${A2X_OUTDIR}" || true ; \ @HAVE_ASCIIDOC_TRUE@ test -d "$@" && rm -rf "$@" || true ; \ @HAVE_ASCIIDOC_TRUE@ for F in $(LINKMAN_INCLUDE_GENERATED) ; do \ @HAVE_ASCIIDOC_TRUE@ rm -f "./$${A2X_OUTDIR}/$$F" || true ; \ @HAVE_ASCIIDOC_TRUE@ done ; \ @HAVE_ASCIIDOC_TRUE@ mv -f "./$${A2X_OUTDIR}/$(@F)" ./ || exit ; \ @HAVE_ASCIIDOC_TRUE@ mv -f "./$${A2X_OUTDIR}/"*.* ./ 2>/dev/null || true ; \ @HAVE_ASCIIDOC_TRUE@ rm -rf "./$${A2X_OUTDIR}" ; \ @HAVE_ASCIIDOC_TRUE@ fi ; \ @HAVE_ASCIIDOC_TRUE@} ### Prior to Asciidoc ~8.6.8, the --destination-dir flag didn't seem to affect the location of the intermediate .xml file. ### This parameter is currently required; see docs/Makefile.am for more detail. @HAVE_ASCIIDOC_TRUE@A2X_MANPAGE_OPTS = --doctype manpage --format manpage $${A2X_VERBOSE} \ @HAVE_ASCIIDOC_TRUE@ --xsltproc-opts="--nonet" \ @HAVE_ASCIIDOC_TRUE@ --attribute=mansource="Network UPS Tools" \ @HAVE_ASCIIDOC_TRUE@ --attribute=manversion="$(PACKAGE_VERSION)" \ @HAVE_ASCIIDOC_TRUE@ --attribute=manmanual="NUT Manual" \ @HAVE_ASCIIDOC_TRUE@ --attribute=srcdir="$(abs_srcdir)/" \ @HAVE_ASCIIDOC_TRUE@ --attribute=builddir="$(abs_builddir)/" \ @HAVE_ASCIIDOC_TRUE@ --attribute=top_srcdir="$(abs_top_srcdir)/" \ @HAVE_ASCIIDOC_TRUE@ --attribute=top_builddir="$(abs_top_builddir)/" \ @HAVE_ASCIIDOC_TRUE@ --destination-dir="$${A2X_OUTDIR}" # When building out-of-tree, be sure to have all asciidoc resources # under the same dir structure (tool limitation) # NOTE: Not including *all* of EXTRA_DIST here, because we also "dist" # the built man pages in the tarball for end-users without an asciidoc # stack (causing a dependency loop)! PREP_SRC = $(LINKMAN_INCLUDE_GENERATED) $(SRC_ALL_PAGES) asciidoc.conf # NOTE: Some "make" implementations prefix a relative or absent path to # the filenames in PREP_SRC, others (e.g. Sun make) prepend the absolute # path to locate the sources, so we end up with bogus trees under docs/. # Code below tries to detect and truncate this mess, including possible # source texts located in/under parent dirs. # We also handle man page links (section-aware) and titles for platforms # where they differ from common defaults. NOTE: Page titles are a line # with the title, followed by another with a sequence of "===" characters # of same length, give or take one (or so). Currently we do not bother to # adjust the second line, as we expect minor length changes like "8"=>"1m". # NOTE: MKDIR_P may be defined via expanded $(top_builddir)/install-sh # so should be run from $(abs_builddir) to be safe, as we jump around # the build workspace # NOTE: For DOCS_NO_MAN case we expect that the top-level Makefile caused # parallel runs of several directories, so we can reasonably wait some # time for the target file to just appear. MAINTAINER_DOCS_PREP_MAN_DELAY = 60 MAINTAINERCLEANFILES = Makefile.in .dirstamp all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .txt-prepped .txt .html .$(MAN_SECTION_CMD_USR) .$(MAN_SECTION_API) .$(MAN_SECTION_CFG) .$(MAN_SECTION_CMD_SYS) .txt-spellchecked $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu docs/man/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu docs/man/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-htmlmanDATA: $(htmlman_DATA) @$(NORMAL_INSTALL) @list='$(htmlman_DATA)'; test -n "$(htmlmandir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmlmandir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmlmandir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmlmandir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmlmandir)" || exit $$?; \ done uninstall-htmlmanDATA: @$(NORMAL_UNINSTALL) @list='$(htmlman_DATA)'; test -n "$(htmlmandir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(htmlmandir)'; $(am__uninstall_files_from_dir) install-manapiDATA: $(manapi_DATA) @$(NORMAL_INSTALL) @list='$(manapi_DATA)'; test -n "$(manapidir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(manapidir)'"; \ $(MKDIR_P) "$(DESTDIR)$(manapidir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(manapidir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(manapidir)" || exit $$?; \ done uninstall-manapiDATA: @$(NORMAL_UNINSTALL) @list='$(manapi_DATA)'; test -n "$(manapidir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(manapidir)'; $(am__uninstall_files_from_dir) install-mancfgDATA: $(mancfg_DATA) @$(NORMAL_INSTALL) @list='$(mancfg_DATA)'; test -n "$(mancfgdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(mancfgdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(mancfgdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(mancfgdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(mancfgdir)" || exit $$?; \ done uninstall-mancfgDATA: @$(NORMAL_UNINSTALL) @list='$(mancfg_DATA)'; test -n "$(mancfgdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(mancfgdir)'; $(am__uninstall_files_from_dir) install-mansysDATA: $(mansys_DATA) @$(NORMAL_INSTALL) @list='$(mansys_DATA)'; test -n "$(mansysdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(mansysdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(mansysdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(mansysdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(mansysdir)" || exit $$?; \ done uninstall-mansysDATA: @$(NORMAL_UNINSTALL) @list='$(mansys_DATA)'; test -n "$(mansysdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(mansysdir)'; $(am__uninstall_files_from_dir) install-manusrDATA: $(manusr_DATA) @$(NORMAL_INSTALL) @list='$(manusr_DATA)'; test -n "$(manusrdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(manusrdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(manusrdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(manusrdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(manusrdir)" || exit $$?; \ done uninstall-manusrDATA: @$(NORMAL_UNINSTALL) @list='$(manusr_DATA)'; test -n "$(manusrdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(manusrdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(htmlmandir)" "$(DESTDIR)$(manapidir)" "$(DESTDIR)$(mancfgdir)" "$(DESTDIR)$(mansysdir)" "$(DESTDIR)$(manusrdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-htmlmanDATA install-manapiDATA \ install-mancfgDATA install-mansysDATA install-manusrDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-htmlmanDATA uninstall-manapiDATA \ uninstall-mancfgDATA uninstall-mansysDATA uninstall-manusrDATA .MAKE: all check check-am install install-am install-exec \ install-strip .PHONY: all all-am check check-am check-local clean clean-generic \ clean-libtool clean-local cscopelist-am ctags-am dist-hook \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-htmlmanDATA install-info install-info-am install-man \ install-manapiDATA install-mancfgDATA install-mansysDATA \ install-manusrDATA install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-htmlmanDATA \ uninstall-manapiDATA uninstall-mancfgDATA uninstall-mansysDATA \ uninstall-manusrDATA .PRECIOUS: Makefile # Note: this intends to be used instead of the "all" target that may have # been provided by automake, since we want to do nothing in certain cases. # Ideally it would refuse "make all" in certain cases, but we can't override # the automake-generated rules in each make implementation we care for. all-optional: $(abs_top_builddir)/docs/man/.prep-src-docs +@case "$(ALL_TGT)" in \ ""|" "|" "|" ") echo " DOCS_NO_MAN SKIP: $@ called in docs/man/Makefile: No format of man page rendering is enabled" ; exit 0 ;; \ *all-*) \ if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then echo " DOCS_NO_MAN SKIP: $@ called in docs/man/Makefile: requested to not work in this code path" ; exit 0 ; fi ; \ echo " DOC-FOLLOW-UP Basic 'make $@' in `pwd` is done, following up with 'make $(ALL_TGT)' to ensure complex document types (if enabled)" ; \ $(MAKE) $(AM_MAKEFLAGS) $(ALL_TGT) ; exit ;; \ esac ; exit 0 # List man pages we intend to deliver (depending on chosen build products) print-MAN_MANS: @echo "$(MAN_MANS)" check-list-MAN_MANS: @FILENAMES='$(MAN_MANS)' ; $(LIST_FILES) # List all (man page) file names we know we should distribute in a tarball # (whether built right now or inherited from a tarball build by itself) print-DIST_ALL_PAGES: @echo "$(DIST_ALL_PAGES)" check-list-DIST_ALL_PAGES: @FILENAMES='$(DIST_ALL_PAGES)' ; $(LIST_FILES) # If any pages are missing, fake them distcheck-light-DIST_ALL_PAGES: @FILENAMES='$(DIST_ALL_PAGES)' ; $(FAKE_FILES) || ( \ if [ x"$(FAKE_PAGES_BUMP_SRC)" = xtrue ] ; then \ cd "$(abs_srcdir)" && touch $(SRC_ALL_PAGES) || echo "$@: Well we tried" >&2 ; \ fi ; ) print-DIST_ALL_MAN_PAGES: @echo "$(DIST_ALL_MAN_PAGES)" check-list-DIST_ALL_MAN_PAGES: @FILENAMES='$(DIST_ALL_MAN_PAGES)' ; $(LIST_FILES) # If any pages are missing, fake them distcheck-light-DIST_ALL_MAN_PAGES: @FILENAMES='$(DIST_ALL_MAN_PAGES)' ; $(FAKE_FILES) || ( \ if [ x"$(FAKE_PAGES_BUMP_SRC)" = xtrue ] ; then \ cd "$(abs_srcdir)" && touch $(SRC_ALL_PAGES) || echo "$@: Well we tried" >&2 ; \ fi ; ) # Likewise for HTML renders (but no fake pages made/needed for dist) print-HTML_MANS: @echo "$(HTML_MANS)" check-list-HTML_MANS: @FILENAMES='$(HTML_MANS)' ; $(LIST_FILES) print-DIST_ALL_HTML_PAGES: @echo "$(DIST_ALL_HTML_PAGES)" check-list-DIST_ALL_HTML_PAGES: @FILENAMES='$(DIST_ALL_HTML_PAGES)' ; $(LIST_FILES) # Likewise for plaintext sources print-SRC_ALL_PAGES: @echo "$(SRC_ALL_PAGES)" check-list-SRC_ALL_PAGES: @FILENAMES='$(SRC_ALL_PAGES)' ; $(LIST_FILES) # Alias page for one text describing two commands: NUT-Monitor-py2gtk2.$(MAN_SECTION_CMD_SYS): NUT-Monitor.$(MAN_SECTION_CMD_SYS) touch $@ NUT-Monitor-py3qt5.$(MAN_SECTION_CMD_SYS): NUT-Monitor.$(MAN_SECTION_CMD_SYS) touch $@ @WITH_NUT_MONITOR_TRUE@NUT-Monitor-py2gtk2.html: NUT-Monitor.html @WITH_NUT_MONITOR_TRUE@ test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ @WITH_NUT_MONITOR_TRUE@NUT-Monitor-py3qt5.html: NUT-Monitor.html @WITH_NUT_MONITOR_TRUE@ test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ $(LIBNUTCLIENT_MISC_DEPS): libnutclient_misc.$(MAN_SECTION_API) touch $@ $(LIBNUTCLIENT_TCP_DEPS): libnutclient_tcp.$(MAN_SECTION_API) touch $@ $(LIBNUTCLIENT_GENERAL_DEPS): libnutclient_general.$(MAN_SECTION_API) touch $@ $(LIBNUTCLIENT_VARIABLES_DEPS): libnutclient_variables.$(MAN_SECTION_API) touch $@ $(LIBNUTCLIENT_COMMANDS_DEPS): libnutclient_commands.$(MAN_SECTION_API) touch $@ $(LIBNUTCLIENT_DEVICES_DEPS): libnutclient_devices.$(MAN_SECTION_API) touch $@ # Alias page for one text describing two commands: upscli_readline_timeout.$(MAN_SECTION_API): upscli_readline.$(MAN_SECTION_API) touch $@ upscli_sendline_timeout.$(MAN_SECTION_API): upscli_sendline.$(MAN_SECTION_API) touch $@ upscli_tryconnect.$(MAN_SECTION_API): upscli_connect.$(MAN_SECTION_API) touch $@ nutscan_scan_ip_range_snmp.$(MAN_SECTION_API): nutscan_scan_snmp.$(MAN_SECTION_API) touch $@ nutscan_scan_ip_range_xml_http.$(MAN_SECTION_API): nutscan_scan_xml_http_range.$(MAN_SECTION_API) touch $@ nutscan_scan_ip_range_nut.$(MAN_SECTION_API): nutscan_scan_nut.$(MAN_SECTION_API) touch $@ nutscan_scan_ip_range_ipmi.$(MAN_SECTION_API): nutscan_scan_ipmi.$(MAN_SECTION_API) touch $@ nutscan_add_commented_option_to_device.$(MAN_SECTION_API): nutscan_add_option_to_device.$(MAN_SECTION_API) touch $@ upscli_readline_timeout.html: upscli_readline.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ upscli_sendline_timeout.html: upscli_sendline.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ upscli_tryconnect.html: upscli_connect.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_scan_ip_range_snmp.html: nutscan_scan_snmp.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_scan_ip_range_xml_http.html: nutscan_scan_xml_http_range.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_scan_ip_range_nut.html: nutscan_scan_nut.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_scan_ip_range_ipmi.html: nutscan_scan_ipmi.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ nutscan_add_commented_option_to_device.html: nutscan_add_option_to_device.html test -n "$?" -a -s "$@" && rm -f $@ && ln -s $? $@ # We may be here because tools are missing, or because caller ran # ./configure --without-doc (but the tools were present and AC_PROG # caused the needed variables to resolve, so pages can in fact get # built, or are present in the release tarball we are building). # Absense of pages can cause "make dist" to fail, unless caller # (like `make distcheck-light`) runs ./configure --with-doc=skip # (or --with-doc=man=skip specifically). # FIXME: See also HAVE_ASCIIDOC (covers several tools in fact) # and DOC_INSTALL_DISTED_MANS for a more granular approach. @SKIP_MANS_FALSE@@WITH_MANS_FALSE@dist-warning: @SKIP_MANS_FALSE@@WITH_MANS_FALSE@ @echo "WARNING: Manpage building was disabled by configure script, and these pages are required for our proper 'make dist'" >&2 @SKIP_MANS_FALSE@@WITH_MANS_FALSE@dist: dist-warning # For builds done from dist'ed sources, there may be a conflict of timestamps # between original *.txt files and pre-built manpages etc. leading to skipping # of manpage re-generation even if that activity is possible and requested. # Possibly a cleaner, but less portable, solution would be to touch the # generated files to long ago. Current solution assumes good valid clocks :) dist-hook: @echo "Fix up manpage source timestamps" && cd $(distdir) && touch $(SRC_ALL_PAGES) linkman-driver-names.txt: @if test x"$(abs_srcdir)" != x"$(abs_builddir)" ; then \ if ! test -s "$(builddir)/$@" && test -s "$(srcdir)/$(@F)" ; then \ ln -fs "$(srcdir)/$(@F)" "$(builddir)/" ; \ fi ; \ fi @if test -s "$@" ; then exit 0 ; fi ; \ (LC_ALL=C; LANG=C; export LC_ALL LANG; \ for F in $(SRC_DRIVERS_PAGES) ; do echo "$$F" ; done \ | grep -vE '^nutupsdrv\.txt$$' \ | sort -n | uniq \ | sed 's,^\(.*\)\.txt$$,- linkman:\1[$(MAN_SECTION_CMD_SYS)],' ; \ ) > "$@" @if test ! -s "$@" ; then echo "- No NUT drivers were built" > "$@" ; fi linkman-drivertool-names.txt: @if test x"$(abs_srcdir)" != x"$(abs_builddir)" ; then \ if ! test -s "$(builddir)/$@" && test -s "$(srcdir)/$(@F)" ; then \ ln -fs "$(srcdir)/$(@F)" "$(builddir)/" ; \ fi ; \ fi @if test -s "$@" ; then exit 0 ; fi ; \ (LC_ALL=C; LANG=C; export LC_ALL LANG; \ for F in $(SRC_DRIVERTOOL_PAGES) ; do echo "$$F" ; done \ | sort -n | uniq \ | sed 's,^\(.*\)\.txt$$,- linkman:\1[$(MAN_SECTION_CMD_SYS)],' ; \ ) > "$@" @if test ! -s "$@" ; then echo "- No NUT driver tools were built" > "$@" ; fi # Dependencies are about particular filenames, since over time # we might have several use-cases for LINKMAN_INCLUDE_GENERATED: $(LINKMAN_INCLUDE_CONSUMERS): linkman-driver-names.txt linkman-drivertool-names.txt # Make sure sources are there for out-of-tree builds: $(HTML_MANS) $(MAN_MANS): $(abs_top_builddir)/docs/man/.prep-src-docs all-html html-man: $(HTML_MANS) # Have a way to build all man pages, not just those that fit currently # configured drivers, daemons, developer aspect, etc. all-man man-man: $(MAN_MANS) dist-html: $(DIST_ALL_HTML_PAGES) dist-man: $(DIST_ALL_MAN_PAGES) @SKIP_MANS_FALSE@@WITH_MANS_TRUE@check-local: check-man @SKIP_MANS_TRUE@@WITH_MANS_TRUE@check-local: check-man-txt check-man-pages @SKIP_MANS_TRUE@@WITH_MANS_TRUE@ @echo "Man-page generation was SKIPPED per user request, so pregenerated pages were sanity-checked (if any)" >&2 @WITH_MANS_FALSE@check-local: check-man-txt check-man-pages @WITH_MANS_FALSE@ @echo "Man-page generation was not done, so pregenerated pages were sanity-checked (if any)" >&2 check-man check-man-man: check-man-txt check-man-pages $(TGT_REQUIRE_CHECK_HTML) # the "for" loops might better use $^ but it might be not portable check-man-html: check-html-man check-html-man: .check-html-man .check-html-man: $(HTML_MANS) Makefile @FAILED=""; CHECKED=0; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(HTML_MANS) ; do \ CHECKED="`expr $$CHECKED + 1`"; \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(XML|HTML.*document|symbolic link)' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED HTML-man sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED HTML-man sanity check (checked $$CHECKED files)"; exit 0 @touch $@ # Note: many man-pages here have code samples and are mis-identified as C code check-man-page: check-man-pages # Man-pages may be pre-generated (srcdir), or re-built (builddir) check-man-pages: .check-man-pages .check-man-pages: $(MAN_MANS) Makefile @FAILED=""; CHECKED=0; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(MAN_MANS) ; do \ CHECKED="`expr $$CHECKED + 1`"; \ ( test -s "$(abs_srcdir)/$$F" && { file "$(abs_srcdir)/$$F" | $(EGREP) -i '(roff.* input|C source|ASCII text)' > /dev/null ; } ) || \ ( test -s "$(abs_builddir)/$$F" && { file "$(abs_builddir)/$$F" | $(EGREP) -i '(roff.* input|C source|ASCII text)' > /dev/null ; } ) || \ FAILED="$$FAILED $$F" ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED man-page sanity check for:$$FAILED" >&2 ; \ ( echo "SRCDIR:"; cd "$(abs_srcdir)/" && file $$FAILED ; \ echo "BUILDDIR:"; cd "$(abs_builddir)/" && file $$FAILED ; \ ) >&2 ; exit 1; \ fi; echo "PASSED man-page sanity check (checked $$CHECKED files)"; exit 0 @touch $@ check-man-source: check-man-txt # Note: (GNU) make can helpfully add VPATH to the short source filenames # which we had listed above, so the "case" below handles two possibilities check-man-txt: .check-man-txt .check-man-txt: $(SRC_ALL_PAGES) Makefile @FAILED=""; CHECKED=0; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ ( cd $(abs_srcdir) ) || exit; \ for F in $(SRC_ALL_PAGES) ; do \ CHECKED="`expr $$CHECKED + 1`"; \ case "$$F" in \ */*) ;; \ *) F="$(abs_srcdir)/$$F" ;; \ esac ; \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(ASCII|UTF-8|Unicode|ISO-8859|English).* text' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED man-source sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED man-source sanity check (checked $$CHECKED files)"; exit 0 @touch $@ @WITH_MANS_TRUE@clean-man-pages: @HAVE_ASCIIDOC_TRUE@@WITH_MANS_FALSE@clean-man-pages: @HAVE_ASCIIDOC_FALSE@@WITH_MANS_FALSE@clean-man-pages: @HAVE_ASCIIDOC_FALSE@@WITH_MANS_FALSE@ @FILENAMES='$(DIST_ALL_MAN_PAGES)' ; $(FAKE_FILES_RM) ### Call the prep step consistently to create symlinks (out-of-tree) ### or just touch-files for peace of mind (in-tree builds). Then we ### use these path names (truncated "-prepped") now surely located ### in the builddir as the sources for rendered docs. @HAVE_ASCIIDOC_TRUE@*.txt-prepped: $(abs_top_builddir)/docs/man/.prep-src-docs #.txt.txt-prepped: $(abs_top_builddir)/docs/man/.prep-src-docs ### Regarding absolute paths in attributes below: by default asciidoc ### resolves include paths relative to the main document, so while we ### see the relative builddir as "." in the makefile, for included ### data it would mean the source directory where the .txt resides. ### Note: `(top_)srcdir` and `(top_)builddir` must end with a path ### separator, or be empty -- so in all cases letting the resulting ### string resolve meaningfully in the filesystem during docs build. @HAVE_ASCIIDOC_TRUE@.txt-prepped.html: @HAVE_ASCIIDOC_TRUE@ @A2X_OUTDIR="tmp/man-html.$(@F).$$$$" ; \ @HAVE_ASCIIDOC_TRUE@ echo " DOC-MAN-HTML Generating $@"; \ @HAVE_ASCIIDOC_TRUE@ $(DOCBUILD_BEGIN) ; RES=0; \ @HAVE_ASCIIDOC_TRUE@ $(ASCIIDOC) --backend=xhtml11 $${A2X_VERBOSE} \ @HAVE_ASCIIDOC_TRUE@ --attribute=localdate="`TZ=UTC date +%Y-%m-%d`" \ @HAVE_ASCIIDOC_TRUE@ --attribute=localtime="`TZ=UTC date +%H:%M:%S`" \ @HAVE_ASCIIDOC_TRUE@ --attribute=nutversion="$(PACKAGE_VERSION)" \ @HAVE_ASCIIDOC_TRUE@ --attribute=srcdir="$(abs_srcdir)/" \ @HAVE_ASCIIDOC_TRUE@ --attribute=builddir="$(abs_builddir)/" \ @HAVE_ASCIIDOC_TRUE@ --attribute=top_srcdir="$(abs_top_srcdir)/" \ @HAVE_ASCIIDOC_TRUE@ --attribute=top_builddir="$(abs_top_builddir)/" \ @HAVE_ASCIIDOC_TRUE@ --attribute=MAN_SECTION_API_BASE='$(MAN_SECTION_API_BASE)' \ @HAVE_ASCIIDOC_TRUE@ --attribute=MAN_SECTION_CFG_BASE='$(MAN_SECTION_CFG_BASE)' \ @HAVE_ASCIIDOC_TRUE@ --attribute=MAN_SECTION_CMD_SYS_BASE='$(MAN_SECTION_CMD_SYS_BASE)' \ @HAVE_ASCIIDOC_TRUE@ --attribute=MAN_SECTION_CMD_USR_BASE='$(MAN_SECTION_CMD_USR_BASE)' \ @HAVE_ASCIIDOC_TRUE@ --attribute=NUT_WEBSITE_BASE='$(NUT_WEBSITE_BASE)' \ @HAVE_ASCIIDOC_TRUE@ -o "$${A2X_OUTDIR}/$(@F)" '$<' || RES=$$? ; \ @HAVE_ASCIIDOC_TRUE@ $(DOCBUILD_END) ; exit $$RES @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@.txt.$(MAN_SECTION_API) .txt-prepped.$(MAN_SECTION_API) \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@.txt.$(MAN_SECTION_CFG) .txt-prepped.$(MAN_SECTION_CFG) \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@.txt.$(MAN_SECTION_CMD_SYS) .txt-prepped.$(MAN_SECTION_CMD_SYS) \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@.txt.$(MAN_SECTION_CMD_USR) .txt-prepped.$(MAN_SECTION_CMD_USR) : @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@ @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not functional (even though found)." ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@ else \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@ echo "Could not find prebuilt $@ manual page." ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed and functional?"; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@ exit 1; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_TRUE@ fi @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@.txt-prepped.$(MAN_SECTION_CMD_USR): @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ @A2X_OUTDIR="tmp/man$(MAN_SECTION_CMD_USR).$(@F).$$$$" ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ echo " DOC-MAN Generating $@"; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(DOCBUILD_BEGIN) ; RES=0; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(A2X) $(A2X_MANPAGE_OPTS) '$<' || RES=$$? ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(DOCBUILD_END) ; exit $$RES @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@.txt-prepped.$(MAN_SECTION_API): @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ @A2X_OUTDIR="tmp/man$(MAN_SECTION_API).$(@F).$$$$" ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ echo " DOC-MAN Generating $@"; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(DOCBUILD_BEGIN) ; RES=0; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(A2X) $(A2X_MANPAGE_OPTS) '$<' || RES=$$? ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(DOCBUILD_END) ; exit $$RES @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@.txt-prepped.$(MAN_SECTION_CFG): @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ @A2X_OUTDIR="tmp/man$(MAN_SECTION_CFG).$(@F).$$$$" ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ echo " DOC-MAN Generating $@"; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(DOCBUILD_BEGIN) ; RES=0; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(A2X) $(A2X_MANPAGE_OPTS) '$<' || RES=$$? ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(DOCBUILD_END) ; exit $$RES @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@.txt-prepped.$(MAN_SECTION_CMD_SYS): @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ @A2X_OUTDIR="tmp/man$(MAN_SECTION_CMD_SYS).$(@F).$$$$" ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ echo " DOC-MAN Generating $@"; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(DOCBUILD_BEGIN) ; RES=0; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(A2X) $(A2X_MANPAGE_OPTS) '$<' || RES=$$? ; \ @HAVE_ASCIIDOC_TRUE@@KNOWN_UNABLE_MANS_FALSE@ $(DOCBUILD_END) ; exit $$RES @HAVE_ASCIIDOC_FALSE@.txt.html: @HAVE_ASCIIDOC_FALSE@ @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ @HAVE_ASCIIDOC_FALSE@ echo "Not (re)building $@ manual page (as HTML), since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ @HAVE_ASCIIDOC_FALSE@ else \ @HAVE_ASCIIDOC_FALSE@ echo "Could not find prebuilt $@ manual page (as HTML)." ; \ @HAVE_ASCIIDOC_FALSE@ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ @HAVE_ASCIIDOC_FALSE@ exit 1; \ @HAVE_ASCIIDOC_FALSE@ fi @HAVE_ASCIIDOC_FALSE@.txt.$(MAN_SECTION_CMD_USR): @HAVE_ASCIIDOC_FALSE@ @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ @HAVE_ASCIIDOC_FALSE@ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ @HAVE_ASCIIDOC_FALSE@ else \ @HAVE_ASCIIDOC_FALSE@ echo "Could not find prebuilt $@ manual page." ; \ @HAVE_ASCIIDOC_FALSE@ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ @HAVE_ASCIIDOC_FALSE@ exit 1; \ @HAVE_ASCIIDOC_FALSE@ fi @HAVE_ASCIIDOC_FALSE@.txt.$(MAN_SECTION_API): @HAVE_ASCIIDOC_FALSE@ @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ @HAVE_ASCIIDOC_FALSE@ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ @HAVE_ASCIIDOC_FALSE@ else \ @HAVE_ASCIIDOC_FALSE@ echo "Could not find prebuilt $@ manual page." ; \ @HAVE_ASCIIDOC_FALSE@ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ @HAVE_ASCIIDOC_FALSE@ exit 1; \ @HAVE_ASCIIDOC_FALSE@ fi @HAVE_ASCIIDOC_FALSE@.txt.$(MAN_SECTION_CFG): @HAVE_ASCIIDOC_FALSE@ @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ @HAVE_ASCIIDOC_FALSE@ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ @HAVE_ASCIIDOC_FALSE@ else \ @HAVE_ASCIIDOC_FALSE@ echo "Could not find prebuilt $@ manual page." ; \ @HAVE_ASCIIDOC_FALSE@ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ @HAVE_ASCIIDOC_FALSE@ exit 1; \ @HAVE_ASCIIDOC_FALSE@ fi @HAVE_ASCIIDOC_FALSE@.txt.$(MAN_SECTION_CMD_SYS): @HAVE_ASCIIDOC_FALSE@ @if [ -r "$@" -o -r "$(srcdir)/$(@F)" ] $(SRC_PREBUILT_CLAUSE); then \ @HAVE_ASCIIDOC_FALSE@ echo "Not (re)building $@ manual page, since 'asciidoc', 'xmllint' or 'xsltproc' were not found." ; \ @HAVE_ASCIIDOC_FALSE@ else \ @HAVE_ASCIIDOC_FALSE@ echo "Could not find prebuilt $@ manual page." ; \ @HAVE_ASCIIDOC_FALSE@ echo "If you are building from Git, do you have all of the asciidoc/a2x tools installed?"; \ @HAVE_ASCIIDOC_FALSE@ exit 1; \ @HAVE_ASCIIDOC_FALSE@ fi # NOTE: Due to portability, we do not use a GNU percent-wildcard extension. # We also have to export some variables that may be tainted by relative # paths when parsing the other makefile (e.g. MKDIR_P that may be defined # via expanded $(top_builddir)/install-sh): #%-spellchecked: % Makefile.am $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ # NOTE: Portable suffix rules do not allow prerequisites, so we shim them here # by a wildcard target in case the make implementation can put the two together. *.txt-spellchecked: Makefile.am $(abs_top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) .txt.txt-spellchecked: +$(MAKE) -s -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC_ONE='$<' SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ spellcheck spellcheck-interactive spellcheck-sortdict: +$(MAKE) -f $(top_builddir)/docs/Makefile $(AM_MAKEFLAGS) MKDIR_P="$(MKDIR_P)" builddir="$(builddir)" srcdir="$(srcdir)" top_builddir="$(top_builddir)" top_srcdir="$(top_srcdir)" SPELLCHECK_SRC="$(SRC_ALL_PAGES)" SPELLCHECK_SRCDIR="$(srcdir)" SPELLCHECK_BUILDDIR="$(builddir)" $@ prep-src-docs: $(abs_top_builddir)/docs/man/.prep-src-docs $(abs_top_builddir)/docs/man/.prep-src-docs: $(PREP_SRC) Makefile @cd "$(@D)" || exit ; \ if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then \ if [ "$(MAINTAINER_DOCS_PREP_MAN_DELAY)" -gt 0 ] 2>/dev/null ; then \ echo " DOCS_NO_MAN BLOCK: $@ called in docs/man/Makefile : waiting for other thread to complete this target" ; \ W=0 ; while [ "$${W}" -lt "$(MAINTAINER_DOCS_PREP_MAN_DELAY)" ] && ( [ \! -e '$@' ] || [ x"`find $(PREP_SRC) \! -newer '$@' 2>/dev/null`" = x ] ) ; do sleep 1 ; W="`expr $$W + 1`"; done ; \ echo " DOCS_NO_MAN SKIP: $@ called in docs/man/Makefile : waited $$W seconds" ; \ fi ; \ exit 0 ; \ fi ; \ linkroot="$(abs_builddir)" ; \ MAN_SECTIONS_DEFAULT=false ; \ if [ x"$(MAN_SECTION_API)$(MAN_SECTION_CFG)$(MAN_SECTION_CMD_SYS)$(MAN_SECTION_CMD_USR)" = x3581 ] ; then \ MAN_SECTIONS_DEFAULT=true ; \ fi ; \ if test x"$(abs_srcdir)" = x"$(abs_builddir)" ; then \ COUNT=0; \ for F in $(PREP_SRC) ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed "s#^$(abs_top_srcdir)/*#./#"`"; \ if test x"$${linkroot}" = x"$(abs_builddir)" ; then \ linkroot="$(abs_top_builddir)" ; \ cd "$(abs_top_builddir)" ; \ fi ;; \ esac ; \ if $$MAN_SECTIONS_DEFAULT ; then \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' ; \ else \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' \ -e 's,\(linkman:[^ []*\[\)3\],\1$(MAN_SECTION_API)],g' \ -e 's,\(linkman:[^ []*\[\)5\],\1$(MAN_SECTION_CFG)],g' \ -e 's,\(linkman:[^ []*\[\)8\],\1$(MAN_SECTION_CMD_SYS)],g' \ -e 's,\(linkman:[^ []*\[\)1\],\1$(MAN_SECTION_CMD_USR)],g' \ -e '1 s,\(^.*(\)3)$$,\1$(MAN_SECTION_API)),g' \ -e '1 s,\(^.*(\)5)$$,\1$(MAN_SECTION_CFG)),g' \ -e '1 s,\(^.*(\)8)$$,\1$(MAN_SECTION_CMD_SYS)),g' \ -e '1 s,\(^.*(\)1)$$,\1$(MAN_SECTION_CMD_USR)),g' ; \ fi < "$${F}" > "$${F}-prepped" || exit ; \ COUNT="`expr $$COUNT + 1`" ; \ done ; \ else \ COUNT=30 ; \ touch "$@.$$$$" ; \ while test -e "$@.working" -a "$$COUNT" -gt 0 ; do sleep 1; COUNT="`expr $$COUNT - 1`"; done ; \ touch "$@.working" ; \ if test -n "`find "$@" -newer "$@.$$$$" 2>/dev/null`" ; then \ rm -f "$@.$$$$" "$@.working" ; \ exit 0; \ fi ; \ rm -f "$@.$$$$" ; \ COUNT=0; \ linksrcroot="$(abs_srcdir)" ; \ for F in `echo $(PREP_SRC) | tr ' ' '\n' | sort -n | uniq` ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed "s#^$(abs_top_srcdir)/*#./#"`"; \ if test x"$${linkroot}" = x"$(abs_builddir)" ; then \ linkroot="$(abs_top_builddir)" ; \ linksrcroot="$(abs_top_srcdir)" ; \ cd "$(abs_top_builddir)" ; \ fi ;; \ "$(srcdir)"/*) F="`echo "$$F" | sed 's#^$(srcdir)/*#./#'`" ;; \ */*) ;; \ *) \ linkroot="$(abs_builddir)" ; \ linksrcroot="$(abs_srcdir)" ; \ cd "$(abs_top_builddir)" ;; \ esac ; \ D="`dirname "$$F"`" ; \ (cd '$(abs_builddir)' && $(MKDIR_P) "$${linkroot}/$$D") || { rm -f "$@.working" ; exit 1 ; } ; \ if ! test -e "$${linkroot}/$$F" && test -s "$${linksrcroot}/$$F" ; then \ echo " LN '$${linksrcroot}/$$F' => '$${linkroot}/$$F' (PWD = '`pwd`')" >&2 ; \ ln -fs "$${linksrcroot}/$$F" "$${linkroot}/$$F" || { rm -f "$@.working" ; exit 1 ; } ; \ COUNT="`expr $$COUNT + 1`" ; \ fi ; \ case "$$F" in \ *.txt|*.adoc) IS_TEXT=true ;; \ *.*) IS_TEXT=false ;; \ *) IS_TEXT=true ;; \ esac; \ if $$IS_TEXT ; then \ grep -w linkman "$${linkroot}/$${F}" > /dev/null || IS_TEXT=false ; \ fi ; \ if $$MAN_SECTIONS_DEFAULT || ! $$IS_TEXT ; then \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' ; \ else \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' \ -e 's,\(linkman:[^ []*\[\)3\],\1$(MAN_SECTION_API)],g' \ -e 's,\(linkman:[^ []*\[\)5\],\1$(MAN_SECTION_CFG)],g' \ -e 's,\(linkman:[^ []*\[\)8\],\1$(MAN_SECTION_CMD_SYS)],g' \ -e 's,\(linkman:[^ []*\[\)1\],\1$(MAN_SECTION_CMD_USR)],g' \ -e '1 s,\(^.*(\)3)$$,\1$(MAN_SECTION_API)),g' \ -e '1 s,\(^.*(\)5)$$,\1$(MAN_SECTION_CFG)),g' \ -e '1 s,\(^.*(\)8)$$,\1$(MAN_SECTION_CMD_SYS)),g' \ -e '1 s,\(^.*(\)1)$$,\1$(MAN_SECTION_CMD_USR)),g' ; \ fi < "$${linkroot}/$${F}" > "$${linkroot}/$${F}-prepped" \ || { rm -f "$@.working" ; exit 1 ; } ; \ COUNT="`expr $$COUNT + 1`" ; \ done ; \ fi ; \ if test "$$COUNT" -gt 0 -o ! -e "$@" ; then touch "$@" ; fi @rm -f "$@.working" clean-local: clean-man-pages $(AM_V_at)rm -rf tmp $(AM_V_at)for F in $(PREP_SRC) ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed "s#^$(abs_top_srcdir)/*#./#"`"; cd "$(abs_top_builddir)" ;; \ esac ; \ if test x"$(abs_srcdir)" != x"$(abs_builddir)" ; then \ if test -L "$$F" || test -h "$$F" ; then \ rm -f "$$F" ; \ fi ; \ fi ; \ rm -f "$${F}-prepped" ; \ done ; \ rm -f "$(abs_top_builddir)/docs/man/.prep-src-docs"* # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/docs/man/upscli_splitname.txt0000644000200500020050000000247315001555412015062 00000000000000UPSCLI_SPLITNAME(3) =================== NAME ---- upscli_splitname - Split a UPS definition into its components SYNOPSIS -------- ------ #include int upscli_splitname(const char *buf, char **upsname, char **hostname, int *port) ------ DESCRIPTION ----------- The *upscli_splitname()* function takes a pointer to the raw UPS definition 'buf' and returns pointers to dynamically allocated memory in 'upsname' and 'hostname'. It also copies the port number into 'port'. FORMATTING ---------- An UPS definition is specified according to this format: [@[:]] When the UPS name is not given, this function will print an error to `stderr` and return '-1' without changing anything. Definitions without an explicit port value receive the default value of '3493'. The default hostname is "localhost". MEMORY USAGE ------------ You must linkmanext:free[3] the pointers to 'upsname' and 'hostname' when you are done with them to avoid memory leaks. RETURN VALUE ------------ The *upscli_splitname()* function returns '0' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_fd[3], linkman:upscli_get[3], linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_splitaddr[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/rhino.80000644000200500020050000000561615001555075012165 00000000000000'\" t .\" Title: rhino .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "RHINO" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" rhino \- Driver for Brazilian Microsol RHINO UPS equipment .SH "SYNOPSIS" .sp \fBrhino\fR \-h .sp \fBrhino\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the rhino driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver has been tested with: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Rhino 6000 VA .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Rhino 7500 VA .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Rhino 10000 VA .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Rhino 20000 VA .RE .sp All Rhino models are sinusoidal on\-line\&. .SH "EXTRA ARGUMENTS" .sp This driver support the following extra optional settings in \fBups.conf\fR(5): .PP \fBbattext=\fR\fIn\fR .RS 4 Default = 0, no extra battery, where n = Ampere*hour\&. .RE .SH "COMMANDS" .PP \fBload\&.on\fR .RS 4 Turn on the load immediately\&. .RE .PP \fBload\&.off\fR .RS 4 Turn off the load immediately\&. .RE .PP \fBbypass\&.start\fR .RS 4 Put the UPS in bypass mode\&. .RE .PP \fBbypass\&.stop\fR .RS 4 Put the UPS out of bypass mode\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Shut down in 3 minutes and do not return\&. .RE .SH "AUTHOR" .sp Silvino B\&. Magalhães .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutclient_get_device_variable_description.30000644000200500020050000000004215001555117021455 00000000000000.so man3/libnutclient_variables.3 nut-2.8.3/docs/man/upsstats.cgi.80000644000200500020050000000565315001555050013467 00000000000000'\" t .\" Title: upsstats.cgi .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSSTATS\&.CGI" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsstats.cgi \- Web\-based UPS status viewer .SH "SYNOPSIS" .sp \fBupsstats\&.cgi\fR .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp As a CGI program, this should be invoked through your web server\&. If you run it from the command line, it will either complain about unauthorized access or spew a bunch of HTML at you\&. .sp .5v .RE .SH "DESCRIPTION" .sp \fBupsstats\&.cgi\fR uses template files to build web pages containing status information from UPS hardware\&. It can repeat sections of those template files to monitor several UPSes simultaneously, or focus on a single UPS\&. .sp These templates can also include references to \fBupsimage.cgi\fR(8) for graphical displays of battery charge levels, voltage readings, and the UPS load\&. .SH "ACCESS CONTROL" .sp upsstats will only talk to \fBupsd\fR(8) servers that have been defined in your \fBhosts.conf\fR(5)\&. If it complains that "Access to that host is not authorized", check that file first\&. .SH "TEMPLATES" .sp The web page that is displayed is actually a template containing commands to upsstats which are replaced by status information\&. .sp The default file used for the overview of devices is upsstats\&.html\&. .sp When monitoring a single UPS, the file displayed is upsstats\-single\&.html\&. .sp The format of these files, including the possible commands, is documented in \fBupsstats.html\fR(5)\&. .SH "FILES" .sp \fBhosts.conf\fR(5), \fBupsstats.html\fR(5), upsstats\-single\&.html .SH "SEE ALSO" .sp \fBupsimage.cgi\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutclient_tcp_set_timeout.30000644000200500020050000000003415001555117016317 00000000000000.so man3/libnutclient_tcp.3 nut-2.8.3/docs/man/nutscan_ip_ranges_iter_inc.txt0000644000200500020050000000242215001555412017057 00000000000000NUTSCAN_IP_RANGES_ITER_INC(3) ============================= NAME ---- nutscan_ip_ranges_iter_inc - Proceed with iteration of an IP address range using a `nutscan_ip_range_list_iter_t` structure. SYNOPSIS -------- ------ #include char * nutscan_ip_ranges_iter_inc(nutscan_ip_range_list_iter_t *irliter); ------ DESCRIPTION ----------- The *nutscan_ip_ranges_iter_inc()* function can walk an iterator from the specified `nutscan_ip_range_list_iter_t` helper object, prepared by linkman:nutscan_ip_ranges_iter_init[3] from a `nutscan_ip_range_list_t` structure. This function skips work if: * the structure pointer is `NULL` (`NULL` is returned); * the structure pointer's `ip_range` list is `NULL` (`NULL` is returned), * the structure pointer's `ip_range_iter` pointer is `NULL` (`NULL` is returned). Returns the next IP address from the currently iterated registered IP address range, or switches iteration to the next range if no addresses remained in the current one. The caller SHOULD NOT free this string while iterating. NOTES ----- Technically, the function is currently defined in 'nutscan-ip.h' file. SEE ALSO -------- linkman:nutscan_init_ip_ranges[3], linkman:nutscan_free_ip_ranges[3], linkman:nutscan_cidr_to_ip[3], linkman:nutscan_ip_ranges_iter_init[3] nut-2.8.3/docs/man/nutdrv_atcl_usb.80000644000200500020050000001074615001555077014246 00000000000000'\" t .\" Title: nutdrv_atcl_usb .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTDRV_ATCL_USB" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutdrv_atcl_usb \- Driver for \*(AqATCL FOR UPS\*(Aq equipment .SH "SYNOPSIS" .sp \fBnutdrv_atcl_usb\fR \-h .sp \fBnutdrv_atcl_usb\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the nutdrv_atcl_usb driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver is for UPS hardware which identifies itself as USB idVendor 0001 and idProduct 0000, and iManufacturer ATCL FOR UPS\&. Known manufacturers include Kanji and Plexus\&. .sp The UPS interface seems to be a generic USB\-to\-serial chip, and for hardware manufactured by Kanji and Plexus, the microcontroller appears to emulate a traditional contact\-closure interface\&. This translates into only three states in ups\&.status: \fBOL\fR, \fBOB\fR and \fBOB LB\fR (similar to \fBgenericups\fR(8)), with no other dynamic status values reported\&. .sp Note that these USB identifiers (including the iManufacturer string) have also been seen on devices that are supported by the fuji subdriver of \fBnutdrv_qx\fR(8), and some others\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional setting: .PP \fBvendor =\fR \fIname\fR .RS 4 In case your iManufacturer (Vendor) string does not exactly match ATCL FOR UPS, you may provide an alternate string here (or specify "NULL" if the device does not provide a vendor string but you want this driver to match)\&. .sp Note that a more likely case for mismatch is that your device is handled by another driver for 0001:0000 devices, such as \fBnutdrv_qx\fR(8)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This driver does not intend to support USB\-matching settings common to other drivers, such as \fBvendorid\fR, \fBproduct\fR, \fBproductid\fR, \fBserial\fR, \fBdevice\fR or \fBbus\fR; also the \fBvendor\fR setting supported here is not a regular expression\&. .sp .5v .RE .RE .SH "BUGS" .sp The UPS returns the same code for "load power is off" as for "on line power"\&. This condition will not be observed if the NUT upsmon in primary mode runs on the box powered by the UPS, but may be an issue if the UPS is monitored by a remote (secondary) system\&. .sp The time between the shutdown command and removal of power seems to be fixed at 30 seconds\&. Ensure that the NUT shutdown script is invoked as late as possible in the shutdown procedure (in case some services take longer than others to clean up)\&. .sp Most contact\-closure UPSes will not power down the load if the line power is present\&. This can create a race when using secondary \fBupsmon\fR(8) systems\&. See the \fBupsmon\fR(8) man page for more information\&. The solution to this problem is to upgrade to a smart protocol UPS of some kind that allows detection and proper load cycling on command\&. .SH "AUTHOR" .sp Charles Lepple .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "The generic serial driver:" .sp \fBgenericups\fR(8) .SS "The Qx driver:" .sp \fBnutdrv_qx\fR(8) (fuji subdriver) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/microdowell.80000644000200500020050000000420415001555074013355 00000000000000'\" t .\" Title: microdowell .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "MICRODOWELL" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" microdowell \- Driver for Microdowell Enterprise UPS series .SH "SYNOPSIS" .sp \fBmicrodowell\fR \-h .sp \fBmicrodowell\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the Microdowell driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver was developed for the Enterprise Nxx and Bxx models\&. Other Microdowell models may work, too\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "AUTHOR" .sp Elio Corbolante .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/bicker_ser.80000644000200500020050000001275715001555067013163 00000000000000'\" t .\" Title: bicker_ser .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BICKER_SER" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" bicker_ser \- Driver for Bicker DC UPS via serial port connections .SH "SYNOPSIS" .sp \fBbicker_ser\fR \-h .sp \fBbicker_ser\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBbicker_ser\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp \fBbicker_ser\fR supports all Bicker UPSes shipped with the PSZ\-1053 extension module such as UPSIC\-1205, UPSIC\-2403, DC2412\-UPS and DC2412\-UPS\-LD\&. .SH "CABLING" .sp The needed cable is a standard pin\-to\-pin serial cable with pins 2, 3 and 5 (on DB9 connector) connected\&. .SH "EXTRA ARGUMENTS" .sp This driver supports no extra arguments from \fBups.conf\fR(5)\&. .SH "VARIABLES" .sp Depending on the type of your UPS unit, some of the following variables may be changed with \fBupsrw\fR(8)\&. If the driver can\(cqt read a variable from the UPS, it will not be made available\&. Whenever not explicitly stated, any variable can be disabled, in which case the action it performs will not be executed\&. To disable a variable, set it to an empty value\&. .PP \fBups\&.delay\&.shutdown\fR (in seconds, default disabled) .RS 4 If activated and the UPS is in battery mode and the set time has expired, the output will be disabled, and the UPS and energy storage will be disconnected\&. .RE .PP \fBups\&.delay\&.start\fR (in seconds, default disabled) .RS 4 If activated and a restart condition switches the UPS output off and on again, the set time is the delay between switching on and off\&. The time should cause a defined off time so that capacities in the application can be discharged\&. .RE .PP \fBbattery\&.charge\&.restart\fR (in percent, default disabled) .RS 4 If activated and the UPS is off or restarts, the UPS output will not be released until the energy storage device has the set charge state\&. The energy storage device is charged in the meantime\&. .RE .PP \fBbattery\&.charge\&.low\fR (in percent, default 20) .RS 4 If activated and the UPS is in battery mode and the battery level drops below the set value, a shutdown command via relay event is signaled\&. .RE .PP \fBexperimental\&.output\&.current\&.low\fR (in mA, default 200) .RS 4 If activated and the UPS is in battery mode and the current drops below the set value, the output of the UPS will shut down and disconnect the energy storage to prevent self\-discharge\&. .RE .PP \fBexperimental\&.ups\&.delay\&.shutdown\&.signal\fR (in seconds, default disabled) .RS 4 If activated and the UPS is in battery mode and the set time has elapsed, a shutdown command via relay event is signaled\&. .RE .PP \fBexperimental\&.ups\&.delay\&.shutdown\&.signal\&.masked\fR (in seconds, default disabled) .RS 4 If activated and the UPS is in battery mode and the signal at the IN\-1 input is high and the set time has expired, a shutdown command via relay event is signaled\&. .RE .PP \fBexperimental\&.battery\&.charge\&.low\&.empty\fR (in percent, default 20) .RS 4 This parameter stores the threshold value for the "Battery Empty" signal\&. Currently this setting is only valid for relay signaling\&. Cannot be disabled\&. .RE .PP \fBexperimental\&.ups\&.relay\&.mode\fR (default 0x01) .RS 4 This parameter controls the behavior of the relay in case of different events\&. Cannot be disabled\&. .sp Available relay modes: .TS tab(:); lt lt lt lt lt lt lt lt lt lt. T{ 0x01 T}:T{ On power fail (normally closed) T} T{ 0x02 T}:T{ On power fail (normally opened) T} T{ 0x03 T}:T{ Shutdown impulse (1 second) T} T{ 0x04 T}:T{ Battery low signal (normally closed) T} T{ 0x05 T}:T{ Battery defect signal (normally closed) T} .TE .sp 1 .RE .SH "INSTANT COMMANDS" .PP \fBshutdown\&.return\fR .RS 4 Turn off the load and return when power is back\&. .RE .SH "KNOWN ISSUES AND BUGS" .PP \fBups\&.delay\&.shutdown is not honored\fR .RS 4 Although that delay is properly set when sending the shutdown command, it seems some UPS ignore it and use a fixed 2 seconds delay instead\&. .RE .SH "AUTHOR" .sp Nicola Fontana .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upssched.conf.txt0000644000200500020050000000677515001555412014262 00000000000000UPSSCHED.CONF(5) ================ NAME ---- upssched.conf - Configuration for upssched timer program DESCRIPTION ----------- This file controls the operations of linkman:upssched[8], the timer-based helper program for linkman:upsmon[8]. IMPORTANT NOTES --------------- * Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message). CONFIGURATION DIRECTIVES ------------------------ *CMDSCRIPT* 'scriptname':: Required. This must be above any AT lines. This script is used to invoke commands when your timers are triggered. It receives a single argument which is the name of the timer that caused it to trigger. *PIPEFN* 'filename':: Required. This sets the file name of the socket which will be used for interprocess communications. This should be in a directory where normal users can't create the file, due to the possibility of symlinking and other evil. CAUTION: if you are running Solaris or similar, the permissions that upssched sets on this file *are not enough* to keep you safe. If your OS ignores the permissions on a FIFO, then you MUST put this in a protected directory! NOTE: by default, linkman:upsmon[8] will run upssched as whatever user you have defined with RUN_AS_USER in linkman:upsmon.conf[8]. Make sure that user can create files and write to files in the path you use for PIPEFN and LOCKFN. My recommendation: create a special directory for upssched, make it owned by your upsmon user, then use it for both. The stock version of the upssched.conf ships with PIPEFN disabled to make you visit this portion of the documentation and think about how your system works before potentially opening a security hole. *LOCKFN* 'filename':: Required. upssched attempts to create this file in order to avoid a race condition when two events are dispatched from upsmon at nearly the same time. This file will only exist briefly. It must not be created by any other process. + You should put this in the same directory as PIPEFN. *AT* 'notifytype' 'upsname' 'command':: Define a handler for a specific event 'notifytype' on UPS 'upsname'. 'upsname' can be the special value * to apply this handler to every UPS. + This will perform the command 'command' when the 'notifytype' and 'upsname' match the current activity. Possible values for 'command' are: *START-TIMER* 'timername' 'interval';; Start a timer of 'interval' seconds. When it triggers, it will pass the argument 'timername' as an argument to your CMDSCRIPT. + Example: + Start a timer that will execute when any UPS (*) has been gone for 10 seconds AT COMMBAD * START-TIMER upsgone 10 *CANCEL-TIMER* 'timername' ['cmd'];; Cancel a running timer called 'timername', if possible. If the timer has passed then pass the optional argument 'cmd' to CMDSCRIPT. + Example: + If a specific UPS (+myups@localhost+) comes back online, then stop the timer before it triggers AT COMMOK myups@localhost CANCEL-TIMER upsgone *EXECUTE* 'command';; Immediately pass 'command' as an argument to CMDSCRIPT. + Example: + If any UPS (*) reverts to utility power, then execute `ups-back-on-line` via CMDSCRIPT. AT ONLINE * EXECUTE ups-back-on-line Note that any AT that matches both the 'notifytype' and the 'upsname' for the current event will be used. For a complete list of 'notifytype' possible values, refer to the section NOTIFY EVENTS in linkman:upsmon[8]. SEE ALSO -------- linkman:upssched[8], linkman:upsmon[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/optiups.txt0000644000200500020050000000542415001555412013211 00000000000000OPTIUPS(8) ========== NAME ---- optiups - Driver for Opti-UPS (Viewsonic) UPS and Zinto D (ONLINE-USV) equipment SYNOPSIS -------- *optiups* -h *optiups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the optiups driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ *optiups* was originally written against a PowerES 280es in nut-0.45. It was revised for nut-2.0.1 and tested against a PowerES 420E. It is expected to work with at least the PowerES, PowerPS, and PowerVS models. This driver additionally supports a Zinto D from ONLINE USV-Systeme AG because of their very similar commands, but it is unknown if it also works with other UPS from them. This driver will not work with the PowerES stock serial cable. You will need to construct your own three conductor cable: UPS 6 -> PC 3 UPS 9 -> PC 2 UPS 4 -> PC 5 The cable for Online-USV uses pin UPS 7 (not UPS 4) -> PC 5. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file: *status_only*:: Only poll for critical status information. Without this, *optiups* (and all NUT drivers) poll all sorts of information from the UPS fairly often. It is probably not often enough to hurt anything, so this option probably is not very useful, unless you have a flaky serial connection or a highly loaded machine. *nowarn_noimp*:: Does not print warnings when the UPS reports that a variable is not implemented or not pollable. Without the option you will get a message sent to your system logs each time NUT polls the UPS. If you specify *nowarn_noimp*, this message will only be logged once. *fake_lowbatt*:: This forces the low battery flag true. Without it, if you want to test your UPS, you will have to unplug it and wait until the battery drops to a low/critical voltage level before NUT will respond and power down your system. With the flag, NUT should power down the system soon after you pull the plug. When you are done testing, you should remove this flag. + For basic shutdown configuration testing, the command 'upsmon -c fsd' is preferred. *powerup*:: Zinto D from ONLINE-USV cannot be identified when switched to standby. Set this flag to allow the driver to power-up your Zinto UPS. This will also power-up your equipment connected to the UPS! BUGS ---- On the 420E, `ups.serial` and `ups.temperature` are unsupported features. This is not a bug in NUT or the NUT driver, just the way things are with this UPS. AUTHORS ------- * Russell Kroll * Scott Heavner * Matthias Goebl SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upsd.users.50000644000200500020050000001362515001555046013153 00000000000000'\" t .\" Title: upsd.users .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSD\&.USERS" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsd.users \- Administrative user definitions for NUT upsd data server .SH "DESCRIPTION" .sp Administrative commands such as setting variables and the instant commands are powerful, and access to them needs to be restricted\&. This file defines who may access them, and what is available\&. .SH "IMPORTANT NOTES" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Balance the run\-time user permissions to access the file (and perhaps the directory it is in) for only upsd to be able to read it; write access is not needed\&. It is common to use chown root:nut and chmod 640 to set up acceptable file permissions\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Packages (and build recipes) typically prepare one set of user and group accounts for NUT\&. Custom builds with minimal configuration might even use nobody:nogroup or similar, which is inherently insecure\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} On systems with extra security concerns, NUT drivers and data server should run as separate user accounts which would be members of one same group for shared access to local Unix socket files and the directory they are in, but different groups for configuration file access\&. This would need some daemons to use customized user, group, RUN_AS_USER and/or RUN_AS_GROUP settings to override the single built\-in value\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Note that the monitoring, logging, etc\&. clients are networked\-only\&. They do not need access to these files and directories, and can run as an independent user and group altogether\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Keep in mind the security of also any backup copies of this file, e\&.g\&. the archive files it might end up in\&. .RE .RE .SH "SECTIONS" .sp Each user gets its own section\&. The fields in that section set the parameters associated with that user\(cqs privileges\&. The section begins with the name of the user in brackets, and continues until the next user name in brackets or EOF\&. These users are independent of /etc/passwd or other OS account databases\&. .sp Here are some examples to get you started: .sp .if n \{\ .RS 4 .\} .nf [admin] password = mypass actions = set actions = fsd instcmds = all .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf [pfy] password = duh instcmds = test\&.panel\&.start instcmds = test\&.panel\&.stop .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf [upswired] password = blah upsmon primary .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf [observer] password = abcd upsmon secondary .fi .if n \{\ .RE .\} .SH "FIELDS" .PP \fBpassword\fR .RS 4 Set the password for this user\&. .RE .PP \fBactions\fR .RS 4 Allow the user to do certain things with upsd\&. To specify multiple actions, use multiple instances of the \fBactions\fR field\&. Valid actions are: .PP SET .RS 4 change the value of certain variables in the UPS .RE .PP FSD .RS 4 set the forced shutdown flag in the UPS\&. This is equivalent to an "on battery + low battery" situation for the purposes of monitoring\&. .RE .sp The list of actions is expected to grow in the future\&. .RE .PP \fBinstcmds\fR .RS 4 Let a user initiate specific instant commands\&. Use "ALL" to grant all commands automatically\&. To specify multiple commands, use multiple instances of the \fBinstcmds\fR field\&. For the full list of what your UPS supports, use upscmd \-l\&. .sp The cmdvartab file supplied with the NUT distribution contains a list of most of the generally known command names\&. .RE .PP \fBupsmon\fR .RS 4 Add the necessary actions for an upsmon process, and can be viewed as a role of a particular client instance to work with this data server instance\&. This is either set to \fIprimary\fR (may request FSD) or \fIsecondary\fR (follows critical situations to shut down when needed)\&. .sp Do not attempt to assign actions to upsmon by hand, as you may miss something important\&. This method of designating a "upsmon user" was created so internal capabilities could be changed later on without breaking existing installations (potentially using actions that are not exposed for direct assignment)\&. .RE .SH "SEE ALSO" .sp \fBupsd\fR(8), \fBupsd.conf\fR(5) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/riello_usb.txt0000644000200500020050000000406715001555412013647 00000000000000RIELLO_USB(8) ============= NAME ---- riello_usb - Driver for Riello UPS Protocol UPS equipment via USB SYNOPSIS -------- *riello_usb* -h *riello_usb* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the riello_usb driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ riello_usb supports all recent Riello UPS with USB. Older Riello UPS products are not supported. EXTRA ARGUMENTS --------------- include::nut_usb_addvars.txt[] You may need to tweak some settings, depending on the make and model of your UPS (see linkman:ups.conf[5]): *localcalculation*:: When enabled, driver will calculate values of `battery.runtime` and `battery.charge` "locally" in the driver. This is for some Riello models (iPlug and iDialog series) which provide incorrect values in hardware readings, or none at all. This "local calculation" is done according to nominal battery capacity, nominal battery voltage, actual battery charge, maximum and actual UPS load. + You may want to also configure 'default.battery.voltage.low' and 'default.battery.voltage.high' in case the built-in default range (from 10.7V to 12.9V) does not match your hardware, or give a shot to 'default.battery.voltage.nominal' (e.g. '24') if your device does not serve that either. + NOTE: Lead (PbAc) battery charge graph is not linear, so guesstimated charge value may not be perfectly accurate. However it should be good enough to determine battery actual status and roughly estimate the time it can still power the system. + WARNING: This keyword may be deprecated in future releases of the driver, in favor of `runtimecal` and other settings which it requires (as seen in linkman:nutdrv_qx[8], linkman:blazer_ser[8] and linkman:blazer_usb[8] drivers). AUTHOR ------ Massimo Zampieri SEE ALSO -------- Related drivers ~~~~~~~~~~~~~~~ linkman:riello_ser[8] The core driver ~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/NUT-Monitor.txt0000644000200500020050000000713115001555412013576 00000000000000NUT-Monitor(8) ============== NAME ---- NUT-Monitor, NUT-Monitor-py2gtk2, NUT-Monitor-py3qt5 - Python UI Client for NUT SYNOPSIS -------- *NUT-Monitor-py2gtk2* *NUT-Monitor-py3qt5* [PREFER_PY2=true] [PYTHON2=python2.7] [PYTHON3=python3.14w] *NUT-Monitor* DESCRIPTION ----------- These programs comprise the NUT-Monitor Python UI Client for NUT with two similar implementations for major Python UI ecosystems still seen in practical deployments. For communications with a NUT data server, both rely on the 'PyNUTClient' module (compatible with both Python 2.x and 3.x) provided by NUT sources that can be installed by your packaging as part of NUT; also releases of the module are published as a PyPI package. * `NUT-Monitor-py2gtk2` is an implementation that relies on a Python 2.x interpreter (tested with 2.6 or 2.7 generation) and GTK2 UI library; * `NUT-Monitor-py3qt5` is an implementation that relies on a Python 3.x interpreter and QT5 UI library; * `NUT-Monitor` is a shell script to pick at run-time the best implementation. In older NUT releases, this was the file name used by the Python 2.x variant directly. Note that depending on your distribution's packaging choices, you may lack the `NUT-Monitor` shell script and just have one set of the desktop window manager integration files directly for one particular implementation of the actual Python UI client. For each individual run, the UI client can connect to a single NUT data server and a device on it. This can use either anonymous read-only connections (like linkman:upsc[8]), or authenticated connections (see linkman:upsd.users[5]) which can also issue commands to the driver (like linkman:upscmd[8]) and set supported variables (like linkman:upsrw[8]) -- propagated to the device, where applicable. The Python UI client can be used on a system different from the NUT data server (the one connected to the actual UPS by communications media and running the NUT driver(s)), and may be using a different OS platform (including Windows). NOTE: Do not confuse this graphical NUT client with an unfortunately named `nut-monitor` service in some packaged distributions, as the name of (or an alias to) the service wrapping the linkman:upsmon[8] client daemon for your system shutdown. EXTRA ARGUMENTS --------------- These scripts do not support command-line arguments, but the `NUT-Monitor` shell script can be influence by environment variables `PYTHON2` and/or `PYTHON3` to provide the program name (or full path name) of your preferred version for the respective implementation of the Python interpreter. This program would be tried first when probing for available prerequisites. The `PREFER_PY2=true` or `PREFER_PY2=false` environment variable value can be used to select the implementation of the client to use if both ecosystems are usable on the current system. Note that the implementation for Python 2.x / GTK2 is slightly better regarding localization; functionally they should be equivalent. AUTHORS ------- * David Goncalves -- original Python 2.x / GTK2 version of the script and the PyNUTClient module * Luke Dashjr -- conversion to Python 3.x / QT5 * Jim Klimov -- wrapper script to choose one of the implementations, occasional fixes, PyPI packaging for the module SEE ALSO -------- linkman:upsc[8], linkman:upscmd[8], linkman:upsrw[8], linkman:upsd.users[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * Releases of PyNUTClient module (packaged from NUT code base): https://pypi.org/project/pynutclient/ nut-2.8.3/docs/man/nutclient_has_device_variable.30000644000200500020050000000004215001555117017046 00000000000000.so man3/libnutclient_variables.3 nut-2.8.3/docs/man/gamatronic.80000644000200500020050000000420715001555071013161 00000000000000'\" t .\" Title: gamatronic .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "GAMATRONIC" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" gamatronic \- Driver for Gamatronic UPS equipment .SH "SYNOPSIS" .sp \fBgamatronic\fR \-h .sp \fBgamatronic\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the gamatronic driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp Various \(em Rebuilt to work with Gamatronic UPS Units, but should recognize any UPS that speaks the SEC protocol at 1200\-19200 bps\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "AUTHOR" .sp Nadav Moskovitch .SH "SEE ALSO" .SS "The core driver" .sp \fBnutupsdrv\fR(8) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upsrw.txt0000644000200500020050000001135015001555412012661 00000000000000UPSRW(8) ======== NAME ---- upsrw - Network UPS Tools device/driver variable administration tool SYNOPSIS -------- *upsrw* [-l] 'ups' *upsrw* -h *upsrw* -s 'variable' [-u 'username'] [-p 'password'] [-w] [-t ] 'ups' DESCRIPTION ----------- *upsrw* allows you to view and change the read/write variables inside your UPS. It sends commands via the server linkman:upsd[8] to your driver, which configures the hardware for you. You must use credentials defined in linkman:upsd.users[5] file on that data server with appropriate permissions. The list of variables that allow you to change their values is based on the capabilities of your UPS equipment. Not all models support this feature. Typically, cheaper hardware does not support any of them. Run `upsrw` with a UPS identifier to see what will work for you. OPTIONS ------- *-s* 'variable':: Specify the variable to be changed inside the UPS. For unattended mode such as in shell scripts, use the format VAR=VALUE to specify both the variable and the value, for example: -s input.transfer.high=129 + Without this argument, upsrw will just display the list of the variables and their possible values. + Some variables are strings, and can be set to any value within the length limit. Others are enumerated types and can only be set to one of those values. Others may be within an allowed range of values. Refer to the list to know what's available in your hardware. *-l*:: Just display the list of the variables and their possible values. + Same as default activity without '-s' argument, provided for CLI similarity with other tools. *-u* 'username':: Set the NUT username for the connection to the server. This is optional, and you will be prompted for this when using the -s option if you don't specify -u on the command line. NUT usernames are defined in linkman:upsd.users[5], and are not linked to system usernames. *-p* 'password':: Set the password to authenticate to the server. This is also optional like -u, and you will be prompted for it if necessary. *-w*:: Wait for the completion of setting execution by the driver and return its actual result from the device. Note that this feature requires that both linkman:upsd[8] and the driver support TRACKING (NUT version 2.8.0 or higher), or it will otherwise fail. + The command will also block until an actual result is provided from the driver, or the timeout is reached (see *-t*). *-t* 'seconds':: Set a timeout when using *-w*. Defaults to 10 seconds. 'ups':: View or change the settings on this UPS. The format for this option is `upsname[@hostname[:port]]`. The default hostname is "localhost". COMMON OPTIONS -------------- *-h*:: Show the command-line help message. *-V*:: Show NUT version banner. More details may be available if you also `export NUT_DEBUG_LEVEL=1` or greater verbosity level. *-W* 'secs':: Set the timeout for initial network connections (by default they are indefinitely non-blocking, or until the system interrupts the attempt). Overrides the optional `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable. UNATTENDED MODE --------------- If you run this program inside a shell script or similar to set variables, you will need to specify all of the information on the command line. This means using `-s VAR=VALUE`, `-u` and `-p`. Otherwise it will put up a prompt and your program will hang. This is not necessary when displaying the list, as the username and password are not required for read-only mode. Moreover, if you run this program inside a shell script or similar, you should only consider using output from stdout, not stderr. DIAGNOSTICS ----------- *upsrw* can't set variables on your UPS unless you provide a valid username and password. If you get "access denied" errors, make sure that your linkman:upsd.users[5] has an entry for you, and that the username you are using has permissions to SET variables. *upsrw* without '-w' would somewhat confusingly show "OK" meaning just that the data server connection was established, and the server did not immediately reject the request due to e.g. unknown driver variable name. If you care to know the actual results, do use the `-w (-t NUM)` option(s) to wait for them. VALUE FORMAT ------------ When using *upsrw* to modify a numeric float value, that values must be given using decimal (base 10) english-based representation, so using a dot, in non-scientific notation. So hexadecimal, exponents, and comma for thousands separator are forbidden. For example: "1200.20" is valid, while "1,200.20" and "1200,20" are invalid. HISTORY ------- This program used to be called upsct2, which was ambiguous and confusing. SEE ALSO -------- linkman:upsd[8], linkman:upscmd[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/macosx-ups.txt0000644000200500020050000000521415001555412013602 00000000000000MACOSX-UPS(8) ============= NAME ---- macosx-ups - Monitor for Mac OS X built-in UPS and battery driver SYNOPSIS -------- *macosx-ups* -h *macosx-ups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *macosx-ups* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ *macosx-ups* supports any USB HID Power Device Class (PDC) UPS which is matched by the Mac OS X built-in drivers. It also can monitor a laptop internal battery as though it were an UPS. If the UPS is visible in the Energy Saver preferences pane of System Preferences, this driver should be able to monitor it. EXTRA ARGUMENTS ---------------- *port*=auto:: Due to changes in the way that Mac OS X lists power sources, the *port* parameter no longer has any effect. The rest of NUT still requires a value here, and our traditional "don't care" value is `auto`. *model*='regex':: Likewise, if you have more than one UPS, it may be necessary to specify a *model* name to match against. This parameter is also a case-insensitive extended regular expression. DIAGNOSTICS ----------- If the driver cannot find an UPS, first open System Preferences and see if there is an "UPS" tab on the Energy Saver panel. If so, re-run the driver with the `-D` flag to list the names of the power sources found. KNOWN ISSUES AND BUGS --------------------- This driver is a monitoring-only driver, and cannot shut down an UPS on its own. However, this should not be a problem in practice: it is monitoring the built-in Mac OS X UPS driver, which has configuration options for several shutdown scenarios. Consult the Energy Saver control panel or linkmanext:pmset[8] for more information. The default distribution of *apcupsd* installs a kernel extension which prevents Mac OS X from attaching to the UPS. In order to use this driver after installing `apcupsd`, you must first run the `apcupsd-uninstall` script and reboot. Note that other UPS monitoring solutions may show more detail than what is provided by the built-in Mac OS X driver. In particular, voltages other than the battery voltage, as well as current and frequency, are typically not shown. It may be possible to monitor these values with *apcupsd* (for APC hardware only) or linkman:usbhid-ups[8]. AUTHOR ------ Charles Lepple SEE ALSO -------- linkman:usbhid-ups[8], linkmanext:pmset[8], linkmanext:regex[3] The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * The apcupsd home page: http://www.apcupsd.org/ nut-2.8.3/docs/man/nutscan_add_option_to_device.30000644000200500020050000001041315001555063016721 00000000000000'\" t .\" Title: nutscan_add_option_to_device .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_ADD_OPTION_T" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_add_option_to_device, nutscan_add_commented_option_to_device \- Add option data to the specified device\&. .SH "SYNOPSIS" .sp .nf #include /* Add enabled option data to the specified device\&. */ void nutscan_add_option_to_device( nutscan_device_t * device, char * option_name, char * value); /* Since libnutscan version 2\&.5\&.0: * Add option data to the specified device with an optional comment tag * for options suggested, but not currently enabled for actual use\&. */ void nutscan_add_commented_option_to_device( nutscan_device_t * device, char * option_name, char * value, char * comment_tag); .fi .SH "DESCRIPTION" .sp The nutscan_device_t contains the following variables: .sp .if n \{\ .RS 4 .\} .nf nutscan_device_type_t type; char * driver; char * alt_driver_names; char * port; nutscan_options_t opt; struct nutscan_device * prev; struct nutscan_device * next; .fi .if n \{\ .RE .\} .sp This is a double linked list of devices\&. Each \fIdevice\fR is described by its type, its driver name, its port and any number of optional data\&. .sp The \fBnutscan_add_option_to_device()\fR adds an optional data in the given \fIdevice\fR\&. Optional data are made of an \fIoption_name\fR and an associated \fIvalue\fR, and optionally a \fIcomment_tag\fR\&. Copies of the \fIoption_name\fR, \fIvalue\fR and \fIcomment_tag\fR are stored in the \fIdevice\fR, so the caller can safely \fBfree\fR(3) all of the original strings used as arguments\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp A non\-NULL value of the \fIcomment_tag\fR makes the option not\-enabled for current use\&. Depending on the output format, it may be either completely ignored, or rendered as a comment with this value as a prefix (a zero\-length string "\e0" may be passed to have no prefix)\&. .sp .5v .RE .sp Such options and their values may be further sanity\-checked and reported as warnings by \fBnutscan_display_sanity_check()\fR dispatcher and its related methods which implement the logic of particular checks\&. This is used for example when generating an ups\&.conf file content suggestions with \fBnutscan_display_ups_conf_with_sanity_check()\fR method\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-device\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_device_to_device\fR(3) nut-2.8.3/docs/man/upssched.txt0000644000200500020050000001100715001555412013316 00000000000000UPSSCHED(8) =========== NAME ---- upssched - Timer helper for scheduling events from upsmon SYNOPSIS -------- *upssched* NOTE: *upssched* should be run from linkman:upsmon[8] via the NOTIFYCMD. You should never run it directly during normal operations. DESCRIPTION ----------- *upssched* was created to allow users to execute programs at times relative to events being monitored by linkman:upsmon[8]. The original purpose was to allow for a shutdown to occur after some fixed period on battery, but there are other uses that are possible. INTEGRATION ----------- upssched needs to be called as the NOTIFYCMD in your linkman:upsmon.conf[5]. It determines what is happening based on the UPSNAME and NOTIFYTYPE environment variables. You should never have to deal with them directly. Set the EXEC flag on the events that you want to see in upssched. For example, to make sure that upssched hears about ONLINE, ONBATT and LOWBATT events, the flags would look like this: NOTIFYFLAG ONLINE EXEC NOTIFYFLAG ONBATT EXEC NOTIFYFLAG LOWBATT EXEC If you also want to continue writing to the syslog, just add it in: NOTIFYFLAG ONLINE SYSLOG+EXEC NOTIFYFLAG ONBATT SYSLOG+EXEC NOTIFYFLAG LOWBATT SYSLOG+EXEC For a full list of notify flags, see the linkman:upsmon[8] documentation. CONFIGURATION ------------- See linkman:upssched.conf[5] for information on configuring this program. EARLY SHUTDOWNS --------------- To shut down the system early, define a timer that starts due to an ONBATT condition. When it triggers, make your CMDSCRIPT call your shutdown routine. It should finish by calling `upsmon -c fsd` so that upsmon gets to shut down the slaves in a controlled manner. Be sure you cancel the timer if power returns (ONLINE). DEBOUNCING EVENTS ----------------- If your UPS goes on and off battery frequently, you can use this program to reduce the number of pager messages that are sent out. Rather than sending pages directly from linkman:upsmon[8], use a short timer here. If the timer triggers with the UPS still on battery, then send the page. If the power returns before then, the timer can be cancelled and no page is necessary. BACKGROUND ---------- This program was written primarily to fulfill the requests of users for the early shutdown scenario. The "outboard" design of the program (relative to upsmon) was intended to reduce the load on the average system. Most people don't have the requirement of shutting down after 'N' seconds on battery, since the usual OB+LB testing is sufficient. This program was created separately so those people don't have to spend CPU time and RAM on something that will never be used in their environments. The design of the timer handler is also geared towards minimizing impact. It will come and go from the process list as necessary. When a new timer is started, a process will be forked to actually watch the clock and eventually start the CMDSCRIPT. When a timer triggers, it is removed from the queue. Cancelling a timer will also remove it from the queue. When no timers are present in the queue, the background process exits. This means that you will only see upssched running when one of two things is happening: - There's a timer of some sort currently running - upsmon just called it, and you managed to catch the brief instance The final optimization handles the possibility of trying to cancel a timer when there are none running. If the timer daemon isn't running, there are no timers to cancel, and furthermore there is no need to start a clock-watcher. So, it skips that step and exits sooner. ENVIRONMENT VARIABLES --------------------- *NUT_DEBUG_LEVEL* sets default debug verbosity if no *-D* arguments were provided on command line, but does not request that the daemon runs in foreground mode. NOTE: Unlike some other NUT daemons, `upssched` with enabled debug does not stop reporting on `stderr`! It forks a background process with the first call as an event handler, which exits soon after all tracked timers have elapsed and were handled (if needed). *UPSNAME* and *NOTIFYTYPE* are required, as detailed above. They are set by `upsmon` when it calls `upssched` as its choice of `NOTIFYCMD`. *NUT_CONFPATH* is the path name of the directory that contains `upssched.conf` and other configuration files. If this variable is not set, *upssched* uses a built-in default, which is often `/usr/local/ups/etc`. FILES ----- linkman:upssched.conf[5] SEE ALSO -------- linkman:upsmon[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_stringify_ip_ranges.30000644000200500020050000000477415001555062016641 00000000000000'\" t .\" Title: nutscan_stringify_ip_ranges .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_STRINGIFY_IP" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_stringify_ip_ranges \- Collect contents of a `nutscan_ip_range_list_t` structure into a string buffer that can be further printed into logs\&. .SH "SYNOPSIS" .sp .nf #include const char * nutscan_stringify_ip_ranges(nutscan_ip_range_list_t *irl); .fi .SH "DESCRIPTION" .sp The \fBnutscan_stringify_ip_ranges()\fR function can walk a nutscan_ip_range_list_t structure to report its contents: count of list items, and a comma\-separated listing with each item as a single token (if start_ip==end_ip in that range) or a range as start_ip \&.\&. end_ip\&. .sp Returns a pointer to internal statically allocated buffer which would be overwritten by subsequent calls, but does not have to be freed by caller\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br .sp Callers should use semaphores if accessing this function in multi\-thread context! .sp .5v .RE .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-ip\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_add_ip_range\fR(3), \fBnutscan_cidr_to_ip\fR(3), \fBnutscan_ip_ranges_iter_init\fR(3), \fBnutscan_ip_ranges_iter_inc\fR(3) nut-2.8.3/docs/man/nutscan_display_ups_conf_with_sanity_check.30000644000200500020050000000456415001555060021707 00000000000000'\" t .\" Title: nutscan_display_ups_conf_with_sanity_check .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_DISPLAY_UPS_" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_display_ups_conf_with_sanity_check \- Display the specified `nutscan_device_t` structure and sanity\-check warnings on stdout\&. .SH "SYNOPSIS" .sp .nf #include void nutscan_display_ups_conf_with_sanity_check(nutscan_device_t * device); .fi .SH "DESCRIPTION" .sp The \fBnutscan_display_ups_conf_with_sanity_check()\fR function displays all NUT devices in \fIdevice\fR to stdout, and follows up with comments about sanity\-check violations (if any)\&. It displays them in a way that it can be directly copied into the ups\&.conf file\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/liebert-gxe.txt0000644000200500020050000000260015001555412013706 00000000000000LIEBERT-GXE(8) =============== NAME ---- liebert-gxe - Driver for Liebert GXE series UPS, using the YDN23 serial protocol SYNOPSIS -------- *liebert-gxe* -h *liebert-gxe* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the liebert-gxe driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ Tested to work on the following units: * Liebert GXE 01k00TS1101C00 + NOTE: This UPS has an RS-232 port and a USB port. The USB port has an ACM interface which functions as a serial port for the host operating system. Both ports can be used managing the device. This is an experimental driver. You have been warned. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in linkman:ups.conf[5]: *addr=*'num':: Set the address of the UPS -- 01 (default) ~ 99. *retry=*'num':: Set the max times of read failures. (UPS sometimes ignores the incoming command and causes driver stales. The driver will ignore *retry* failures if occurred in a row. However, this does increase the latency if a real stale happened. Default to 3) AUTHORS ------- * Gong Zhile SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_get.30000644000200500020050000001272315001555051013166 00000000000000'\" t .\" Title: upscli_get .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_GET" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_get \- Retrieve data from an UPS .SH "SYNOPSIS" .sp .nf #include int upscli_get( UPSCONN_t *ups, size_t numq, const char **query, size_t *numa, char ***answer) .fi .SH "DESCRIPTION" .sp The \fBupscli_get()\fR function takes the pointer \fIups\fR to a UPSCONN_t state structure, and the pointer \fIquery\fR to an array of \fInumq\fR query elements\&. It builds a properly\-formatted request from those elements and transmits it to \fBupsd\fR(8)\&. .sp Upon success, the response will be split into separate components\&. A pointer to those components will be returned in \fIanswer\fR\&. The number of usable answer components will be returned in \fInuma\fR\&. .SH "USES" .sp This function implements the "GET" command in the NUT protocol\&. As a result, you can use it to request many different things from the server\&. .sp Some examples are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} GET NUMLOGINS .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} GET UPSDESC .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} GET VAR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} GET TYPE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} GET DESC .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} GET CMDDESC .RE .SH "QUERY FORMATTING" .sp To generate a request for GET NUMLOGINS su700, you would populate query and numq as follows: .sp .if n \{\ .RS 4 .\} .nf size_t numq; const char *query[2]; query[0] = "NUMLOGINS"; query[1] = "su700"; numq = 2; .fi .if n \{\ .RE .\} .sp All escaping of special characters and quoting of elements with spaces is handled for you inside this function\&. .SH "ANSWER FORMATTING" .sp The raw response from upsd to the above query would be NUMLOGINS su700 1\&. .sp Since this is split up for you, the values work out like this: .sp .if n \{\ .RS 4 .\} .nf size_t numa; numa = 3; answer[0] = "NUMLOGINS" answer[1] = "su700" answer[2] = "1" .fi .if n \{\ .RE .\} .sp Notice that the value which you seek typically starts at answer[numq]\&. .SH "ERROR CHECKING" .sp This function will check your query against the response from \fBupsd\fR(8) data server\&. .sp For example, if you send "VAR" "su700" "ups\&.status", it will expect to see those at the beginning of the response\&. .sp If the results from upsd do not pass this case\-insensitive test against your request, this function will return an error\&. When this happens, \fBupscli_upserror\fR(3) will return \fIUPSCLI_ERR_PROTOCOL\fR\&. .SH "ANSWER ARRAY LIFETIME" .sp The pointers contained within the \fIanswer\fR array are only valid until the next call to an \fIupsclient\fR function which references them\&. If you need to use data from multiple calls, you must copy it somewhere else first\&. .sp The \fIanswer\fR array and its elements may change locations, so you must not rely on previous addresses\&. You must only use the addresses which were returned by the most recent call\&. You also must not attempt to use more than \fInuma\fR elements in \fIanswer\fR\&. Such behavior is undefined, and may yield bogus data or a crash\&. .sp The array will be deleted after calling \fBupscli_disconnect\fR(3)\&. Any access after that point is also undefined\&. .SH "RETURN VALUE" .sp The \fBupscli_get()\fR function returns \fI0\fR on success, or \fI\-1\fR if an error occurs\&. .sp If \fBupsd\fR disconnects, you may need to handle or ignore SIGPIPE in order to prevent your program from terminating the next time that the library writes to the disconnected socket\&. .sp The following code in your initialization function will allow the \fBupscli_get()\fR call to return an error in that case: .sp .if n \{\ .RS 4 .\} .nf #include \&.\&.\&. signal (SIGPIPE, SIG_IGN); \&.\&.\&. .fi .if n \{\ .RE .\} .SH "SEE ALSO" .sp \fBupscli_list_start\fR(3), \fBupscli_list_next\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/socomec_jbus.txt0000644000200500020050000001344115001555412014157 00000000000000SOCOMEC_JBUS(8) =============== NAME ---- socomec_jbus - Driver for Socomec JBUS UPS with RS-232 serial Modbus connection. SYNOPSIS -------- *socomec_jbus* -h *socomec_jbus* -a 'DEVICE_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the socomec_jbus driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports Socomec JBUS series, online (double conversion) UPS with the following characteristics. 1. Single phase and 3-phase UPS 2. Connection: RS-232 These are typically provided with a Netvision WEB/SNMP management card / external box that would be better served by the linkman:snmp-ups[8] driver. In case netvision isn't available, you can hook up the UPS directly via the serial port and use this driver. Currently, it has only been tested on the following model. * DIGYS 3/3 15kVA In theory, any Socomec JBUS model should work. It should be discovered as ``Unknown Socomec JBUS'' with a numeric id that I'll need to add it to the list of supported UPSs. Sadly, Socomec document only mentions DELPHYS MX and DELPHYS MX elite and I have the id of my own DIGYS, so chances are, your model will not be recognized but will probably mostly work. Please report successful or unsuccessful results to the bug tracker or the mailing list. Make sure to include the full model number of your UPS manually in your report. socomec_jbus uses the libmodbus project, for Modbus implementation. CABLING ------- The UPS has an RS-232 port which should be connected with a NULL-modem cable to a PC serial port. The UPS tested has a female DB9 connector, so if you construct the cable yourself, make note of the connector type to avoid using gender changers. RS-232 is supported on all operating systems, either via a built-in serial port on your computer, or by using an external USB-to-RS-232 converter. If you plan to use an USB-to-RS-232 converter, make sure it's supported by your operating system. INSTALLATION ------------ This driver should be built by default if libmodbus and development headers are available. You can force the `configure` script to build it with the following arguments: :; ./configure --with-serial=yes --with-modbus=yes You also need to give proper (R/W) permissions on the local serial device file to allow the NUT driver run-time user to access it. This may need additional setup for start-up scripting, udev or upower rules, to apply the rights on every boot -- especially if your device nodes are tracked by a virtual filesystem. For example, a USB-to-serial converter can be identified as `/dev/ttyACM0` or `/dev/ttyUSB0` on Linux, or `/dev/ttyU0` on FreeBSD (note the capital "U"). A built-in serial port can be identified as `/dev/ttyS0` on Linux or one of `/dev/cua*` names on FreeBSD. INSTANT COMMANDS ---------------- This driver does not (yet?) support sending commands to the UPS. VARIABLES --------- This driver does not support writable runtime variables (see linkman:upsrw[8]): for the same reasons. Both should be trivial to implement, but since I've already found one or two inconsistencies in the documentation, I'm withholding from trying them. KNOWN ISSUES AND BUGS --------------------- Well, it is an alpha release at best, but so far appears to report the UPS status reliably. Mostly based on the work of Yifeng Li on the linkman:huawei-ups2000[8] in that very same source tree. Read failure on some JBUS addresses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The driver polls all documented JBUS addresses, and it is quite possible that your UPS model does not support one of them (e.g. the Digys does not support address '0x1020' which should provide the current UPS status). This should be logged with `LOG_ERR` from `modbus_read_input_registers()` along with the address that produced the error. Data stale ~~~~~~~~~~~ Under certain circumstances, some registers can return invalid values and trigger a "data stale" error. Once a data stale error has occurred, you should see error messages similar to the example below in the system log. socomec_jbus: modbus_read_input_registers(addr:XXXX, count:Z): Illegal data address upsd: Data for UPS [socomec] is stale - check driver upsd: UPS [socomec] data is no longer stale So far all known problems have been fixed by the author, but an unknown one cannot be ruled out. If you have encountered "data stale" problems during normal uses, please file a bug report with full logs attached. Before troubleshooting or reporting a problem, it's important to check your *dmesg* log for USB connect and disconnect events to avoid wasting time on the NUT driver when the actual problem is USB. For example, if someone yanks the cable out of the USB port, or if a new USB device is plugged into a USB host/hub that is struggling to power its ports (common on single-board computers like Raspberry Pi), or if you have flaky cabling or EMI noise, the serial converter can get disconnected from USB, at least briefly. This creates a permanent data stale, the driver must be restarted (plugging the USB back won't fix it, since the driver is still using the nonexistent serial device). These USB problems usually have nothing to do with NUT. If it's the case, you should solve the underlying USB problem -- check the cable, check the converter, try a powered USB hub, try a full-speed USB isolator, etc. AUTHOR ------ Thanos Chatziathanassiou SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * Socomec JBUS/Modbus Reference Guide: https://www.socomec.com/files/live/sites/systemsite/files/GB-JBUS-MODBUS-for-Delphys-MP-and-Delphys-MX-operating-manual.pdf * libmodbus home page: http://libmodbus.org nut-2.8.3/docs/man/upscli_sendline.30000644000200500020050000000520715001555053014211 00000000000000'\" t .\" Title: upscli_sendline .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_SENDLINE" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_sendline, upscli_sendline_timeout \- Send a single command to a UPS .SH "SYNOPSIS" .sp .nf #include #include /* or on some platforms */ int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen); int upscli_sendline_timeout(UPSCONN_t *ups, const char *buf, size_t buflen, const time_t timeout); .fi .SH "DESCRIPTION" .sp The \fBupscli_sendline()\fR and \fBupscli_sendline_timeout()\fR functions take the pointer \fIups\fR to a UPSCONN_t state structure and transmit a buffer \fIbuf\fR of size \fIbuflen\fR to the server\&. .sp The data in \fIbuf\fR must be a fully formatted protocol command as no parsing of the buffer occurs within this function\&. .sp The difference between the two functions is that \fBupscli_sendline_timeout()\fR lets the caller decide the amount of time (\fItimeout\fR seconds) after which it should give up and return, whereas \fBupscli_sendline()\fR does not offer this freedom, and uses an immediate timeout (0 second)\&. .SH "RETURN VALUE" .sp The \fBupscli_sendline()\fR and \fBupscli_sendline_timeout()\fR functions return \fI0\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_fd\fR(3), \fBupscli_get\fR(3), \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/isbmex.txt0000644000200500020050000000137115001555412012772 00000000000000ISBMEX(8) ========= NAME ---- isbmex - Driver for ISBMEX UPS equipment SYNOPSIS -------- *isbmex* -h *isbmex* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the isbmex driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports SOLA/BASIC Mexico ISBMEX protocol UPS equipment. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. AUTHOR ------ Edscott Wilson Garcia SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/sms_ser.txt0000644000200500020050000000173715001555412013164 00000000000000SMS_SER(8) ========== NAME ---- sms_ser - Driver for SMS UPS Protocol 1Phase. SYNOPSIS -------- *sms_ser* -h *sms_ser* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the sms_ser driver. For information about the core driver, see linkman:nutupsdrv[8], and for the technical background check the `docs/sms-brazil-protocol.txt` file in NUT sources. NOTE: Given the proximity of this protocol to Megatec Qx family, this driver may later become part of `nutdrv_qx` collection. SUPPORTED HARDWARE ------------------ sms_ser supports only the "sms 1phase" SMS Product, as described in the `monofasico.xml` file delivered with the device. Other SMS protocols (for their other products) are not supported by this driver. AUTHOR ------ Alex W. Baulé SEE ALSO -------- The core driver ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_cleanup.30000644000200500020050000000340315001555051014031 00000000000000'\" t .\" Title: upscli_cleanup .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_CLEANUP" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_cleanup \- Clean\-up upsclient module after usage\&. .SH "SYNOPSIS" .sp .nf #include int upscli_cleanup(void); .fi .SH "DESCRIPTION" .sp The \fBupscli_cleanup()\fR function flushes SSL caches and frees memory used internally in upsclient module\&. .SH "RETURN VALUE" .sp The \fBupscli_cleanup()\fR function returns \fI1\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_init\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/NUT-Monitor.80000644000200500020050000001307415001555047013135 00000000000000'\" t .\" Title: NUT-Monitor .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUT\-MONITOR" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" NUT-Monitor, NUT-Monitor-py2gtk2, NUT-Monitor-py3qt5 \- Python UI Client for NUT .SH "SYNOPSIS" .sp \fBNUT\-Monitor\-py2gtk2\fR .sp \fBNUT\-Monitor\-py3qt5\fR .sp [PREFER_PY2=true] [PYTHON2=python2\&.7] [PYTHON3=python3\&.14w] \fBNUT\-Monitor\fR .SH "DESCRIPTION" .sp These programs comprise the NUT\-Monitor Python UI Client for NUT with two similar implementations for major Python UI ecosystems still seen in practical deployments\&. For communications with a NUT data server, both rely on the \fIPyNUTClient\fR module (compatible with both Python 2\&.x and 3\&.x) provided by NUT sources that can be installed by your packaging as part of NUT; also releases of the module are published as a PyPI package\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NUT\-Monitor\-py2gtk2 is an implementation that relies on a Python 2\&.x interpreter (tested with 2\&.6 or 2\&.7 generation) and GTK2 UI library; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NUT\-Monitor\-py3qt5 is an implementation that relies on a Python 3\&.x interpreter and QT5 UI library; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} NUT\-Monitor is a shell script to pick at run\-time the best implementation\&. In older NUT releases, this was the file name used by the Python 2\&.x variant directly\&. .RE .sp Note that depending on your distribution\(cqs packaging choices, you may lack the NUT\-Monitor shell script and just have one set of the desktop window manager integration files directly for one particular implementation of the actual Python UI client\&. .sp For each individual run, the UI client can connect to a single NUT data server and a device on it\&. This can use either anonymous read\-only connections (like \fBupsc\fR(8)), or authenticated connections (see \fBupsd.users\fR(5)) which can also issue commands to the driver (like \fBupscmd\fR(8)) and set supported variables (like \fBupsrw\fR(8)) \(em propagated to the device, where applicable\&. .sp The Python UI client can be used on a system different from the NUT data server (the one connected to the actual UPS by communications media and running the NUT driver(s)), and may be using a different OS platform (including Windows)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Do not confuse this graphical NUT client with an unfortunately named nut\-monitor service in some packaged distributions, as the name of (or an alias to) the service wrapping the \fBupsmon\fR(8) client daemon for your system shutdown\&. .sp .5v .RE .SH "EXTRA ARGUMENTS" .sp These scripts do not support command\-line arguments, but the NUT\-Monitor shell script can be influence by environment variables PYTHON2 and/or PYTHON3 to provide the program name (or full path name) of your preferred version for the respective implementation of the Python interpreter\&. This program would be tried first when probing for available prerequisites\&. .sp The PREFER_PY2=true or PREFER_PY2=false environment variable value can be used to select the implementation of the client to use if both ecosystems are usable on the current system\&. .sp Note that the implementation for Python 2\&.x / GTK2 is slightly better regarding localization; functionally they should be equivalent\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} David Goncalves \(em original Python 2\&.x / GTK2 version of the script and the PyNUTClient module .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Luke Dashjr \(em conversion to Python 3\&.x / QT5 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Jim Klimov \(em wrapper script to choose one of the implementations, occasional fixes, PyPI packaging for the module .RE .SH "SEE ALSO" .sp \fBupsc\fR(8), \fBupscmd\fR(8), \fBupsrw\fR(8), \fBupsd.users\fR(5) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Releases of PyNUTClient module (packaged from NUT code base): https://pypi\&.org/project/pynutclient/ .RE nut-2.8.3/docs/man/nutclient_tcp_create_client.30000644000200500020050000000003415001555117016557 00000000000000.so man3/libnutclient_tcp.3 nut-2.8.3/docs/man/upscmd.txt0000644000200500020050000001017715001555412013002 00000000000000UPSCMD(8) ========= NAME ---- upscmd - Network UPS Tools device/driver instant commands administration tool SYNOPSIS -------- *upscmd* -h *upscmd* -l 'ups' *upscmd* [-u 'username'] [-p 'password'] [-w] [-t ] 'ups' 'command' DESCRIPTION ----------- *upscmd* allows you to invoke "instant commands" in your UPS hardware. It sends commands via the server linkman:upsd[8] to your driver, which manages the hardware for you. You must use credentials defined in linkman:upsd.users[5] file on that data server with appropriate permissions. Not all hardware supports this, so check the list with -l to see if anything will work on your equipment. On hardware that supports it, you can use this program to start and stop battery tests, invoke a front panel test (beep!), turn the load on or off, and more. OPTIONS ------- *-l* 'ups':: Show the list of supported instant commands on that UPS. Some hardware may not support any of them. *-u* 'username':: Set the username for the connection to the server. This is optional, and you will be prompted for this when invoking a command if -u is not used. *-p* 'password':: Set the password to authenticate to the server. This is also optional like -u, and you will be prompted for it if necessary. *-w*:: Wait for the completion of command execution by the driver and return its actual result from the device. Note that this feature requires that both linkman:upsd[8] and the driver support TRACKING (NUT version 2.8.0 or higher), or it will otherwise fail. + The command will also block until an actual result is provided from the driver, or the timeout is reached (see *-t*). *-t* 'seconds':: Set a timeout when using *-w*. Defaults to 10 seconds. 'ups':: Connect to this UPS. The format is `upsname[@hostname[:port]]`. The default hostname is "localhost". COMMON OPTIONS -------------- *-h*:: Show the command-line help message. *-V*:: Show NUT version banner. More details may be available if you also `export NUT_DEBUG_LEVEL=1` or greater verbosity level. *-W* 'secs':: Set the timeout for initial network connections (by default they are indefinitely non-blocking, or until the system interrupts the attempt). Overrides the optional `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable. UNATTENDED MODE --------------- If you run this program inside a shell script or similar to invoke a command, you will need to specify all of the information on the command line. This means using -u and -p. Otherwise it will put up a prompt and your program will hang. This is not necessary when displaying the list, as the username and password are not required for read-only mode. Moreover, if you run this program inside a shell script or similar, you should only consider using output from stdout, not stderr. DANGEROUS COMMANDS ------------------ Some drivers like linkman:apcsmart[8] have built-in paranoia for the dangerous commands like `load.off`. To make them actually turn off the load, you will have to send the command twice within a short window. That is, you will have to send it once, then send it again after 3 seconds elapse but before 15 seconds pass. This paranoia is entirely defined within the driver. upsd and upscmd have no control over the timing. DIAGNOSTICS ----------- *upscmd* won't work unless you provide a valid username and password. If you get "access denied" errors, make sure that your linkman:upsd.users[5] has an entry for you, and that the username you are using has permissions to SET variables. *upscmd* without '-w' would somewhat confusingly show "OK" meaning just that the data server connection was established, and the server did not immediately reject the request due to e.g. unknown instant command name. If you care to know the actual results, do use the `-w (-t NUM)` option(s) to wait for them. BUGS ---- There is currently no way to tell the user when the driver requires confirmation to invoke a command such as `load.off`. This is on the list of things to fix in the future, so don't despair. It involves magic cookies. SEE ALSO -------- linkman:upsd[8], linkman:upsrw[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_add_host_cert.txt0000644000200500020050000000212015001555412015655 00000000000000UPSCLI_ADD_HOST_CERT(3) ======================= NAME ---- upscli_add_host_cert - Register a security rule for an host. SYNOPSIS -------- ------ #include void upscli_add_host_cert( const char* hostname, const char* certname, int certverify, int forcessl); ------ DESCRIPTION ----------- The *upscli_add_host_cert()* function registers a security rule associated to the 'hostname'. All connections to this host use this rule. The rule is composed of the certificate name 'certname' expected for the host, 'certverify' if the certificate must be validated for the host and 'forcessl' if a secured connection must be used to connect to the host. Note: This call only functions if upsclient has been compiled with NSS support. If instead it was compiled with OpenSSL support, this function contains an empty definition and will take no action when called. RETURN VALUE ------------ *upscli_add_host_cert()* returns no value. SEE ALSO -------- linkman:upscli_init[3], linkman:upscli_connect[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/upsd.txt0000644000200500020050000001660315001555412012462 00000000000000UPSD(8) ======= NAME ---- upsd - Network UPS Tools data server SYNOPSIS -------- *upsd* -h *upsd* ['OPTIONS'] DESCRIPTION ----------- *upsd* is responsible for serving the data from the drivers to the clients. It connects to each driver and maintains a local cache of the current state. Queries from the clients are served from this cache, so delays are minimal. It also conveys administrative messages from the clients back to the drivers, such as starting tests, or setting values. Communication between *upsd* and clients is handled on a TCP port. Configuration details for this port are described in linkman:upsd.conf[8]. This program is essential, and must be running at all times to actually make any use out of the drivers and clients (except for final UPS power-off commands just before your server goes down, which NUT driver programs can do alone when called as `drivername -k` in a shutdown hook or late ordered SysV init script). Controls in the configuration files allow you to limit access to the server, but you should also use a firewall for extra protection. Client processes such as linkman:upsmon[8] trust *upsd* for status information about the UPS hardware, so keep it secure. OPTIONS ------- *-c* 'command':: Send 'command' to the background process as a signal. Valid commands are: *reload*;; reread configuration files *stop*;; stop process and exit *-P* 'pid':: Send the command signal above using specified PID number, rather than consulting the PID file. This can help define service units which start `upsd` as a foreground process so it does not create a PID file. See also `-FF` option as an alternative. *-D*:: Raise the debugging level. upsd will run in the foreground by default, and will print information on stdout about the monitoring process. Use this option multiple times for more details. *-F*:: upsd will run in the foreground, regardless of debugging settings. Specify twice (`-FF` or `-F -F`) to save the PID file even in this mode. *-B*:: upsd will run in the background, regardless of debugging settings. *-h*:: Display the help text. *-r* 'directory':: upsd will linkmanext:chroot[2] to 'directory' shortly after startup and before parsing any configuration files with this option set. You can use this to create a "jail" for greater security. + You must coordinate this with your drivers, as upsd must be able to find the state path within 'directory'. See linkman:upsdrvctl[8] and linkman:nutupsdrv[8]. *-u* 'user':: Switch to user 'user' after startup if started as root. This overrides whatever you may have compiled in with `configure --with-user`. *-V*:: Display the version of the program. RELOADING --------- upsd can reload its configuration files without shutting down the process if you send it a SIGHUP or start it again with `-c reload`. This only works if the background process is able to read those files (permissions, `chroot` jail), and if the daemon did save a PID file when it started (for the `reload` command to find the older instance). [NOTE] ====== Service instances wrapped by systemd or SMF might not save them by default -- use respective `reload`/`refresh` framework actions instead then), e.g. `systemctl reload nut-server` NUT releases after 2.8.0 define aliases for these units, so if your Linux distribution uses NUT-provided unit definitions, `systemctl reload upsd` may also work. ====== If you think that `upsd` can't reload, check your syslog for error messages. If it's complaining about not being able to read the files, then you need to adjust your system to make it possible. Either change the permissions on the files, or run `upsd` as another user that will be able to read them, or restart it fully (may be needed e.g. if running in a `chroot` jail). DO NOT make your linkman:upsd.conf[5] or linkman:upsd.users[5] files world-readable, as they hold important authentication information. In the wrong hands, it could be used by some evil person to spoof your primary-mode `upsmon` and command your systems to shut down, for example. DIAGNOSTICS ----------- upsd expects the drivers to either update their status regularly or at least answer periodic queries, called pings. If a driver doesn't answer, upsd will declare it "stale" and no more information will be provided to the clients. If upsd complains about staleness when you start it, then either your driver or configuration files are probably broken. Be sure that the driver is actually running, and that the UPS definition in linkman:ups.conf[5] is correct. Also make sure that you start your driver(s) before starting upsd. Data can also be marked stale if the driver can no longer communicate with the UPS. In this case, the driver should also provide diagnostic information in the syslog. If this happens, check the serial or USB cabling, or inspect the network path in the case of a SNMP UPS. ACCESS CONTROL -------------- If the server is build with tcp-wrappers support enabled, it will check if the NUT username is allowed to connect from the client address through the `/etc/hosts.allow` and `/etc/hosts.deny` files. Note that this will only be done for commands that require to be logged into the server. Further details are described in linkmanext:hosts_access[5]. FILES ----- The general `upsd` configuration file is linkman:upsd.conf[5]. The administrative functions like `SET` and `INSTCMD` for users, and various `upsmon` roles, are defined and controlled in linkman:upsd.users[5]. UPS definitions are found in linkman:ups.conf[5] (shared with actual drivers). ENVIRONMENT VARIABLES --------------------- *NUT_DEBUG_LEVEL* sets default debug verbosity if no *-D* arguments were provided on command line, but does not request that the daemon runs in foreground mode. *NUT_CONFPATH* is the path name of the directory that contains `upsd.conf` and other configuration files. If this variable is not set, *upsd* uses a built-in default, which is often `/usr/local/ups/etc`. *NUT_STATEPATH* is the path name of the directory in which *upsd* keeps state information. If this variable is not set, *upsd* uses a built-in default, which is often `/var/state/ups`. The *STATEPATH* directive in linkman:upsd.conf[5] overrides this variable. *NUT_ALTPIDPATH* is the path name of the directory in which *upsd* and drivers store .pid files. If this variable is not set, *upsd* and drivers use either *NUT_STATEPATH* if set, or ALTPIDPATH if set, or otherwise the built-in default *STATEPATH*. *NUT_QUIET_INIT_UPSNOTIFY=true* can be used to prevent daemons which can notify service management frameworks (such as systemd) about passing their lifecycle milestones from emitting such notifications (including those about lack of system support for such modern features, once per run). *NUT_QUIET_INIT_BANNER=true* can be used to suppress NUT tool name and version banner. NOT recommended for services due to adverse troubleshooting impact, but may be helpful in shell profiles or scripts which process NUT tool outputs. SEE ALSO -------- Clients: ~~~~~~~~ - linkman:upsc[8] - linkman:upscmd[8] - linkman:upsrw[8] - linkman:upslog[8] - linkman:upsmon[8] CGI programs: ~~~~~~~~~~~~~ - linkman:upsset.cgi[8] - linkman:upsstats.cgi[8] - linkman:upsimage.cgi[8] Driver control: ~~~~~~~~~~~~~~~ include::{builddir}linkman-drivertool-names.txt[] Drivers: ~~~~~~~~ - linkman:nutupsdrv[8] include::{builddir}linkman-driver-names.txt[] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_display_ups_conf_with_sanity_check.txt0000644000200500020050000000226715001555412022363 00000000000000NUTSCAN_DISPLAY_UPS_CONF_WITH_SANITY_CHECK(3) ============================================= NAME ---- nutscan_display_ups_conf_with_sanity_check - Display the specified `nutscan_device_t` structure and sanity-check warnings on stdout. SYNOPSIS -------- ------ #include void nutscan_display_ups_conf_with_sanity_check(nutscan_device_t * device); ------ DESCRIPTION ----------- The *nutscan_display_ups_conf_with_sanity_check()* function displays all NUT devices in 'device' to `stdout`, and follows up with comments about sanity-check violations (if any). It displays them in a way that it can be directly copied into the `ups.conf` file. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/nutdrv_qx.80000644000200500020050000014555415001555101013074 00000000000000'\" t .\" Title: nutdrv_qx .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTDRV_QX" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutdrv_qx \- Driver for Q* protocol serial and USB based UPS equipment .SH "SYNOPSIS" .sp \fBnutdrv_qx\fR \-h .sp \fBnutdrv_qx\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBnutdrv_qx\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The protocol originates from Mega System Technologies, Inc\&. in Taiwan and was used by numerous vendors, as well as evolved over time, growing both in features and nuance incompatibilities\&. NUT documentation usually refers to this large family of similar dialects as the \fIMegatec Q*\fR or \fIMegatec Qx\fR protocol family\&. .sp The \fBnutdrv_qx\fR driver is known to work with various UPSes from \fIArmac\fR, \fIBlazer\fR, \fIEnergy Sistem\fR, \fIFenton Technologies\fR, \fIGeneral Electric\fR, \fIGtec\fR, \fIHunnox\fR, \fIMasterguard\fR, \fIMustek\fR, \fIPowercool\fR, \fIVoltronic Power\fR, \fISKE\fR (rebranded by many, many \(em have I said many? \(em others\&... .sp Long story short: if your UPS came with a software called \fIViewpower\fR, chances are high that it works with this driver with one of the \fIvoltronic*\fR protocols or with the \fImecer\fR one), and many others\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Due to historical reasons, two important tunables of this driver are somewhat inconveniently named \fBprotocol\fR (for the Qx dialect) and \fBsubdriver\fR (for USB to serial link conversion)\&. Other multi\-dialect drivers refer to their dialect modules as \fBsubdrivers\fR, and actually the modular source code of nutdrv_qx also does\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Due to the amount of supported Qx dialects, and the time it takes to query for relevant combinations of commands and wait for a reply or absence thereof, in order to detect hardware/firmware support of some particular way for the driver to communicate with the device, automatic nutdrv_qx driver initialization may take about a minute\&. It is recommended to store the detected and reported protocol and/or subdriver values into your \fBups.conf\fR(5) file to speed up later driver start\-ups and avoid possible service timeouts\&. .sp .5v .RE .sp The NUT compatibility table lists all the known supported models\&. Keep in mind, however, that other models not listed there may also be supported, but haven\(cqt been tested or reported back\&. .sp All devices with a serial interface and many with a USB interface are supported\&. .SH "EXTRA ARGUMENTS" .sp You may need to override or provide defaults for some values, depending on the make and model of your UPS\&. .sp The following are the ones that most likely will need changing (see \fBups.conf\fR(5)): .PP \fBondelay =\fR \fIvalue\fR .RS 4 Time to wait before switching on the UPS (seconds)\&. This value is truncated to units of 60 seconds\&. .sp Note that a value below 3 minutes, may cause earlier firmware versions to not switch on automatically, so it defaults to 3 minutes (i\&.e\&. 180 seconds)\&. .sp This option provides a default value for \fBups\&.delay\&.start\fR that will then be used by the driver in the automatic shutdown sequence (i\&.e\&. calling the driver with the \fB\-k\fR option, calling \fBupsdrvctl\fR(8) with the \fBshutdown\fR option or when the FSD flag is set and \fBupsmon\fR(8) enters its shutdown sequence): however you can change this value \(oqon the fly\(cq for the actual session, only for the use with instant commands, setting \fBups\&.delay\&.start\fR with \fBupsrw\fR(8)\&. .RE .PP \fBoffdelay =\fR \fIvalue\fR .RS 4 Time to wait before shutting down the UPS (seconds)\&. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds)\&. Defaults to 30 seconds\&. .sp This option provides a default value for \fBups\&.delay\&.shutdown\fR that will then be used by the driver in the automatic shutdown sequence (i\&.e\&. calling the driver with the \fB\-k\fR option, calling \fBupsdrvctl\fR(8) with the \fBshutdown\fR option or when the FSD flag is set and \fBupsmon\fR(8) enters its shutdown sequence): however you can change this value "on the fly" for the actual session, only for the use with instant commands, setting \fBups\&.delay\&.shutdown\fR with \fBupsrw\fR(8)\&. .RE .PP \fBstayoff\fR .RS 4 If you set stayoff in \fBups.conf\fR(5) when FSD arises the UPS will call a \fBshutdown\&.stayoff\fR shutting down after \fBups\&.delay\&.shutdown\fR seconds and won\(cqt return (see KNOWN PROBLEMS), otherwise (standard behaviour) the UPS will call \fBshutdown\&.return\fR shutting down after \fBups\&.delay\&.shutdown\fR seconds and then turn on after \fBups\&.delay\&.start\fR seconds (if mains meanwhile returned)\&. .RE .PP \fBprotocol =\fR \fIstring\fR .RS 4 Skip autodetection of the protocol to use and only use the one specified\&. Supported values: \fIbestups\fR, \fIgtec\fR, \fIhunnox\fR, \fIinnovart31\fR, \fImasterguard\fR, \fImecer\fR, \fImegatec\fR, \fImegatec/old\fR, \fImustek\fR, \fIq1\fR, \fIq2\fR, \fIq6\fR, \fIvoltronic\fR, \fIvoltronic\-qs\fR, \fIvoltronic\-qs\-hex\fR and \fIzinto\fR\&. .sp Run the driver program with the \-\-help option to see the exact list of protocol values it would currently recognize\&. .sp Note that if you end up using the \fIq1\fR protocol, you may want to give a try to the \fImecer\fR, \fImegatec\fR and \fIzinto\fR ones setting the \fBnovendor\fR/\fBnorating\fR flags (only one, or both)\&. .RE .PP \fBpollfreq =\fR \fInum\fR .RS 4 Set polling interval for full updates, in seconds, to reduce the message traffic\&. Between two polling requests, the driver will do \fIquick polls\fR dealing just with \fBups\&.status\fR at an interval specified by the \fBpollinterval\fR driver option (details in \fBups.conf\fR(5))\&. The default value is 30 (in seconds)\&. .RE .sp If your UPS doesn\(cqt report either \fBbattery\&.charge\fR or \fBbattery\&.runtime\fR you may want to add the following ones in order to have guesstimated values: .PP \fBdefault\&.battery\&.voltage\&.high =\fR \fIvalue\fR .RS 4 Maximum battery voltage that is reached after about 12 to 24 hours charging\&. If you want the driver to report a guesstimated \fBbattery\&.charge\fR, you need to specify this (see BATTERY CHARGE GUESSTIMATION)\&. .RE .PP \fBdefault\&.battery\&.voltage\&.low =\fR \fIvalue\fR .RS 4 Minimum battery voltage just before the UPS automatically shuts down\&. If you want the driver to report a guesstimated \fBbattery\&.charge\fR, you need to specify this (see BATTERY CHARGE GUESSTIMATION)\&. .RE .PP \fBdefault\&.battery\&.voltage\&.nominal =\fR \fIvalue\fR, \fBoverride\&.battery\&.voltage\&.nominal =\fR \fIvalue\fR .RS 4 Some devices show a wrong nominal battery voltage (or none at all), so you may need to override or set a default value\&. .RE .PP \fBoverride\&.battery\&.packs =\fR \fIvalue\fR .RS 4 Some devices "natively" report just a part of the total battery voltage (see also \fBbattery_voltage_reports_one_pack\fR below)\&. .sp For instance, if \fBbattery\&.voltage\&.nominal\fR is 24 V, but it reports a \fBbattery\&.voltage\fR of around 2 V, the number of \fBbattery\&.packs\fR to correct this reading would be 12\&. .sp The driver will attempt to detect this number automatically, but if this fails somehow, you may want to override this value\&. .sp Note that this is primarily useful for "guesstimation" of battery\&.charge and/or battery\&.runtime (with runtimecal setting), if those readings are not provided by the device directly\&. .RE .PP \fBbattery_voltage_reports_one_pack\fR .RS 4 Some devices "natively" report just report a part of the total battery voltage (see also \fBoverride\&.battery\&.packs\fR above, if that value is not reported by the device or properly guessed by the driver otherwise)\&. .sp If this flag is set, most of the subdrivers (except those which know about more complicated device\-specific nuances, currently: \fBablerex\fR, \fBmasterguard\fR and \fBvoltronic\-qs\-hex\fR) adjust their ultimately reported \fBbattery\&.voltage\fR value as a multiple of \fBbattery\&.packs\fR and "native" \fBbattery\&.voltage\fR)\&. .sp Note this is primarily useful for consistent diagnostics and graphing of the numbers, and should not impact the "guesstimation" of battery\&.charge and/or battery\&.runtime \(em so rather a cosmetic adjustment, than critical\&. .RE .PP \fBruntimecal =\fR \fIvalue,value,value,value\fR .RS 4 Parameter used in the (optional) runtime estimation\&. This takes two runtimes at different loads\&. Typically, this uses the runtime at full load and the runtime at half load\&. For instance, if your UPS has a rated runtime of 240 seconds at full load and 720 seconds at half load, you would enter .sp .if n \{\ .RS 4 .\} .nf runtimecal = 240,100,720,50 .fi .if n \{\ .RE .\} .sp The first load should always be higher than the second\&. If you have values available for loads other than 100 and 50 % respectively, you can use those too, but keep them spaced apart as far as reasonably possible\&. Just don\(cqt get too close to no load (prediction of runtime depends more on idle load for the battery then)\&. .RE .PP \fBchargetime =\fR \fIvalue\fR .RS 4 The time needed to fully recharge the battery after being fully discharged\&. If not specified, the driver defaults to 43200 seconds (12 hours)\&. Only used if \fBruntimecal\fR is also specified\&. .RE .PP \fBidleload =\fR \fIvalue\fR .RS 4 Minimum battery load used by the driver to estimate the runtime\&. If not specified, the driver defaults to 10%\&. Only used if \fBruntimecal\fR is also specified\&. .RE .SS "BESTUPS, INNOVART31, MECER, MEGATEC, MEGATEC/OLD, MUSTEK, Q1, Q2, Q6, VOLTRONIC\-QS, VOLTRONIC\-QS\-HEX, ZINTO PROTOCOLS" .PP \fBignoresab\fR .RS 4 Some UPSes incorrectly report the \(oqShutdown Active\(cq bit as always on, consequently making the driver believe the UPS is nearing a shutdown (and, as a result, ups\&.status always contains FSD\&... and you know what this means)\&. Setting this flag will make the driver ignore the \(oqShutdown Active\(cq bit\&. .RE .SS "MECER, MEGATEC, MEGATEC/OLD, MUSTEK, ZINTO PROTOCOLS" .PP \fBondelay\fR .RS 4 The acceptable range is 0\&.\&.599940 seconds\&. .RE .PP \fBoffdelay\fR .RS 4 The acceptable range is 12\&.\&.600 seconds\&. .RE .PP \fBnorating\fR .RS 4 Some UPSes will lock up if you attempt to read rating information from them\&. Setting this flag will make the driver skip this step\&. .RE .PP \fBnovendor\fR .RS 4 Some UPSes will lock up if you attempt to read vendor information from them\&. Setting this flag will make the driver skip this step\&. .RE .SS "BESTUPS PROTOCOL" .PP \fBondelay\fR .RS 4 The acceptable range is 60\&.\&.599940 seconds\&. .RE .PP \fBoffdelay\fR .RS 4 The acceptable range is 12\&.\&.5940 seconds\&. .RE .PP \fBpins_shutdown_mode =\fR \fIvalue\fR .RS 4 Set shutdown mode functionality of Pin 1 and Pin 7 on the UPS DB9 communication port (Per Best Power\(cqs EPS\-0059) to \fIvalue\fR [0\&.\&.6]\&. .RE .SS "MASTERGUARD PROTOCOL" .PP \fBslave_addr =\fR \fIvalue\fR .RS 4 Make the claim function verify it\(cqs talking to the specified \fIslave address\fR (\fBups\&.id\fR)\&. Safeguard against talking to the wrong one of several identical UPSes on the same USB bus\&. Note that when changing \fBups\&.id\fR (through \fBupsrw\fR(8)) the driver will continue to talk to the UPS with the new \fIslave address\fR, but won\(cqt claim it again on restart until the \fBslave_addr\fR parameter is adjusted\&. .RE .SS "INNOVART31, Q1, Q2, Q6 PROTOCOLS" .PP \fBondelay\fR .RS 4 The acceptable range is 0\&.\&.599940 seconds\&. .RE .PP \fBoffdelay\fR .RS 4 The acceptable range is 12\&.\&.600 seconds\&. .RE .SS "Q2, Q6 PROTOCOLS" .PP \fBnooutstats\fR .RS 4 Some UPSes don\(cqt support WA command which returns output load stats\&. Using this flag will make the driver ignore these requests\&. .RE .SS "VOLTRONIC\-QS, VOLTRONIC\-QS\-HEX PROTOCOLS" .PP \fBondelay\fR .RS 4 The acceptable range is 60\&.\&.599940 seconds\&. .RE .PP \fBoffdelay\fR .RS 4 The acceptable range is 12\&.\&.540 seconds\&. .RE .SS "VOLTRONIC PROTOCOL" .sp The following options are supported only by the \fIvoltronic\fR protocol\&. Not all of them are available on all the UPSes supported by this protocol\&. .PP \fBondelay\fR .RS 4 The acceptable range is 0\&.\&.599940 seconds\&. .RE .PP \fBoffdelay\fR .RS 4 The acceptable range is 12\&.\&.5940 seconds\&. .RE .PP \fBbattery_number =\fR \fIvalue\fR .RS 4 Set number of batteries that make a pack to \fIvalue\fR [1\&.\&.9]\&. This setting will change the charge and runtime estimation reported by the UPS\&. .RE .PP \fBoutput_phase_angle =\fR \fIvalue\fR .RS 4 Changes output phase angle to the provided value [000, 120, 180, 240]\(de\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBUPS CAPABILITY SETTINGS\fR .RS 4 .PP \fBreset_to_default\fR .RS 4 Reset capability options and their voltage and frequency limits to safe default values\&. (\fBDoable only when the UPS is in Standby Mode\fR) .sp Note that setting this option will reset also \fBups\&.start\&.auto\fR, \fBbattery\&.protection\fR, \fBbattery\&.energysave\fR, \fBups\&.start\&.battery\fR, \fBoutlet\&.0\&.switchable\fR, \fBinput\&.transfer\&.high\fR, \fBinput\&.transfer\&.low\fR, \fBinput\&.frequency\&.high\fR and \fBinput\&.frequency\&.low\fR\&. .RE .sp These UPSes can be fine\-tuned to suit your needs enabling or disabling the following options (the driver should tell you which one the UPS is capable of on startup: the settable ones will be reported either are \fIenabled\fR or \fIdisabled\fR in the logs): .PP \fBalarm_control =\fR \fIstring\fR .RS 4 Enable or disable alarm (BEEP!) [enabled/disabled]\&. Settable also \(oqon the fly\(cq with \fBbeeper\&.enable\fR and \fBbeeper\&.disable\fR instant commands\&. .RE .PP \fBbypass_alarm =\fR \fIstring\fR .RS 4 Enable or disable alarm (BEEP!) at Bypass Mode [enabled/disabled]\&. .RE .PP \fBbattery_alarm =\fR \fIstring\fR .RS 4 Enable or disable alarm (BEEP!) at Battery Mode [enabled/disabled]\&. .RE .PP \fBbypass_when_off =\fR \fIstring\fR .RS 4 Enable or disable bypass when the UPS is Off [enabled/disabled]\&. If enabled, AC will directly provide power to connected devices when the UPS is off\&. .RE .PP \fBbypass_forbidding =\fR \fIstring\fR .RS 4 Enable or disable Bypass Forbidding [enabled/disabled]\&. If enabled, the UPS will not transfer to bypass mode under any condition\&. .RE .PP \fBconverter_mode =\fR \fIstring\fR .RS 4 Enable or disable Converter Mode [enabled/disabled]\&. When input frequency is within 40 Hz to 70 Hz, the UPS can be set at a constant output frequency, 50 Hz or 60 Hz\&. The UPS will still charge battery under this mode\&. .RE .PP \fBeco_mode =\fR \fIstring\fR .RS 4 Enable or disable ECO Mode [enabled/disabled]\&. When input voltage/frequency are within acceptable range, the UPS will bypass voltage to output for energy saving\&. PFC and INVERTER are still active at this mode\&. Settable also \(oqon the fly\(cq with \fBbypass\&.start\fR and \fBbypass\&.stop\fR instant commands\&. .RE .PP \fBadvanced_eco_mode =\fR \fIstring\fR .RS 4 Enable or disable Advanced ECO Mode [enabled/disabled]\&. When input voltage/frequency are within acceptable range, the UPS will bypass voltage to output for energy saving\&. PFC and INVERTER are off at this mode\&. .RE .PP \fBbattery_open_status_check =\fR \fIstring\fR .RS 4 Enable or disable Battery Open Status Check [enabled/disabled]\&. If enabled, when the UPS is turned on, it will check if the battery is connected or not\&. .RE .PP \fBsite_fault_detection =\fR \fIstring\fR .RS 4 Enable or disable site fault detection [enabled/disabled]\&. If enabled, the UPS will beep when the input neutral and hot wires are reversed\&. .RE .PP \fBconstant_phase_angle =\fR \fIstring\fR .RS 4 Enable or disable Constant Phase Angle Function (output and input phase angles are not equal) [enabled/disabled]\&. .RE .PP \fBlimited_runtime_on_battery =\fR \fIstring\fR .RS 4 Enable or disable limited runtime on battery mode [enabled/disabled]\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBBYPASS MODE VOLTAGE/FREQUENCY LIMITS\fR .RS 4 .sp Variables to fine\-tune voltage and frequency limits for Bypass mode\&. These limits are reset to safe default values by \fBreset_to_default\fR\&. .sp If AC voltage and frequency are within acceptable range, Bypass mode will be used (If the UPS is capable of and it\(cqs enabled)\&. .sp Since these values are device\-specific, if your UPS support them, you will get their settable limits printed in the logs on startup\&. .PP \fBmax_bypass_volt =\fR \fIvalue\fR .RS 4 Maximum voltage for Bypass Mode (V)\&. .RE .PP \fBmin_bypass_volt =\fR \fIvalue\fR .RS 4 Minimum voltage for Bypass Mode (V)\&. .RE .PP \fBmax_bypass_freq =\fR \fIvalue\fR .RS 4 Maximum frequency for Bypass Mode (Hz)\&. .RE .PP \fBmin_bypass_freq =\fR \fIvalue\fR .RS 4 Minimum frequency for Bypass Mode (Hz)\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBOPTIONS SPECIFIC FOR P31 UPSES\fR .RS 4 .sp The following options are available only on P31 UPSes\&. .PP \fBwork_range_type =\fR \fIstring\fR .RS 4 Device grid working range for P31 UPSes [Appliance/UPS]\&. .RE .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBTESTING\fR .RS 4 .sp This protocol comes with a couple of functions that are not enabled by default because of the lack of knowledge of some part of the communication protocol used by these UPSes by your friendly neighborhood developer\&. Since these functions are supposed to be queries to the UPS for some kind of information, they \fIshould\fR not make your UPS go boom\&. So if you are brave enough to risk your UPS and attached devices\*(Aq life to help the developers, this will be very appreciated\&. \fBDo it at your own risk\fR\&. .PP \fBtesting\fR .RS 4 If invoked the driver will exec also commands that still need testing\&. .RE .RE .SS "SERIAL INTERFACE ONLY" .PP \fBcablepower =\fR \fIstring\fR .RS 4 By default the driver will set DTR and clear RTS (\fInormal\fR)\&. If you find that your UPS isn\(cqt detected or the communication with the UPS is unreliable, you may try if clear DTR and set RTS (\fIreverse\fR), set DTR and RTS (\fIboth\fR) or clear DTR and RTS (\fInone\fR) improves this situation\&. .RE .SS "USB INTERFACE ONLY" .PP \fBport =\fR \fIstring\fR .RS 4 Some \fIvalue\fR must be set, typically \fBauto\fR\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This could be a device filesystem path like /dev/usb/hiddev0 but current use of libusb API precludes knowing and matching by such identifiers\&. They may also be inherently unreliable (dependent on re\-plugging and enumeration order)\&. At this time the actual \fIvalue\fR is ignored, but syntactically some \fIport\fR configuration must still be there\&. .sp .5v .RE .RE .sp It is possible to control multiple UPS units simultaneously by running several instances of this driver, provided they can be uniquely distinguished by setting some combination of the \fBvendor\fR, \fBproduct\fR, \fBvendorid\fR, \fBproductid\fR, \fBserial\fR, \fBbus\fR and/or \fBdevice\fR options detailed below\&. For devices or operating systems that do not provide sufficient information, the \fBallow_duplicates\fR option can be of use (limited and risky!) .PP \fBvendorid =\fR \fIregex\fR, \fBproductid =\fR \fIregex\fR, \fBvendor =\fR \fIregex\fR, \fBproduct =\fR \fIregex\fR, \fBserial =\fR \fIregex\fR .RS 4 Select a specific UPS, in case there is more than one connected via USB\&. Each option specifies an extended regular expression (see \fBregex\fR(7) for more information on regular expressions), which must match the UPS\(cqs entire respective vendor/product/serial string values (minus any surrounding whitespace), or the whole 4\-digit hexadecimal code for vendorid and productid\&. .sp Try \fBlsusb\fR(8) or running this NUT driver with \-DD command\-line argument for finding out the strings to match\&. .sp Examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendor="Foo\&.Corporation\&.*" .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendorid="051d*" (APC) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x product="\&.*(Smart|Back)\-?UPS\&.*" .RE .RE .PP \fBbus =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB bus or group of buses\&. The argument is a regular expression that must match the bus name where the UPS is connected (e\&.g\&. bus="002" or bus="00[2\-3]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .RE .PP \fBdevice =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB device or group of devices\&. The argument is a regular expression that must match the device name where the UPS is connected (e\&.g\&. device="001" or device="00[1\-2]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br device numbers are not guaranteed by the OS to be stable across re\-boots or device re\-plugging\&. .sp .5v .RE .RE .PP \fBbusport =\fR \fIregex\fR .RS 4 If supported by the hardware, OS and libusb on the particular deployment, this option should allow to specify physical port numbers on an USB hub, rather than logical device enumeration values, and in turn \(em this should be less volatile across reboots or re\-plugging\&. The value may be seen in the USB topology output of lsusb \-tv on systems with that tool, for example\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br this option is not practically supported by some NUT builds (it should be ignored with a warning then), and not by all systems that NUT can run on\&. .sp .5v .RE .RE .PP \fBallow_duplicates\fR .RS 4 If you have several UPS devices which may not be uniquely identified by the options above (e\&.g\&. only \fIVID:PID\fR can be discovered there), this flag allows each driver instance where it is set to take the first match if available, or proceed to try another\&. .sp Normally the driver initialization would abort at this point claiming "Resource busy" or similar error, assuming that the otherwise properly matched device is unique \(em and some other process already handles it\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This feature is inherently non\-deterministic! The association of driver instance name to actual device may vary between runs! .sp If you only care to know that \fBat least\fR one of your no\-name UPSes is online, this option can help\&. .sp If you must really know \fBwhich\fR one, it will not! .sp .5v .RE .RE .PP \fBusb_set_altinterface =\fR \fIbAlternateSetting\fR .RS 4 Force redundant call to usb_set_altinterface(), especially if needed for devices serving multiple USB roles where the UPS is not represented by the interface number 0 (default)\&. .RE .PP \fBusb_config_index\fR, \fBusb_hid_rep_index\fR, \fBusb_hid_desc_index\fR, \fBusb_hid_ep_in\fR, \fBusb_hid_ep_out\fR .RS 4 Force use of specific interface, endpoint, descriptor index etc\&. numbers, rather than defaulting to \fI0\fR (rarely other values in certain drivers for some devices known to use non\-zero numbers)\&. Specified as a hexadecimal number\&. .sp As a rule of thumb for usb_hid_desc_index discovery, you can see larger wDescriptorLength values (roughly 600+ bytes) in reports of lsusb or similar tools\&. .RE .PP \fBLIBUSB_DEBUG =\fR \fIINTEGER\fR .RS 4 Run\-time troubleshooting of USB\-capable NUT drivers can involve not only raising the common NUT debug verbosity (e\&.g\&. using the DEBUG_MIN setting in \fBups.conf\fR(5) or protocol commands to change the driver\&.debug value), but may also benefit from LibUSB specific debugging\&. .sp For the latter, you can set the LIBUSB_DEBUG driver option; alternatively you can classically export the environment variable LIBUSB_DEBUG before starting a NUT driver program (may be set and "exported" in driver init script or service method, perhaps via \fBnut.conf\fR(5)), to a numeric value such as 4 ("All messages are emitted")\&. .sp For more details, including the currently supported values for your version of the library, see e\&.g\&.: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/group__libusb__lib\&.html .RE .RE .PP \fBsubdriver =\fR \fIstring\fR .RS 4 Select a serial\-over\-USB subdriver to use\&. You have a choice between \fBablerex\fR, \fBarmac\fR, \fBcypress\fR, \fBfabula\fR, \fBfuji\fR, \fBgtec\fR, \fBhunnox\fR, \fBippon\fR, \fBkrauler\fR, \fBphoenix\fR, \fBphoenixtec\fR, \fBsgs\fR and \fBsnr\fR\&. .sp Run the driver program with the \-\-help option to see the exact list of subdriver values it would currently recognize\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br When using this option, it is mandatory to also specify the \fBvendorid\fR and \fBproductid\fR matching parameters\&. .sp .5v .RE .RE .PP \fBlangid_fix =\fR \fIvalue\fR .RS 4 Apply the language ID workaround to the \fBkrauler\fR subdriver\&. This is mandatory for some devices to work (LDLC, Dynamix and others)\&. You must provide \fBvalue\fR (0x409 or 0x4095), according to your device entry in NUT hardware compatibility list (HCL)\&. .RE .PP \fBnoscanlangid\fR .RS 4 If this flag is set, don\(cqt autoscan valid range for langid\&. .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBIMPLEMENTATION NOTES\fR .RS 4 .PP \fB\fIarmac\fR\fR\fB subdriver\fR .RS 4 The Armac communication subdriver reproduces a communication protocol used by an old release of "PowerManagerII" software, which doesn\(cqt seem to be Armac specific: its banner is "2004 Richcomm Technologies, Inc\&. Dec 27 2005 ver 1\&.1\&." Maybe other Richcomm UPSes would work with this \(em maybe better than with the older standalone richcomm_usb driver\&. .RE .PP \fB\fIfabula\fR\fR\fB subdriver\fR .RS 4 This subdriver, meant to be used with the \fImegatec\fR protocol, does \fBnot\fR support the various \fBtest\&.battery\fR commands\&. Plus, the \fBshutdown\&.return\fR command ignores the values set in \fIups\&.delay\&.start\fR/\fBondelay\fR and makes the UPS turn on the load as soon as power is back\&. .RE .PP \fB\fIgtec\fR\fR\fB subdriver\fR .RS 4 Currently, the Gtec specific support is only known to work with USB devices (tested with a Gtec ZP120N), and was not seen with Serial port\&. .sp This mode is not automatically detected, and should be enabled manually in your \fIups\&.conf\fR, e\&.g\&.: .sp .if n \{\ .RS 4 .\} .nf [gtec\-ups] driver = "nutdrv_qx" port = "auto" subdriver = "gtec" protocol = "gtec" .fi .if n \{\ .RE .\} .sp Other subdrivers and protocol implementations (including \fBblazer_usb\fR(8)) sort of work, but both have two problems: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} They use the simple "Q1" query, which doesn\(cqt report the result of the latest battery test\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} For some reason the UPS reports normal battery voltage even when the battery is completely disconnected\&. So you won\(cqt know the battery is dead until a power failure\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} This driver sends the more advanced "Q4" request instead\&. Here the answer includes status letters with more information than the Q1 binary flags, including battery status\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} USB reply is read in 8\-byte chunks, which causes the UPS to disconnect from USB\&. The UPS reconnects in a second, but it still breaks the initialization of nutdrv_qx, where the query is sent twice in a short time (unlike blazer_usb)\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The solution is simple: read the whole reply at once\&. .RE .RE .RE .PP \fB\fIhunnox\fR\fR\fB subdriver\fR .RS 4 This protocol subdriver is closely related to \fIfabula\fR one, with a few tweaks for devices not directly supported by that driver\&. .RE .PP \fB\fIfuji\fR\fR\fB subdriver\fR .RS 4 This subdriver, meant to be used with the \fImegatec\fR protocol, does \fBnot\fR support the \fBshutdown\&.stayoff\fR and \fBload\&.off\fR commands\&. Plus, the \fBshutdown\&.return\fR command ignores the values set in \fIups\&.delay\&.start\fR/\fBondelay\fR and makes the UPS turn on the load as soon as power is back\&. .RE .PP \fB\fIkrauler\fR\fR\fB subdriver\fR .RS 4 This subdriver, meant to be used with the \fImegatec\fR protocol, does \fBnot\fR support the shutdown commands, i\&.e\&.: \fBshutdown\&.return\fR, \fBshutdown\&.stayoff\fR and \fBload\&.off\fR\&. .RE .PP \fB\fIsnr\fR\fR\fB subdriver\fR .RS 4 This subdriver, meant to be used with the \fImegatec\fR protocol, does \fBnot\fR support the shutdown commands, i\&.e\&.: \fBshutdown\&.return\fR, \fBshutdown\&.stayoff\fR and \fBload\&.off\fR\&. .RE .RE .SH "UPS COMMANDS" .sp This driver supports some instant commands (see \fBupscmd\fR(8)): .PP \fBbeeper\&.toggle\fR .RS 4 Toggle the UPS beeper\&. (Not available on some hardware) .RE .PP \fBload\&.on\fR .RS 4 Turn on the load immediately\&. (Not available on some hardware) .RE .PP \fBload\&.off\fR .RS 4 Turn off the load immediately (see KNOWN PROBLEMS)\&. .RE .PP \fBshutdown\&.return\fR .RS 4 Turn off the load and return when power is back\&. Uses the timers defined by \fBups\&.delay\&.start\fR and \fBups\&.delay\&.shutdown\fR\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Turn off the load and remain off (see KNOWN PROBLEMS)\&. Uses the timer defined by \fBups\&.delay\&.shutdown\fR\&. .RE .PP \fBshutdown\&.stop\fR .RS 4 Stop a shutdown in progress\&. .RE .PP \fBtest\&.battery\&.start\&.deep\fR .RS 4 Perform a long battery test\&. (Not available on some hardware) .RE .PP \fBtest\&.battery\&.start\&.quick\fR .RS 4 Perform a quick (10 second) battery test\&. .RE .PP \fBtest\&.battery\&.stop\fR .RS 4 Stop a running battery test\&. (Not available on some hardware) .RE .SS "BESTUPS, INNOVART31, MECER, MEGATEC, MEGATEC/OLD, MUSTEK, Q1, Q2, Q6, ZINTO PROTOCOLS" .PP \fBtest\&.battery\&.start\fR \fIvalue\fR .RS 4 Perform a battery test for the duration of \fIvalue\fR seconds (truncated to 60 seconds) [60\&.\&.5940]\&. .RE .SS "MASTERGUARD PROTOCOL" .PP \fBbeeper\&.enable\fR .RS 4 Enable the UPS beeper\&. .RE .PP \fBbeeper\&.disable\fR .RS 4 Disable the UPS beeper\&. .RE .PP \fBtest\&.battery\&.start\fR \fIvalue\fR .RS 4 Perform a battery test for the duration of \fIvalue\fR seconds (truncated to 60 seconds) [0\&.\&.5940]\&. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds)\&. .RE .PP \fBbypass\&.start\fR .RS 4 Put the UPS in bypass mode .RE .PP \fBbypass\&.stop\fR .RS 4 Take the UPS in normal mode .RE .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBVOLTRONIC POWER P98 UNITS (WITH MECER PROTOCOL)\fR .RS 4 .PP \fBtest\&.battery\&.start\fR \fIvalue\fR .RS 4 Perform a battery test for the duration of \fIvalue\fR seconds (truncated to 60 seconds) [12\&.\&.5940]\&. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds)\&. .RE .RE .SS "VOLTRONIC PROTOCOL" .sp The following instant commands are available for the \fIvoltronic\fR protocol\&. Not all of them are available on all the UPSes supported by this protocol\&. .PP \fBbeeper\&.enable\fR .RS 4 Enable the UPS beeper\&. .RE .PP \fBbeeper\&.disable\fR .RS 4 Disable the UPS beeper\&. .RE .PP \fBtest\&.battery\&.start\fR \fIvalue\fR .RS 4 Perform a battery test for the duration of \fIvalue\fR seconds [12\&.\&.5940]\&. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds)\&. .RE .PP \fBoutlet\&.1\&.load\&.off\fR .RS 4 Turn off outlet 1 load immediately\&. .RE .PP \fBoutlet\&.1\&.load\&.on\fR .RS 4 Turn on outlet 1 load immediately\&. .RE .PP \fBoutlet\&.2\&.load\&.off\fR .RS 4 Turn off outlet 2 load immediately\&. .RE .PP \fBoutlet\&.2\&.load\&.on\fR .RS 4 Turn on outlet 2 load immediately\&. .RE .PP \fBoutlet\&.3\&.load\&.off\fR .RS 4 Turn off outlet 3 load immediately\&. .RE .PP \fBoutlet\&.3\&.load\&.on\fR .RS 4 Turn on outlet 3 load immediately\&. .RE .PP \fBoutlet\&.4\&.load\&.off\fR .RS 4 Turn off outlet 4 load immediately\&. .RE .PP \fBoutlet\&.4\&.load\&.on\fR .RS 4 Turn on outlet 4 load immediately\&. .RE .PP \fBbypass\&.start\fR .RS 4 Put the UPS in ECO Mode\&. .RE .PP \fBbypass\&.stop\fR .RS 4 Take the UPS out of ECO Mode\&. .RE .SH "BATTERY CHARGE GUESSTIMATION" .sp Due to popular demand, this driver will report a guesstimated \fBbattery\&.charge\fR and optionally \fBbattery\&.runtime\fR, provided you specified a couple of the EXTRA ARGUMENTS listed above\&. .sp If you specify both \fBbattery\&.voltage\&.high\fR and \fBbattery\&.voltage\&.low\fR in \fBups.conf\fR(5), but don\(cqt enter \fBruntimecal\fR, it will guesstimate the state of charge by looking at the battery voltage alone\&. This is not reliable under load, as this only gives reasonably accurate readings if you disconnect the load, let the battery rest for a couple of minutes and then measure the open cell voltage\&. This just isn\(cqt practical if the power went out and the UPS is providing power for your systems\&. .sp .if n \{\ .RS 4 .\} .nf battery\&.voltage \- battery\&.voltage\&.low battery\&.charge = \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- x 100 % battery\&.voltage\&.high \- battery\&.voltage\&.low .fi .if n \{\ .RE .\} .sp There is a way to get better readings without disconnecting the load but this requires one to keep track on how much (and how fast) current is going in and out of the battery\&. If you specified the \fBruntimecal\fR, the driver will attempt to do this\&. Note however, that this heavily relies on the values you enter and that the UPS must be able to report the load as well\&. There are quite a couple of devices that report 0 % (or any other fixed value) at all times, in which case this obviously doesn\(cqt work\&. .sp The driver also has no way of determining the degradation of the battery capacity over time, so you\(cqll have to deal with this yourself (by adjusting the values in \fBruntimecal\fR)\&. Also note that the driver guesses the initial state of charge based on the battery voltage, so this may be less than 100 %, even when you are certain that they are full\&. There is just no way to reliably measure this between 0 and 100 % full charge\&. .sp This is better than nothing (but not by much)\&. If any of the above calculations is giving you incorrect readings, you are the one that put in the values in \fBups.conf\fR(5), so don\(cqt complain with the author\&. If you need something better, buy a UPS that reports \fBbattery\&.charge\fR and \fBbattery\&.runtime\fR all by itself without the help of a NUT driver\&. .SH "NOTES FOR THE PREVIOUS USER OF MEGATEC DRIVERS" .sp The \fBnutdrv_qx\fR driver having replaced the megatec ones, some configuration changes may be required by users switching to \fBnutdrv_qx\fR\&. .sp Part of this, the following megatec options, in \fBups.conf\fR(5), have to be changed: .PP \fBbattvolts\fR .RS 4 You need to use \fIdefault\&.battery\&.voltage\&.high\fR and \fIdefault\&.battery\&.voltage\&.low\fR .RE .PP \fBdtr\fR and \fBrts\fR .RS 4 You need to use \fIcablepower\fR .RE .PP \fBignoreoff\fR .RS 4 This parameter can simply be discarded, since it was a wrong understanding of the specification\&. .RE .SH "NOTES FOR THE PREVIOUS USER OF BLAZER DRIVERS" .sp The \fBnutdrv_qx\fR driver having replaced the blazer ones, some configuration changes may be required by users switching to \fBnutdrv_qx\fR\&. .sp Part of this, the following blazer options, in \fBups.conf\fR(5), have to be changed: .PP \fBondelay\fR .RS 4 While the previous blazer drivers expected minutes, the new \fBnutdrv_qx\fR driver wants seconds\&. .RE .sp The following instant command has also been changed: .PP \fBtest\&.battery\&.start\fR \fIvalue\fR .RS 4 While the old blazer drivers expected a \fIvalue\fR in minutes, the \fBnutdrv_qx\fR driver wants a \fIvalue\fR in seconds\&. .RE .SH "NOTES FOR THE PREVIOUS USER OF BESTUPS DRIVER" .sp The \fBnutdrv_qx\fR driver having replaced the bestups one, some configuration changes may be required by users switching to \fBnutdrv_qx\fR\&. .sp Part of this, the following bestups options, in \fBups.conf\fR(5), are no longer supported by this driver: .PP \fBnombattvolt\fR, \fBbattvoltmult\fR .RS 4 See BATTERY CHARGE GUESSTIMATION\&. .RE .PP \fBID\fR .RS 4 Discarded\&. .RE .SH "NOTES FOR THE PREVIOUS USER OF VOLTRONIC DRIVERS" .sp The \fBnutdrv_qx\fR driver having replaced the voltronic ones, some configuration changes may be required by users switching to \fBnutdrv_qx\fR\&. .sp Part of this, the following voltronic options, in \fBups.conf\fR(5), have to be changed: .PP \fBondelay\fR .RS 4 While the previous voltronic drivers expected minutes, the new \fBnutdrv_qx\fR driver wants seconds\&. It no longer defaults to 0 minutes but to 3 minutes (i\&.e\&. 180 seconds) for compatibility with the users switching from the old blazer drivers\&. .RE .PP \fBbattnumb\fR .RS 4 This option has been renamed to \fBbattery_number\fR\&. .RE .sp The following options are no longer supported by this driver, you can now change them more conveniently "on the fly" calling \fBupsrw\fR(8) with the appropriate NUT variable \(em provided that your UPS supports them\&. .TS tab(:); lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt. T{ .sp \fBbattpacks\fR T}:T{ .sp → \fBbattery\&.packs\fR .sp Set number of battery packs in parallel [1\&.\&.99]\&. This setting will change the charge and runtime estimation reported by the UPS\&. T} T{ .sp \fBbattlow\fR T}:T{ .sp → \fBbattery\&.voltage\&.low\fR .sp Set minimum battery voltage just before the UPS automatically shuts down\&. This setting will change the charge and runtime estimation reported by the UPS\&. T} T{ .sp \fBauto_reboot\fR T}:T{ .sp → \fBups\&.start\&.auto\fR .sp Enable or disable auto reboot [enabled/disabled]\&. If enabled, the UPS will auto recover when AC power returns\&. T} T{ .sp \fBbattery_protection\fR T}:T{ .sp → \fBbattery\&.protection\fR .sp Enable or disable battery deep discharge protection [enabled/disabled]\&. T} T{ .sp \fBenergy_saving\fR T}:T{ .sp → \fBbattery\&.energysave\fR .sp Enable or disable Green power function [enabled/disabled]\&. If enabled, for energy saving, the UPS will auto off when there is no load\&. T} T{ .sp \fBcold_start\fR T}:T{ .sp → \fBups\&.start\&.battery\fR .sp Enable or disable Cold Start [enabled/disabled]\&. If enabled, the UPS can be turned on also if AC is not connected to the UPS\&. T} T{ .sp \fBoutlet_control\fR T}:T{ .sp → \fBoutlet\&.0\&.switchable\fR .sp Enable or disable programmable outlets control at battery mode [enabled/disabled]\&. If enabled, the UPS will cut off programmable outlets after backup time (set through \fBoutlet\&.\fR{\fB1\fR,\fB2\fR,\fB3\fR,\fB4\fR}\fB\&.delay\&.shutdown\fR) arrives\&. If disabled, the UPS will provide continuous power to programmable outlets until the battery is running out\&. T} T{ .sp \fBmax_eco_volt\fR T}:T{ .sp → \fBinput\&.transfer\&.high\fR .sp Maximum voltage for ECO Mode (V)\&. If AC voltage is within acceptable range, ECO mode will be used (If the UPS is capable of and it\(cqs enabled)\&. T} T{ .sp \fBmin_eco_volt\fR T}:T{ .sp → \fBinput\&.transfer\&.low\fR .sp Minimum voltage for ECO Mode (V)\&. If AC voltage is within acceptable range, ECO mode will be used (If the UPS is capable of and it\(cqs enabled)\&. T} T{ .sp \fBmax_eco_freq\fR T}:T{ .sp → \fBinput\&.frequency\&.high\fR .sp Maximum frequency for ECO Mode (Hz)\&. If AC frequency is within acceptable range, ECO mode will be used (If the UPS is capable of and it\(cqs enabled)\&. T} T{ .sp \fBmin_eco_freq\fR T}:T{ .sp → \fBinput\&.frequency\&.low\fR .sp Minimum frequency for ECO Mode (Hz)\&. If AC frequency is within acceptable range, ECO mode will be used (If the UPS is capable of and it\(cqs enabled)\&. T} T{ .sp \fBoutlet1_delay\fR T}:T{ .sp → \fBoutlet\&.1\&.delay\&.shutdown\fR .sp Delay time before programmable outlet 1 shuts down the load when on battery mode [0\&.\&.59940] (seconds)\&. T} T{ .sp \fBoutlet2_delay\fR T}:T{ .sp → \fBoutlet\&.2\&.delay\&.shutdown\fR .sp Delay time before programmable outlet 2 shuts down the load when on battery mode [0\&.\&.59940] (seconds)\&. T} T{ .sp \fBoutlet3_delay\fR T}:T{ .sp → \fBoutlet\&.3\&.delay\&.shutdown\fR .sp Delay time before programmable outlet 3 shuts down the load when on battery mode [0\&.\&.59940] (seconds)\&. T} T{ .sp \fBoutlet4_delay\fR T}:T{ .sp → \fBoutlet\&.4\&.delay\&.shutdown\fR .sp Delay time before programmable outlet 4 shuts down the load when on battery mode [0\&.\&.59940] (seconds)\&. T} T{ .sp \fBbatt_type\fR T}:T{ .sp → \fBbattery\&.type\fR .sp Battery type (for P31 UPSes only) [Li/Flooded/AGM]\&. T} .TE .sp 1 .SH "KNOWN PROBLEMS" .sp Some UPS commands aren\(cqt supported by all models\&. In most cases, the driver will send a message to the system log when the user tries to execute an unsupported command\&. Unfortunately, some models don\(cqt even provide a way for the driver to check for this, so the unsupported commands will silently fail\&. .sp Both the \fBload\&.off\fR and \fBshutdown\&.stayoff\fR instant commands are meant to turn the load off indefinitely\&. However, some UPS models don\(cqt allow this\&. .sp Some models report a bogus value for the beeper status (will always be \fIenabled\fR or \fIdisabled\fR)\&. So, the \fBbeeper\&.toggle\fR command may appear to have no effect in the status reported by the driver when, in fact, it is working fine\&. .sp The temperature and load value is known to be bogus in some models\&. .SS "MASTERGUARD UNITS" .sp The driver is supposed to support both "new" A series (A700/1000/2000/3000 and their \-19 cousins) and E series (E60/100/200) but was tested only on A due to lack of E hardware\&. .SS "VOLTRONIC\-QS UNITS" .sp Both \fBload\&.off\fR and \fBshutdown\&.stayoff\fR instant commands are known to work as expected (i\&.e\&. turn the load off indefinitely) only if mains is present, otherwise, as soon as mains returns the load will be powered\&. .sp After issuing a \fBshutdown\&.return\fR instant command, the UPS won\(cqt wait \fBondelay\fR before powering on the load, provided the following conditions are met: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} if the load has been previously (no matter how long before) powered off through \fBload\&.off\fR/\fBshutdown\&.stayoff\fR \fIand\fR powered on through \fBload\&.on\fR/\fBshutdown\&.stop\fR \fIand\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} if AC wasn\(cqt cut after issuing the \fBload\&.off\fR/\fBshutdown\&.stayoff\fR (i\&.e\&. the UPS didn\(cqt turn itself off) \fIand\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} if there\(cqs a power outage after issuing the \fBshutdown\&.return\fR command .RE .sp In this case, as soon as mains returns the load will be powered\&. .SS "VOLTRONIC\-QS\-HEX UNITS" .sp \fBshutdown\&.return\fR, \fBload\&.off\fR, and \fBshutdown\&.stayoff\fR instant commands are known to work as expected only if mains is present, otherwise, as soon as mains returns the load will be powered\&. .SH "UPS WARNINGS (VOLTRONIC PROTOCOL)" .sp The UPSes supported by \fIvoltronic\fR protocol report warnings through a 64bit flag (bit1bit2\&...bit63bit64) where 1 means that a warning arose, while 0 means no warning\&. Since more than one warning at a time can be signaled, and because of the limited space in the ups\&.alarm variable, if the length of the warnings exceeds that of ups\&.alarms variable, they will be reported as bits\&. If you want to know the explanation of that bit you can either watch the log or see the next table (unlisted bits equal to unknown warnings)\&. .sp .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .B Table\ \&1.\ \&UPS Warnings for \fIvoltronic\fR UPSes .TS allbox tab(:); ltB ltB. T{ # T}:T{ Corresponding Warning T} .T& lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt. T{ .sp 1 T}:T{ .sp Battery disconnected T} T{ .sp 2 T}:T{ .sp Neutral not connected T} T{ .sp 3 T}:T{ .sp Site fault T} T{ .sp 4 T}:T{ .sp Phase sequence incorrect T} T{ .sp 5 T}:T{ .sp Phase sequence incorrect in bypass T} T{ .sp 6 T}:T{ .sp Input frequency unstable in bypass T} T{ .sp 7 T}:T{ .sp Battery overcharged T} T{ .sp 8 T}:T{ .sp Low battery T} T{ .sp 9 T}:T{ .sp Overload alarm T} T{ .sp 10 T}:T{ .sp Fan alarm T} T{ .sp 11 T}:T{ .sp EPO enabled T} T{ .sp 12 T}:T{ .sp Unable to turn on UPS T} T{ .sp 13 T}:T{ .sp Over temperature alarm T} T{ .sp 14 T}:T{ .sp Charger alarm T} T{ .sp 15 T}:T{ .sp Remote auto shutdown T} T{ .sp 16 T}:T{ .sp L1 input fuse not working T} T{ .sp 17 T}:T{ .sp L2 input fuse not working T} T{ .sp 18 T}:T{ .sp L3 input fuse not working T} T{ .sp 19 T}:T{ .sp Positive PFC abnormal in L1 T} T{ .sp 20 T}:T{ .sp Negative PFC abnormal in L1 T} T{ .sp 21 T}:T{ .sp Positive PFC abnormal in L2 T} T{ .sp 22 T}:T{ .sp Negative PFC abnormal in L2 T} T{ .sp 23 T}:T{ .sp Positive PFC abnormal in L3 T} T{ .sp 24 T}:T{ .sp Negative PFC abnormal in L3 T} T{ .sp 25 T}:T{ .sp Abnormal in CAN\-bus communication T} T{ .sp 26 T}:T{ .sp Abnormal in synchronous signal circuit T} T{ .sp 27 T}:T{ .sp Abnormal in synchronous pulse signal circuit T} T{ .sp 28 T}:T{ .sp Abnormal in host signal circuit T} T{ .sp 29 T}:T{ .sp Male connector of parallel cable not connected well T} T{ .sp 30 T}:T{ .sp Female connector of parallel cable not connected well T} T{ .sp 31 T}:T{ .sp Parallel cable not connected well T} T{ .sp 32 T}:T{ .sp Battery connection not consistent in parallel systems T} T{ .sp 33 T}:T{ .sp AC connection not consistent in parallel systems T} T{ .sp 34 T}:T{ .sp Bypass connection not consistent in parallel systems T} T{ .sp 35 T}:T{ .sp UPS model types not consistent in parallel systems T} T{ .sp 36 T}:T{ .sp Capacity of UPSs not consistent in parallel systems T} T{ .sp 37 T}:T{ .sp Auto restart setting not consistent in parallel systems T} T{ .sp 38 T}:T{ .sp Battery cell over charge T} T{ .sp 39 T}:T{ .sp Battery protection setting not consistent in parallel systems T} T{ .sp 40 T}:T{ .sp Battery detection setting not consistent in parallel systems T} T{ .sp 41 T}:T{ .sp Bypass not allowed setting not consistent in parallel systems T} T{ .sp 42 T}:T{ .sp Converter setting not consistent in parallel systems T} T{ .sp 43 T}:T{ .sp High loss point for frequency in bypass mode not consistent in parallel systems T} T{ .sp 44 T}:T{ .sp Low loss point for frequency in bypass mode not consistent in parallel systems T} T{ .sp 45 T}:T{ .sp High loss point for voltage in bypass mode not consistent in parallel systems T} T{ .sp 46 T}:T{ .sp Low loss point for voltage in bypass mode not consistent in parallel systems T} T{ .sp 47 T}:T{ .sp High loss point for frequency in AC mode not consistent in parallel systems T} T{ .sp 48 T}:T{ .sp Low loss point for frequency in AC mode not consistent in parallel systems T} T{ .sp 49 T}:T{ .sp High loss point for voltage in AC mode not consistent in parallel systems T} T{ .sp 50 T}:T{ .sp Low loss point for voltage in AC mode not consistent in parallel systems T} T{ .sp 51 T}:T{ .sp Warning for locking in bypass mode after 3 consecutive overloads within 30 min T} T{ .sp 52 T}:T{ .sp Warning for three\-phase AC input current unbalance T} T{ .sp 53 T}:T{ .sp Warning for a three\-phase input current unbalance detected in battery mode T} T{ .sp 54 T}:T{ .sp Warning for Inverter inter\-current unbalance T} T{ .sp 55 T}:T{ .sp Programmable outlets cut off pre\-alarm T} T{ .sp 56 T}:T{ .sp Warning for Battery replace T} T{ .sp 57 T}:T{ .sp Abnormal warning on input phase angle T} T{ .sp 58 T}:T{ .sp Warning!! Cover of maintain switch is open T} T{ .sp 62 T}:T{ .sp EEPROM operation error T} .TE .sp 1 .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Daniele Pezzini .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arnaud Quette .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} John Stamp .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Peter Selinger .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arjen de Korte .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Alexander Gordeev .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Edgar Fuß .RE .SH "SEE ALSO" .sp \fBblazer_ser\fR(8), \fBblazer_usb\fR(8), \fBnutupsdrv\fR(8), \fBups.conf\fR(5), \fBupsc\fR(8), \fBupscmd\fR(8), \fBupsdrvctl\fR(8), \fBupsmon\fR(8), \fBupsrw\fR(8) .SS "Internet Resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT HCL: https://www\&.networkupstools\&.org/stable\-hcl\&.html .RE nut-2.8.3/docs/man/generic_gpio.80000644000200500020050000001236015001555101013460 00000000000000'\" t .\" Title: generic gpio .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "GENERIC GPIO" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" generic_gpio \- Driver for GPIO connected UPSes .SH "SYNOPSIS" .sp \fBgeneric_gpio\fR \-h .sp \fBgeneric_gpio\fR \-a \fIgpiochip0\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the \fBgeneric_gpio\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This is the driver for GPIO attached UPS devices\&. .sp The driver has been tested against CyberPower CyberShield CSN27U12V attached to Orange Pi Zero GPIO\&. .PP More information about this UPS can be found here: .RS 4 https://www\&.cyberpowersystems\&.com/resources/csn27u12v\-um/ .RE .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file: .SS "Driver control:" .PP \fBrules\fR=\fIvalue\fR .RS 4 A string consisting of sub\-strings\&. Each sub\-string describes GPIO line states conversion formula to specific NUT state, like .sp .if n \{\ .RS 4 .\} .nf nut_state=[^]line_num[logical_operation[^]line_num]\&.\&.\&.; .fi .if n \{\ .RE .\} .sp The logical "Not" (^), "And" (&), and "Or" (|) operations are supported for now\&. .sp The nut_state should correspond to NUT state, and line_num to the GPIO line number connected to UPS open collector pin\&. .sp CyberShield CSN27U12V describes pins as: .TS allbox tab(:); lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt. T{ Battery state T}:T{ State details T}:T{ GPIO line T} T{ ON BATTERY T}:T{ \fBLow\fR when operating from utility line .sp \fBOpen\fR when operating from battery T}:T{ 0 T} T{ REPLACE BATTERY T}:T{ \fBLow\fR when battery is charged .sp \fBOpen\fR when battery fails the Self Test T}:T{ 1 T} T{ BATTERY MISSING T}:T{ \fBLow\fR when battery is present .sp \fBOpen\fR when battery is missing T}:T{ 6 T} T{ LOW BATTERY T}:T{ \fBLow\fR when battery is near full charge capacity .sp \fBOpen\fR when operating from a battery with < 20% capacity T}:T{ 3 T} .TE .sp 1 .RE .sp and then the \fIrules\fR value might be defined as .sp + .sp .if n \{\ .RS 4 .\} .nf rules = "OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6;" .fi .if n \{\ .RE .\} .sp + assuming battery pin connection to GPIO lines as listed in table\&. .sp + Expecting simple formula to be used for each state, extra may increase state reliability and may need to be checked on each specific UPS\&. .SS "Battery Charge:" .PP \fBdefault\&.battery\&.charge\&.low\fR=\fIvalue\fR .RS 4 An integer specifying the battery charge level reported in LB case\&. .RE .SH "CONFIGURATION" .sp Here is an example of GPIO driver configuration in \fBups\&.conf\fR file: .sp .if n \{\ .RS 4 .\} .nf [CyberPower12v] driver = GENERIC_GPIO port = gpiochip0 desc = "Modem and DNS server UPS" mfr = CyberPower model = "CyberShield CSN27U12V" rules = "OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6;" default\&.battery\&.charge\&.low = 20 .fi .if n \{\ .RE .\} .SH "SHUTDOWN COMMAND" .sp This driver does not support shutdown command\&. .SH "INSTALLATION" .sp This driver may be not built by default\&. You can build it by installing libgpiod and running configure \-\-with\-gpio=yes\&. .sp You also need to give proper permissions on the local serial device file (/dev/gpiochip0 for example) to allow the run\-time NUT driver user account to access it, like by adding the following rule to Linux rules\&.d directory: .sp .if n \{\ .RS 4 .\} .nf SUBSYSTEM=="gpio*", PROGRAM="/bin/sh \-c \*(Aq\e chown \-R nut:nut /dev/gpiochip0 && chmod \-R 700 /dev/gpiochip0\*(Aq .fi .if n \{\ .RE .\} .SH "AUTHOR" .sp Modris Berzonis .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8), \fBups.conf\fR(5) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} libgpiod home page: https://git\&.kernel\&.org/pub/scm/libs/libgpiod/libgpiod\&.git/ .RE nut-2.8.3/docs/man/upsc.txt0000644000200500020050000000651515001555412012462 00000000000000UPSC(8) ======= NAME ---- upsc - Lightweight read-only NUT client SYNOPSIS -------- *upsc* -l | -L ['host'] *upsc* 'ups' ['variable'] *upsc* -c 'ups' DESCRIPTION ----------- *upsc* is provided as a quick way to poll the status of a UPS server. It can be used inside shell scripts and other programs that need UPS data but don't want to include the full interface. OPTIONS ------- *-l* 'host':: List all UPS names configured at 'host', one name per line. The hostname defaults to "localhost". You may optionally add a colon and a port number. *-L* 'host':: As above, list all UPS names configured at 'host', including their description provided by the remote linkman:upsd[8] from its linkman:ups.conf[5]. The hostname defaults to "localhost". You may optionally add a colon and a port number to override the default port. *-c* 'ups':: Lists each client connected on 'ups', one name per line. 'ups':: Display the status of that UPS. The format for this option is 'upsname[@hostname[:port]]'. The default hostname is "localhost". 'variable':: Display the value of this variable only. By default, `upsc` retrieves the list of variables from the server and then displays the value for each. This option may be useful in shell scripts to save an additional pipe into `grep`. COMMON OPTIONS -------------- *-h*:: Show the command-line help message. *-V*:: Show NUT version banner. More details may be available if you also `export NUT_DEBUG_LEVEL=1` or greater verbosity level. *-W* 'secs':: Set the timeout for initial network connections (by default they are indefinitely non-blocking, or until the system interrupts the attempt). Overrides the optional `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable. EXAMPLES -------- To list all variables on an UPS named "myups" on a host called "mybox", with linkman:upsd[8] running on port '1234': :; upsc myups@mybox:1234 battery.charge: 100.0 battery.voltage: 13.9 battery.voltage.nominal: 13.6 . . . To list the UPSes configured on this system, along with their descriptions: :; upsc -L apc: Back-UPS 500 ppro2: Patriot Pro II To retrieve the status for all UPSes connected to mybox, using Bourne-shell syntax: :; for UPS in `upsc -l mybox:1234`; do upsc $UPS ups.status done To list clients connected on "myups": :; upsc -c myups 127.0.0.1 ::1 192.168.1.2 SCRIPTED MODE ------------- If you run this program inside a shell script or similar to get the list of devices and variables, you should only consider using output from `stdout`, not `stderr`. DIAGNOSTICS ----------- `upsc` will either print a list of UPS names, a list of all supported variables and their values on the UPS, or an error message. If you do receive an error, make sure you have specified a valid UPS on the command line, that linkman:upsd[8] is really running on the other host, and that no firewalls are blocking you. HISTORY ------- Earlier versions of this program used the 'upsfetch' library and UDP sockets to talk to upsd. This version of upsc uses the new 'upsclient' library, which only talks TCP. This is why 'upsct' no longer exists. SEE ALSO -------- linkman:upslog[8], linkman:ups.conf[5], linkman:upsd[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutclient_get_device_variables.30000644000200500020050000000004215001555117017235 00000000000000.so man3/libnutclient_variables.3 nut-2.8.3/docs/man/nutscan_free_ip_ranges.30000644000200500020050000000470715001555061015537 00000000000000'\" t .\" Title: nutscan_free_ip_ranges .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_FREE_IP_RANG" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_free_ip_ranges \- Free contents of a `nutscan_ip_range_list_t` structure populated (and optionally created) by `nutscan_init_ip_ranges()` and, more importantly, filled by a series of `nutscan_add_ip_range()` calls\&. .SH "SYNOPSIS" .sp .nf #include void nutscan_free_ip_ranges(nutscan_ip_range_list_t *irl); .fi .SH "DESCRIPTION" .sp The \fBnutscan_free_ip_ranges()\fR function can free a nutscan_ip_range_list_t structure\&. Doing so, it frees the whole linked list of nutscan_ip_range_t entries, and zeroes out helper properties\&. .sp The structure itself is not freed (as it can be a statically allocated variable on the stack), and can be re\-used for a new list if needed\&. .sp The caller must ultimately free the structure object if it was allocated dynamically (e\&.g\&. by originally calling nutscan_init_ip_ranges(NULL))\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-ip\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_add_ip_range\fR(3), \fBnutscan_stringify_ip_ranges\fR(3), \fBnutscan_cidr_to_ip\fR(3), \fBnutscan_ip_ranges_iter_init\fR(3), \fBnutscan_ip_ranges_iter_inc\fR(3) nut-2.8.3/docs/man/apcupsd-ups.80000644000200500020050000001334015001555076013304 00000000000000'\" t .\" Title: apcupsd-ups .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "APCUPSD\-UPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" apcupsd-ups \- Driver for apcupsd client access .SH "SYNOPSIS" .sp \fBapcupsd\-ups\fR \-h .sp \fBapcupsd\-ups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the \fBapcupsd\-ups\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "DESCRIPTION" .sp This driver is a client to \fBapcupsd\fR (another UPS monitoring project)\&. .sp \fBapcupsd\-ups\fR acts as an \fBapcupsd\fR client, simply forwarding data\&. This can be useful in cases where both protocols are required in a network, or in case apcupsd code base has a required UPS access mode missing from NUT\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in \fBnut.conf\fR(5): .PP \fBport\fR=[:] .RS 4 This is the name of a remote host running apcupsd (plus an optional port)\&. .RE .sp For instance: .sp .if n \{\ .RS 4 .\} .nf [apcupsd] driver = apcupsd\-ups port = localhost desc = "apcupsd client" .fi .if n \{\ .RE .\} .SH "BACKGROUND" .sp This driver was originally written in one evening to allow interoperating with \fBapcupsd\fR\&. .SH "SUPPORTED VARIABLES" .sp The following variables are translated from \fBapcupsd\fR to NUT\&. All times should be converted to seconds (please file a bug if you notice a mismatch in units)\&. .TS allbox tab(:); ltB ltB. T{ apcupsd variable T}:T{ NUT variable(s) T} .T& lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt. T{ .sp BCHARGE T}:T{ .sp battery\&.charge T} T{ .sp MBATTCHG T}:T{ .sp battery\&.charge\&.low T} T{ .sp RETPCT T}:T{ .sp battery\&.charge\&.restart T} T{ .sp BATTDATE T}:T{ .sp battery\&.date T} T{ .sp TIMELEFT T}:T{ .sp battery\&.runtime T} T{ .sp MINTIMEL T}:T{ .sp battery\&.runtime\&.low T} T{ .sp BATTV T}:T{ .sp battery\&.voltage T} T{ .sp NOMBATTV T}:T{ .sp battery\&.voltage\&.nominal T} T{ .sp LINEFREQ T}:T{ .sp input\&.frequency T} T{ .sp SENSE T}:T{ .sp input\&.sensitivity T} T{ .sp HITRANS T}:T{ .sp input\&.transfer\&.high T} T{ .sp LOTRANS T}:T{ .sp input\&.transfer\&.low T} T{ .sp LASTXFER T}:T{ .sp input\&.transfer\&.reason T} T{ .sp LINEV T}:T{ .sp input\&.voltage T} T{ .sp MAXLINEV T}:T{ .sp input\&.voltage\&.maximum T} T{ .sp MINLINEV T}:T{ .sp input\&.voltage\&.minimum T} T{ .sp NOMINV T}:T{ .sp input\&.voltage\&.nominal T} T{ .sp LINEFREQ T}:T{ .sp output\&.frequency T} T{ .sp OUTPUTV T}:T{ .sp output\&.voltage T} T{ .sp NOMOUTV T}:T{ .sp output\&.voltage\&.nominal T} T{ .sp DATE T}:T{ .sp ups\&.date, ups\&.time T} T{ .sp DSHUTD T}:T{ .sp ups\&.delay\&.shutdown T} T{ .sp DWAKE T}:T{ .sp ups\&.delay\&.start T} T{ .sp FIRMWARE T}:T{ .sp ups\&.firmware, ups\&.firmware\&.aux T} T{ .sp UPSNAME T}:T{ .sp ups\&.id T} T{ .sp LOADPCT T}:T{ .sp ups\&.load T} T{ .sp MANDATE T}:T{ .sp ups\&.mfr\&.date T} T{ .sp NOMPOWER T}:T{ .sp ups\&.realpower\&.nominal T} T{ .sp SERIALNO T}:T{ .sp ups\&.serial T} T{ .sp STATUS T}:T{ .sp ups\&.status T} T{ .sp ITEMP T}:T{ .sp ups\&.temperature T} T{ .sp STESTI T}:T{ .sp ups\&.test\&.interval T} T{ .sp SELFTEST T}:T{ .sp ups\&.test\&.result T} .TE .sp 1 .SH "LIMITATIONS" .sp Access to \fBapcupsd\fR is strictly read only: no commands can be issued\&. This stems from the design of \fBapcupsd\fR, where the settings are changed in \fBapctest\fR\&. In order to run \fBapctest\fR, \fBapcupsd\fR must be stopped (and it is \fBapcupsd\fR that exposes the UPS to the network and to this NUT driver as its client)\&. .SH "AUTHOR" .sp Andreas Steinmetz .SH "SEE ALSO" .sp \fBups.conf\fR(5), \fBnutupsdrv\fR(8) .SS "Internet Resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The apcupsd home page: http://www\&.apcupsd\&.org/ .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Development of \fBapcupsd\fR project itself seems to have stalled in 2016/2017, with release 3\&.14\&.14 being the latest official tag\&. Its community discussions do remain quite active, however\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Just in case, a replica of its sources is stored at https://github\&.com/networkupstools/apcupsd .RE .RE nut-2.8.3/docs/man/upsset.conf.50000644000200500020050000001022615001555050013274 00000000000000'\" t .\" Title: upsset.conf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSSET\&.CONF" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsset.conf \- Configuration for Network UPS Tools upsset\&.cgi .SH "DESCRIPTION" .sp This file only does one job \(em it lets you convince \fBupsset.cgi\fR(8) that your system\(cqs CGI directory is secure\&. The program will not run until this file has been properly defined\&. .SH "IMPORTANT NOTES" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message)\&. .RE .SH "SECURITY REQUIREMENTS" .sp \fBupsset.cgi\fR(8) allows you to try login name and password combinations\&. There is no rate limiting, as the program shuts down between every request\&. Such is the nature of CGI programs\&. .sp Credentials are provided to upsset\&.cgi as part of your browsing session, so it is highly recommended to set up HTTPS on the web server; ways to do so are outside the scope of this document\&. .sp Normally, attackers would not be able to access your \fBupsd\fR(8) server directly, as it would be protected by the LISTEN directives in your \fBupsd.conf\fR(5) file, tcp\-wrappers (if available when NUT was built), and hopefully local firewall settings in your OS\&. .sp \fBupsset\fR runs on your web server, so upsd will see it as a connection from a host on an internal network\&. It doesn\(cqt know that the connection is actually initiated by someone further outside\&. This is why you must secure it\&. .sp On Apache, you can use the \&.htaccess file or put the directives in your httpd\&.conf\&. It looks something like this, assuming the \&.htaccess method for older Apache releases: .sp .if n \{\ .RS 4 .\} .nf deny from all allow from your\&.network\&.addresses .fi .if n \{\ .RE .\} .sp You will probably have to set AllowOverride Limit for this directory in your server\-level configuration file as well\&. .sp Modern Apache enjoys a more detailed syntax, like this: .sp .if n \{\ .RS 4 .\} .nf ScriptAlias /upsstats\&.cgi /usr/share/nut/cgi/upsstats\&.cgi ScriptAlias /upsset\&.cgi /usr/share/nut/cgi/upsset\&.cgi Options +Includes +ExecCGI AllowOverride Limit Require local Require ip aa\&.bb\&.cc\&.dd/nn .fi .if n \{\ .RE .\} .sp If this doesn\(cqt make sense, then stop reading and leave this program alone\&. It\(cqs not something you absolutely need to have anyway\&. .sp Assuming you have all this done, and it actually works (test it!), then you may add the following directive to this file: .sp .if n \{\ .RS 4 .\} .nf I_HAVE_SECURED_MY_CGI_DIRECTORY .fi .if n \{\ .RE .\} .sp If you lie to the program and someone beats on your upsd through your web server, don\(cqt blame me\&. .SH "SEE ALSO" .sp \fBupsset.cgi\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan_add_device_to_device.30000644000200500020050000000574415001555063016663 00000000000000'\" t .\" Title: nutscan_add_device_to_device .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_ADD_DEVICE_T" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_add_device_to_device \- Concatenate two devices structure\&. .SH "SYNOPSIS" .sp .nf #include nutscan_device_t * nutscan_add_device_to_device( nutscan_device_t * first, nutscan_device_t * second); .fi .SH "DESCRIPTION" .sp The nutscan_device_t contains the following variables: .sp .if n \{\ .RS 4 .\} .nf nutscan_device_type_t type; char * driver; char * alt_driver_names; char * port; nutscan_options_t opt; struct nutscan_device * prev; struct nutscan_device * next; .fi .if n \{\ .RE .\} .sp This is a double linked list of device\&. Each device is described by its type, its driver name, its port and any number of optional data\&. .sp The \fBnutscan_add_device_to_device()\fR concatenates \fIfirst\fR and \fIsecond\fR devices to a unique device\&. No new device is created, the two linked lists are simply linked to each other\&. So \fIfirst\fR and \fIsecond\fR devices are likely to be modified by this function\&. .SH "RETURN VALUE" .sp The \fBnutscan_add_device_to_device()\fR functions returns a pointer to a device containing both passed devices\&. Note that it\(cqs not a new device, so it is either \fIfirst\fR or \fIsecond\fR which is returned\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-device\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3) nut-2.8.3/docs/man/nutscan_scan_nut_simulation.30000644000200500020050000000547015001555057016650 00000000000000'\" t .\" Title: nutscan_scan_nut_simulation .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_SCAN_NUT_SIM" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_scan_nut_simulation \- Scan your sysconfig directory for NUT simulation devices\&. .SH "SYNOPSIS" .sp .nf #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_nut_simulation(); .fi .SH "DESCRIPTION" .sp The \fBnutscan_scan_nut_simulation()\fR function tries to detect available NUT simulation devices, by finding *\&.dev and *\&.seq files in your "sysconfig" directory\&. .sp You MUST call \fBnutscan_init\fR(3) before using this function\&. .SH "BUGS" .sp This function currently uses the built\-in location of the "sysconfig" directory, and does not consider an override with NUT_CONFPATH environment variable accepted by most of the NUT code base\&. .SH "RETURN VALUE" .sp The \fBnutscan_scan_nut_simulation()\fR function returns a pointer to a nutscan_device_t structure containing all found devices or NULL if an error occurs or no device is found\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_scan_eaton_serial\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/nutclient_has_device_command.30000644000200500020050000000004115001555117016676 00000000000000.so man3/libnutclient_commands.3 nut-2.8.3/docs/man/asem.txt0000644000200500020050000000470315001555412012432 00000000000000ASEM(8) ======= NAME ---- asem - Driver for UPS in ASEM PB1300 SYNOPSIS -------- *asem* -h *asem* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *asem* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The *asem* driver supports the UPS in ASEM PB1300 embedded PCs. Likely other I2C devices from the same manufacturer will work too, since this is a "custom" charger. Seems that there are two versions of the charger. Older one is based on Max1667, newer one is a custom solution. Both are on I2C address *0x09*. To be compatible with both versions, the driver just reads *bit 15* of address *0x13* which yields online/on battery status. Battery monitor is a BQ2060 at address *0x0B*. EXTRA ARGUMENTS --------------- The required parameter for this driver is the I2C bus name: *port*='dev-node':: On the Asem PB1300, this should be `/dev/i2c-7` for the i801 SMBUS adapter. This driver also supports the following optional settings: *lb*='num':: Set the low battery threshold to 'num' volts. *hb*='num':: Set the high battery threshold to 'num' volts. INSTALLATION ------------ This driver is specific to the Linux I2C API, and requires the libi2c-dev library and headers from lm_sensors project, or its equivalent, to compile. Beware that the SystemIO memory used by the I2C controller is reserved by ACPI. If only a native I2C driver (e.g. `i2c_i801`, as of 3.5.X Linux kernels) is available, then you'll need to relax the ACPI resources check. For example, you can boot with the `acpi_enforce_resources=lax` option. ////////////////////////////////////////// Optional: use DIAGNOSTICS to describe troubleshooting techniques that are longer than what can be conveniently described in the driver error messages. DIAGNOSTICS ----------- ////////////////////////////////////////// KNOWN ISSUES AND BUGS --------------------- The driver shutdown function is not implemented, so other arrangements must be made to turn off the UPS. AUTHOR ------ Giuseppe Corbelli SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * PB1300 specifications: http://www.asem.it/en/products/industrial-automation/box-pcs/performance/pb1300/ * BQ2060 datasheet: http://www.ti.com/lit/ds/symlink/bq2060.pdf * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_scan_snmp.30000644000200500020050000001142215001555056014544 00000000000000'\" t .\" Title: nutscan_scan_snmp .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_SCAN_SNMP" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_scan_snmp \- Scan network for SNMP devices\&. .SH "SYNOPSIS" .sp .nf #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_snmp( const char * start_ip, const char * stop_ip, useconds_t timeout, nutscan_snmp_t * sec); nutscan_device_t * nutscan_scan_ip_range_snmp( nutscan_ip_range_list_t * irl, useconds_t usec_timeout, nutscan_snmp_t * sec); .fi .SH "DESCRIPTION" .sp The \fBnutscan_scan_snmp()\fR and \fBnutscan_scan_ip_range_snmp()\fR functions try to detect NUT compatible SNMP devices\&. The former tries SNMP queries on every IP ranging from \fIstart_ip\fR to \fIstop_ip\fR, where \fIstartIP\fR is mandatory and \fIstopIP\fR is optional (one \fIstartIP\fR address is scanned if \fIstopIP\fR is NULL); while the latter can walk several IP address ranges represented by a nutscan_ip_range_list_t structure\&. .sp Those IP arguments may be either IPv4 or IPv6 addresses or host names\&. .sp You MUST call \fBnutscan_init\fR(3) before using this function\&. .sp This function waits up to \fItimeout\fR microseconds before considering an IP address does not respond to SNMP queries\&. .sp A valid nutscan_snmp_t structure must be passed to this function\&. .sp The nutscan_snmp_t structure contains the following members which must be filled as described below: .sp .if n \{\ .RS 4 .\} .nf char * \*(Aqcommunity\*(Aq; char * \*(AqsecLevel\*(Aq; char * \*(AqsecName\*(Aq; char * \*(AqauthPassword\*(Aq; char * \*(AqprivPassword\*(Aq; char * \*(AqauthProtocol\*(Aq; char * \*(AqprivProtocol\*(Aq; .fi .if n \{\ .RE .\} .sp If \fIcommunity\fR is not NULL, SNMP v1 request are sent using this \fIcommunity\fR\&. .sp If \fIcommunity\fR is NULL and \fIsecLevel\fR is NULL, SNMP v1 is selected and \fIcommunity\fR is set to "public"\&. .sp In the other cases, SNMP v3 is used\&. \fIsecLevel\fR may be one of SNMP_SEC_LEVEL_NOAUTH, SNMP_SEC_LEVEL_AUTHNOPRIV or SNMP_SEC_LEVEL_AUTHPRIV\&. \fIsecName\fR is the security name and must be non NULL\&. .sp If \fIsecLevel\fR is set to SNMP_SEC_LEVEL_AUTHNOPRIV, \fIauthPassword\fR must be non NULL\&. .sp If \fIsecLevel\fR is set to SNMP_SEC_LEVEL_AUTHPRIV, \fIauthPassword\fR and \fIprivPassword\fR must be non NULL\&. .sp If \fIauthProtocol\fR is NULL, MD5 protocol is used\&. Else you can set \fIauthProtocol\fR to either "MD5" or "SHA"\&. .sp If \fIprivProtocol\fR is NULL, DES protocol is used\&. Else you can set \fIprivProtocol\fR to either "AES" or "DES"\&. .sp \fIpeername\fR and \fIhandle\fR are used internally and do not need any initialization\&. .SH "RETURN VALUE" .sp The \fBnutscan_scan_snmp()\fR function returns a pointer to a nutscan_device_t structure containing all found devices or NULL if an error occurs or no device is found\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_scan_eaton_serial\fR(3), \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_add_ip_range\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/apcsmart.txt0000644000200500020050000003424115001555412013317 00000000000000APCSMART(8) =========== NAME ---- apcsmart - Driver for American Power Conversion Smart Protocol UPS equipment SYNOPSIS -------- *apcsmart* -h *apcsmart* -a 'UPS_NAME' [-x option=value ...] NOTE: This man page only documents the hardware-specific features of the apcsmart driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The apcsmart driver should recognize (or at the very least, work with) the majority of Smart-UPS models -- which includes Smart-UPS, Matrix-UPS and Back-UPS lineups, among few other ones. Currently, we can roughly divide APC hardware into four groups (note that the division isn't strict by any means, and the borders between those are pretty fuzzy): [very] "old" models:: These models usually have old APC logo, white color and _no_ programmable EEPROM; you won't find them listed anywhere on APC's site either. The support for those will be usually based on driver's compatibility tables, or if the model (firmware) is not listed in those -- the driver will try to follow the very basic subset of features, while still trying to remain useful. Despite "smart" tagname, they often tend to behave in pretty dumb way (see the section below about shutdown behaviour). + -- .Example models: * Smart-UPS 2000I * Smart-UPS 900I -- "new" models:: These models usually come from late 1990s / pre-2009 times. They are often referred to as "3rd. gen". For the most part, they have programmable EEPROM, report supported commands and capabilities, and should work just fine with the apcsmart driver. "microlink" models:: WARNING: these are not _natively_ supported by *apcsmart* (or as of this writing by *apcupsd*, for that matter, if you're wondering). Around 2007, APC (now APC Schneider) decided to go back to its proprietary roots, and all the new models (SMT, SMX, SURTD) use completely different protocol and cables. If you purchased a new APC UPS -- that uses cable with RJ45 on the one end, and DB-9 on the other -- then you have such model. Your only option to support it through *NUT* is to purchase a "legacy communications card" -- part #AP9620 (google 'AP9620' for more details). Or if that's not an option, rely on official software. + -- .UPDATE: Later releases of *apcupsd* claimed support for new APC protocols, so it is worth checking if *apcupsd* software would work with your device, and *apcupsd-ups* NUT driver would handle it as part of NUT-managed ecosystem. -- Microsol models:: Several Microsol serial models sold in Brazil have been rebranded as APC Back-UPS, and the model numbers tend to start with "BZ". If you have one of these "Nobreaks", they will not work with the *apcsmart* driver -- please see the linkman:solis[8] driver instead. + -- .Example models: * Back-UPS BZ1200-BR * Back-UPS BZ2200BI-BR -- Another thing to remember is that Smart protocol is not USB protocol. If you have UPS with both USB and serial ports, then depending on how you connect it, you will need either `apcsmart` or `usbhid-ups` driver. CABLING ------- This driver expects to see a 940-0024C cable or a clone by default. You can switch to the 940-0095B dual-mode cable support with the 'cable=' definition described below. If your 940-xx24X cable is broken or missing, use this diagram to build a clone: https://www.networkupstools.org/cables.html#_940_0024c_clone NOTE: The "xx" is either "00" for a short cable, or the number of feet of a longer cable. The "X" is a letter representing the minor revision of the physical cable and its connectors ("C" and "E" are commonly found revisions). All minor revisions should use the same pin-outs and wiring. You can specify alternate cable in linkman:ups.conf[5]: *cable*=940-0095B Alternatively, you can also provide it on the command line using: -x *cable*=940-0095B TTY MODES --------- By default the driver works in canonical mode, but it proved to be a problem in Windows systems. Furthermore there's a possibility of some obscure serial cards or serial-USB converters that could cause problems as well. You can use 'ttymode=' option to force non-canonical discipline in linkman:ups.conf[5]: *ttymode*=raw Alternatively, you can also provide it on the command line using: -x *ttymode*=raw NOTE: Any other value will make the driver work in the canonical mode. EXPLANATION OF SHUTDOWN METHODS SUPPORTED BY APC UPSES ------------------------------------------------------ APC hardware supports a lot of shutdown methods, that themselves can differ in behaviour quite a bit, depending on the model. *S* (soft hibernate):: This is most basic command present in probably all APC models. It will hibernate the UPS, and subsequently wake it up when the mains supply returns. *The command doesn't work if the UPS is running on mains.* + -- "old" models: :: The behaviour here is unfortunately pretty primitive - when the power returns, the UPS just wakes up. No grace periods, no min. battery charge condition, etc. This is probably not what you want. "new" models: :: The behaviour here is as expected -- the power is cut off after the EEPROM defined grace period. The UPS will wake up when the power returns, after the EEPROM defined delay AND if the EEPROM defined min. battery charge level is met. The delay is counted from the power's return. -- + *CS* (aka "force OB hack"):: This is a trick to make UPS power down even if it's running on mains. Immediately before issuing *S*, "simulate power failure" is issued. The remaining behaviour is as in *S* case. + There's a delay between "simulate power failure" and *S* -- by default set to 3.5s. You can control it through *cshdelay* option (allowed values are from 0 to 9.9). + The name came from APC CS models, where such trick was used to power down UPSes in consistent fashion using only *S*. It's better to use *@nnn* command if your UPS supports it (and is not too old, see below). *@nnn* (hard hibernate):: This is basic command used to hibernate UPS regardless if it's running on batteries or on mains. The option takes 3 digits argument which can be used to specify additional wake-up delay (in 6 minute units). + -- "old" models: :: The behaviour is -- unfortunately -- similarly primitive to *S*. The UPS unconditionally wakes up after $$nnn*6$$ minutes: *it doesn't care if the power returned !* + NOTE: If 'nnn = 000', then UPS will do precisely nothing. On those models you should better specify 'nnn > 0', if you can estimate the kind of power problems that might be happening in your environment. + Another thing to consider with "old" models -- you might lose the connection with the UPS, until it wakes up (with *S*, the serial connection is kept alive). "new" models: :: All the usual variables defined in EEPROM are respected (see *S*). Additionally, if 'nnn > 0', the $$nnn*6$$ minutes are added to EEPROM defined delay. UPS will not power up if it's running on batteries, contrary to what "old" models used to do -- the combined delay is counted from the moment of power return. -- + Supposedly there exist models that take 2 digits instead of 3. Just in case, NUT also supports such variation. You have to provide exactly 2 digits to trigger it (*awd* option, or argument to one of the supported instant commands). *K* (delayed poweroff):: This is permanent poweroff -- the UPS will not wake up automatically. On newer units, it will respect applicable EEPROM variables. *Z* (instant poweroff):: This is also permanent poweroff -- the UPS will not wake up automatically. The poweroff is executed immediately. SHUTDOWN CONTROL BY NUT ----------------------- There are three options used to control the shutdown behaviour. *sdtype*=[0-5]:: This option takes a single digit (0-5) as an argument. See below for details. *advorder*=no|[0-4]+:: This option takes string of digits as an argument. Methods listed are tried in turn until one of them succeeds. Note that the meaning of digits is different from *sdtype*. See below for details. *awd*=[0-9]{1,3}:: This option lets you specify additional wake-up delay used by *@*. If you provide exactly 2 digits, the driver will try 2 digits variation (see previous section for more info). Otherwise standard 3 digits variation is used. *Note: the time unit is 6 minutes !* Keep in mind that *sdtype* and *advorder* are mutually exclusive. If *advorder* is provided, *sdtype* is ignored. If *advorder* is set to 'no', *sdtype* is used instead. If nothing is provided, *NUT* will assume *sdtype*=0 -- which is generally fine for anything not too ancient or not too quirky. SDTYPE ~~~~~~ The values permitted are from 0 to 5. Only one can be specified. Anything else will cause apcsmart to exit. 0:: issue soft hibernate (*S*) if the UPS is running on batteries, otherwise issue hard hibernate (*@*) 1:: issue soft hibernate (*S*) (if on batteries), and if it fails (or on mains) -- try hard hibernate (*@*) 2:: issue instant poweroff (*Z*) 3:: issue delayed poweroff (*K*) 4:: issue "force OB hack" (*CS*) 5:: issue hard hibernate (*@*) NOTE: Hard hibernate's additional wake-up delay can be provided by *awd*. ADVORDER ~~~~~~~~ The argument is either a word 'no', or a string of 1..5 digits in [0..4] range. Each digit maps to the one of shutdown methods supported by APC UPSes. Methods listed in this way are tried in order, until one of them succeeds. If *advorder* is undefined or set to 'no', *sdtype* is used instead. The mapping is as follows: [horizontal] 0:: soft hibernate (*S*) 1:: hard hibernate (*@*) 2:: delayed poweroff (*K*) 3:: instant poweroff (*Z*) 4:: "force OB hack" (*CS*) NOTE: Hard hibernate's additional wake-up delay can be provided by *awd*. IGNORING LB STATE ----------------- APC units -- even if they report LB mode -- will not go into shutdown automatically. This gives us even more control with reference to "when to actually shutdown PSU". Since version 2.6.2, NUT supports *ignorelb* option in driver's section of linkman:ups.conf[5]. When such option is in effect, the core driver will ignore LB state as reported by specific driver and start shutdown basing the decision _only_ on two conditions: battery.charge < battery.charge.low *OR* battery.runtime < battery.runtime.low Of course -- if any of the variables are not available, the appropriate condition is not checked. If you want to explicitly disable one of the conditions, simply override the right hand variable causing the condition to always evaluate to false (you can even provide negative numbers). APC UPSes don't have `battery.charge.low` -- you will have to define it if you want to use such condition (prefix the variable with `override.` or `default.`). "New" units have `battery.runtime.low`, but depending on battery quality, firmware version, calibration and UPS load -- this variable can be underestimated quite a bit -- especially right after going into OB state. This in turn can cause LB to be asserted, which under normal conditions will cause *NUT* to initiate the shutdown. You might want to disable this condition entirely, when relying on *ignorelb* option (this was actually the main motivation behind introduction of such feature). Simple example: ---- [apc] ignorelb override.battery.charge.low = 15 override.battery.runtime.low = -1 ---- This would cause apcsmart to go into shutdown _only_ if detected battery charge < 15%. Runtime condition is always false in this example. You could ask -- why bother? Well, the reason is already hinted above. APC units can be very picky about the batteries, and their firmware can underestimate the remaining runtime (especially right after going into OB state). *ignorelb* option and *$$override.*$$* let you remain in control of the UPS, not UPS in control of you. Furthermore, this allows to specify conditions similarly to how it's done in apcupsd daemon, so it should be welcome by people used to that software. SUPPORTED INSTANT COMMANDS -------------------------- The apcsmart driver exposes following instant commands: shutdown.return:: executes soft hibernate shutdown.return cs:: executes "force OB hack" shutdown.return at::: executes "hard hibernate" with $$*6$$ minutes additional wake-up delay ( format is the same as of *awd* option) shutdown.stayoff:: executes "delayed poweroff" load.off:: executes "instant poweroff" All the above commands must be issued 2nd time to have any effect (no less than 3 seconds, and no more than 15 seconds after the initial call). Those commands are mostly useful for manual testing, when your machine is not powered by the UPS you're testing. Other supported commands: - load.on - test.panel.start - test.failure.start - test.battery.start - test.battery.stop - bypass.start - bypass.stop - calibrate.start - calibrate.stop PREVIOUS DRIVER VERSION ----------------------- Previous driver is still available as *apcsmart-old*, should there be any need to use earlier version (bugs, incompatibilities with new functionality, etc.). In due time, *apcsmart-old* will be phased out completely, but this won't happen until the new version gets solid exposure with no pending issues. BUGS ---- Some older APC UPS models return bogus data in the status register during a front panel test. This is usually detected and discarded, but some other unexpected values have occasionally slipped through. APC UPS models with both USB and serial ports require a power cycle when switching from USB communication to serial, and perhaps vice versa. AUTHORS AND HISTORY ------------------- Nigel Metheringham (drawing heavily on the original `apcsmart` driver by Russell Kroll) wrote a driver called `newapc` for a time, which was renamed in the 1.5 series. In 2.6.2 that driver was renamed finally to `apcsmart-old`, being superseded by this updated version with new features which currently holds the `apcsmart` name, and is maintained by Michal Soltys . SEE ALSO -------- linkman:nutupsdrv[8], linkman:ups.conf[5], linkman:usbhid-ups[8], linkman:solis[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ // vim: tw=80 ai si ts=8 sts=4 sw=4 et : nut-2.8.3/docs/man/nutconf.80000644000200500020050000004115415001555050012510 00000000000000'\" t .\" Title: nutconf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTCONF" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutconf \- NUT configuration tool .SH "SYNOPSIS" .sp \fBnutconf\fR \-\-help .sp \fBnutconf\fR [\fIOPTIONS\fR] .SH "DESCRIPTION" .sp \fBnutconf\fR tool is used to create and manipulate NUT configuration files\&. It also supports device scanning (to suggest configuration of devices)\&. .SH "INSTALLATION" .sp The scanning feature depends on the very same compile time and run time dependencies as the \fBnut\-scanner\fR\&. .SH "OPTIONS" .PP \fB\-h\fR | \fB\-help\fR | \fB\-\-help\fR .RS 4 Display the help text\&. .RE .PP \fB\-v\fR | \fB\-\-verbose\fR .RS 4 Increase output verbosity (may be used multiple times)\&. .RE .PP \fB\-\-is\-configured\fR .RS 4 Checks whether NUT was configured, before\&. .RE .PP \fB\-\-system\fR .RS 4 System configuration directory shall be used\&. .RE .PP \fB\-\-local\fR \fIdirectory\fR .RS 4 Sets alternative configuration directory\&. .RE .PP \fB\-\-get\-mode\fR .RS 4 Prints current NUT configuration mode .RE .PP \fB\-\-set\-mode\fR \fImode\fR .RS 4 Sets NUT configuration mode\&. .sp Known modes are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} standalone .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} netserver .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} netclient .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} controlled .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} manual .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} none .RE .RE .SH "CONFIGURATION ENTRY SET/ADD OPTIONS" .sp These options mostly have 2 forms: \fI\-\-set\-\&...\fR or \fI\-\-add\-\&...\fR\&. .sp The difference is that the set options discard previous settings while the add options keep them\&. .sp Note that such options may be specified multiple times for one run (to enable setting multiple entries at once)\&. .PP \fB\-\-set\-monitor\fR | \fB\-\-add\-monitor\fR \fI\fR .RS 4 Sets/adds a NUT monitor\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arguments: .sp .if n \{\ .RS 4 .\} .nf \*(Aq\*(Aq \*(Aq[:]\*(Aq \*(Aq\*(Aq \*(Aq\*(Aq \*(Aq\*(Aq \*(Aq(\e"master\e"|\e"slave\e")\*(Aq .fi .if n \{\ .RE .\} .RE .RE .PP \fB\-\-set\-listen\fR | \fB\-\-add\-listen\fR \fI
    \fR \fI[]\fR .RS 4 Sets/adds \fBupsd\fR(8) daemon listen address\&. .RE .PP \fB\-\-set\-device\fR | \fB\-\-add\-device\fR \fI\fR .RS 4 Sets/adds a device (typically a UPS)\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arguments: .sp .if n \{\ .RS 4 .\} .nf \*(Aq\*(Aq \*(Aq\*(Aq \*(Aq\*(Aq \*(Aq[=]*\*(Aq .fi .if n \{\ .RE .\} .sp The attribute/value pairs follow device configuration syntax\&. Devices may have very different configuration attributes depending on the driver\&. Exhaustive description of them is beyond this man page and may be found in NUT documentation\&. .RE .RE .PP \fB\-\-set\-notifyflags\fR | \fB\-\-add\-notifyflags\fR \fI\fR \fI+\fR .RS 4 Sets/adds notification flags for the notification type\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Notification types are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIONLINE\fR (mains is present) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIONBATT\fR (mains is gone) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fILOWBATT\fR (remaining battery capacity is low) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIFSD\fR (shutdown was forced) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fICOMMOK\fR (communication with device established) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fICOMMBAD\fR (lost communication with device) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fISHUTDOWN\fR (system is going down, now) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIREPLBATT\fR (UPS battery needs replacing) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOCOMM\fR (device is unavailable) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOPARENT\fR (upsmon parent process died, shutdown is impossible) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fICAL\fR (calibration in progress) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOTCAL\fR (calibration finished) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIOFF\fR (UPS is administratively OFF or asleep, should wake up on command) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOTOFF\fR (UPS is no longer administratively OFF or asleep) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIBYPASS\fR (on bypass = powered, not protecting) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOTBYPASS\fR (no longer on bypass) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIALARM\fR (UPS is in an alarm state (has active alarms)) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOTALARM\fR (UPS is no longer in an alarm state (no active alarms)) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIOVER\fR (overloaded) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOTOVER\fR (no longer overloaded) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fITRIM\fR (trimming incoming voltage) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOTTRIM\fR (no longer trimming incoming voltage) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIBOOST\fR (boosting incoming voltage) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOTBOOST\fR (no longer boosting incoming voltage) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIOTHER\fR (UPS has at least one unclassified status token) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fINOTOTHER\fR (UPS has no unclassified status tokens anymore) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fISUSPEND_STARTING\fR (OS is entering sleep/suspend/hibernate mode) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fISUSPEND_FINISHED\fR (OS just finished sleep/suspend/hibernate mode) .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Notification flags: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fISYSLOG\fR (use syslogd to log the notification) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIWALL\fR (push a message to users\*(Aq terminals) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIEXEC\fR (execute a command) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIIGNORE\fR (don\(cqt act) .RE .RE .RE .PP \fB\-\-set\-notifymsg\fR \fI\fR \fI\fR .RS 4 Sets message for the specified notification type\&. .RE .PP \fB\-\-set\-shutdowncmd\fR \fI\fR .RS 4 Sets command used to shut the system down\&. .RE .PP \fB\-\-set\-user\fR | \fB\-\-add\-user\fR \fI\fR .RS 4 Sets/adds NUT user\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arguments: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI\fR (specifies user name)\&. For \fIupsmon\fR user, it has a special form of upsmon=(primary|master|secondary|slave) which specifies the monitoring mode\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIpassword=\fR sets password for the user .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIactions=\fR sets actions (\fISET\fR, \fIFSD\fR are supported) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIinstcmds=\fR sets instant commands allowed for the user (may be used multiple times) .RE .RE .RE .SH "SCANNING OPTIONS" .sp Availability of each scanning option depends on availability of various 3rd\-party libraries both at compile time and run time\&. .sp Run the tool with the \fB\-\-help\fR option to check which of the \fB\-\-scan\-\&...\fR options are actually supported\&. .sp All timeouts are in microseconds\&. .PP \fB\-\-scan\-snmp\fR \fI\fR \fI\fR \fI[=]*\fR .RS 4 Scans for SNMP devices on IP addresses from the specified range\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Known attributes are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fItimeout\fR device scan timeout .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIcommunity\fR SNMP community (default: \fBpublic\fR) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIsec\-level\fR security level (SNMPv3); one of \fBnoAuthNoPriv\fR \fBauthNoPriv\fR, \fBauthPriv\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIsec\-name\fR security name (SNMPv3); mandatory companion of \fBsec\-level\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIauth\-password\fR authentication password (SNMPv3); mandatory for \fBauthNoPriv\fR and \fBauthPriv\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIpriv\-password\fR privacy password (SNMPv3); mandatory for \fBauthPriv\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIauth\-protocol\fR authentication protocol (SNMPv3): \fBMD5\fR or \fBSHA\fR, \fBMD5\fR is the default .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIpriv\-protocol\fR priv\&. protocol (SNMPv3): \fBDES\fR or \fBAES\fR, \fBDES\fR is the default .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIpeer\-name\fR peer name .RE .RE .RE .PP \fB\-\-scan\-usb\fR .RS 4 Scans the USB bus for known devices .RE .PP \fB\-\-scan\-xml\-http\fR \fI[]\fR .RS 4 Scans for XML/HTTP devices on the network\&. .RE .PP \fB\-\-scan\-nut\fR \fI\fR \fI\fR \fI\fR \fI[]\fR .RS 4 Scans for NUT (pseudo\-)devices on the network\&. .RE .PP \fB\-\-scan\-avahi\fR \fI[]\fR .RS 4 Scans for Avahi devices\&. .RE .PP \fB\-\-scan\-ipmi\fR \fI\fR \fI\fR \fI[=]\fR* .RS 4 Scans for IPMI devices on IP addresses from the specified range\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Known attributes are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIusername\fR username (mandatory for IPMI/LAN) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIpassword\fR user password (mandatory for IPMI/LAN) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIauth\-type\fR authentication type (see below) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIcipher\-suite\-id\fR cipher suite ID (see below) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIK\-g\-BMC\-key\fR optional second key (???) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIpriv\-level\fR priv\&. level .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIworkaround\-flags\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIversion\fR (1\&.5 or 2\&.0) .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Authentication types: .sp Specifies the IPMI 1\&.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5)\&. This forces connection through the \fIlan\fR IPMI interface, thus in IPMI 1\&.5 mode\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fInone\fR (authentication is disabled) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIMD2\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIMD5\fR (default) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIplain\-password\fR (no ciphering used for password sending) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIOEM\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIRMCPplus\fR .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Cipher suite IDs: .sp Specifies the IPMI 2\&.0 cipher suite ID to use\&. .sp The Cipher Suite ID identifies a set of authentication, integrity, and confidentiality algorithms to use for IPMI 2\&.0 communication\&. .sp The authentication algorithm identifies the algorithm to use for session setup, the integrity algorithm identifies the algorithm to use for session packet signatures, and the confidentiality algorithm identifies the algorithm to use for payload encryption (default=3)\&. .sp The following cipher suite IDs are currently supported: .TS allbox tab(:); ltB ltB ltB ltB. T{ Code T}:T{ Authentication T}:T{ Integrity T}:T{ Confidentiality T} .T& lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt lt. T{ \fI0\fR T}:T{ None T}:T{ None T}:T{ None T} T{ \fI1\fR T}:T{ HMAC\-SHA1 T}:T{ None T}:T{ None T} T{ \fI2\fR T}:T{ HMAC\-SHA1 T}:T{ HMAC\-SHA1\-96 T}:T{ None T} T{ \fI3\fR T}:T{ HMAC\-SHA1 T}:T{ HMAC\-SHA1\-96 T}:T{ AES\-CBC\-128 T} T{ \fI6\fR T}:T{ HMAC\-MD5 T}:T{ None T}:T{ None T} T{ \fI7\fR T}:T{ HMAC\-MD5 T}:T{ HMAC\-MD5\-128 T}:T{ None T} T{ \fI8\fR T}:T{ HMAC\-MD5 T}:T{ HMAC\-MD5\-128 T}:T{ AES\-CBC\-128 T} T{ \fI11\fR T}:T{ HMAC\-MD5 T}:T{ MD5\-128 T}:T{ None T} T{ \fI12\fR T}:T{ HMAC\-MD5 T}:T{ MD5\-128 T}:T{ AES\-CBC\-128 T} T{ \fI15\fR T}:T{ HMAC\-SHA256 T}:T{ None T}:T{ None T} T{ \fI16\fR T}:T{ HMAC\-SHA256 T}:T{ HMAC_SHA256_128 T}:T{ None T} T{ \fI17\fR T}:T{ HMAC\-SHA256 T}:T{ HMAC_SHA256_128 T}:T{ AES\-CBC\-128 T} .TE .sp 1 .RE .RE .PP \fB\-\-scan\-serial\fR \fI\fR* .RS 4 Scans for serial devices (of supported types) on the specified serial port(s)\&. .RE .SH "EXAMPLES" .sp To set alternative directory for configuration files: .sp .if n \{\ .RS 4 .\} .nf :; nutconf \-\-local ~/test/nut/etc .fi .if n \{\ .RE .\} .sp To add another user (keeping the existing ones): .sp .if n \{\ .RS 4 .\} .nf :; nutconf \-\-add\-user bart password=qwerty .fi .if n \{\ .RE .\} .sp To scan USB devices and serial devices (on the first two ports): .sp .if n \{\ .RS 4 .\} .nf :; nutconf \-\-scan\-usb \-\-scan\-serial /dev/ttyS1 /dev/ttyS2 .fi .if n \{\ .RE .\} .SH "SEE ALSO" .sp \fBups.conf\fR(5) \fBnut-scanner\fR(8) .SH "INTERNET RESOURCES" .sp The NUT (Network UPS Tools) home page: http://www\&.networkupstools\&.org/ nut-2.8.3/docs/man/mge-utalk.txt0000644000200500020050000000461715001555412013377 00000000000000MGE-UTALK(8) ============ NAME ---- mge-utalk - Driver for MGE UPS SYSTEMS UTalk protocol equipment SYNOPSIS -------- *mge-utalk* -h *mge-utalk* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the mge-utalk driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ mge-utalk supports the following legacy units, using the MGE UTalk protocol: * Pulsar ESV+ * Pulsar ES+ * Pulsar EL * Pulsar EX * Pulsar EXtreme * Comet EXtreme * Comet (Utalk Serial Card, ref 66060) * Galaxy (Utalk Serial Card, ref 66060) This driver also support some newer models with backward UTalk compatibility, such as Pulsar Evolution and Pulsar EXtreme C. As these models also support the SHUT protocol, prefer linkman:mge-shut[8] for serial communication, or use the USB port, if available, with the linkman:usbhid-ups[8]] driver. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *lowbatt*='num':: Set the low battery warning threshold at which shutdown is initiated by linkman:upsmon[8]. + The factory default value is '30' (in percent), and can be settable depending on the exact model. *offdelay*='num':: Set the timer before the UPS is turned off after the kill power command is sent (via the `-k` switch). + The default value is 20 (in seconds). *ondelay*='num':: Set the delay before the UPS is turned on, after the power returns. + The default value is 1 (in minutes). *oldmac*:: Set this flag if you are running Linux on an Oldworld Macintosh box (all beige Apple Macintosh). This might also be needed for other OSs (like *BSD) running on PowerMac. KNOWN ISSUES ------------ Repetitive timeout and staleness ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Older models, such as ES/ESV ones, might report repetitive "data stale" errors. This is due to the fact that these models don't support too much polling. To solve this problem, add `pollinterval=20` in `ups.conf`, and change the value of `MAXAGE` to '25' in `upsd.conf`, and `DEADTIME` to '25' in `upsmon.conf`. AUTHORS ------- * Hans Ekkehard Plesser * Arnaud Quette * Martin Loyer * Patrick Agrain * Nicholas Reilly * Dave Abbott * Marek Kralewski SEE ALSO -------- The core driver ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/netxml-ups.txt0000644000200500020050000001012215001555412013611 00000000000000netxml-ups(8) ============= NAME ---- netxml-ups - Driver for Eaton / MGE Network Management Card / Proxy (XML/HTTP Protocol) equipment SYNOPSIS -------- *netxml-ups* -h *netxml-ups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the netxml-ups driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ netxml-ups supports all recent Eaton / MGE models which use a Network Management Card or Proxy (MGE XML/HTTP protocol based). This applies to both Eaton (previously MGE Office Protection Systems) and to MGE UPS SYSTEMS. Supported card and proxy models are: * NMC Minislot (Ref 66102, firmware EA or newer), * SNMP/Web Minislot card (Ref 66244) * NMC Transverse (Ref 66074), * NMC & Modbus/JBus (Ref 66103), * Network Management Proxy, * ePDU Monitored (newer version). Older models, such as SNMP card (Ref 66062 and Ref 66045), use the SNMP protocol and should use the linkman:snmp-ups[8] driver with the `mibs=mge` parameter. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *timeout*='value':: The timeout for connecting to and reading from the UPS. Defaults to 5 seconds. Don't change this value unless you know exactly what you're doing. + This value *must never* be higher than half the `MAXAGE` value specified in linkman:upsd.conf[5], otherwise you run the risk that linkman:upsd[8] declares the driver stale while it is waiting for a connection to timeout. *subscribe*:: Connect to the NMC in subscribed mode. This allows to receive notifications and alarms more quickly, beside from the standard polling requests. *login*='value':: Set the login value for authenticated mode. This feature also needs the *password* argument, and allows value settings in the card. This feature is not used yet. *password*='value':: Set the password value, needed with the login for authenticated mode. This feature is not used yet. *shutdown_duration*='value':: Set the shutdown duration of the operating system, in seconds. This represents the amount of time needed by the system to operate a clean shutdown. Defaults to 120 seconds. *shutdown_timer*='value':: Set the shutdown timer, in seconds. After 'value' seconds running on battery, the local system will receive a notification to shut down. Defaults to "none" (disabled). *do_convert_deci*:: If this flag value is present, the driver assumes you have a very old MGE networked UPS (or rather an old network management card firmware) which serves certain measurements spelled 10x too big in the XML markup. + Originally such measurements were decimated by the driver -- but this is wrong for newer, more sane, devices -- so this behavior was deprecated and is now disabled by default. Enabling this flag in configuration of a particular driver instance restores the old behavior for those measurements. IMPLEMENTATION -------------- The hostname of the networked UPS is specified with the `port` value in `ups.conf`, i.e.: [mgexml] driver = netxml-ups port = http://netxml-ups.example.com:80 Specifying the method to connect to the UPS (http, https) is mandatory. If the port is equal to the default for the method specified (80 for http, 443 for https) it may be omitted. In order not to overload older NMCs by polling them too frequently, it is recommended to increase the "pollinterval" (see linkman:nutupsdrv[8]) and linkman:ups.conf[5]) to at least 5 seconds. KNOWN ISSUES ------------ Don't connect to the UPS through a proxy. Although it would be trivial to add support for proxies, this is not recommended and don't ask for it. Not only because it will prevent the driver to make a persistent connection to the UPS, but also it adds an additional failure mode. If the proxy goes down (for whatever reason), the driver will no longer be able to reach the UPS. AUTHORS ------- Arjen de Korte SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_disconnect.txt0000644000200500020050000000146215001555412015214 00000000000000UPSCLI_DISCONNECT(3) ==================== NAME ---- upscli_disconnect - Disconnect from a UPS server SYNOPSIS -------- ------ #include int upscli_disconnect(UPSCONN_t *ups); ------ DESCRIPTION ----------- The *upscli_disconnect()* function takes the pointer 'ups' to a `UPSCONN_t` state structure, shuts down the connection to the server, and frees dynamic memory used by the state structure. The `UPSCONN_t` structure is no longer valid after this function is called. This function must be called, or your program will leak memory and file descriptors. RETURN VALUE ------------ The *upscli_disconnect()* function returns '0' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_connect[3], linkman:upscli_fd[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/nutclient_device_forced_shutdown.30000644000200500020050000000003515001555117017625 00000000000000.so man3/libnutclient_misc.3 nut-2.8.3/docs/man/upsdrvctl.txt0000644000200500020050000002720615001555412013536 00000000000000UPSDRVCTL(8) ============ NAME ---- upsdrvctl - Network UPS Tools driver controller SYNOPSIS -------- *upsdrvctl* -h *upsdrvctl* ['OPTIONS'] {start | stop | shutdown | status} ['ups'] *upsdrvctl* ['OPTIONS'] {list | -l} ['ups'] *upsdrvctl* ['OPTIONS'] -c COMMAND ['ups'] DESCRIPTION ----------- *upsdrvctl* provides a uniform interface for controlling your UPS drivers. You should use `upsdrvctl` command instead of direct calls to the drivers whenever possible. When used properly, `upsdrvctl` lets you maintain identical startup scripts across multiple systems with different UPS configurations. [WARNING] ========= For operating systems with service management frameworks, such as Solaris/illumos SMF or Linux systemd, the linkman:upsdrvsvcctl[8] may be a better choice. In fact, service instances prepared by linkman:nut-driver-enumerator[8] based on contents of your linkman:ups.conf[5] file and automatically maintained by the respective framework can conflict with manual execution of drivers. In this case, `upsdrvctl` would emit a warning in NUT builds with that capability (can be silenced by exporting a `NUT_QUIET_INIT_NDE_WARNING` environment variable with any value). ========= You may be required to stop service units (if used) and run driver programs directly rather than via `upsdrvctl` for troubleshooting, e.g. to facilitate debug log collection or test any custom builds of drivers without conflict with a normally running packaged instance. OPTIONS ------- *-h*:: Display the help text. *-r* 'directory':: If starting a driver, this value will direct it to linkmanext:chroot[2] into 'directory'. This can be useful when securing systems. + This may be set in the linkman:ups.conf[5] with the +chroot+ directive in the global section. *-t*:: Enable testing mode. This also enables debug mode. Testing mode makes upsdrvctl display the actions it would execute without actually doing them. Use this to test out your configuration without actually doing anything to your UPS drivers. + This may be helpful when defining the +sdorder+ directive in your linkman:ups.conf[5] section for the device. *-u* 'username':: If starting a driver, this value will direct it to linkmanext:setuid[2] to the user id associated with 'username'. + If the driver is started as 'root' without specifying this value, it will use the username that was compiled into the binary. This defaults to 'nobody' (if not otherwise configured), which is far from ideal. + This may be set in linkman:ups.conf[5] with the +user+ directive in the global section. *-D*:: Raise the debug level. Use this multiple times for additional details. + Note that this does not preclude the `upsdrvctl` tool from exiting after its job is done (however an explicit *-F* option does). + Also note that this option alone modifies the debug verbosity of the tool, but not of the drivers it launches. See the additional *-d* option for that. *-d*:: Pass the selected debug level from `upsdrvctl` to launched drivers. + Note that by default for NUT daemons, enabled debugging means running in foreground mode; you can specify *-B* additionally to avoid that. *-F*:: Driver will run in the foreground (not fork away from the `upsdrvctl` process), regardless of debugging settings. It would also keep the tool program itself foregrounded with driver daemons running as its children (in case of a single driver startup, it would not even fork). + It would also not wait for drivers to complete initialization, so `upsdrvctl` will warn about such situations. + Specify twice (`-FF` or `-F -F`) to save the driver PID file even in this mode (not saved by default when staying in foreground). *-B*:: Drivers will run in the background, regardless of debugging settings, as set by *-D* and passed-through by *-d* options. *-l*:: Alias for `list` command. COMMANDS -------- `upsdrvctl` supports three active commands -- `start`, `stop` and `shutdown`. It also supports passing requests to running drivers using `-c COMMAND` syntax, similar to that in some other daemons. A couple of helper commands are also available -- `list` and `status`. They all can take an optional argument which is a UPS name from linkman:ups.conf[5]. Without that argument, they operate on every UPS that is currently configured. NOTE: `upsdrvctl` can not manage devices not listed in `ups.conf` (such as test drivers started with `-s TMP` option). *start*:: Start the UPS driver(s). In case of failure to start within 'maxstartdelay' time-frame, further attempts may be executed by using the 'maxretry' and 'retrydelay' values. Conversely, the 'nowait' global option can be used, especially to speed up parallel start of many drivers. + See linkman:ups.conf[5] about these options. Built-in defaults are: 'maxstartdelay=75' (sec), 'maxretry=1' (meaning one attempt at starting), 'retrydelay=5' (sec). *stop*:: Stop the UPS driver(s). This does not send commands to the UPS. *shutdown*:: Command the UPS driver(s) to run their shutdown sequence. This assumes that the driver is no longer running, and starts a fresh instance via `drivername -k`. It is intended to be used as the last step in system shutdown, after the filesystems are no longer mounted 'rw'. Drivers are stopped according to their `sdorder` value -- see linkman:ups.conf[5]. WARNING: This will probably power off your computers, so don't play around with this option. Only use it when your systems are prepared to lose power. NOTE: Refer to linkman:ups.conf[5] for using the *nowait* parameter. It can be overridden by `NUT_IGNORE_NOWAIT` environment variable (e.g. used to work around certain issues with systemd otherwise). *list*:: Without a further argument, report all currently known device configuration names to `stdout`, one per line. With an argument, also try to report that name, but exit with an error code if that name is not known. NOTE: The tool would exit with an error if `ups.conf` file is not found, readable, or does not define any device sections (whose names are reported here and managed in other commands). NOTE: The tool name and NUT version banner line is also printed to `stdout` before any other processing. This can be suppressed by `NUT_QUIET_INIT_BANNER` environment variable (exported by caller and empty or "true"): :; NUT_QUIET_INIT_BANNER=true upsdrvctl list dummy UPS1 UPS2 *status*:: Similar to `list`, but reports more information -- also the driver name, the PID if it is running, and result of a signal probe to check it is responding. The `NUT_QUIET_INIT_BANNER` suppression can be helpful for scripted parsing. If there is anything to print (at least one device is known), the first line of status report would be the heading with column names: :; NUT_QUIET_INIT_BANNER=true upsdrvctl status UPSNAME UPSDRV RUNNING PF_PID S_RESPONSIVE S_PID S_STATUS dummy dummy-ups N/A -3 NOT_RESPONSIVE N/A eco650 usbhid-ups RUNNING 3559207 RESPONSIVE 3559207 "OL" UPS2 dummy-ups RUNNING 31455 RESPONSIVE 31455 "OL BOOST" + Values are TAB-separated, but UPSNAME and UPSDRV may be padded by spaces on the right and on the left respectively. Any complex string values would be encased in double-quotes. + Fields reported (`PF_*` = according to PID file, if any; `S_*` = via socket protocol): + -- *UPSNAME*;; driver section configuration name *UPSDRV*;; driver program name per `ups.conf` *RUNNING*;; `RUNNING` if `PF_PID` or `S_PID` is valid, `STOPPED` if at least one PID value was parsed but none was found running with a correct program name; `N/A` if no PID file/socket reply or failed to parse. First the PID file is consulted, but it may be absent either due to command-line parameters of daemons, or due to platform (WIN32). If no PID value was found and confirmed this way, we fall back to checking the PID reported via protocol (if available and different). *PF_PID*;; PID of driver according to PID file (if any), or some negative values upon errors (as defined in `common.c`) including an absent PID file, invalid contents, or unsupported platform for this mechanism (e.g. WIN32) *S_RESPONSIVE*;; `RESPONSIVE` if `PING`/`PONG` during socket protocol session setup succeeded; `NOT_RESPONSIVE` otherwise *S_PID*;; PID of driver according to `GETPID` active query, or `N/A` if the query failed *S_STATUS*;; Quoted value of `ups.status` variable -- + This mode does not discover drivers that are not in `ups.conf` (e.g. started manually for experiments with many `-x` CLI options). *-c* 'command':: Send 'command' to the background process as a signal. Valid commands are: + -- *dump*;; tell the driver(s) to dump currently known state information to their `stdout` (if attached anywhere) *reload*;; reread configuration files, ignoring modified settings which can not be applied "on the fly" *reload-or-error*;; reread configuration files, ignoring but counting changed values which require a driver restart (can not be changed on the fly), and return a success/fail code based on that count, so the caller can decide the fate of the currently running driver instance *reload-or-exit*;; reread configuration files, exiting the old driver process if it encounters modified settings which can not be applied "on the fly" (so caller like systemd can launch another copy of the driver) ///////// *reload-or-restart*;; reread configuration files, causing the old driver process to close the device connection and re-exec itself if it encounters modified settings which can not be applied "on the fly" (may fail for critical changes like run-time user/group accounts) ///////// *exit*;; tell the currently running driver instance to just exit (so an external caller like the new driver instance, or the systemd or SMF frameworks would start another copy) -- If the `upsdrvctl` was launched to remain in memory and manage NUT driver processes, it can receive supported signals and pass them to those drivers. ENVIRONMENT VARIABLES --------------------- *NUT_DEBUG_LEVEL* sets default debug verbosity if no *-D* arguments were provided on command line, but does not request that the daemon runs in foreground mode. *NUT_CONFPATH* is the path name of the directory that contains `ups.conf` and other configuration files. If this variable is not set, *upsdrvctl* (and the drivers) use a built-in default, which is often `/usr/local/ups/etc`. *NUT_ALTPIDPATH* is the path name of the directory in which *upsd* and drivers store .pid files. If this variable is not set, *upsd* and drivers use either *NUT_STATEPATH* if set, or ALTPIDPATH if set, or otherwise the built-in default *STATEPATH*. DIAGNOSTICS ----------- `upsdrvctl` will return a nonzero exit code if it encounters an error while performing the desired operation. This will also happen if a driver takes longer than the 'maxstartdelay' period to enter the background. SEE ALSO -------- linkman:upsdrvsvcctl[8], linkman:nut-driver-enumerator[8], linkman:nutupsdrv[8], linkman:upsd[8], linkman:ups.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_display_parsable.30000644000200500020050000000606515001555061016104 00000000000000'\" t .\" Title: nutscan_display_parsable .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_DISPLAY_PARS" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_display_parsable \- Display the specified `nutscan_device_t` structure on stdout\&. .SH "SYNOPSIS" .sp .nf #include void nutscan_display_parsable(nutscan_device_t * device); .fi .SH "DESCRIPTION" .sp The \fBnutscan_display_parsable()\fR function displays all NUT devices in \fIdevice\fR to stdout\&. It displays them in a way that can be easily parsed, which is: .sp .if n \{\ .RS 4 .\} .nf :driver="",port=""[,="",="",\&.\&.\&.] .fi .if n \{\ .RE .\} .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} may be one of USB, SNMP, XML, NUT, IPMI or AVAHI\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} is the name of the driver\(cqs binary corresponding to this device\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} and depend on , see the corresponding driver\(cqs man page\&. .RE .sp Note that this format is for machine consumption, so is not associated with sanity checks that may be used along with display method for the ups\&.conf file format\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/hosts.conf.txt0000644000200500020050000000271615001555412013573 00000000000000HOSTS.CONF(5) ============= NAME ---- hosts.conf - Access control for Network UPS Tools CGI programs DESCRIPTION ----------- The CGI programs (linkman:upsset.cgi[8], linkman:upsstats.cgi[8], linkman:upsimage.cgi[8]) use this file to determine if they are allowed to talk to a host. This keeps random visitors from using your web server to annoy others by creating outgoing connections. IMPORTANT NOTES --------------- * Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message). * This file does not contain passwords. Read-only monitoring in NUT is anonymous, and the linkman:upsset[8] program asks for credentials in the browser session when commanding a particular UPS (web-server should be secured, as reported to the program by linkman:upsset.conf[5] file). DIRECTIVES ---------- *MONITOR* 'ups' 'description':: The 'ups' element is in the form `upsname[@hostname[:port]]`. + To allow connections to an UPS called "snoopy" on a system called "doghouse" that runs `upsd` on port 7877, it would look like this: MONITOR snoopy@doghouse:7877 "Joe Cool" + The description must be one element, so if it has spaces, then it must be wrapped with quotes as shown above. The default hostname is "localhost". SEE ALSO -------- linkman:upsset.cgi[8], linkman:upsstats.cgi[8], linkman:upsimage.cgi[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_new_device.txt0000644000200500020050000000210115001555412015336 00000000000000NUTSCAN_NEW_DEVICE(3) ====================== NAME ---- nutscan_new_device - Create a new nutscan_device_t structure. SYNOPSIS -------- ------ #include nutscan_device_t * nutscan_new_device(void); ------ DESCRIPTION ----------- The *nutscan_new_device()* function allocates a new `nutscan_device_type_t` structure. RETURN VALUE ------------ The *nutscan_new_device()* function returns the newly allocated `nutscan_device_type_t` structure. NOTES ----- Technically, the function is currently defined in 'nutscan-device.h' file. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3] linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3] linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3] linkman:nutscan_add_device_to_device[3] nut-2.8.3/docs/man/bestups.80000644000200500020050000001417515001555066012533 00000000000000'\" t .\" Title: bestups .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BESTUPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" bestups \- Driver for Best Power / SOLA (Phoenixtec protocol) UPS equipment .SH "SYNOPSIS" .sp \fBbestups\fR \-h .sp \fBbestups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the bestups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "NOTE" .sp Please note that this driver is deprecated and will not receive new development\&. If it works for managing your devices \(em fine, but if you are running it to try setting up a new device, please consider the newer \fBnutdrv_qx\fR(8) instead, which should handle all \fIQ*\fR protocol variants for NUT\&. .sp If your device works with this driver, but does not work with \fBnutdrv_qx\fR(8), please report this via the mailing list or issue tracker\&. .SH "SUPPORTED HARDWARE" .sp \fBbestups\fR was designed to monitor Best Power UPS hardware like the Fortress, Fortress Telecom, Axxium Rackmount and Patriot Pro\&. It also recognizes and supports SOLA units such as the 325, 520 and 620\&. In addition, the Best 610 is supported using the \(oqID\(cq option\&. .sp Other UPS hardware using the Phoenixtec protocol should also work, but they will generate a warning since their battery information is not known\&. .sp This driver does not support some older Best/SOLA units\&. (For older Fortress units, see \fBbestfortress\fR(8)\&.) .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBnombattvolt=\fR\fInum\fR .RS 4 Override the battery float voltage which is normally determined by asking the hardware\&. This is useful if your UPS constantly reports battery\&.charge values just below 100% even when it\(cqs completely charged\&. .sp If you have this problem, set this to whatever battery\&.voltage reports when the UPS is known to be completely charged with a good battery\&. .sp The author\(cqs Best Fortress 750 uses nombattvolt=27\&.4\&. .RE .PP \fBbattvoltmult=\fR\fInum\fR .RS 4 Multiply the reported battery voltage by this number\&. Some devices report only a fraction of the total battery voltage\&. .sp For example, the SOLA 610 700VA UPS (with a 24V battery) reports the single cell voltage (about 2\&.27V when fully charged)\&. In this particular case you can set battvoltmult = 12 in \fBups.conf\fR(8) to fix this\&. .RE .PP \fBID=\fR\fIstring\fR .RS 4 Set the Identification response string\&. This should only be used with hardware that supports the Phoenixtec protocol status inquiry commands, but not the "ID" command, such as the Best/SOLA 610\&. Format of the ID string is: AAA,BBBB,CCC,DDD,EE\&.E,FF\&.F .sp AAA is the three\-character identification for the UPS model\&. .sp BBBB is the output power in VA (volt amperes)\&. B is an integer number ranging from 0 to 9\&. .sp CCC is the Nominal Input Voltage\&. C is an integer number ranging from 0 to 9\&. The unit is Volts AC\&. .sp DDD is the Nominal Output Voltage\&. D is an integer number ranging from 0 to 9\&. The unit is Volts AC\&. .sp EE\&.E is the Battery Voltage that will cause the UPS to shut itself off\&. E is an integer number ranging from 0 to 9\&. Then unit is Volts DC and a decimal point is present\&. .sp FF\&.F or FFF\&.F is the Battery Voltage at full charge\&. F is an integer number ranging from 0 to 9\&. Then unit is Volts DC\&. Typically, for 700VA, 1KVA and 1\&.5KVA units, the format is FF\&.F\&. For 2KVA and 3KVA units, the format is FFF\&.F\&. .sp Example: a Best 610 1\&.5KVA unit would use the string "610,1500,120,120,10\&.0,48\&.0"\&. .RE .SH "BUGS" .sp The battery charge percentage value (in battery\&.charge) is derived from the voltage data that the UPS returns, since the UPS doesn\(cqt return that value directly\&. On some hardware, the charge will remain at 100% for a long time and then drops quickly shortly before the battery runs out\&. You can confirm from the battery\&.voltage readings that this is a problem with the UPS and not this driver\&. .sp Similarly, the float from the charger in some models forces the battery charge percentage back up to 100% immediately after the UPS goes back on\-line, so you can\(cqt tell when it is really recharged\&. .sp Finally, some models give one value for the battery\(cqs nominal voltage and yet actually have a nominal voltage slightly below that\&. This leads to things such as the perpetual 98\&.7% charge on the author\(cqs Fortress 750, even when it\(cqs been charging for weeks\&. You can use nombattvolt= in \fBups.conf\fR(8) to fix this\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Russell Kroll .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Jason White .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nut-recorder.txt0000644000200500020050000000301615001555412014112 00000000000000NUT-RECORDER(8) =============== NAME ---- nut-recorder - Utility to record device status and values changes SYNOPSIS -------- *nut-recorder* 'device-name' [output-file] [interval] DESCRIPTION ----------- *nut-recorder* is an utility to record sequences from running devices (such as power failures, or any other value changes) from linkman:upsd[8] data server, and dump it in a `.seq` format. The `.seq` file can then be used by the linkman:dummy-ups[8] driver to replay the sequence. OPTIONS ------- 'device-name':: Record the changes of this device. The format for this option is 'devname[@hostname[:port]]'. The default hostname is "localhost". 'output-file':: Optional. Data will be saved to this file. The default is 'dummy-device.seq'. 'interval':: Optional. The status of the device will be checked every 'interval'. The default is 5 seconds. EXAMPLES -------- To record data from 'ups1@host1' every 10 seconds: :; nut-recorder ups1@host1' ups1-output.seq 10 . . . battery.charge: 100.0 battery.voltage: 13.9 battery.voltage.nominal: 13.6 ups.status: OL . . . battery.charge: 90.0 ups.status: OB . . . You can then define a dummy device in linkman:ups.conf[5]: [ups-test] driver = dummy-ups port = ups1-output.seq AUTHOR ------ Arnaud Quette SEE ALSO -------- The dummy-ups driver: ~~~~~~~~~~~~~~~~~~~~~ linkman:dummy-ups[8] The logging daemon: ~~~~~~~~~~~~~~~~~~~ linkman:upslog[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/adelsystem_cbi.80000644000200500020050000000765015001555101014023 00000000000000'\" t .\" Title: adelsystem_cbi .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "ADELSYSTEM_CBI" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" adelsystem_cbi \- Driver for the ADELSYSTEM CB/CBI DC\-UPS .SH "SYNOPSIS" .sp \fBadelsystem_cbi\fR \-h .sp \fBadelsystem_cbi\fR \-a \fIDEVICE_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the \fBadelsystem_cbi\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This is the driver for the adelsystem cb/cbi dc\-ups devices\&. .sp The driver has been tested against CBI2801224A, all in one 12/24Vdc DC\-UPS\&. .PP More information about this UPS can be found here: .RS 4 https://www\&.adelsystem\&.com/en/products/dc\-ups\-/ .RE .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file: .SS "Serial:" .PP \fBser_baud_rate\fR=\fIvalue\fR .RS 4 A integer specifying the serial port baud rate (default 9600)\&. .RE .PP \fBser_data_bit\fR=\fIvalue\fR .RS 4 A integer specifying the serial port data bit (default 8)\&. .RE .PP \fBser_parity\fR=\fIvalue\fR .RS 4 A character specifying the serial port parity (default N)\&. .RE .PP \fBser_stop_bit\fR=\fIvalue\fR .RS 4 An integer specifying the serial port stop bit (default 1)\&. .RE .SS "Modbus:" .PP \fBdev_slave_id\fR=\fIvalue\fR .RS 4 An integer specifying the device modbus slave ID (default 1)\&. .RE .SH "CONFIGURATION" .sp Here is an example of adelsystem_cbi driver configuration in \fBups\&.conf\fR file: .sp .if n \{\ .RS 4 .\} .nf [adelsystem_cbi] driver = adelsystem_cbi port = /dev/ttyUSB0 desc = "adelsystem cb/cbi ups driver" # serial settings ser_baud_rate = 9600 ser_parity = N ser_data_bit = 8 ser_stop_bit = 1 # modbus slave id dev_slave_id = 5 .fi .if n \{\ .RE .\} .SH "INSTANT COMMANDS" .sp This driver support the following instant commands: .PP load\&.off .RS 4 executes "instant poweroff" .RE .SH "INSTALLATION" .sp This driver may be not built by default\&. You can build it by installing libmodbus and running configure \-\-with\-modbus=yes\&. .sp You also need to give proper permissions on the local serial device file (/dev/ttyUSB0 for example) to allow the run\-time NUT driver user account to access it\&. .SH "AUTHOR" .sp Dimitris Economou .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8), \fBups.conf\fR(5) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} libmodbus home page: http://libmodbus\&.org .RE nut-2.8.3/docs/man/bestfortress.80000644000200500020050000000526115001555066013567 00000000000000'\" t .\" Title: bestfortress .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BESTFORTRESS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" bestfortress \- Driver for old Best Fortress UPS equipment .SH "SYNOPSIS" .sp \fBbestfortress\fR \-h .sp \fBbestfortress\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the bestfortress driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports old Best Fortress UPS equipment using a serial connection\&. .sp One example is the "Fortress LI660", sold in (at least) 1995\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBbaudrate\fR=\fInum\fR .RS 4 Set the speed of the serial connection \(em 1200, 2400, 4800 or 9600\&. .RE .PP \fBmax_load\fR=\fIVA\fR .RS 4 Set the full\-scale value of the \fBups\&.load\fR variable\&. .RE .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Holger Dietze .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Stuart D\&. Gathman .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "The newer Best Power drivers:" .sp \fBbestups\fR(8), \fBbestuferrups\fR(8), \fBbestfcom\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upscode2.txt0000644000200500020050000000546015001555412013232 00000000000000UPSCODE2(8) =========== NAME ---- upscode2 - Driver for UPScode II compatible UPS equipment SYNOPSIS -------- *upscode2* -h *upscode2* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the upscode2 driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports UPS equipment which can be controlled via the UPScode II protocol. This is mainly Fiskars, Powerware equipment, but also some (probably OEM'ed) products from Compaq. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *manufacturer*='value':: Autodetection of this parameter is not possible yet (and it probably never will be). Therefore, this user-defined string accepts any name. The default is 'unknown'. *input_timeout*='value':: The timeout waiting for a response from the UPS. Some UPS models have shown to be rather slow, resulting in frequent messages about empty responses from the UPS. If you see this, try increasing this value. *output_pace*='value':: Delay between characters sent to the UPS. This was added for completeness with the above parameter. It has not shown to be needed yet. *baudrate*='value':: The default baudrate is 1200, which is the standard for the UPScode II protocol. *full_update_timer*='value':: Number of seconds between collection of normative values. *use_crlf*:: Flag to set if commands towards to UPS need to be terminated with CR-LF, and not just CR. *use_pre_lf*:: Flag to set if commands towards to UPS need to be introduced with an LF. A Compaq T1500h is known to need this. COMMANDS -------- The driver supports the following commands for those UPSes that support them. The available commands are autodetected during initialization, so you should check availability with 'upscmd -l'. * test.panel.start - Start UPS self test * test.battery.start - Start battery self test * beeper.enable - Enable UPS beeper * beeper.disable - Disable UPS beeper * shutdown.return - Shut down in 1 second and wait for power to return * shutdown.stayoff - Shut down in 1 seconds * shutdown.reboot - Shut down in 1 seconds and reboot after 1 minute * shutdown.reboot.graceful - Shut down in 20 seconds and reboot after 1 minute NOTES ----- The Powerware UPS models that this driver has been tested against until now have not returned a value for 'battery.charge'. Therefore, the driver will guesstimate a value based on the nominal battery min/max and the current battery voltage. AUTHORS ------- * Håvard Lygre * Niels Baggesen SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutclient_get_device_description.30000644000200500020050000000004015001555117017606 00000000000000.so man3/libnutclient_devices.3 nut-2.8.3/docs/man/upsd.conf.50000644000200500020050000003070015001555046012730 00000000000000'\" t .\" Title: upsd.conf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSD\&.CONF" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsd.conf \- Configuration for Network UPS Tools upsd data server .SH "DESCRIPTION" .sp \fBupsd\fR(8) uses this file to control access to the server and set some other miscellaneous configuration values\&. This file contains details on access controls, so keep it secure\&. Ideally, only the upsd process should be able to read it\&. .SH "IMPORTANT NOTES" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Balance the run\-time user permissions to access the file (and perhaps the directory it is in) for only upsd to be able to read it; write access is not needed\&. It is common to use chown root:nut and chmod 640 to set up acceptable file permissions\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Packages (and build recipes) typically prepare one set of user and group accounts for NUT\&. Custom builds with minimal configuration might even use nobody:nogroup or similar, which is inherently insecure\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} On systems with extra security concerns, NUT drivers and data server should run as separate user accounts which would be members of one same group for shared access to local Unix socket files and the directory they are in, but different groups for configuration file access\&. This would need some daemons to use customized user, group, RUN_AS_USER and/or RUN_AS_GROUP settings to override the single built\-in value\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Note that the monitoring, logging, etc\&. clients are networked\-only\&. They do not need access to these files and directories, and can run as an independent user and group altogether\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Keep in mind the security of also any backup copies of this file, e\&.g\&. the archive files it might end up in\&. .RE .RE .SH "CONFIGURATION DIRECTIVES" .PP \fBMAXAGE \fR\fB\fIseconds\fR\fR .RS 4 upsd usually allows a driver to stop responding for up to 15 seconds before declaring the data "stale"\&. If your driver takes a very long time to process updates but is otherwise operational, you can use MAXAGE to make upsd wait longer\&. .sp Most users should leave this at the default value\&. .RE .PP \fBTRACKINGDELAY \fR\fB\fIseconds\fR\fR .RS 4 When instant commands and variables setting status tracking is enabled, status execution information are kept during this amount of time, and then cleaned up\&. This defaults to 3600 (1 hour)\&. .RE .PP \fBALLOW_NO_DEVICE \fR\fB\fIBoolean\fR\fR .RS 4 Normally upsd requires that at least one device section is defined in ups\&.conf when the daemon starts, to serve its data\&. For automatically managed services it may be preferred to have upsd always running, and reload the configuration when power devices become defined\&. .sp Boolean values \fItrue\fR, \fIyes\fR, \fIon\fR and \fI1\fR mean that the server would not refuse to start with zero device sections found in ups\&.conf\&. .sp Boolean values \fIfalse\fR, \fIno\fR, \fIoff\fR and \fI0\fR mean that the server should refuse to start if zero device sections were found in ups\&.conf\&. This is the default, unless the calling environment sets a same\-named variable to enforce a value for the current run\&. One way this can happen is somebody un\-commenting it in the \fInut\&.conf\fR file used by init\-scripts and service unit method scripts\&. .RE .PP \fBALLOW_NOT_ALL_LISTENERS \fR\fB\fIBoolean\fR\fR .RS 4 Normally upsd requires that all LISTEN directives can be honoured at the moment the daemon starts\&. If your LAN IP address (or host name) used in one of the LISTEN directives may be not always accessible, and for some reason do not want to just LISTEN * on the wildcard interface, but e\&.g\&. you still want to use upsmon on localhost, this option can help\&. Note you would have to restart upsd to pick up the LISTEN\*(Aqed IP address if it appears later\&. .sp Boolean values \fItrue\fR, \fIyes\fR, \fIon\fR and \fI1\fR mean that the server would not refuse to start if it can listen on at least one interface\&. .sp Boolean values \fIfalse\fR, \fIno\fR, \fIoff\fR and \fI0\fR mean that the server should refuse to start if it can not LISTEN on each and every (non\-localhost) interface found in upsd\&.conf\&. This is the default, unless the calling environment sets a same\-named variable to enforce a value for the current run\&. One way this can happen is somebody un\-commenting it in the \fInut\&.conf\fR file used by init\-scripts and service unit method scripts\&. .RE .PP \fBSTATEPATH \fR\fB\fIpath\fR\fR .RS 4 Tell upsd to look for the driver state sockets in \fIpath\fR rather than the default that was compiled into the program\&. .sp Note that the drivers must use the same path, so upsd would prefer the same\-named setting from ups\&.conf global section, if present, over its own\&. .sp Environment variable NUT_STATEPATH set by caller (e\&.g\&. init script or service method) can override this setting\&. .RE .PP \fBLISTEN \fR\fB\fIinterface\fR\fR\fB \fR\fB\fIport\fR\fR .RS 4 Bind a listening port to the interface specified by its Internet address or name\&. This may be useful on hosts with multiple interfaces\&. You should not rely exclusively on this for security, as it can be subverted on many systems\&. .sp Optionally listen on TCP port \fIport\fR instead of the default value which was compiled into the code\&. This overrides any value you may have set with configure \-\-with\-port\&. If you don\(cqt change it with configure or this value, upsd will listen on port \fI3493\fR for this interface\&. .sp Multiple LISTEN addresses may be specified\&. The default is to bind to 127\&.0\&.0\&.1 if no LISTEN addresses are specified (and also ::1 if IPv6 support is compiled in)\&. .sp To listen on all available interfaces and configured IP addresses of your system, you may also use :: for IPv6 and 0\&.0\&.0\&.0 for IPv4, respectively\&. As a special case, a single LISTEN * directive (with an asterisk) will try to listen on both IPv6 (::0) and IPv4 (0\&.0\&.0\&.0) wild\-card IP addresses, subject to upsd command\-line arguments or system configuration\&. Note that if the system supports IPv4\-mapped IPv6 addressing per RFC\-3493, and does not allow to disable this mode, then there may be one listening socket to handle both address families\&. .sp .if n \{\ .RS 4 .\} .nf LISTEN 127\&.0\&.0\&.1 LISTEN 192\&.168\&.50\&.1 LISTEN myhostname\&.mydomain LISTEN ::1 LISTEN 2001:0db8:1234:08d3:1319:8a2e:0370:7344 .fi .if n \{\ .RE .\} .sp This parameter will only be read at startup\&. You\(cqll need to restart (rather than merely reload) upsd to apply any changes made here\&. .sp Please note that older NUT releases could have been using the IPv4\-mapped IPv6 addressing (sometimes also known as "dual\-stack") mode, if provided by the system\&. Current versions (since NUT v2\&.8\&.1 release) explicitly try to restrict their listening sockets to only support one address family on each socket, and so avoid IPv4\-mapped mode where possible\&. .RE .PP \fBMAXCONN \fR\fB\fIconnections\fR\fR .RS 4 This defaults to maximum number allowed on your system\&. Each UPS, each LISTEN address and each client count as one connection\&. If the server runs out of connections, it will no longer accept new incoming client connections\&. Only set this if you know exactly what you\(cqre doing\&. .RE .PP \fBCERTFILE \fR\fB\fIcertificate file\fR\fR .RS 4 When compiled with SSL support with OpenSSL backend, you can enter the certificate file here\&. .sp The certificates must be in PEM format and must be sorted starting with the subject\(cqs certificate (server certificate), followed by intermediate CA certificates (if applicable) and the highest level (root) CA\&. It should end with the server key\&. See docs/security\&.txt in NUT sources, or the Security chapter of NUT user manual, for more information on the SSL support in NUT\&. .RE .PP \fBCERTPATH \fR\fB\fIcertificate database\fR\fR .RS 4 When compiled with SSL support with NSS backend, you can enter the certificate path here\&. .sp Certificates are stored in a dedicated database (data split in 3 files)\&. Specify the path of the database directory\&. .RE .PP \fBCERTIDENT \fR\fB\fIcertificate name\fR\fR\fB \fR\fB\fIdatabase password\fR\fR .RS 4 When compiled with SSL support with NSS backend, you can specify the certificate name to retrieve from database to authenticate itself and the password required to access certificate related private key\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br Be sure to enclose "certificate name" in double\-quotes if you are using a value with spaces in it\&. .sp .5v .RE .RE .PP \fBCERTREQUEST \fR\fB\fIcertificate request level\fR\fR .RS 4 When compiled with SSL support with NSS backend and client certificate validation (disabled by default, see \(oqdocs/security\&.txt` in NUT sources), you can specify if upsd requests or requires clients\(cq certificates\&. .sp Possible values are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI0\fR to not request to clients to provide any certificate .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI1\fR to require to all clients a certificate .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI2\fR to require to all clients a valid certificate .RE .RE .PP \fBDISABLE_WEAK_SSL \fR\fB\fIBOOLEAN\fR\fR .RS 4 Tell upsd to disable older/weak SSL/TLS protocols and ciphers\&. With relatively recent versions of OpenSSL or NSS it will be restricted to TLSv1\&.2 or better\&. .sp Unless you have really ancient clients, you probably want to enable this\&. Currently disabled by default to ensure compatibility with existing setups\&. .RE .PP \fBDEBUG_MIN \fR\fB\fIINTEGER\fR\fR .RS 4 Optionally specify a minimum debug level for upsd data daemon, e\&.g\&. for troubleshooting a deployment, without impacting foreground or background running mode directly\&. Command\-line option \-D can only increase this verbosity level\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br If the running daemon receives a reload command, presence of the DEBUG_MIN NUMBER value in the configuration file can be used to tune debugging verbosity in the running service daemon (it is recommended to comment it away or set the minimum to explicit zero when done, to avoid huge journals and I/O system abuse)\&. Keep in mind that for this run\-time tuning, the DEBUG_MIN value \fBpresent\fR in \fBreloaded\fR configuration files is applied instantly and overrides any previously set value, from file or CLI options, regardless of older logging level being higher or lower than the newly found number; a missing (or commented away) value however does not change the previously active logging verbosity\&. .sp .5v .RE .RE .SH "SEE ALSO" .sp \fBupsd\fR(8), \fBnutupsdrv\fR(8), \fBupsd.users\fR(5) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/libupsclient-config.10000644000200500020050000000574115001555050014767 00000000000000'\" t .\" Title: libupsclient-config .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIBUPSCLIENT\-CONFIG" "1" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libupsclient-config \- Script to get information about the installed version of libupsclient .SH "SYNOPSIS" .sp \fBlibupsclient\-config\fR [\-\-version] [\-\-libs] [\-\-cflags] .SH "DESCRIPTION" .sp \fBlibupsclient\-config\fR is a tool that is used to determine the compiler and linker flags that should be used to compile and link programs that use the \fBlibupsclient\fR from the Network UPS Tools project (also known as the "upscli" API)\&. .sp It allows to simplify build automation for systems without a pkg\-config implementation which would instead use the libupsclient\&.pc file installed with the NUT development files\&. .sp Note that to rebuild current NUT with same settings as the installed NUT v2\&.8\&.1 or newer, you can use lib/libupsclient\-config \-\-config\-flags, where supported\&. Note that the pkg\-config manifest libupsclient\&.pc does not easily convey this information\&. .SH "OPTIONS" .sp \fBlibupsclient\-config\fR accepts the following options: .PP \fB\-\-version\fR .RS 4 Print the currently installed version of \fBlibupsclient\fR on the standard output\&. .RE .PP \fB\-\-libs\fR .RS 4 Print the linker flags that are necessary to link a \fBlibupsclient\fR program\&. .RE .PP \fB\-\-cflags\fR .RS 4 Print the compiler flags that are necessary to compile a \fBlibupsclient\fR program\&. .RE .PP \fB\-\-config\-flags\fR .RS 4 Print the flags passed to configure script when this installation of NUT was originally built (supported since release v2\&.8\&.1)\&. .RE .SH "AUTHORS" .sp This manual page was written by Arnaud Quette \&. .SH "SEE ALSO" .sp \fBupsclient\fR(3), \fBnutclient\fR(3) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan_add_device_to_device.txt0000644000200500020050000000324215001555412017325 00000000000000NUTSCAN_ADD_DEVICE_TO_DEVICE(3) =============================== NAME ---- nutscan_add_device_to_device - Concatenate two devices structure. SYNOPSIS -------- ------ #include nutscan_device_t * nutscan_add_device_to_device( nutscan_device_t * first, nutscan_device_t * second); ------ DESCRIPTION ----------- The `nutscan_device_t` contains the following variables: nutscan_device_type_t type; char * driver; char * alt_driver_names; char * port; nutscan_options_t opt; struct nutscan_device * prev; struct nutscan_device * next; This is a double linked list of device. Each device is described by its `type`, its `driver` name, its `port` and any number of optional data. The *nutscan_add_device_to_device()* concatenates 'first' and 'second' devices to a unique device. No new device is created, the two linked lists are simply linked to each other. So 'first' and 'second' devices are likely to be modified by this function. RETURN VALUE ------------ The *nutscan_add_device_to_device()* functions returns a pointer to a device containing both passed devices. Note that it's not a new device, so it is either 'first' or 'second' which is returned. NOTES ----- Technically, the function is currently defined in 'nutscan-device.h' file. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3] nut-2.8.3/docs/man/libnutclient.30000644000200500020050000000532715001555055013532 00000000000000'\" t .\" Title: libnutclient .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIBNUTCLIENT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libnutclient \- Network UPS Tools high\-level client access library .SH "SYNOPSIS" .sp .nf #include .fi .sp Refer to this file for more information\&. .SH "DESCRIPTION" .sp The Network UPS Tools (NUT) \fBnutclient\fR library provides a number of useful functions for programs to use when communicating with \fBupsd\fR(8)\&. It provides high\-level representation of NUT data through client connection, devices, variables and commands\&. Unlike \fBupsclient\fR(3) (also known as "upscli" API), here all low\-level protocol details are hidden\&. .sp State is maintained across calls in an opaque structure called NUTCLIENT_t\&. Callers are expected to create one per client connection\&. These will be provided to most of the \fBnutclient\fR functions\&. The format of this structure is subject to change, and client programs must not reference elements within it directly\&. .sp NUTCLIENT_t represents the common connection information\&. Derived versions exist for each connection type (NUTCLIENT_TCP_t for TCP connection; actually the unique connection type, NUTCLIENT_TCP_t can be passed as NUTCLIENT_t parameter)\&. .sp See the nutclient\&.h header for more information\&. .SH "ERROR HANDLING" .sp There is currently no specific mechanism around error handling\&. .SH "SEE ALSO" .sp \fBlibnutclient_devices\fR(3) \fBlibnutclient_commands\fR(3) \fBlibnutclient_general\fR(3) \fBlibnutclient_misc\fR(3) \fBlibnutclient_tcp\fR(3) \fBlibnutclient_variables\fR(3) nut-2.8.3/docs/man/NUT-Monitor-py2gtk2.80000644000200500020050000000002715001555117014425 00000000000000.so man8/NUT-Monitor.8 nut-2.8.3/docs/man/upscli_cleanup.txt0000644000200500020050000000102415001555412014504 00000000000000UPSCLI_CLEANUP(3) ================= NAME ---- upscli_cleanup - Clean-up upsclient module after usage. SYNOPSIS -------- ------ #include int upscli_cleanup(void); ------ DESCRIPTION ----------- The *upscli_cleanup()* function flushes SSL caches and frees memory used internally in upsclient module. RETURN VALUE ------------ The *upscli_cleanup()* function returns '1' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_init[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/nutscan_init.30000644000200500020050000000700315001555063013524 00000000000000'\" t .\" Title: nutscan_init .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_INIT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_init \- Initialize the nutscan library\&. .SH "SYNOPSIS" .sp .nf #include void nutscan_init(void); .fi .SH "DESCRIPTION" .sp The \fBnutscan_init()\fR function must be called at least once before using any other function of the nutscan library\&. .sp It updates the following global variables which can be used by nutscan library user to know which scan methods are available at run\-time\&. .sp This depends on further libraries installed on the system: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} nutscan_avail_avahi = 1: AVAHI NUT scan is available .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} nutscan_avail_ipmi = 1: IPMI scan is available .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} nutscan_avail_nut = 1: "Old" NUT method is available .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} nutscan_avail_nut_simulation = 1: NUT simulation devices method is available .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} nutscan_avail_snmp = 1: SNMP method is available .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} nutscan_avail_usb = 1: USB method is available .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} nutscan_avail_xml_http = 1: XML HTTP method is available .RE .sp Note that if a method is reported as unavailable by those variables, the call to the corresponding nutscan_scan_* function will always return NULL\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-init\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_nut_simulation\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3) nut-2.8.3/docs/man/powerman-pdu.txt0000644000200500020050000000362415001555412014124 00000000000000POWERMAN-PDU(8) =============== NAME ---- powerman-pdu - Driver for Powerman PDU SYNOPSIS -------- *powerman-pdu* -h *powerman-pdu* -a 'PDU_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the powerman-pdu driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports a wide range of PDUs through the Powerman project. This includes various models from APC, Baytech, Cyclades, but also support IPMI and various blade management modules from HP, IBM and Sun. EXTRA ARGUMENTS --------------- This driver doesn't support any optional settings. INSTALLATION ------------ This driver may be not built by default. You can build it by installing prerequisites and using `configure --with-powerman=yes`. UPS COMMANDS ------------ The following instant commands (see linkman:upscmd[8]) are available for each outlet of the PDU, with *X* standing for the outlet number: *outlet.X.load.on*:: Power on the outlet. *outlet.X.load.off*:: Power off the outlet. *outlet.X.load.cycle*:: Cycle the outlet (power off then power on, possibly with a delay). IMPLEMENTATION -------------- The hostname of the Powerman server is specified using the "port" value in *ups.conf*, i.e.: [pdu] driver = powerman-pdu port = host.example.com:port The port used to reach 'powermand' is optional if the default port is used. KNOWN ISSUES ------------ In the current NUT version as of this writing (2.4.1), `ups.status` is still exposed, with the value "WAIT". Some other values from the `ups` collection are also exposed. AUTHOR ------ Arnaud Quette SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * The PowerMan home page: https://github.com/chaos/powerman nut-2.8.3/docs/man/solis.80000644000200500020050000000711315001555075012171 00000000000000'\" t .\" Title: solis .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "SOLIS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" solis \- Driver for Brazilian Microsol SOLIS UPS equipment .SH "SYNOPSIS" .sp \fBsolis\fR \-h .sp \fBsolis\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the solis driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver has been tested with: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Solis 1000 VA .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Solis 1500 VA .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Solis 2000 VA .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Solis 3000 VA .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Back\-UPS BZ1200\-BR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Back\-UPS BZ2200BI\-BR .RE .sp All Solis models are sinusoidal on\-line\&. .sp In 2009, Schneider Electric acquired Microsol Technologies, and by 2012, the entire Microsol line of equipment was being sold under the APC brand\&. Newer devices may be better supported by \fBmicrosol-apc\fR(8) driver instead\&. .SH "EXTRA ARGUMENTS" .sp This driver support the following extra optional settings in the \fBups.conf\fR(5)\&. .PP \fBbattext=\fR\fIn\fR .RS 4 Default = 0, no extra battery, where n = Ampere*hour\&. .RE .PP \fBprgshut=\fR\fIn\fR .RS 4 Default = 0, no programmable shutdown; 1 to enable one\&. .RE .SH "COMMANDS" .PP \fBshutdown\&.return\fR .RS 4 Shut down in \&.3 minutes and restart in \&.3 minutes after that\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Shut down in \&.3 minutes and do not return\&. .RE .SH "ISSUES" .sp The APC version of the Microsol protocol is slightly incompatible with the \fBsolis\fR driver\&. As of version 0\&.62 of the \fBsolis\fR driver, the driver will connect to the UPS, but some values are read incorrectly\&. .SH "AUTHOR" .sp Silvino B\&. Magalhães .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Driver for newer devices under same brand:" .sp \fBmicrosol-apc\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upsclient.30000644000200500020050000001160015001555051013027 00000000000000'\" t .\" Title: upsclient .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLIENT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsclient \- Network UPS Tools client access library .SH "DESCRIPTION" .sp The Network UPS Tools (NUT) \fBupsclient\fR library provides a number of useful functions for client programs to use when communicating with \fBupsd\fR(8)\&. Many of the low\-level socket and protocol details are handled automatically when using this interface, also known as "upscli" API\&. .sp State is maintained across calls in an opaque structure called UPSCONN_t\&. Callers are expected to create one per connection\&. These will be provided to most of the \fBupsclient\fR functions\&. The format of this structure is subject to change, and client programs must not reference elements within it directly\&. .SH "INITIALIZATION AND CLEANUP" .sp Before creating any connection, and in general using any upscli function, you must call \fBupscli_init\fR(3) with proper parameters to initialize upscli module\&. .sp To register a specific host security policy, you must call \fBupscli_add_host_cert\fR(3) before initializing a connection to it\&. .sp In the same way, just before exiting, and after all upscli usage, you must call \fBupscli_cleanup\fR(3) to flush cache files and perform other cleanup\&. .SH "NETWORK FUNCTIONS" .sp To create a new connection, use \fBupscli_connect\fR(3)\&. This will also initialize the UPSCONN_t structure\&. To verify that a connection has been established later, \fBupscli_fd\fR(3) can be used to return the file descriptor\&. Clients wishing to check for the presence and operation of SSL on a connection may call \fBupscli_ssl\fR(3)\&. .sp The majority of clients will use \fBupscli_get\fR(3) to retrieve single items from the server\&. To retrieve a list, use \fBupscli_list_start\fR(3) to get it started, then call \fBupscli_list_next\fR(3) for each element\&. .sp Raw lines of text may be sent to \fBupsd\fR(8) with \fBupscli_sendline\fR(3)\&. Reading raw lines is possible with \fBupscli_readline\fR(3)\&. Client programs are expected to format these lines according to the protocol, as no checking will be performed before transmission\&. .sp At the end of a connection, you must call \fBupsclient_disconnect\fR(3) to disconnect from \fBupsd\fR and release any dynamic memory associated with the UPSCONN_t structure\&. Failure to call this function will result in memory and file descriptor leaks in your program\&. .SH "STRING FUNCTIONS" .sp To parse the ups\&.status values (check whether a particular token is present) you are encouraged to use the \fBupscli_str_contains_token\fR(3) method\&. .sp To collect unique tokens into a string in the same manner a NUT driver does, the \fBupscli_str_add_unique_token\fR(3) can be helpful\&. .sp You are welcome to consult the NUT source code base for use of equivalent methods to implement such features as status_init(), status_get(), status_set() and status_commit() methods in its data\-processing loops\&. .SH "ERROR HANDLING" .sp In the event of an error, \fBupscli_strerror\fR(3) will provide human\-readable details on what happened\&. \fBupscli_upserror\fR(3) may also be used to retrieve the error number\&. These numbers are defined in \fBupsclient\&.h\fR as \fIUPSCLI_ERR_*\fR\&. .SH "SEE ALSO" .sp \fBnutclient\fR(3), \fBlibupsclient-config\fR(1), \fBupscli_init\fR(3), \fBupscli_cleanup\fR(3), \fBupscli_add_host_cert\fR(3), \fBupscli_connect\fR(3), \fBupscli_disconnect\fR(3), \fBupscli_fd\fR(3), \fBupscli_getvar\fR(3), \fBupscli_list_next\fR(3), \fBupscli_list_start\fR(3), \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_splitaddr\fR(3), \fBupscli_splitname\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3), \fBupscli_str_add_unique_token\fR(3), \fBupscli_str_contains_token\fR(3) nut-2.8.3/docs/man/bicker_ser.txt0000644000200500020050000000756315001555412013624 00000000000000BICKER_SER(8) ============= NAME ---- bicker_ser - Driver for Bicker DC UPS via serial port connections SYNOPSIS -------- *bicker_ser* -h *bicker_ser* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *bicker_ser* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ *bicker_ser* supports all Bicker UPSes shipped with the PSZ-1053 extension module such as UPSIC-1205, UPSIC-2403, DC2412-UPS and DC2412-UPS-LD. CABLING ------- The needed cable is a standard pin-to-pin serial cable with pins 2, 3 and 5 (on DB9 connector) connected. EXTRA ARGUMENTS --------------- This driver supports no extra arguments from linkman:ups.conf[5]. VARIABLES --------- Depending on the type of your UPS unit, some of the following variables may be changed with linkman:upsrw[8]. If the driver can't read a variable from the UPS, it will not be made available. Whenever not explicitly stated, any variable can be disabled, in which case the action it performs will not be executed. To disable a variable, set it to an empty value. *ups.delay.shutdown* (in seconds, default disabled):: If activated and the UPS is in battery mode and the set time has expired, the output will be disabled, and the UPS and energy storage will be disconnected. *ups.delay.start* (in seconds, default disabled):: If activated and a restart condition switches the UPS output off and on again, the set time is the delay between switching on and off. The time should cause a defined off time so that capacities in the application can be discharged. *battery.charge.restart* (in percent, default disabled):: If activated and the UPS is off or restarts, the UPS output will not be released until the energy storage device has the set charge state. The energy storage device is charged in the meantime. *battery.charge.low* (in percent, default `20`):: If activated and the UPS is in battery mode and the battery level drops below the set value, a shutdown command via relay event is signaled. *experimental.output.current.low* (in mA, default `200`):: If activated and the UPS is in battery mode and the current drops below the set value, the output of the UPS will shut down and disconnect the energy storage to prevent self-discharge. *experimental.ups.delay.shutdown.signal* (in seconds, default disabled):: If activated and the UPS is in battery mode and the set time has elapsed, a shutdown command via relay event is signaled. *experimental.ups.delay.shutdown.signal.masked* (in seconds, default disabled):: If activated and the UPS is in battery mode and the signal at the IN-1 input is high and the set time has expired, a shutdown command via relay event is signaled. *experimental.battery.charge.low.empty* (in percent, default `20`):: This parameter stores the threshold value for the "Battery Empty" signal. Currently this setting is only valid for relay signaling. Cannot be disabled. *experimental.ups.relay.mode* (default `0x01`):: This parameter controls the behavior of the relay in case of different events. Cannot be disabled. + Available relay modes: [horizontal] `0x01`::: On power fail (normally closed) `0x02`::: On power fail (normally opened) `0x03`::: Shutdown impulse (1 second) `0x04`::: Battery low signal (normally closed) `0x05`::: Battery defect signal (normally closed) INSTANT COMMANDS ---------------- *shutdown.return*:: Turn off the load and return when power is back. KNOWN ISSUES AND BUGS --------------------- *ups.delay.shutdown is not honored*:: Although that delay is properly set when sending the shutdown command, it seems some UPS ignore it and use a fixed 2 seconds delay instead. AUTHOR ------ Nicola Fontana SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_list_start.30000644000200500020050000000745615001555053014610 00000000000000'\" t .\" Title: upscli_list_start .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_LIST_START" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_list_start \- Begin multi\-item retrieval from a UPS .SH "SYNOPSIS" .sp .nf #include int upscli_list_start(UPSCONN_t *ups, size_t numq, const char **query) .fi .SH "DESCRIPTION" .sp The \fBupscli_list_start()\fR function takes the pointer \fIups\fR to a UPSCONN_t state structure, and the pointer \fIquery\fR to an array of \fInumq\fR query elements\&. It builds a properly\-formatted request from those elements and transmits it to \fBupsd\fR(8)\&. .sp Upon success, the caller must call \fBupscli_list_next\fR(3) to retrieve the elements of the list\&. Failure to retrieve the list will most likely result in the client getting out of sync with the server due to buffered data\&. .SH "USES" .sp This function implements the "LIST" command in the protocol\&. As a result, you can use it to request many different things from the server\&. Some examples are: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} LIST UPS .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} LIST VAR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} LIST RW .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} LIST CMD .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} LIST ENUM .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} LIST RANGE .RE .SH "QUERY FORMATTING" .sp To see the list of variables on a UPS called \fIsu700\fR, the protocol command would be LIST VAR su700\&. To start that list with this function, you would populate query and numq as follows: .sp .if n \{\ .RS 4 .\} .nf size_t numq; const char *query[2]; query[0] = "VAR"; query[1] = "su700"; numq = 2; .fi .if n \{\ .RE .\} .sp All escaping of special characters and quoting of elements with spaces are handled for you inside this function\&. .SH "ERROR CHECKING" .sp This function checks the response from \fBupsd\fR(8) against your query\&. If it is not starting a list, or is starting the wrong type of list, it will return an error code\&. .sp When this happens, \fBupscli_upserror\fR(3) will return UPSCLI_ERR_PROTOCOL\&. .SH "RETURN VALUE" .sp The \fBupscli_list_start()\fR function returns \fI0\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_fd\fR(3), \fBupscli_get\fR(3), \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/libnutclient_tcp.30000644000200500020050000000760015001555056014375 00000000000000'\" t .\" Title: libnutclient_tcp .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIBNUTCLIENT_TCP" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libnutclient_tcp, nutclient_tcp_create_client, nutclient_tcp_is_connected, nutclient_tcp_disconnect, nutclient_tcp_reconnect, nutclient_tcp_set_timeout, nutclient_tcp_get_timeout \- TCP protocol related function for Network UPS Tools high\-level client access library .SH "SYNOPSIS" .sp .nf #include #include /* uint16_t */ #include /* time_t */ typedef NUTCLIENT_t NUTCLIENT_TCP_t; NUTCLIENT_TCP_t nutclient_tcp_create_client( const char* host, uint16_t port); int nutclient_tcp_is_connected(NUTCLIENT_TCP_t client); void nutclient_tcp_disconnect(NUTCLIENT_TCP_t client); int nutclient_tcp_reconnect(NUTCLIENT_TCP_t client); void nutclient_tcp_set_timeout(NUTCLIENT_TCP_t client, time_t timeout); time_t nutclient_tcp_get_timeout(NUTCLIENT_TCP_t client); .fi .SH "DESCRIPTION" .sp These functions allow to manage connections to \fBupsd\fR(8) using NUT TCP protocol\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_tcp_create_client()\fR function create the \fINUTCLIENT_TCP_t\fR context and intend to connect to upsd at \fIhost\fR and \fIport\fR\&. .sp The context must be freed by \fInutclient_destroy()\fR\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIhost\fR can be a sever name or a valid IPv4 or IPv6 address like "localhost", "127\&.0\&.0\&.1" or "::1"\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIport\fR is a valid TCP port, generally \fI3493\fR\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_tcp_is_connected()\fR function test if the connection is valid\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_tcp_disconnect()\fR function force to disconnect the specified connection\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_tcp_reconnect()\fR function force to reconnect a connection, disconnecting it if needed\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_tcp_set_timeout()\fR function set the timeout duration for I/O operations\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_tcp_get_timeout()\fR function retrieve the timeout duration for I/O operations\&. .sp \fItimeout\fR values are specified in seconds, use negative values for blocking\&. .RE .SH "SEE ALSO" .sp \fBlibnutclient\fR(3) \fBlibnutclient_general\fR(3) nut-2.8.3/docs/man/nutclient_get_device_num_logins.30000644000200500020050000000003515001555117017441 00000000000000.so man3/libnutclient_misc.3 nut-2.8.3/docs/man/hwmon_ina219.txt0000644000200500020050000000645215001555412013723 00000000000000HWMON_INA219(8) =============== NAME ---- hwmon_ina219 - Driver for UPS based on INA219 SYNOPSIS -------- *hwmon_ina219* -h *hwmon_ina219* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the *hwmon_ina219* driver. For information about the core driver, see linkman:nutupsdrv[8]. The driver implements reading of current and voltage from INA219 by using hwmon sysfs API of the Linux Kernel. There is no other UPS-like logic in there. Based on the measurements of the battery voltage and charging current, the driver makes assumptions of the current state of the system. SUPPORTED HARDWARE ------------------ The *hwmon_ina219* driver is based on setup with Raspberry PI Compute Module 4 and its baseboard Waveshare CM4-POE-UPS-BASE. EXTRA ARGUMENTS --------------- The required parameter for this driver: *port*='hwmon-dir':: Path to appropriate /sys/hwmon/hwmonX or 'auto' to detect automatically. Optional parameters: *default.battery.charge.low*='low-battery-threshold':: Threshold for low battery state (in percent). *default.battery.voltage.nominal*='voltage-value':: Nominal voltage (V) value of utilized batteries, used to derive their low and high watermark settings (see below). Default: 3.6. + Known pre-sets include: `3.6`, `3.7`, `3.8`, `3.85`. *default.battery.voltage.low*='voltage-value':: Low voltage (V) value of used batteries. Practically, it denotes depleted batteries. If not given, it is derived from the *battery.voltage.nominal*. *default.battery.voltage.high*='voltage-value':: High voltage (V) value of used batteries. Practically, it denotes fully charged batteries. If not given, it is derived from the *battery.voltage.nominal*. INSTALLATION ------------ This driver is specific to the Linux hwmon API. When using with the Waveshare CM4-POE-UPS-BASE baseboard, there are few steps to be done to enable access to the INA219 circuit: . edit boot/config.txt: + ---- dtparam=i2c_vc=on dtoverlay=i2c-ina219 ---- . create a new device tree overlay file i2c-ina219.dts: + ---- /dts-v1/; /plugin/; / { compatible = "brcm,bcm2835"; fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; #size-cells = <0>; ina219@43 { status = "okay"; compatible = "ti,ina219"; reg = <0x43>; shunt-resistor = <100000>; // R100 }; }; }; }; ---- . convert i2c-ina219.dts to dtbo and place it into /boot/overlays: + ---- $ dtc -@ -I dts -O dtb -o /boot/overlays/i2c-ina219.dtbo i2c-ina219.dts ---- . configure hwmon_ina219 UPS driver for NUT (ups.conf): + ---- [ina219] driver = hwmon_ina219 port = auto ---- KNOWN ISSUES AND BUGS --------------------- The driver shutdown function is not implemented. AUTHORS ------- Andrew Anderson SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * Initial pull requests adding this driver: ** https://github.com/networkupstools/nut/pull/2430 ** https://github.com/networkupstools/nut/issues/2378 * Baseboard with INA219: https://www.waveshare.com/wiki/CM4-POE-UPS-BASE * TI INA219: https://www.ti.com/lit/ds/symlink/ina219.pdf * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/generic_gpio.txt0000644000200500020050000000652615001555412014144 00000000000000GENERIC GPIO(8) =============== NAME ---- generic_gpio - Driver for GPIO connected UPSes SYNOPSIS -------- *generic_gpio* -h *generic_gpio* -a 'gpiochip0' ['OPTIONS'] NOTE: This man page only documents the specific features of the *generic_gpio* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This is the driver for GPIO attached UPS devices. The driver has been tested against CyberPower CyberShield CSN27U12V attached to Orange Pi Zero GPIO. More information about this UPS can be found here: :: https://www.cyberpowersystems.com/resources/csn27u12v-um/ EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file: Driver control: ~~~~~~~~~~~~~~ *rules*='value':: A string consisting of sub-strings. Each sub-string describes GPIO line states conversion formula to specific NUT state, like + ---- nut_state=[^]line_num[logical_operation[^]line_num]...; ---- + The logical "Not" (`^`), "And" (`&`), and "Or" (`|`) operations are supported for now. + The `nut_state` should correspond to NUT state, and `line_num` to the GPIO line number connected to UPS open collector pin. + CyberShield CSN27U12V describes pins as: + |=== |Battery state|State details|GPIO line |ON BATTERY|*Low* when operating from utility line *Open* when operating from battery|0 |REPLACE BATTERY|*Low* when battery is charged *Open* when battery fails the Self Test|1 |BATTERY MISSING|*Low* when battery is present *Open* when battery is missing|6 |LOW BATTERY|*Low* when battery is near full charge capacity *Open* when operating from a battery with < 20% capacity|3 |=== and then the 'rules' value might be defined as + ---- rules = "OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6;" ---- + assuming battery pin connection to GPIO lines as listed in table. + Expecting simple formula to be used for each state, extra may increase state reliability and may need to be checked on each specific UPS. Battery Charge: ~~~~~~~~~~~~~~ *default.battery.charge.low*='value':: An integer specifying the battery charge level reported in LB case. CONFIGURATION ------------- Here is an example of GPIO driver configuration in *ups.conf* file: ---- [CyberPower12v] driver = GENERIC_GPIO port = gpiochip0 desc = "Modem and DNS server UPS" mfr = CyberPower model = "CyberShield CSN27U12V" rules = "OL=^0;OB=0;LB=3;RB=1;DISCHRG=0&^6;BYPASS=6;" default.battery.charge.low = 20 ---- SHUTDOWN COMMAND ---------------- This driver does not support shutdown command. INSTALLATION ------------ This driver may be not built by default. You can build it by installing libgpiod and running `configure --with-gpio=yes`. You also need to give proper permissions on the local serial device file (`/dev/gpiochip0` for example) to allow the run-time NUT driver user account to access it, like by adding the following rule to Linux `rules.d` directory: SUBSYSTEM=="gpio*", PROGRAM="/bin/sh -c '\ chown -R nut:nut /dev/gpiochip0 && chmod -R 700 /dev/gpiochip0' AUTHOR ------ Modris Berzonis SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8], linkman:ups.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * libgpiod home page: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/ nut-2.8.3/docs/man/nutclient_tcp_reconnect.30000644000200500020050000000003415001555117015736 00000000000000.so man3/libnutclient_tcp.3 nut-2.8.3/docs/man/upscli_connect.txt0000644000200500020050000000561715001555412014522 00000000000000UPSCLI_CONNECT(3) ================= NAME ---- upscli_connect, upscli_tryconnect - Open a connection to a NUT upsd data server SYNOPSIS -------- ------ #include /* Open a connection to a NUT upsd data server (blocking by default) */ int upscli_connect(UPSCONN_t *ups, const char *host, uint16_t port, int flags); /* Open a connection to a NUT upsd data server with specified timeout */ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags, struct timeval * timeout); ------ DESCRIPTION ----------- The *upscli_connect()* function takes the pointer 'ups' to a `UPSCONN_t` state structure and opens a TCP connection to the 'host' on the given 'port'. By default this makes a blocking connection attempt (until the system transport layer times out the underlying linkmanext:select[2] call). A program-wide default timeout for this method can be configured with the linkman:upscli_set_default_connect_timeout[3] or linkman:upscli_init_default_connect_timeout[3] methods. For operations with explicit operation-specific timeout please use the *upscli_tryconnect()* method instead. NOTE: As part of general initialization, both the linkman:upscli_init[3] function or the first call to *upscli_connect()* function, can call the linkman:upscli_init_default_connect_timeout[3] method (if it was never used before): this allows unmodified (legacy) NUT clients to consistently benefit from presence of the `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable for linkman:upscli_connect[3] attempts to be not blocking (as per default). 'flags' may be either `UPSCLI_CONN_TRYSSL` to try a SSL connection, or `UPSCLI_CONN_REQSSL` to require a SSL connection. Introduced in version 2.7, an additional flag `UPSCLI_CONN_CERTVERIF` now exists to verify the signature offered during the SSL handshake. This flag should be used in conjunction with linkman:upscli_init[3] and/or linkman:upscli_add_host_cert[3] calls before connecting in order to define a CA certificate with which to verify. If SSL mode is required, this function will only return successfully if it is able to establish a SSL connection with the server. Possible reasons for failure include no SSL support on the server, and if *upsclient* itself hasn't been compiled with SSL support. You must call linkman:upscli_disconnect[3] when finished with a connection, or your program will slowly leak memory and file descriptors. RETURN VALUE ------------ The *upscli_connect()* function modifies the `UPSCONN_t` structure and returns '0' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_disconnect[3], linkman:upscli_fd[3], linkman:upscli_init[3], linkman:upscli_splitaddr[3], linkman:upscli_splitname[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_get_default_connect_timeout[3], linkman:upscli_set_default_connect_timeout[3], linkman:upscli_init_default_connect_timeout[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/upscli_splitaddr.30000644000200500020050000000465115001555053014400 00000000000000'\" t .\" Title: upscli_splitaddr .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_SPLITADDR" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_splitaddr \- Split a listening address into its components .SH "SYNOPSIS" .sp .nf #include int upscli_splitaddr(const char *buf, char **hostname, int *port) .fi .SH "DESCRIPTION" .sp The \fBupscli_splitaddr()\fR function takes a pointer to the listening address definition \fIbuf\fR and returns the pointer to dynamically allocated memory in \fIhostname\fR\&. It also copies the port number into \fIport\fR\&. .SH "FORMATTING" .sp A listening address definition is specified according to this format: .sp .if n \{\ .RS 4 .\} .nf [:] .fi .if n \{\ .RE .\} .sp Definitions without an explicit port value receive the default value of \fI3493\fR\&. .SH "MEMORY USAGE" .sp You must \fBfree\fR(3) the pointer \fIhostname\fR when you are done with it to avoid memory leaks\&. .SH "RETURN VALUE" .sp The \fBupscli_splitaddr()\fR function returns \fI0\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_fd\fR(3), \fBupscli_get\fR(3), \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_splitname\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/riello_ser.80000644000200500020050000000725215001555075013203 00000000000000'\" t .\" Title: riello_ser .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "RIELLO_SER" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" riello_ser \- Driver for Riello UPS Protocol UPS equipment via serial port connections .SH "SYNOPSIS" .sp \fBriello_ser\fR \-h .sp \fBriello_ser\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the riello_ser driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp riello_ser supports all recent Riello UPS, Aros UPS models which use the Riello UPS GPSER and SENTR protocols\&. .sp Older Riello UPS products are not supported\&. .SH "EXTRA ARGUMENTS" .sp You may need to tweak some settings, depending on the make and model of your UPS (see \fBups.conf\fR(5)): .PP \fBlocalcalculation\fR .RS 4 When enabled, driver will calculate values of battery\&.runtime and battery\&.charge "locally" in the driver\&. This is for some Riello models which provide incorrect values in hardware readings, or none at all\&. This "local calculation" is done according to nominal battery capacity, nominal battery voltage, actual battery charge, maximum and actual UPS load\&. .sp You may want to also configure \fIdefault\&.battery\&.voltage\&.low\fR and \fIdefault\&.battery\&.voltage\&.high\fR in case the built\-in default range (from 10\&.7V to 12\&.9V) does not match your hardware, or give a shot to \fIdefault\&.battery\&.voltage\&.nominal\fR (e\&.g\&. \fI24\fR) if your device does not serve that either\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br Lead (PbAc) battery charge graph is not linear, so guesstimated charge value may not be perfectly accurate\&. However it should be good enough to determine battery actual status and roughly estimate the time it can still power the system\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This keyword may be deprecated in future releases of the driver, in favor of runtimecal and other settings which it requires (as seen in \fBnutdrv_qx\fR(8), \fBblazer_ser\fR(8) and \fBblazer_usb\fR(8) drivers)\&. .sp .5v .RE .RE .SH "AUTHOR" .sp Massimo Zampieri .SH "SEE ALSO" .SS "Related drivers" .sp \fBriello_usb\fR(8) .SS "The core driver" .sp \fBnutupsdrv\fR(8) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/usbhid-ups.80000644000200500020050000007057615001555100013125 00000000000000'\" t .\" Title: usbhid-ups .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "USBHID\-UPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" usbhid-ups \- Driver for USB/HID UPS equipment .SH "SYNOPSIS" .sp \fBusbhid\-ups\fR \-h .sp \fBusbhid\-ups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the usbhid\-ups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp \fBusbhid\-ups\fR brings USB/HID UPS monitoring to NUT on all platforms supporting USB through libusb\&. It should detect any UPS that uses the HID Power Device Class, but the amount of data will vary depending on the manufacturer and model\&. .sp At the present time, usbhid\-ups supports: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the newer Eaton USB models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} all MGE USB models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} all Dell USB models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} all AMETEK Powervar UPM models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} some APC models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} some Belkin models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} some Cyber Power Systems models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} some Powercom models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} some PowerWalker models, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} some TrippLite models\&. .RE .sp For a more complete list, refer to the NUT hardware compatibility list, available in the NUT source distribution as data/driver\&.list, or on the NUT website\&. .sp You may use the explore driver option to gather information from HID UPSes which are not yet supported, to help add such support; see below for details\&. .sp This driver is known to work on: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} most Linux systems, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} FreeBSD (beta stage) and maybe other *BSD, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Darwin / Mac OS X, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Solaris 10 and illumos\-based distributions\&. .RE .SH "EXTRA ARGUMENTS" .sp This driver also supports the following optional settings: .PP \fBport =\fR \fIstring\fR .RS 4 Some \fIvalue\fR must be set, typically \fBauto\fR\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This could be a device filesystem path like /dev/usb/hiddev0 but current use of libusb API precludes knowing and matching by such identifiers\&. They may also be inherently unreliable (dependent on re\-plugging and enumeration order)\&. At this time the actual \fIvalue\fR is ignored, but syntactically some \fIport\fR configuration must still be there\&. .sp .5v .RE .RE .sp It is possible to control multiple UPS units simultaneously by running several instances of this driver, provided they can be uniquely distinguished by setting some combination of the \fBvendor\fR, \fBproduct\fR, \fBvendorid\fR, \fBproductid\fR, \fBserial\fR, \fBbus\fR and/or \fBdevice\fR options detailed below\&. For devices or operating systems that do not provide sufficient information, the \fBallow_duplicates\fR option can be of use (limited and risky!) .PP \fBvendorid =\fR \fIregex\fR, \fBproductid =\fR \fIregex\fR, \fBvendor =\fR \fIregex\fR, \fBproduct =\fR \fIregex\fR, \fBserial =\fR \fIregex\fR .RS 4 Select a specific UPS, in case there is more than one connected via USB\&. Each option specifies an extended regular expression (see \fBregex\fR(7) for more information on regular expressions), which must match the UPS\(cqs entire respective vendor/product/serial string values (minus any surrounding whitespace), or the whole 4\-digit hexadecimal code for vendorid and productid\&. .sp Try \fBlsusb\fR(8) or running this NUT driver with \-DD command\-line argument for finding out the strings to match\&. .sp Examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendor="Foo\&.Corporation\&.*" .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendorid="051d*" (APC) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x product="\&.*(Smart|Back)\-?UPS\&.*" .RE .RE .PP \fBbus =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB bus or group of buses\&. The argument is a regular expression that must match the bus name where the UPS is connected (e\&.g\&. bus="002" or bus="00[2\-3]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .RE .PP \fBdevice =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB device or group of devices\&. The argument is a regular expression that must match the device name where the UPS is connected (e\&.g\&. device="001" or device="00[1\-2]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br device numbers are not guaranteed by the OS to be stable across re\-boots or device re\-plugging\&. .sp .5v .RE .RE .PP \fBbusport =\fR \fIregex\fR .RS 4 If supported by the hardware, OS and libusb on the particular deployment, this option should allow to specify physical port numbers on an USB hub, rather than logical device enumeration values, and in turn \(em this should be less volatile across reboots or re\-plugging\&. The value may be seen in the USB topology output of lsusb \-tv on systems with that tool, for example\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br this option is not practically supported by some NUT builds (it should be ignored with a warning then), and not by all systems that NUT can run on\&. .sp .5v .RE .RE .PP \fBallow_duplicates\fR .RS 4 If you have several UPS devices which may not be uniquely identified by the options above (e\&.g\&. only \fIVID:PID\fR can be discovered there), this flag allows each driver instance where it is set to take the first match if available, or proceed to try another\&. .sp Normally the driver initialization would abort at this point claiming "Resource busy" or similar error, assuming that the otherwise properly matched device is unique \(em and some other process already handles it\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This feature is inherently non\-deterministic! The association of driver instance name to actual device may vary between runs! .sp If you only care to know that \fBat least\fR one of your no\-name UPSes is online, this option can help\&. .sp If you must really know \fBwhich\fR one, it will not! .sp .5v .RE .RE .PP \fBusb_set_altinterface =\fR \fIbAlternateSetting\fR .RS 4 Force redundant call to usb_set_altinterface(), especially if needed for devices serving multiple USB roles where the UPS is not represented by the interface number 0 (default)\&. .RE .PP \fBusb_config_index\fR, \fBusb_hid_rep_index\fR, \fBusb_hid_desc_index\fR, \fBusb_hid_ep_in\fR, \fBusb_hid_ep_out\fR .RS 4 Force use of specific interface, endpoint, descriptor index etc\&. numbers, rather than defaulting to \fI0\fR (rarely other values in certain drivers for some devices known to use non\-zero numbers)\&. Specified as a hexadecimal number\&. .sp As a rule of thumb for usb_hid_desc_index discovery, you can see larger wDescriptorLength values (roughly 600+ bytes) in reports of lsusb or similar tools\&. .RE .PP \fBLIBUSB_DEBUG =\fR \fIINTEGER\fR .RS 4 Run\-time troubleshooting of USB\-capable NUT drivers can involve not only raising the common NUT debug verbosity (e\&.g\&. using the DEBUG_MIN setting in \fBups.conf\fR(5) or protocol commands to change the driver\&.debug value), but may also benefit from LibUSB specific debugging\&. .sp For the latter, you can set the LIBUSB_DEBUG driver option; alternatively you can classically export the environment variable LIBUSB_DEBUG before starting a NUT driver program (may be set and "exported" in driver init script or service method, perhaps via \fBnut.conf\fR(5)), to a numeric value such as 4 ("All messages are emitted")\&. .sp For more details, including the currently supported values for your version of the library, see e\&.g\&.: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/group__libusb__lib\&.html .RE .RE .PP \fBsubdriver\fR=\fIregex\fR .RS 4 Select the USB HID subdriver for the device manually, where automatic match by device attributes alone does not suffice (e\&.g\&. new devices for which no vendorid/productid pair was built into any driver \(em but common USB HID support is anticipated, or for different\-capability devices with same interface chips, notably "phoenixtec/liebert" and "mge")\&. .sp Run the driver program with the \-\-help option to see the exact list of subdriver values it would currently recognize\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This option first checks for exact matches to subdriver identification strings, such as "TrippLite HID 0\&.85" (which are prone to bit\-rot), and if there was no exact match \(em retries with a case\-insensitive extended regular expression\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br When using this option, it is mandatory to also specify the \fBvendorid\fR and \fBproductid\fR matching parameters\&. .sp .5v .RE .RE .PP \fBlowbatt\fR=\fInum\fR .RS 4 Set the percentage at which the UPS will consider the battery charge as critically low, possibly resulting in a forced shutdown (FSD) situation\&. .sp This value is typically dictated by the UPS device, although there is a fallback default value of 30 (in percent)\&. Overriding this value can be helpful when the UPS sets this value to a lower percentage than intended\&. .RE .PP \fBoffdelay\fR=\fInum\fR .RS 4 Set the timer before the UPS is turned off after the kill power command is sent (via the \fB\-k\fR switch)\&. .sp The default value is 20 (in seconds), or 60 for CPS devices\&. Usually this \fBmust be lower\fR than \fIondelay\fR, but the driver will \fBnot\fR warn you upon startup if it isn\(cqt\&. .sp Note that many Cyber Power Systems (CPS) models tend to divide this delay by 60 and round down, so the minimum advisable value is 60 to avoid powering off immediately after NUT sends the shutdown command to the UPS\&. More details below\&. .RE .PP \fBondelay\fR=\fInum\fR .RS 4 Set the timer for the UPS to switch on in case the power returns after the kill power command had been sent, but before the actual switch off\&. This ensures the machines connected to the UPS are, in all cases, rebooted after a power failure\&. .sp The default value is 30 (in seconds), or 120 for CPS devices\&. Usually this \fBmust be greater\fR than offdelay, but the driver will \fBnot\fR warn you upon startup if it isn\(cqt\&. Some UPSes will restart no matter what, even if the power is (still) out at the moment this timer elapses\&. In that case, you could see whether setting ondelay = \-1 in \fBups\&.conf\fR helps\&. .sp Note that many CPS models tend to divide this delay by 60 and round down, so the minimum advisable value is 120 to allow a short delay between when the UPS shuts down, and when the power returns\&. According to support statement (for at least some CPS models), "our UPS systems are unable to set up power on delay"\&. .RE .PP \fBpollfreq\fR=\fInum\fR .RS 4 Set polling frequency for full updates, in seconds\&. Compared to the quick updates performed every "pollinterval" (the latter option is described in \fBups.conf\fR(5)), the "pollfreq" interval is for polling the less\-critical variables\&. The default value is 30 (in seconds), or 12 sec for CPS devices\&. .RE .PP \fBpollonly\fR .RS 4 If this flag is set, the driver will not use Interrupt In transfers during the shorter "pollinterval" cycles (not recommended, but needed if these reports are broken on your UPS)\&. .RE .PP \fBinterrupt_pipe_no_events_tolerance\fR=\fInum\fR .RS 4 Set the tolerance for how many times in a row could we have "Got 0 HID objects" when using USB interrupt mode? This may normally be due to a device having nothing urgent to report, so the default value is \-1 and this situation is not handled in any way specially\&. However with some devices this was seen in conjunction with a frozen controller, where only a driver reconnection restored the data exchange (e\&.g\&. APC BXnnnnMI) \(em in such cases you may want to use a reasonable non\-negative value here\&. .RE .PP \fBonlinedischarge_battery\fR .RS 4 If this flag is set, the driver will treat OL+DISCHRG status as offline/on\-battery\&. .sp For most devices this combination means calibration or similar maintenance; however some UPS models (e\&.g\&. CyberPower UT series) emit OL+DISCHRG when wall power is lost \(em and need this option to handle shutdowns\&. .RE .PP \fBonlinedischarge\fR .RS 4 DEPRECATED, old name for onlinedischarge_battery described above\&. .RE .PP \fBonlinedischarge_calibration\fR .RS 4 If this flag is set, the driver will treat OL+DISCHRG status as calibration\&. Some UPS models (e\&.g\&. APC were seen to do so) report OL+DISCHRG when they are in calibration mode\&. This usually happens after a few seconds reporting an OFF state as well, while the hardware is switching to on\-battery mode\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br If it takes so long on your device that a shutdown gets issued, you may want to look at upsmon option OFFDURATION used to filter out temporary values of "administrative OFF" as not a loss of a feed for the powered load\&. .sp .5v .RE .RE .PP \fBonlinedischarge_log_throttle_sec\fR=\fInum\fR .RS 4 Set the minimum frequency (in seconds) at which warnings would be emitted for an otherwise not handled OL+DISCHRG device status combination\&. Negative values disable sequentially repeated messages (when this state appears and persists)\&. .sp If the device does not report battery\&.charge, the default value is 30 seconds (fairly frequent, in case the UPS\-reported state combination does reflect a bad power condition and so the situation is urgent)\&. .sp If it does report battery\&.charge, by default the repeated notifications would only be logged if this charge is different from when the message was emitted previously (e\&.g\&. when the battery is really discharging)\&. .sp If both this option is set, and battery\&.charge is correctly reported, either of these rules allow the notification to be logged\&. .RE .PP \fBonlinedischarge_log_throttle_hovercharge\fR=\fInum\fR .RS 4 See details in onlinedischarge_log_throttle_sec and battery\&.charge based log message throttling description above\&. This option adds a concept of UPS "hovering" a battery charge at some level deemed safe for its chemistry, and not forcing it to be fully charged all the time\&. As long as the current value of battery\&.charge remains at or above this threshold percentage (default 100), the OL+DISCHRG message logging is not triggered by variations of the charge\&. .RE .PP \fBlbrb_log_delay_sec\fR=\fInum\fR .RS 4 Set to delay status\-setting (and log messages) about device entering LB or LB+RB state\&. .sp Some APC BXnnnnMI device models or firmware versions (reportedly 2023\-2024) frequently report low battery, replace battery, and all ok within a couple of seconds, sometimes but not always preceded by OL+DISCHRG (presumably calibration)\&. This setting lets the driver ignore short\-lived states and only pay attention if they persist longer than this setting (and the device power state is OL)\&. .RE .PP \fBlbrb_log_delay_without_calibrating\fR .RS 4 Set to apply lbrb_log_delay_sec even if device is not calibrating\&. .RE .PP \fBdisable_fix_report_desc\fR .RS 4 Set to disable fix\-ups for broken USB encoding, etc\&. which we apply by default on certain models (vendors/products) which were reported as not following the protocol strictly\&. This flag allows to disable the feature in particular device configurations\&. .sp It is always possible that the vendors eventually release fixed firmware, or re\-use identifiers by which we match suspected broken devices for unrelated products, so processing these fix\-ups would be a waste of time there\&. .sp It is also always possible that NUT fix\-ups cause issues on some devices, whether due to NUT bugs or because the vendor protocol implementation is broken in more than one place\&. .RE .PP \fBpowercom_sdcmd_byte_order_fallback\fR .RS 4 Original PowerCOM HID subdriver code (until version 0\&.7) sent UPS shutdown and stayoff commands in a wrong byte order, than what is needed by actual devices seen in the field in 2024\&. The byte order is fixed to satisfy new devices by default since version 0\&.71\&. Just in case there are different firmwares out there with opposite behaviors, we provide this toggle to use old behavior in a particular deployment\&. Maybe it was just a bug and nobody needs this fall\-back\&... .RE .PP \fBexplore\fR .RS 4 With this option, the driver will connect to any device, including ones that are not yet supported\&. This must always be combined with the "vendorid" option\&. In this mode, the driver will not do anything useful except for printing debugging information (typically used with \-DD)\&. .RE .PP \fBmaxreport\fR .RS 4 With this option, the driver activates a tweak to workaround buggy firmware returning invalid HID report length\&. Some APC Back\-UPS units are known to have this bug\&. .RE .PP \fBinterruptonly\fR .RS 4 If this flag is set, the driver will not poll UPS\&. This also implies using of INPUT flagged objects\&. Some Powercom units need this option\&. .RE .PP \fBinterruptsize\fR=\fInum\fR .RS 4 Limit the number of bytes to read from interrupt pipe\&. For some Powercom units this option should be equal to 8\&. .RE .PP \fBwaitbeforereconnect\fR=\fInum\fR .RS 4 The driver automatically tries to reconnect to the UPS on unexpected error\&. This parameter (in seconds) allows it to wait before attempting the reconnection\&. The default value is 0\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br for instance, it was found that Eaton MGE Ellipse Max 1500 FR UPS firmware stops responding every few hours, which causes usbhid\-ups driver to detect an libusb insufficient memory error; in this case, when the usbhid\-ups driver tries to reconnect too early, the activity sometimes led the UPS firmware to crash and turn off the load immediately! Setting this parameter to 30 seconds solved this problem (while 20 seconds were not enough)\&. .sp .5v .RE .RE .SH "INSTALLATION" .sp This driver may be not built by default\&. You can build it by installing prerequisites and using configure \-\-with\-usb=yes\&. Note that it will also install other USB drivers\&. .sp You also need to install manually the legacy \fBhotplug\fR files (libhidups and libhid\&.usermap, generally in /etc/hotplug/usb/), or the \fBudev\fR file (nut\-usbups\&.rules, generally in /etc/udev/rules\&.d/) to address the permission settings problem\&. For more information, refer to the scripts/hotplug/README\&.adoc or scripts/udev/README\&.adoc files in NUT sources\&. .SH "IMPLEMENTATION" .SS "Selecting a specific UPS" .sp As mentioned above, the driver ignores the "port" value in \fBups\&.conf\fR\&. .sp Unlike previous versions of this driver, it is now possible to control multiple UPS units simultaneously with instances of this driver running in parallel, provided they can be distinguished by setting some combination of the device\-matching options\&. .sp For example: .sp .if n \{\ .RS 4 .\} .nf [mge] driver = usbhid\-ups port = auto vendorid = 0463 [tripplite] driver = usbhid\-ups port = auto vendorid = 09ae .fi .if n \{\ .RE .\} .sp To monitor devices using the same vendor and product identification (e\&.g\&. two pieces of the same model), you would need to find a reliable unique matching criteria: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fIserial\fR number is the best option, if populated\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Link\-level bus/device/busport may be unreliable (due to re\-enumeration on a whim by the operating system)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If nothing else helps, allow_duplicates may be an option in some cases\&. .RE .SS "USB Polling and Interrupt Transfers" .sp The \fBusbhid\-ups\fR driver has two polling intervals\&. The "pollinterval" configuration option controls what can be considered the "inner loop", where the driver polls and waits briefly for "interrupt" reports\&. The "pollfreq" option is for less frequent updates of a larger set of values, and as such, we recommend setting that interval to several times the value of "pollinterval"\&. .sp Many UPSes will respond to a USB Interrupt In transfer with HID reports corresponding to values which have changed\&. This saves the driver from having to poll each value individually with USB Control transfers\&. Since the OB and LB status flags are important for a clean shutdown, the driver also explicitly polls the HID paths corresponding to those status bits during the inner "pollinterval" time period\&. The "pollonly" option can be used to skip the Interrupt In transfers if they are known not to work\&. .SH "KNOWN ISSUES AND BUGS" .SS "UPS reports 65535 sec (or 18:12:15) of battery\&.runtime capability" .sp From a number of reports, it seems that some devices either can not report more than a 16\-bit unsigned value in the standard field for remaining run time (vendor extended fields may exist but be unknown to the mapping tables in your current NUT driver build), or return \-1 for error and that gets treated as an unsigned 16\-bit 65535 value\&. .sp According to some issue discussions, passing a battery test (calibration) can help the UPS re\-estimate the time more correctly\&. .sp This problem may also be linked to a very lightly loaded large\-capacity UPS\&. In some cases vendor documentation explicitly states that runtime calculation is not reliable with loads under e\&.g\&. 10%\&. .SS "Repetitive timeout and staleness" .sp Some models tends to be unresponsive with the default polling frequency\&. The result is that your system log will have lots of messages like: .sp .if n \{\ .RS 4 .\} .nf usb 2\-1: control timeout on ep0in usb 2\-1: usbfs: USBDEVFS_CONTROL failed cmd usbhid\-ups rqt 128 rq 6 len 256 ret \-110 .fi .if n \{\ .RE .\} .sp In this case, simply modify the general parameter "pollinterval" to a higher value (such as 10 seconds)\&. This should solve the issue\&. .sp Note that if you increase "pollinterval" beyond 10 or 15 seconds, you might also want to increase "pollfreq" by the same factor\&. .sp With certain devices and operating systems, notably MGE/Eaton USB Vendor ID (0x0463) on some versions of the Linux kernel, you might encounter poor interaction with the "USB HID quirk" mechanism, which precludes Linux from seeing the device as a hid\-generic first, to hand it over to a NUT driver later\&. For more details, see the NUT FAQ document\&. This particular quirk can be tuned with a kernel boot parameter (via GRUB etc\&.): .sp .if n \{\ .RS 4 .\} .nf usbhid\&.quirks=0x0463:0xffff:0x08 .fi .if n \{\ .RE .\} .sp Conversely, some hardware controllers may "fall asleep" when not contacted for too long; CPS devices are commonly associated with such behaviour\&. In this case, consider enabling pollonly flag and/or keeping pollfreq and/or pollinterval small\&. .SS "Got EPERM: Operation not permitted upon driver startup" .sp You have forgotten to install the hotplug files, as explained in the INSTALLATION section above\&. Don\(cqt forget to restart hotplug so that it applies these changes\&. .SS "Unattended shutdowns" .sp The hardware which was used for development of this driver is almost certainly different from what you have, and not all manufacturers follow the USB HID Power Device Class specifications to the letter\&. You don\(cqt want to find out that yours has issues here when a power failure hits your server room and you\(cqre not around to manually restart your servers\&. .sp If you rely on the UPS to shutdown your systems in case of mains failure and to restart them when the power returns, you \fBmust\fR test this\&. You can do so by running \fIupsmon \-c fsd\fR\&. With the mains present, this should bring your systems down and then cycle the power to restart them again\&. If you do the same without mains present, it should do the same, but in this case, the outputs shall remain off until mains power is applied again\&. .SS "UPS cuts power too soon" .sp Note that many Cyber Power Systems (CPS) models tend to divide offdelay by 60 and round down, so the minimum advisable value is 60 (seconds) to avoid powering off immediately after NUT sends the shutdown command to the UPS\&. .sp For many Cyberpower UPSs, offdelay must be set to 0 for normal behavior (the load is restored when AC power returns)\&. Setting offdelay above 0 will restart the UPS load \fBregardless of whether or not power has returned\fR, and setting offdelay below 0 will disable the auto\-power\-on function of the UPS, keeping the load off even when power returns\&. .SS "UPS does not set battery\&.charge\&.low but says OK" .sp Note that many Cyber Power Systems (CPS) models tend to allow only certain values for battery\&.charge\&.low and anything outside of the set of allowed values are rounded or ignored\&. .sp A shell loop like this can help you map out the allowed values: .sp .if n \{\ .RS 4 .\} .nf for i in `seq 90 \-1 0`; do echo "set to $i"; \e upsrw \-s battery\&.charge\&.low=$i \-u * \-p * cps\-big; \e sleep 1; upsc cps\-big battery\&.charge\&.low; echo ""; \e done .fi .if n \{\ .RE .\} .sp For example, for CPS PR1000LCDRTXL2U model, the only allowed values are [60,55,50,45,40,35,30,25,20] and in some cases, your UPS may effectively not support a value of 10 for the battery\&.charge\&.low setting\&. .SH "HISTORY" .sp This driver, formerly called \fInewhidups\fR, replaces the legacy \fIhidups\fR driver, which only supported Linux systems\&. .SH "AUTHORS" .sp Originally sponsored by MGE UPS SYSTEMS\&. .sp Now sponsored by Eaton http://opensource\&.eaton\&.com .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arnaud Quette .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Peter Selinger .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arjen de Korte .RE .SH "SEE ALSO" .SS "The core driver" .sp \fBnutupsdrv\fR(8) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan_get_serial_ports_list.txt0000644000200500020050000000373215001555412017641 00000000000000NUTSCAN_GET_SERIAL_PORTS_LIST(3) ================================ NAME ---- nutscan_get_serial_ports_list - Get a port list name from a range of port. SYNOPSIS -------- ------ #include char ** nutscan_get_serial_ports_list(const char *ports_range); ------ DESCRIPTION ----------- The *nutscan_get_serial_ports_list()* function returns a null terminated array of strings generated from a port range. The 'ports_range' may be one of: * a single character from `0` to `9` or `a` to `z`, representing a serial communication port depending on the operating system. For instance: - `0` is converted to `/dev/ttyS0` and `/dev/ttyUSB0` on Linux; - `1` is converted to `COM1` on Windows; - `c` is converted to `/dev/ttyc` on Solaris... * a range of character in the form `X-Y`. For instance - `0-1` will be converted to `/dev/ttyS0`, `/dev/ttyS1`, `/dev/ttyUSB0` and `/dev/ttyUSB1` on Linux; - `1-3` will be converted to `COM1`, `COM2` and `COM3` on Windows; - `a-c` will be converted to `/dev/ttya`, `/dev/ttyb` and `/dev/ttyc` on Solaris. * a single port name (`/dev/ttyS5`, `COM4`...). * a list of port names separated with commas: `/dev/ttyS0,/dev/ttyS2,/dev/ttyS4` or `COM1,COM3`... The returned array can be used in a call to *nutscan_scan_eaton_serial* to get the serial-port device on a system. RETURN VALUE ------------ The *nutscan_get_serial_ports_list()* function returns NULL if an error occurred (invalid port range) or a pointer to a NULL-terminated array of strings on success. NOTES ----- Technically, the function is currently defined in 'nutscan-serial.h' file. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_eaton_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_display_ups_conf[3] nut-2.8.3/docs/man/upscli_ssl.txt0000644000200500020050000000137615001555412013670 00000000000000UPSCLI_SSL(3) ============= NAME ---- upscli_ssl - Check SSL mode for current connection SYNOPSIS -------- ------ #include int upscli_ssl(UPSCONN_t *ups); ------ DESCRIPTION ----------- The *upscli_ssl*() function takes the pointer 'ups' to a `UPSCONN_t` state structure. It only returns '1' if SSL support has been compiled into the linkman:upsclient[3] library, and if it was successfully enabled for this connection. RETURN VALUE ------------ The *upscli_ssl*() function returns '1' if SSL is running, and '0' if not. It returns '-1' in the event of an error. SEE ALSO -------- linkman:upscli_fd[3], linkman:upscli_get[3], linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/nutscan_display_sanity_check.txt0000644000200500020050000000240515001555412017426 00000000000000NUTSCAN_DISPLAY_SANITY_CHECK(3) =============================== NAME ---- nutscan_display_sanity_check - Display sanity check warnings about the specified `nutscan_device_t` structure on stdout. SYNOPSIS -------- ------ #include void nutscan_display_sanity_check(nutscan_device_t * device); ------ DESCRIPTION ----------- The *nutscan_display_sanity_check()* function calls all sanity-check analyzers against displays all NUT devices in 'device', and they may print comments to `stdout`. It displays them in a way that it can be directly copied into the `ups.conf` file. It is called from *nutscan_display_ups_conf_with_sanity_check()* to provide an aggregate content for `ups.conf` file in one shot. SEE ALSO -------- linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/microsol-apc.txt0000644000200500020050000000366315001555412014101 00000000000000MICROSOL-APC(8) =============== NAME ---- microsol-apc - Driver for APC Back-UPS BR UPS equipment SYNOPSIS -------- *microsol-apc* -h *microsol-apc* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the microsol-apc driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports the following UPS models: * APC Back-UPS BZ1500-BR * APC Back-UPS BZ2200I-BR * APC Back-UPS BZ2200BI-BR In 2009, Schneider Electric acquired Microsol Technologies, and by 2012, the entire Microsol line was being sold under the APC brand. This driver supports these newer, APC-branded models. Older equipment should use linkman:solis[8]. EXTRA ARGUMENTS --------------- This driver support the following extra optional settings in the linkman:ups.conf[5]. *battext=*'n':: Default = 0, no extra battery, where `n` = Ampere*hour. *prgshut=*'n':: Default = 0, no programmable shutdown; `1` to enable one. COMMANDS -------- *shutdown.return*:: Shut down in .3 minutes and restart in .3 minutes after that. *shutdown.stayoff*:: Shut down in .3 minutes and do not return. ISSUES ------ For other APC-Microsol models, the reported voltages, currents and power will be incorrect, as the communication protocol reports unprocessed data instead of real values, needing model-specific post-processing by the driver. Monitoring of UPS state (on-battery/on-line, critical battery) should work for other models, but is untested. AUTHORS ------- * Ygor A. S. Regados * Roberto P. Velloso * Silvino B. Magalhães SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Driver for older devices under same brand: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ linkman:solis[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/phoenixcontact_modbus.80000644000200500020050000001341515001555100015426 00000000000000'\" t .\" Title: phoenixcontact_modbus .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "PHOENIXCONTACT_MODBU" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" phoenixcontact_modbus \- Driver for Phoenix Contact .SH "SYNOPSIS" .sp \fBphoenixcontact_modbus\fR \-h .sp \fBphoenixcontact_modbus\fR \-a \fIDEVICE_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the phoenixcontact_modbus driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver should support the PhoenixContact QUINT\-UPS industrial DC UPS, model 2320461 and all compatible models\&. More information about this UPS can be found among Internet resources below\&. .sp phoenixcontact_modbus uses the libmodbus project, for Modbus implementation\&. .SH "HOW TO CONFIGURE THE UPS" .sp Note: this UPS and its manual refers to Low\-Batt as "Shutdown Event"\&. .sp You need the "IFS\-RS232\-DATACABLE" to communicate with the UPS in Linux as the IFS\-USB cable doesn\(cqt seem to be supported\&. FYI communication parameters are: 115200,E,8,1\&. .sp You also need the UPS\-CONF Windows software (free; download from their site), to configure the UPS signals and timers\&. .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} Run the UPS\-CONF .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} Go to Settings→Time Setting .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} Choose "state of charge shutdown delay" .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} Choose Remote starts PC\-Shutdown in Mains and Battery mode .RE .sp .RS 4 .ie n \{\ \h'-04' 5.\h'+01'\c .\} .el \{\ .sp -1 .IP " 5." 4.2 .\} On the PC\-Shutdown enter the maximum value (5 minutes) .RE .sp .RS 4 .ie n \{\ \h'-04' 6.\h'+01'\c .\} .el \{\ .sp -1 .IP " 6." 4.2 .\} On the PC\-Restart delay enter the time you want the UPS to leave the output power off before restarting (e\&.g\&. 60 seconds), after mains power is restored\&. .RE .sp .RS 4 .ie n \{\ \h'-04' 7.\h'+01'\c .\} .el \{\ .sp -1 .IP " 7." 4.2 .\} On the UPS, turn the screw to the "PC\-MODE" position .RE .sp Configuring the above way ensures that: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} When power is lost, UPS constantly calculates remaining battery time .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} When remaining battery time is less than 5 minutes (PC\-Shutdown setting), it will raise the "Shutdown" event (seen as LOW\-BATT in NUT) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} From that moment even if input power is restored, the UPS will cut the output power to its load after 5 minutes .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} When the input power is restored, the UPS will restore output power after 60 seconds (PC\-RESTART delay setting)\&. .RE .sp Meaning of settings: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} PC\-Shutdown: How long before output cutoff the UPS will raise the "shutdown event" signal\&. Max value for this is 5 minutes\&. So PC should be able to shutdown within 5 minutes\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} PC\-Restart: How long to delay output power after power is restored\&. Max is 60 seconds\&. .RE .SH "EXTRA ARGUMENTS" .sp This driver doesn\(cqt support any optional settings\&. .SH "INSTALLATION" .sp This driver may be not built by default\&. You can build it by installing libmodbus and running configure \-\-with\-modbus=yes\&. .sp You also need to give proper permissions on the local serial device file (/dev/ttyS0 for example) to allow the NUT user to access it\&. .SH "INSTANT COMMANDS" .sp This driver doesn\(cqt support any instant commands\&. .SH "AUTHOR" .sp Spiros Ioannou .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} libmodbus home page: http://libmodbus\&.org .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} More information about PhoenixContact QUINT\-UPS industrial DC UPS, model 2320461 UPS series can be found here: https://www\&.phoenixcontact\&.com/online/portal/us?uri=pxc\-oc\-itemdetail:pid=2320461 .RE nut-2.8.3/docs/man/liebert.80000644000200500020050000000522115001555071012460 00000000000000'\" t .\" Title: liebert .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIEBERT" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" liebert \- Driver for Liebert contact\-closure UPS equipment .SH "SYNOPSIS" .sp \fBliebert\fR \-h .sp \fBliebert\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the liebert driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports some Liebert UPS equipment with a contact\-closure interface\&. This includes the UPStation GXT2 with their contact\-closure cable\&. .sp The smart mode ("Multilink") cable is NOT supported by this driver\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "BUGS" .sp This driver does not yet support shutdowns by raising DTR\&. Be aware that shutdowns are not possible with the stock contact\-closure cable\&. You may have to build another cable with DTR connected through to the UPS for it to work\&. .sp There is no way for this driver to detect the hardware or cable\&. It will start up successfully even if no UPS is present\&. This is a fundamental limitation of any contact\-closure driver\&. .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upscli_connect.30000644000200500020050000001045515001555051014040 00000000000000'\" t .\" Title: upscli_connect .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_CONNECT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_connect, upscli_tryconnect \- Open a connection to a NUT upsd data server .SH "SYNOPSIS" .sp .nf #include /* Open a connection to a NUT upsd data server (blocking by default) */ int upscli_connect(UPSCONN_t *ups, const char *host, uint16_t port, int flags); /* Open a connection to a NUT upsd data server with specified timeout */ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags, struct timeval * timeout); .fi .SH "DESCRIPTION" .sp The \fBupscli_connect()\fR function takes the pointer \fIups\fR to a UPSCONN_t state structure and opens a TCP connection to the \fIhost\fR on the given \fIport\fR\&. .sp By default this makes a blocking connection attempt (until the system transport layer times out the underlying \fBselect\fR(2) call)\&. A program\-wide default timeout for this method can be configured with the \fBupscli_set_default_connect_timeout\fR(3) or \fBupscli_init_default_connect_timeout\fR(3) methods\&. For operations with explicit operation\-specific timeout please use the \fBupscli_tryconnect()\fR method instead\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp As part of general initialization, both the \fBupscli_init\fR(3) function or the first call to \fBupscli_connect()\fR function, can call the \fBupscli_init_default_connect_timeout\fR(3) method (if it was never used before): this allows unmodified (legacy) NUT clients to consistently benefit from presence of the NUT_DEFAULT_CONNECT_TIMEOUT environment variable for \fBupscli_connect\fR(3) attempts to be not blocking (as per default)\&. .sp .5v .RE .sp \fIflags\fR may be either UPSCLI_CONN_TRYSSL to try a SSL connection, or UPSCLI_CONN_REQSSL to require a SSL connection\&. .sp Introduced in version 2\&.7, an additional flag UPSCLI_CONN_CERTVERIF now exists to verify the signature offered during the SSL handshake\&. This flag should be used in conjunction with \fBupscli_init\fR(3) and/or \fBupscli_add_host_cert\fR(3) calls before connecting in order to define a CA certificate with which to verify\&. .sp If SSL mode is required, this function will only return successfully if it is able to establish a SSL connection with the server\&. Possible reasons for failure include no SSL support on the server, and if \fBupsclient\fR itself hasn\(cqt been compiled with SSL support\&. .sp You must call \fBupscli_disconnect\fR(3) when finished with a connection, or your program will slowly leak memory and file descriptors\&. .SH "RETURN VALUE" .sp The \fBupscli_connect()\fR function modifies the UPSCONN_t structure and returns \fI0\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_disconnect\fR(3), \fBupscli_fd\fR(3), \fBupscli_init\fR(3), \fBupscli_splitaddr\fR(3), \fBupscli_splitname\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_get_default_connect_timeout\fR(3), \fBupscli_set_default_connect_timeout\fR(3), \fBupscli_init_default_connect_timeout\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/upscli_set_default_connect_timeout.30000644000200500020050000000527215001555052020167 00000000000000'\" t .\" Title: upscli_set_default_connect_timeout .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_SET_DEFAULT_C" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_set_default_connect_timeout \- Configure upsclient module aspect of default timeout for initial connections\&. .SH "SYNOPSIS" .sp .nf #include int upscli_set_default_connect_timeout(const char *secs); .fi .SH "DESCRIPTION" .sp The \fBupscli_set_default_connect_timeout()\fR function assigns upsclient module internal default connection timeout for \fBupscli_connect\fR(3) from a C string which represents a floating\-point non\-negative number (invalid parsing is ignored and does not modify the previously stored value), a NULL argument value sets the internal timeout to \fI0\fR meaning indefinitely blocking (NUT default for this method over at least 20 years)\&. .sp While this method can be called explicitly, it is recommended to call the \fBupscli_init_default_connect_timeout\fR(3) for consistent setting from a number of sources with different priority\&. .SH "RETURN VALUE" .sp The \fBupscli_set_default_connect_timeout()\fR function returns \fI0\fR on success (either if the strings was NULL so the built\-in default \fI0\fR is applied, or if its content was valid and its value got applied), or \fI\-1\fR if an error occurs (string was not NULL, and its content was not valid \(em not a number, negative, etc\&.) .SH "SEE ALSO" .sp \fBupscli_connect\fR(3), \fBupscli_tryconnect\fR(3), \fBupscli_init_default_connect_timeout\fR(3), \fBupscli_get_default_connect_timeout\fR(3) nut-2.8.3/docs/man/nutscan_free_device.txt0000644000200500020050000000172215001555412015476 00000000000000NUTSCAN_FREE_DEVICE(3) ====================== NAME ---- nutscan_free_device - Free a `nutscan_device_t` structure created by `nutscan_new_device`. SYNOPSIS -------- ------ #include void nutscan_free_device(nutscan_device_t * device); ------ DESCRIPTION ----------- The *nutscan_free_device()* function can free a `nutscan_device_type_t` structure. Doing so, it frees the whole linked list, not only the given device. NOTES ----- Technically, the function is currently defined in 'nutscan-device.h' file. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3] nut-2.8.3/docs/man/upscli_list_start.txt0000644000200500020050000000404115001555412015247 00000000000000UPSCLI_LIST_START(3) ==================== NAME ---- upscli_list_start - Begin multi-item retrieval from a UPS SYNOPSIS -------- ------ #include int upscli_list_start(UPSCONN_t *ups, size_t numq, const char **query) ------ DESCRIPTION ----------- The *upscli_list_start()* function takes the pointer 'ups' to a `UPSCONN_t` state structure, and the pointer 'query' to an array of 'numq' query elements. It builds a properly-formatted request from those elements and transmits it to linkman:upsd[8]. Upon success, the caller must call linkman:upscli_list_next[3] to retrieve the elements of the list. Failure to retrieve the list will most likely result in the client getting out of sync with the server due to buffered data. USES ---- This function implements the "LIST" command in the protocol. As a result, you can use it to request many different things from the server. Some examples are: - LIST UPS - LIST VAR - LIST RW - LIST CMD - LIST ENUM - LIST RANGE QUERY FORMATTING ---------------- To see the list of variables on a UPS called 'su700', the protocol command would be `LIST VAR su700`. To start that list with this function, you would populate query and numq as follows: ------ size_t numq; const char *query[2]; query[0] = "VAR"; query[1] = "su700"; numq = 2; ------ All escaping of special characters and quoting of elements with spaces are handled for you inside this function. ERROR CHECKING -------------- This function checks the response from linkman:upsd[8] against your query. If it is not starting a list, or is starting the wrong type of list, it will return an error code. When this happens, linkman:upscli_upserror[3] will return `UPSCLI_ERR_PROTOCOL`. RETURN VALUE ------------ The *upscli_list_start()* function returns '0' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_fd[3], linkman:upscli_get[3], linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/nutscan_scan_snmp.txt0000644000200500020050000000633515001555412015224 00000000000000NUTSCAN_SCAN_SNMP(3) ==================== NAME ---- nutscan_scan_snmp - Scan network for SNMP devices. SYNOPSIS -------- ------ #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_snmp( const char * start_ip, const char * stop_ip, useconds_t timeout, nutscan_snmp_t * sec); nutscan_device_t * nutscan_scan_ip_range_snmp( nutscan_ip_range_list_t * irl, useconds_t usec_timeout, nutscan_snmp_t * sec); ------ DESCRIPTION ----------- The *nutscan_scan_snmp()* and *nutscan_scan_ip_range_snmp()* functions try to detect NUT compatible SNMP devices. The former tries SNMP queries on every IP ranging from 'start_ip' to 'stop_ip', where 'startIP' is mandatory and 'stopIP' is optional (one 'startIP' address is scanned if 'stopIP' is NULL); while the latter can walk several IP address ranges represented by a `nutscan_ip_range_list_t` structure. Those IP arguments may be either IPv4 or IPv6 addresses or host names. You MUST call linkman:nutscan_init[3] before using this function. This function waits up to 'timeout' microseconds before considering an IP address does not respond to SNMP queries. A valid `nutscan_snmp_t` structure must be passed to this function. The `nutscan_snmp_t` structure contains the following members which must be filled as described below: char * 'community'; char * 'secLevel'; char * 'secName'; char * 'authPassword'; char * 'privPassword'; char * 'authProtocol'; char * 'privProtocol'; If 'community' is not NULL, SNMP v1 request are sent using this 'community'. If 'community' is NULL and 'secLevel' is NULL, SNMP v1 is selected and 'community' is set to "public". In the other cases, SNMP v3 is used. 'secLevel' may be one of `SNMP_SEC_LEVEL_NOAUTH`, `SNMP_SEC_LEVEL_AUTHNOPRIV` or `SNMP_SEC_LEVEL_AUTHPRIV`. 'secName' is the security name and must be non NULL. If 'secLevel' is set to `SNMP_SEC_LEVEL_AUTHNOPRIV`, 'authPassword' must be non NULL. If 'secLevel' is set to `SNMP_SEC_LEVEL_AUTHPRIV`, 'authPassword' and 'privPassword' must be non NULL. If 'authProtocol' is NULL, MD5 protocol is used. Else you can set 'authProtocol' to either "MD5" or "SHA". If 'privProtocol' is NULL, DES protocol is used. Else you can set 'privProtocol' to either "AES" or "DES". 'peername' and 'handle' are used internally and do not need any initialization. RETURN VALUE ------------ The *nutscan_scan_snmp()* function returns a pointer to a `nutscan_device_t` structure containing all found devices or NULL if an error occurs or no device is found. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], linkman:nutscan_init_ip_ranges[3], linkman:nutscan_free_ip_ranges[3], linkman:nutscan_add_ip_range[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/nutconf.txt0000644000200500020050000002047415001555412013164 00000000000000NUTCONF(8) ========== NAME ---- nutconf - NUT configuration tool SYNOPSIS -------- *nutconf* --help *nutconf* ['OPTIONS'] DESCRIPTION ----------- *nutconf* tool is used to create and manipulate NUT configuration files. It also supports device scanning (to suggest configuration of devices). INSTALLATION ------------ The scanning feature depends on the very same compile time and run time dependencies as the *nut-scanner*. OPTIONS ------- *-h* | *-help* | *--help*:: Display the help text. *-v* | *--verbose*:: Increase output verbosity (may be used multiple times). *--is-configured*:: Checks whether NUT was configured, before. *--system*:: System configuration directory shall be used. *--local* 'directory':: Sets alternative configuration directory. *--get-mode*:: Prints current NUT configuration mode *--set-mode* 'mode':: Sets NUT configuration mode. + Known modes are: - standalone - netserver - netclient - controlled - manual - none CONFIGURATION ENTRY SET/ADD OPTIONS ----------------------------------- These options mostly have 2 forms: '--set-...' or '--add-...'. The difference is that the set options discard previous settings while the add options keep them. Note that such options may be specified multiple times for one run (to enable setting multiple entries at once). *--set-monitor* | *--add-monitor* '':: Sets/adds a NUT monitor. + * Arguments: + ---- '' '[:]' '' '' '' '(\"master\"|\"slave\")' ---- *--set-listen* | *--add-listen* '
    ' '[]':: Sets/adds linkman:upsd[8] daemon listen address. *--set-device* | *--add-device* '':: Sets/adds a device (typically a UPS). + * Arguments: + ---- '' '' '' '[=]*' ---- + The attribute/value pairs follow device configuration syntax. Devices may have very different configuration attributes depending on the driver. Exhaustive description of them is beyond this man page and may be found in NUT documentation. *--set-notifyflags* | *--add-notifyflags* '' '+':: + -- Sets/adds notification flags for the notification type. * Notification types are: - 'ONLINE' (mains is present) - 'ONBATT' (mains is gone) - 'LOWBATT' (remaining battery capacity is low) - 'FSD' (shutdown was forced) - 'COMMOK' (communication with device established) - 'COMMBAD' (lost communication with device) - 'SHUTDOWN' (system is going down, now) - 'REPLBATT' (UPS battery needs replacing) - 'NOCOMM' (device is unavailable) - 'NOPARENT' (upsmon parent process died, shutdown is impossible) - 'CAL' (calibration in progress) - 'NOTCAL' (calibration finished) - 'OFF' (UPS is administratively OFF or asleep, should wake up on command) - 'NOTOFF' (UPS is no longer administratively OFF or asleep) - 'BYPASS' (on bypass = powered, not protecting) - 'NOTBYPASS' (no longer on bypass) - 'ALARM' (UPS is in an alarm state (has active alarms)) - 'NOTALARM' (UPS is no longer in an alarm state (no active alarms)) - 'OVER' (overloaded) - 'NOTOVER' (no longer overloaded) - 'TRIM' (trimming incoming voltage) - 'NOTTRIM' (no longer trimming incoming voltage) - 'BOOST' (boosting incoming voltage) - 'NOTBOOST' (no longer boosting incoming voltage) - 'OTHER' (UPS has at least one unclassified status token) - 'NOTOTHER' (UPS has no unclassified status tokens anymore) - 'SUSPEND_STARTING' (OS is entering sleep/suspend/hibernate mode) - 'SUSPEND_FINISHED' (OS just finished sleep/suspend/hibernate mode) * Notification flags: - 'SYSLOG' (use syslogd to log the notification) - 'WALL' (push a message to users' terminals) - 'EXEC' (execute a command) - 'IGNORE' (don't act) -- *--set-notifymsg* '' '':: Sets message for the specified notification type. *--set-shutdowncmd* '':: Sets command used to shut the system down. *--set-user* | *--add-user* '':: Sets/adds NUT user. + * Arguments: - '' (specifies user name). For 'upsmon' user, it has a special form of `upsmon=(primary|master|secondary|slave)` which specifies the monitoring mode. - 'password=' sets password for the user - 'actions=' sets actions ('SET', 'FSD' are supported) - 'instcmds=' sets instant commands allowed for the user (may be used multiple times) SCANNING OPTIONS ---------------- Availability of each scanning option depends on availability of various 3rd-party libraries both at compile time and run time. Run the tool with the *--help* option to check which of the *--scan-...* options are actually supported. All timeouts are in microseconds. *--scan-snmp* '' '' '[=]*':: Scans for SNMP devices on IP addresses from the specified range. + * Known attributes are: - 'timeout' device scan timeout - 'community' SNMP community (default: *public*) - 'sec-level' security level (SNMPv3); one of *noAuthNoPriv* *authNoPriv*, *authPriv* - 'sec-name' security name (SNMPv3); mandatory companion of *sec-level* - 'auth-password' authentication password (SNMPv3); mandatory for *authNoPriv* and *authPriv* - 'priv-password' privacy password (SNMPv3); mandatory for *authPriv* - 'auth-protocol' authentication protocol (SNMPv3): *MD5* or *SHA*, *MD5* is the default - 'priv-protocol' priv. protocol (SNMPv3): *DES* or *AES*, *DES* is the default - 'peer-name' peer name *--scan-usb*:: Scans the USB bus for known devices *--scan-xml-http* '[]':: Scans for XML/HTTP devices on the network. *--scan-nut* '' '' '' '[]':: Scans for NUT (pseudo-)devices on the network. *--scan-avahi* '[]':: Scans for Avahi devices. *--scan-ipmi* '' '' '[=]'*:: + -- Scans for IPMI devices on IP addresses from the specified range. * Known attributes are: - 'username' username (mandatory for IPMI/LAN) - 'password' user password (mandatory for IPMI/LAN) - 'auth-type' authentication type (see below) - 'cipher-suite-id' cipher suite ID (see below) - 'K-g-BMC-key' optional second key (???) - 'priv-level' priv. level - 'workaround-flags' - 'version' (1.5 or 2.0) * Authentication types: + Specifies the IPMI 1.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5). This forces connection through the 'lan' IPMI interface, thus in IPMI 1.5 mode. - 'none' (authentication is disabled) - 'MD2' - 'MD5' (default) - 'plain-password' (no ciphering used for password sending) - 'OEM' - 'RMCPplus' * Cipher suite IDs: + Specifies the IPMI 2.0 cipher suite ID to use. + The Cipher Suite ID identifies a set of authentication, integrity, and confidentiality algorithms to use for IPMI 2.0 communication. + The authentication algorithm identifies the algorithm to use for session setup, the integrity algorithm identifies the algorithm to use for session packet signatures, and the confidentiality algorithm identifies the algorithm to use for payload encryption (default=3). + The following cipher suite IDs are currently supported: + [options="header"] |=========================================================================== | Code | Authentication | Integrity | Confidentiality | '0' | None | None | None | '1' | HMAC-SHA1 | None | None | '2' | HMAC-SHA1 | HMAC-SHA1-96 | None | '3' | HMAC-SHA1 | HMAC-SHA1-96 | AES-CBC-128 | '6' | HMAC-MD5 | None | None | '7' | HMAC-MD5 | HMAC-MD5-128 | None | '8' | HMAC-MD5 | HMAC-MD5-128 | AES-CBC-128 | '11' | HMAC-MD5 | MD5-128 | None | '12' | HMAC-MD5 | MD5-128 | AES-CBC-128 | '15' | HMAC-SHA256 | None | None | '16' | HMAC-SHA256 | HMAC_SHA256_128 | None | '17' | HMAC-SHA256 | HMAC_SHA256_128 | AES-CBC-128 |=========================================================================== -- *--scan-serial* ''*:: Scans for serial devices (of supported types) on the specified serial port(s). EXAMPLES -------- To set alternative directory for configuration files: :; nutconf --local ~/test/nut/etc To add another user (keeping the existing ones): :; nutconf --add-user bart password=qwerty To scan USB devices and serial devices (on the first two ports): :; nutconf --scan-usb --scan-serial /dev/ttyS1 /dev/ttyS2 SEE ALSO -------- linkman:ups.conf[5] linkman:nut-scanner[8] INTERNET RESOURCES ------------------ The NUT (Network UPS Tools) home page: http://www.networkupstools.org/ nut-2.8.3/docs/man/richcomm_usb.txt0000644000200500020050000000317115001555412014155 00000000000000RICHCOMM_USB(8) =============== NAME ---- richcomm_usb - Driver UPS equipment using Richcomm dry-contact to USB solution SYNOPSIS -------- *richcomm_usb* -h *richcomm_usb* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the richcomm_usb driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The Richcomm dry-contact to USB solution is a generic interface that is used to upgrade an existing (RS-232) contact closure UPS interface to USB. As such, all the limitations of the underlying contact closure interface apply. This means that you will only get the essentials in `ups.status`: `OL`, `OB`, and `LB`. See also linkman:genericups[8]. //////// TODO: Uncomment after solving https://github.com/networkupstools/nut/issues/1768 EXTRA ARGUMENTS --------------- include::nut_usb_addvars.txt[] //////// BUGS ---- Most contact-closure UPSes will not power down the load if the line power is present. This can create a race when using secondary linkman:upsmon[8] systems. See the linkman:upsmon[8] man page for more information. The solution to both of these problems is to upgrade to a smart protocol UPS of some kind that allows detection and proper load cycling on command. AUTHORS ------- * Peter van Valderen * Dirk Teurlings SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] The generic serial driver: ~~~~~~~~~~~~~~~~~~~~~~~~~~ linkman:genericups[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/sockdebug.80000644000200500020050000001033415001555064013003 00000000000000'\" t .\" Title: sockdebug .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "SOCKDEBUG" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" sockdebug \- Simple developer/troubleshooting aid utility to communicate with a NUT driver using the socket protocol .SH "SYNOPSIS" .sp \fBsockdebug\fR socketname .sp For example (WIN32 and POSIX builds): .sp .nf :; sockdebug\&.exe dummy\-ups\-UPS1 .fi .sp For example (POSIX\-compliant systems using an alternate state path): .sp .nf :; sockdebug /var/state/ups/dummy\-ups\-UPS1 .fi .SH "DESCRIPTION" .sp \fBsockdebug\fR is a tool built when NUT configure \-\-with\-dev is enabled\&. It may alternatively be built by calling make sockdebug in the root of the build workspace\&. Actual source files used depend on the platform\&. .sp It is used to connect to a NUT driver using the socket protocol on an Unix socket or Windows pipe, similarly to how the \fBupsd\fR(8) data server talks to the locally running drivers in order to represent them on the network further using the common NUT protocol of the Network UPS Tools project, or how driver programs can communicate to their already running instances to implement commands like live reload\-or\-error\&. .sp This tool allows a developer or troubleshooter to watch the broadcast updates emitted by the driver, as well as to issue unicast commands and receive replies (during an interactive investigation session, you may want to command NOBROADCAST first)\&. .sp For more details see the docs/sock\-protocol\&.txt file in NUT sources\&. .SH "OPTIONS" .sp \fBsockdebug\fR accepts (and requires) the following option: .PP \fBsocketname\fR .RS 4 Either a full path (in POSIX builds) or the base name of device socket/pipe (on all platforms), comprised of a drivername\-devicename tuple, e\&.g\&. some dummy\-ups\-UPS1 for a dummy\-ups driver instance handling an UPS1 device configuration (which in turn may originate in the ups\&.conf file or be dynamically constructed for tests by calling the driver program with a \-s TMP CLI option)\&. .sp On POSIX systems, if this argument only represents a base name and not a full path to the Unix socket file, the tool should first look for the file in the current directory, and then fall back to configured (built\-in) state path or the value of NUT_STATEPATH environment variable, if set; e\&.g\&.: .sp .if n \{\ .RS 4 .\} .nf :; NUT_STATEPATH=/tmp \&./server/sockdebug dummy\-ups\-UPS1 .fi .if n \{\ .RE .\} .RE .SH "AUTHORS" .sp This manual page was written by Jim Klimov \&. .sp The program is currently maintained as two separate sources, with one of them used for a build depending on the target platform: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} server/sockdebug\&.c (POSIX version) was originally written by Russell Kroll , and .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} server/pipedebug\&.c (Windows version) was originally written by Frederic Bohe \&. .RE .SH "SEE ALSO" .sp \fBupsd\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upsclient.txt0000644000200500020050000000732515001555412013516 00000000000000UPSCLIENT(3) ============ NAME ---- upsclient - Network UPS Tools client access library DESCRIPTION ----------- The Network UPS Tools (NUT) *upsclient* library provides a number of useful functions for client programs to use when communicating with linkman:upsd[8]. Many of the low-level socket and protocol details are handled automatically when using this interface, also known as "upscli" API. State is maintained across calls in an opaque structure called `UPSCONN_t`. Callers are expected to create one per connection. These will be provided to most of the *upsclient* functions. The format of this structure is subject to change, and client programs must not reference elements within it directly. INITIALIZATION AND CLEANUP -------------------------- Before creating any connection, and in general using any upscli function, you must call linkman:upscli_init[3] with proper parameters to initialize upscli module. To register a specific host security policy, you must call linkman:upscli_add_host_cert[3] before initializing a connection to it. In the same way, just before exiting, and after all upscli usage, you must call linkman:upscli_cleanup[3] to flush cache files and perform other cleanup. NETWORK FUNCTIONS ----------------- To create a new connection, use linkman:upscli_connect[3]. This will also initialize the `UPSCONN_t` structure. To verify that a connection has been established later, linkman:upscli_fd[3] can be used to return the file descriptor. Clients wishing to check for the presence and operation of SSL on a connection may call linkman:upscli_ssl[3]. The majority of clients will use linkman:upscli_get[3] to retrieve single items from the server. To retrieve a list, use linkman:upscli_list_start[3] to get it started, then call linkman:upscli_list_next[3] for each element. Raw lines of text may be sent to linkman:upsd[8] with linkman:upscli_sendline[3]. Reading raw lines is possible with linkman:upscli_readline[3]. Client programs are expected to format these lines according to the protocol, as no checking will be performed before transmission. At the end of a connection, you must call linkman:upsclient_disconnect[3] to disconnect from *upsd* and release any dynamic memory associated with the `UPSCONN_t` structure. Failure to call this function will result in memory and file descriptor leaks in your program. STRING FUNCTIONS ---------------- To parse the `ups.status` values (check whether a particular token is present) you are encouraged to use the linkman:upscli_str_contains_token[3] method. To collect unique tokens into a string in the same manner a NUT driver does, the linkman:upscli_str_add_unique_token[3] can be helpful. You are welcome to consult the NUT source code base for use of equivalent methods to implement such features as `status_init()`, `status_get()`, `status_set()` and `status_commit()` methods in its data-processing loops. ERROR HANDLING -------------- In the event of an error, linkman:upscli_strerror[3] will provide human-readable details on what happened. linkman:upscli_upserror[3] may also be used to retrieve the error number. These numbers are defined in *upsclient.h* as 'UPSCLI_ERR_*'. SEE ALSO -------- linkman:nutclient[3], linkman:libupsclient-config[1], linkman:upscli_init[3], linkman:upscli_cleanup[3], linkman:upscli_add_host_cert[3], linkman:upscli_connect[3], linkman:upscli_disconnect[3], linkman:upscli_fd[3], linkman:upscli_getvar[3], linkman:upscli_list_next[3], linkman:upscli_list_start[3], linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_splitaddr[3], linkman:upscli_splitname[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3], linkman:upscli_str_add_unique_token[3], linkman:upscli_str_contains_token[3] nut-2.8.3/docs/man/metasys.txt0000644000200500020050000000313215001555412013165 00000000000000METASYS(8) ========== NAME ---- metasys - Driver for Meta System UPS equipment SYNOPSIS -------- *metasys* -h *metasys* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the metasys driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The *metasys* driver was written with the "Meta System UPS Protocol Rev.1.12" kindly supplied from Meta System. The driver should support all the common features of the UPS models: - HF Line (/2) 1-8 boards - HF Millennium (810, 820) - HF TOP Line (910, 920, 930, 940, 950, 970, 980) - ECO Network (750, 1000, 1050, 1500, 1800, 2000, 2100, 2500, 3000) - ECO (305, 308, 311, 511, 516, 519, 522, SX, SXI) - ally HF (800, 1000, 1250, 1600, 2000, 2500) - Megaline (1250, 2500, 3750, 5000, 6250, 7500, 8750, 10000) CABLING ------- The needed cable is a standard pin-to-pin serial cable with at least pins 2, 3, and 5 (on DB9 connector) connected. EXTRA ARGUMENTS --------------- This driver supports no extra arguments from linkman:ups.conf[5]. BUGS ---- This driver has been tested on Meta System HF Millennium 820 and ally HF 1000 only. Any information about the use of the driver with the other listed UPS are really welcome. AUTHOR ------ Fabio Di Niro SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * Meta System UPS protocol: https://networkupstools.org/ups-protocols.html#_legrand nut-2.8.3/docs/man/victronups.txt0000644000200500020050000000265615001555412013726 00000000000000VICTRONUPS(8) ============= NAME ---- victronups - Driver for IMV/Victron UPS unit Match, Match Lite, NetUps SYNOPSIS -------- *victronups* -h *victronups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the the victronups driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The victronups driver should recognize all Victron models that use a serial protocol at 1200 bps. These include Match Lite, Match and the NetUps line. The Match Lite line may only report a handful of variables. This is usually not a bug -- they just don't support anything else. CABLING ------- If your Victron cable is broken or missing, use this diagram to build a clone: * https://github.com/networkupstools/nut/blob/master/docs/cables/ge-imv-victron.txt * link:docs/cables/ge-imv-victron.txt[] EXTRA ARGUMENTS --------------- This driver supports the following optional setting in the linkman:ups.conf[5]: *modelname*='name':: Set model name *usd*='delay':: Set delay before shutdown on UPS BUGS ---- The protocol for this UPS is not officially documented. AUTHORS ------- * Radek Benedikt * Daniel Prynych SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/apcsmart-old.80000644000200500020050000001064015001555065013424 00000000000000'\" t .\" Title: apcsmart-old .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "APCSMART\-OLD" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" apcsmart-old \- Driver for American Power Conversion Smart Protocol UPS equipment .SH "SYNOPSIS" .sp \fBapcsmart\-old\fR \-h .sp \fBapcsmart\-old\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the apcsmart\-old driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp apcsmart\-old should recognize all recent APC models that use a serial protocol at 2400 bps\&. This is primarily the Smart\-UPS, Matrix\-UPS and Back\-UPS Pro lines\&. .sp The driver attempts to support every bell and whistle of the APC reporting interface, whether or not this is strictly sensible\&. .sp Some older hardware may only report a handful of variables\&. This is usually not a bug\(emthey just don\(cqt support anything else\&. .SH "CABLING" .sp This driver expects to see a 940\-0024C cable or a clone by default\&. You can switch to the 940\-0095B dual\-mode cable support with the cable= definition described below\&. .sp If your 940\-0024C cable is broken or missing, use this diagram to build a clone: .sp https://www\&.networkupstools\&.org/cables/940\-0024C\&.jpg .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBcable=940\-0095B\fR .RS 4 Configure the serial port for the APC 940\-0095B dual\-mode cable\&. .RE .PP \fBsdtype=\fR\fInum\fR .RS 4 Use shutdown type \fInum\fR, according to this table: .PP 0 .RS 4 soft shutdown or powerdown, depending on battery status .RE .PP 1 .RS 4 soft shutdown followed by powerdown .RE .PP 2 .RS 4 instant power off .RE .PP 3 .RS 4 power off with grace period .RE .PP 4 .RS 4 "force OB" hack method for CS 350 .RE .RE .sp Modes 0 and 1 will power up the load when power returns\&. Modes 2 and 3 will keep the load turned off when the power returns\&. .sp Mode 4 exploits an oddity in the CS 350 models since they only seem to support the S command, but then only when running on battery\&. As a result, the driver will force the UPS to go on battery if necessary before sending the shutdown command\&. This ensures that the load gets reset\&. .SH "BUGS" .sp Some older APC UPS models return bogus data in the status register during a front panel test\&. This is usually detected and discarded, but some other unexpected values have occasionally slipped through\&. .sp APC UPS models with both USB and serial ports require a power cycle when switching from USB communication to serial, and perhaps vice versa\&. .SH "AUTHORS AND HISTORY" .sp Nigel Metheringham (drawing heavily on the original apcsmart driver by Russell Kroll)\&. .sp This driver was called newapc for a time and was renamed in the 1\&.5 series\&. .sp In 2\&.6\&.2 the driver was renamed to apcsmart\-old, being superseded by updated version with new features which currently holds the apcsmart name\&. .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/bestuferrups.txt0000644000200500020050000000153115001555412014232 00000000000000BESTUFERRUPS(8) =============== NAME ---- bestuferrups - Driver for Best Power Micro-Ferrups SYNOPSIS -------- *bestuferrups* -h *bestuferrups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the bestuferrups driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ Best Power Micro-Ferrups ME3100, probably other similar models too. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. AUTHORS ------- * Andreas Wrede, John Stone (bestuferrups) * Grant Taylor (bestfort) * Russell Kroll (bestups) SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/sockdebug.txt0000644000200500020050000000540015001555412013446 00000000000000SOCKDEBUG(8) ============ NAME ---- sockdebug - Simple developer/troubleshooting aid utility to communicate with a NUT driver using the socket protocol SYNOPSIS -------- *sockdebug* socketname For example (WIN32 and POSIX builds): :; sockdebug.exe dummy-ups-UPS1 For example (POSIX-compliant systems using an alternate state path): :; sockdebug /var/state/ups/dummy-ups-UPS1 DESCRIPTION ----------- *sockdebug* is a tool built when NUT `configure --with-dev` is enabled. It may alternatively be built by calling `make sockdebug` in the root of the build workspace. Actual source files used depend on the platform. It is used to connect to a NUT driver using the socket protocol on an Unix socket or Windows pipe, similarly to how the linkman:upsd[8] data server talks to the locally running drivers in order to represent them on the network further using the common NUT protocol of the Network UPS Tools project, or how driver programs can communicate to their already running instances to implement commands like live `reload-or-error`. This tool allows a developer or troubleshooter to watch the broadcast updates emitted by the driver, as well as to issue unicast commands and receive replies (during an interactive investigation session, you may want to command `NOBROADCAST` first). For more details see the `docs/sock-protocol.txt` file in NUT sources. OPTIONS ------- *sockdebug* accepts (and requires) the following option: *socketname*:: Either a full path (in POSIX builds) or the base name of device socket/pipe (on all platforms), comprised of a `drivername-devicename` tuple, e.g. some `dummy-ups-UPS1` for a `dummy-ups` driver instance handling an `UPS1` device configuration (which in turn may originate in the `ups.conf` file or be dynamically constructed for tests by calling the driver program with a `-s TMP` CLI option). + On POSIX systems, if this argument only represents a base name and not a full path to the Unix socket file, the tool should first look for the file in the current directory, and then fall back to configured (built-in) state path or the value of `NUT_STATEPATH` environment variable, if set; e.g.: + ------ :; NUT_STATEPATH=/tmp ./server/sockdebug dummy-ups-UPS1 ------ AUTHORS ------- This manual page was written by Jim Klimov . The program is currently maintained as two separate sources, with one of them used for a build depending on the target platform: * `server/sockdebug.c` (POSIX version) was originally written by Russell Kroll , and * `server/pipedebug.c` (Windows version) was originally written by Frederic Bohe . SEE ALSO -------- linkman:upsd[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upsdrvsvcctl.txt0000644000200500020050000002124315001555412014245 00000000000000UPSDRVSVCCTL(8) =============== NAME ---- upsdrvsvcctl - Network UPS Tools driver service instance controller SYNOPSIS -------- *upsdrvsvcctl* -h *upsdrvsvcctl* ['OPTIONS'] {start | stop | status} ['ups'] DESCRIPTION ----------- *upsdrvsvcctl* provides a uniform interface for controlling your UPS drivers wrapped into service instances on platforms which support that (currently this covers Linux distributions with systemd and systems derived from Solaris 10 codebase, including proprietary Sun/Oracle Solaris and numerous open-source illumos distributions with SMF). It may be not installed in packaging for other operating systems. When used properly, `upsdrvsvcctl` lets you maintain identical startup scripts across multiple systems with different UPS configurations. The goal of this solution is to allow the services of linkman:upsd[8] data server to start up even if some of the power devices are currently not accessible, and for NUT drivers to be automatically restarted by the system in case of problems (driver bug, startup failure). It also allows for faster startup of systems which monitor several devices, by letting each driver to start in parallel with others and as soon as the required subsystem for the specific driver's media is available, i.e. not with a sequential loop like was done previously. Independent service instances for each NUT driver also allow one to configure further dependencies, such as that networking must be available for SNMP and similar drivers (but is not needed for local-medium drivers such as serial or USB). The old monolithic "all or nothing" solution requiring that all drivers must be running, which sufficed for deployments with a few UPSes, did not really work well for monitoring larger deployments. It was also not easy to strike a pre-packaged balance between early UPS protection for USB/serial home setups vs. waiting for network on larger ones. *upsdrvsvcctl* is a script which mimics the operation of linkman:upsdrvctl[8] program (where possible) to provide similar end-user experience when manipulating drivers wrapped into service instances rather than as directly executed daemons. It relies on linkman:nut-driver-enumerator[8] for a large part of actual operations. You should use `upsdrvsvcctl` instead of direct calls to the drivers and daemon-based management with linkman:upsdrvctl[8] whenever possible (that is, for "production" use on compatible OSes). Otherwise (testing, other OSes) the `upsdrvctl` is a recommended option. OPTIONS ------- *-h*:: Display the help text, including the built-in version of the script. *-V*:: Display the version of NUT binaries (calling *upsdrvctl -V*), which normally should not differ much from the built-in version of the script shown in help. But with custom builds everything is possible, so it may be useful to know. *-t*:: Enable testing mode. Testing mode makes upsdrvsvcctl display the actions it would execute without actually doing them. *--timeout-cmd * and *--timeout-args *:: Service management calls will be time-limited by calling the specified program with its args. By default, if coreutils timeout is found, it would be used to limit service calls by 90 sec, to avoid/work around certain hangs that happen in some systemd version under stress. OPTIONS OF UPSDRVCTL NOT (CURRENTLY) APPLICABLE TO UPSDRVSVCCTL --------------------------------------------------------------- Options like '-r', '-u' or '-D' could be handled by properties of the service instances themselves, with this script helping to configure them (assuming proper privileges of the user who called it). This is not a "production" use case, though, to change such options on a configured system -- so for experiments and troubleshooting, it may be better to stop the service instance and play with *upsdrvctl* directly. *-r* 'directory':: If starting a driver, this value will direct it to linkmanext:chroot[2] into 'directory'. This can be useful when securing systems. + This may be set in the linkman:ups.conf[5] with the +chroot+ directive in the global section. *-u* 'username':: If starting a driver, this value will direct it to linkmanext:setuid[2] to the user id associated with 'username'. + If the driver is started as 'root' without specifying this value, it will use the username that was compiled into the binary. This defaults to 'nobody' (if not otherwise configured), which is far from ideal. + This may be set in linkman:ups.conf[5] with the +user+ directive in the global section. *-D*:: Raise the driver debug level. Use this multiple times for additional details. COMMANDS -------- *upsdrvsvcctl* supports three of the commands processed by *upsdrvctl* -- start, stop and shutdown. They take an optional argument which is a UPS name from linkman:ups.conf[5]. Without that argument, they operate on every UPS that is currently configured. Note: shutdown is currently supported by stopping the driver service instances to release the potentially held ports etc., calling the *upsdrvctl* directly for issuing the shutdown command, and restarting the driver service instances to reconnect when the device comes back online. *start*:: Start the UPS driver(s). In case of failure, further attempts may be executed by using the 'maxretry' and 'retrydelay' options -- see linkman:ups.conf[5]. *stop*:: Stop the UPS driver(s). *status*:: Query run-time status of all configured devices (or one specified device). Currently defers work to linkman:upsdrvctl[8], to list known device configurations and their driver daemon details (PID, responsiveness, `ups.status`) and to linkman:nut-driver-enumerator[8] to map device names to service unit instances to report their names and states in the service management framework. *upsdrvsvcctl* also supports further operations for troubleshooting the mapping of NUT driver section names to the service instance names (which may differ due to limitations of various systems). *list*:: list the currently active mapping of service instances to device sections *resync*:: update the mapping of service instances for NUT drivers to device section names used in 'ups.conf' (register new instances, tear down obsoleted ones). COMMANDS OF UPSDRVCTL NOT (CURRENTLY) APPLICABLE TO UPSDRVSVCCTL ---------------------------------------------------------------- *shutdown*:: Command the UPS driver(s) to run their shutdown sequence. Drivers are stopped according to their `sdorder` value -- see linkman:ups.conf[5]. WARNING: this will probably power off your computers, so don't play around with this option. Only use it when your systems are prepared to lose power. NOTE: refer to linkman:ups.conf[5] for using the *nowait* parameter. It can be overridden by `NUT_IGNORE_NOWAIT` environment variable (e.g. used to work around certain issues with systemd otherwise). ENVIRONMENT VARIABLES --------------------- *NUT_CONFPATH* is the path name of the directory that contains `upsd.conf` and other configuration files. If this variable is not set, *upsdrvsvcctl* (or rather *nut-driver-enumerator.sh*) would use a built-in default, which is often `/usr/local/ups/etc`. DIAGNOSTICS ----------- upsdrvsvcctl will return a nonzero exit code if it encounters an error while performing the desired operation. This will also happen if a driver takes longer than the 'maxstartdelay' period to enter the background. Any messages issued by the *upsdrvctl* program used to start the NUT drivers as part of the service instances' implementations, or by the drivers themselves, will be logged by the service management framework facilities and will not appear in your interactive terminal used to manage the driver. Use `upsdrvsvcctl list` or `upsdrvsvcctl list NUT-device` to find out the service instance name for the NUT driver (section name) you are interested in. Then look up the service logs (where the outputs of the service implementation program as well as the framework messages about this service are stored), as suggested below: *Linux systemd*:: Messages will normally be kept in the service journal, so: journalctl -lu nut-driver@instance-name + Note that your local system configuration may be impacted by such nuances as passing the journal data to a standard syslog server, and/or by having a small cache for locally stored journal messages (so older entries would disappear). There may also be or not be a copy of the journals stored in the persistent filesystem at all. *Solaris SMF*:: Look for `/var/svc/log/system-power-nut-driver:instance-name.log` file. AUTHOR ------ Jim Klimov SEE ALSO -------- linkman:upsdrvctl[8], linkman:nutupsdrv[8], linkman:upsd[8], linkman:nut-driver-enumerator[8], linkman:ups.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/libnutclient_general.txt0000644000200500020050000000226415001555412015676 00000000000000LIBNUTCLIENT_GENERAL(3) ======================= NAME ---- libnutclient_general, nutclient_destroy, strarr_alloc, strarr_free - General and utility functions in Network UPS Tools high-level client access library SYNOPSIS -------- ------ #include typedef void* NUTCLIENT_t; void nutclient_destroy(NUTCLIENT_t client); typedef char** strarr; strarr strarr_alloc(unsigned short count); void strarr_free(strarr arr); ------ DESCRIPTION ----------- The *nutclient_destroy()* function destroys a 'NUTCLIENT_t' or derived (like 'NUTCLIENT_TCP_t') connection object, and frees allocated memory. * The *strarr* type represents an array of C strings (array of char pointer). The array must always be terminated by a NULL pointer. + Pointed strings must be allocated by `(x)calloc` or `(x)strdup`. * The *strarr_alloc()* function allocates a 'strarr' array with the specified number of (non-initialized) string pointers. + Another additional pointer set to NULL is added at the end of the array. * The *strarr_free* function frees a 'strarr' array. It also frees all pointed strings. Common arguments: * 'dev' is the device name. SEE ALSO -------- linkman:libnutclient[3] nut-2.8.3/docs/man/nutupsdrv.txt0000644000200500020050000002655415001555412013567 00000000000000NUTUPSDRV(8) ============ NAME ---- nutupsdrv - Generic manual for unified NUT drivers SYNOPSIS -------- *nutupsdrv* '-h' *nutupsdrv* [OPTIONS] DESCRIPTION ----------- *nutupsdrv* is not actually a driver. This is a combined man page for the shared code that is the core of many drivers within the Network UPS Tools package. For information on the specific drivers, see their individual man pages. UPS drivers provide a communication channel between the physical UPS hardware and the linkman:upsd[8] server. The driver is responsible for translating the native protocol of the UPS to the common format used by the rest of this package. The core has three modes of operation which are determined by the command line switches. In the normal mode, the driver will periodically poll the UPS for its state and parameters, as per the *pollinterval* parameter in linkman:ups.conf[5]. The results of this command are presented to upsd. The driver will also handle setting variables and instant commands if available. In the second mode, using *-k*, the driver can instruct the UPS to shut down the load, possibly after some delay. This mode of operation is intended for cases when it is known that the UPS is running out of battery power and the systems attached must be turned off to ensure a proper reboot when power returns. In the third mode, using *-d*, the driver will exit after some update loops, dumping the data tree (in linkman:upsc[8]-like format) to `stdout`. This can be useful to complement the linkman:nut-scanner[8] to discover devices, along with in-depth data. NOTE: You probably don't want to use any of these options directly. You should use linkman:upsdrvctl[8] (or linkman:upsdrvsvcctl[8] on systems with a service management framework like systemd or SMF) to control your drivers, and linkman:ups.conf[5] to configure them. The rest of this manual describes options and parameters that generally are not needed by normal users. OPTIONS ------- *-h*:: Display a help message without doing anything else. This will also list possible values for '-x' in that driver, and other help text that the driver's author may have provided. *-a* 'id':: Autoconfigure this driver using the 'id' section of linkman:ups.conf[5]. *This argument is mandatory when calling the driver directly.* *-s* 'id':: Configure this driver only with command line arguments instead of reading linkman:ups.conf[5]. To be used instead of *-a* option when need to run a driver not present in driver configuration file. Instead, driver configuration have to be set with *-x* options directly in the command line. As such driver instance cannot be controlled by linkman:upsdrvctl[8] or linkman:upsdrvsvcctl[8], this option should be used for specific needs only. *-D*:: Raise the debugging level. Use this multiple times to see more details. Running a driver in debug mode will (by default) prevent it from backgrounding after startup. It will keep on logging information to the console until it receives a *SIGINT* (usually Ctrl-C) or *SIGTERM* signal. + The level of debugging needed depends both on the driver and the problem you're trying to diagnose. Therefore, first explain the problem you have with a driver to a developer/maintainer, before sending them debugging output. More often than not, if you just pick a level, the output may be either too limited or too verbose to be of any use. *-d* 'update_count':: Dump the data tree (in linkman:upsc[8]-like format) to `stdout` after running the driver update loop for the specified 'update_count' times and exit. + By default this prevents the driver process from backgrounding after startup. Note that the driver banner will be printed too, so when using this option in scripts, don't forget to trim the first line, or use the `NUT_QUIET_INIT_BANNER` environment variable. *-q*:: Raise log level threshold. Use this multiple times to log more details. + The debugging comment above also applies here. *-c* 'command':: Send 'command' to the background process as a signal. Valid commands are: *reload*;; reread configuration files, ignoring modified settings which can not be applied "on the fly" *reload-or-error*;; reread configuration files, ignoring but counting changed values which require a driver restart (can not be changed on the fly), and return a success/fail code based on that count, so the caller can decide the fate of the currently running driver instance *reload-or-exit*;; reread configuration files, exiting the old driver process if it encounters modified settings which can not be applied "on the fly" (so caller like systemd can launch another copy of the driver) ///////// *reload-or-restart*;; reread configuration files, causing the old driver process to close the device connection and re-exec itself if it encounters modified settings which can not be applied "on the fly" (may fail for critical changes like run-time user/group accounts) ///////// *exit*;; tell the currently running driver instance to just exit (so an external caller like the new driver instance, or the systemd or SMF frameworks would start another copy) With recent NUT v2.8.x releases, such commands can be sent using the Unix socket for driver-server interaction. As a fallback, like older releases, signals can be sent to the old driver instance's PID (where possible). *-P* 'pid':: Send the command signal above using specified PID number, rather than consulting the PID file. This can help define service units which start each NUT driver as a foreground process so it does not create a PID file. See also `-FF` option as an alternative. *-F*:: Enforce running the driver as a foreground process, regardless of debugging or data-dumping settings. Specify twice (`-FF` or `-F -F`) to save the PID file even in this mode. *-B*:: Enforce running the driver as a background process, regardless of debugging or data-dumping settings. *-i* 'interval':: Set the poll interval for the device. The default value is 2 (in seconds). *-V*:: Print only version information, then exit. *-L*:: Print a parsable list of driver variables. Mostly useful for configuration wizard programs. *-k*:: ("Kill" power) Forced shutdown mode. The UPS will power off the attached load, if possible. + You should use `upsdrvctl shutdown` whenever possible instead of calling this directly. Note that the constrained operating system context for shutdown typically rules out use of `upsdrvsvcctl shutdown`. *-r* 'directory':: The driver will linkmanext:chroot[2] to 'directory' during initialization. This can be useful when securing systems. + In addition to the state path, many systems will require `/dev/null` to exist within 'directory' for this to work. The serial ports are opened before the `chroot` call, so you do not need to create them inside the jail. In fact, it is somewhat safer if you do not (but reconnection to devices may be no longer possible and could require a full restart of the driver). *-u* 'username':: Override the unprivileged username that the driver may use after startup. If started as root, after opening configuration files (and optionally calling linkmanext:chroot[2], as described in the previous option), the driver will look up 'username' in the `passwd` database, then change to the user and group identities associated with 'username'. (If started with a nonzero UID or effective UID, the driver will silently ignore this option.) + When compiling NUT from source, the default username is typically `nobody`, and this may cause permission errors when the driver opens the UPS device node. You can use this option to temporarily override the defaults. For testing purposes, you can set this option to `root` to bypass permission errors, especially with USB-based drivers. However, you will want to remove this option later in order to avoid permission conflicts between the driver and the unprivileged copy of linkman:upsd[8]. *-g* 'groupname':: Override the unprivileged group name that the driver may use after startup to set permissions for the filesystem socket so `upsd` may still access it if the run-time `user` of the driver normally would deny that access. *-x* 'var'='val':: Define a variable called 'var' with the value of 'var' in the driver. This varies from driver to driver -- see their specific man pages for more information. + This is like setting 'var'='val' in linkman:ups.conf[5], but *-x* overrides any settings from that file. DIAGNOSTICS ----------- Information about the startup process is printed to `stdout` and/or `stderr`. Additional messages after that point are only available in the syslog, unless the driver remains in foreground (e.g. due to raised debugging verbosity). After linkman:upsd[8] starts, the UPS clients such as linkman:upsc[8] can be used to query the status of an UPS. PROGRAM CONTROL --------------- You should always use linkman:upsdrvctl[8] (or linkman:upsdrvsvcctl[8] on systems with a service management framework like systemd or SMF) to control the drivers. While drivers can be started by hand for testing purposes, it is not recommended for production use. FILES ----- ups.conf:: Required configuration file. This contains all details on which drivers to start and where the hardware is attached. ENVIRONMENT VARIABLES --------------------- *NUT_DEBUG_LEVEL* sets default debug verbosity if no *-D* arguments were provided on command line, but does not request that the daemon runs in foreground mode. *NUT_CONFPATH* is the path name of the directory that contains `ups.conf` and other configuration files. If this variable is not set, drivers use a built-in default, which is often `/usr/local/ups/etc`. *NUT_STATEPATH* is the path name of the directory in which *upsd* and drivers keep shared state information. If this variable is not set, *upsd* and drivers use a built-in default, which is often `/var/state/ups`. The *STATEPATH* directive in linkman:upsd.conf[5] overrides this variable. *NUT_ALTPIDPATH* is the path name of the directory in which *upsd* and drivers store .pid files. If this variable is not set, *upsd* and drivers use either *NUT_STATEPATH* if set, or ALTPIDPATH if set, or otherwise the built-in default *STATEPATH*. *NUT_QUIET_INIT_UPSNOTIFY=true* can be used to prevent daemons which can notify service management frameworks (such as systemd) about passing their lifecycle milestones from emitting such notifications (including those about lack of system support for such modern features, once per run). *NUT_QUIET_INIT_BANNER=true* can be used to suppress NUT tool name and version banner. NOT recommended for services due to adverse troubleshooting impact, but may be helpful in shell profiles or scripts which process NUT tool outputs. BUGS ---- Some of the drivers may have bugs. See their manuals for more information. SEE ALSO -------- Configuration: ~~~~~~~~~~~~~~ - linkman:ups.conf[5] - linkman:nut.conf[5] Server: ~~~~~~~ - linkman:upsd[8] Clients: ~~~~~~~~ - linkman:upsc[8] - linkman:upscmd[8] - linkman:upsrw[8] - linkman:upslog[8] - linkman:upsmon[8] CGI programs: ~~~~~~~~~~~~~ - linkman:upsset.cgi[8] - linkman:upsstats.cgi[8] - linkman:upsimage.cgi[8] Driver control: ~~~~~~~~~~~~~~~ include::{builddir}linkman-drivertool-names.txt[] Drivers: ~~~~~~~~ include::{builddir}linkman-driver-names.txt[] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/isbmex.80000644000200500020050000000406115001555071012322 00000000000000'\" t .\" Title: isbmex .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "ISBMEX" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" isbmex \- Driver for ISBMEX UPS equipment .SH "SYNOPSIS" .sp \fBisbmex\fR \-h .sp \fBisbmex\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the isbmex driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports SOLA/BASIC Mexico ISBMEX protocol UPS equipment\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "AUTHOR" .sp Edscott Wilson Garcia .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upscli_list_next.30000644000200500020050000000652715001555052014426 00000000000000'\" t .\" Title: upscli_list_next .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_LIST_NEXT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_list_next \- Retrieve list items from a UPS .SH "SYNOPSIS" .sp .nf #include int upscli_list_next( UPSCONN_t *ups, size_t numq, const char **query, size_t *numa, char ***answer) .fi .SH "DESCRIPTION" .sp The \fBupscli_list_next()\fR function takes the pointer \fIups\fR to a UPSCONN_t state structure, and the pointer \fIquery\fR to an array of \fInumq\fR query elements\&. It performs a read from the network and expects to find either another list item or the end of a list\&. .sp You must call \fBupscli_list_start\fR(3) before calling this function\&. .sp This function will return \fI1\fR and set values in \fInuma\fR and \fIanswer\fR if a list item is received\&. If the list is done, it will return \fI0\fR, and the values in \fInuma\fR and \fIanswer\fR are undefined\&. .sp Calling this function after it returns something other than \fI1\fR is undefined behavior\&. .SH "QUERY FORMATTING" .sp You may not change the values of \fInumq\fR or \fIquery\fR between the call to \fBupscli_list_start\fR(3) and the first call to this function\&. You also may not change the values between calls to this function\&. .SH "ANSWER FORMATTING" .sp The contents of \fInuma\fR and \fIanswer\fR work just like a call to \fBupscli_get\fR(3)\&. The values returned by \fBupsd\fR(8) are identical to a single item request, so this is not surprising\&. .SH "ERROR CHECKING" .sp This function checks the response from \fBupsd\fR(8) against your query\&. If the response is not part of the list you have requested, it will return an error code\&. .sp When this happens, \fBupscli_upserror\fR(3) will return UPSCLI_ERR_PROTOCOL\&. .SH "RETURN VALUE" .sp The \fBupscli_list_next()\fR function returns \fI1\fR when list data is present, \fI0\fR if the list is finished, or \fI\-1\fR if an error occurs\&. .sp It is possible to have an empty list\&. The function will return \fI0\fR for its first call in that case\&. .SH "SEE ALSO" .sp \fBupscli_list_start\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/tripplite_usb.80000644000200500020050000003643215001555077013735 00000000000000'\" t .\" Title: tripplite_usb .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "TRIPPLITE_USB" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" tripplite_usb \- Driver for older Tripp Lite USB UPSes (not PDC HID) .SH "SYNOPSIS" .sp \fBtripplite_usb\fR \-h .sp \fBtripplite_usb\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .SH "SUPPORTED HARDWARE" .sp This driver should work with older Tripp Lite UPSes which are detected as USB HID\-class devices, but are not true HID Power\-Device Class devices\&. So far, the devices supported by tripplite_usb have product ID \fI0001\fR, and the newer units (such as those with "LCD" in the model name) with product ID \fI2001\fR require the \fBusbhid-ups\fR(8) driver instead\&. .sp Please report success or failure to the nut\-upsuser mailing list\&. A key piece of information is the protocol number, returned in ups\&.firmware\&.aux\&. Also, be sure to turn on debugging (\-DDD) for more informative log messages\&. .sp If your Tripp Lite UPS uses a serial port, you may wish to investigate the \fBtripplite\fR(8) or \fBtripplitesu\fR(8) drivers\&. .sp This driver has been tested with the following models: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} INTERNETOFFICE700 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} OMNIVS1000 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} OMNIVS1500XL (some warnings) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} SMART700USB .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} SMART1500RM2U .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} SMART2200RMXL2U .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} SMART3000RM2U .RE .sp If you have used Tripp Lite\(cqs PowerAlert software to connect to your UPS, there is a good chance that tripplite_usb will work if it uses one of the following protocols: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Protocol 0004 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Protocol 1001 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Protocol 2001 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Protocol 3003 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Protocol 3005 .RE .sp On the other hand, if the web page for your UPS on the Tripp\-Lite website says "HID\-compliant USB port also enables direct integration with built\-in power management and auto\-shutdown features of Windows and MAC OS X", then you should use the \fBusbhid-ups\fR(8) driver instead\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file (or with \fI\-x\fR on the command line): .PP \fBport =\fR \fIstring\fR .RS 4 Some \fIvalue\fR must be set, typically \fBauto\fR\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This could be a device filesystem path like /dev/usb/hiddev0 but current use of libusb API precludes knowing and matching by such identifiers\&. They may also be inherently unreliable (dependent on re\-plugging and enumeration order)\&. At this time the actual \fIvalue\fR is ignored, but syntactically some \fIport\fR configuration must still be there\&. .sp .5v .RE .RE .sp It is possible to control multiple UPS units simultaneously by running several instances of this driver, provided they can be uniquely distinguished by setting some combination of the \fBvendor\fR, \fBproduct\fR, \fBvendorid\fR, \fBproductid\fR, \fBserial\fR, \fBbus\fR and/or \fBdevice\fR options detailed below\&. For devices or operating systems that do not provide sufficient information, the \fBallow_duplicates\fR option can be of use (limited and risky!) .PP \fBvendorid =\fR \fIregex\fR, \fBproductid =\fR \fIregex\fR, \fBvendor =\fR \fIregex\fR, \fBproduct =\fR \fIregex\fR, \fBserial =\fR \fIregex\fR .RS 4 Select a specific UPS, in case there is more than one connected via USB\&. Each option specifies an extended regular expression (see \fBregex\fR(7) for more information on regular expressions), which must match the UPS\(cqs entire respective vendor/product/serial string values (minus any surrounding whitespace), or the whole 4\-digit hexadecimal code for vendorid and productid\&. .sp Try \fBlsusb\fR(8) or running this NUT driver with \-DD command\-line argument for finding out the strings to match\&. .sp Examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendor="Foo\&.Corporation\&.*" .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendorid="051d*" (APC) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x product="\&.*(Smart|Back)\-?UPS\&.*" .RE .RE .PP \fBbus =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB bus or group of buses\&. The argument is a regular expression that must match the bus name where the UPS is connected (e\&.g\&. bus="002" or bus="00[2\-3]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .RE .PP \fBdevice =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB device or group of devices\&. The argument is a regular expression that must match the device name where the UPS is connected (e\&.g\&. device="001" or device="00[1\-2]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br device numbers are not guaranteed by the OS to be stable across re\-boots or device re\-plugging\&. .sp .5v .RE .RE .PP \fBbusport =\fR \fIregex\fR .RS 4 If supported by the hardware, OS and libusb on the particular deployment, this option should allow to specify physical port numbers on an USB hub, rather than logical device enumeration values, and in turn \(em this should be less volatile across reboots or re\-plugging\&. The value may be seen in the USB topology output of lsusb \-tv on systems with that tool, for example\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br this option is not practically supported by some NUT builds (it should be ignored with a warning then), and not by all systems that NUT can run on\&. .sp .5v .RE .RE .PP \fBallow_duplicates\fR .RS 4 If you have several UPS devices which may not be uniquely identified by the options above (e\&.g\&. only \fIVID:PID\fR can be discovered there), this flag allows each driver instance where it is set to take the first match if available, or proceed to try another\&. .sp Normally the driver initialization would abort at this point claiming "Resource busy" or similar error, assuming that the otherwise properly matched device is unique \(em and some other process already handles it\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This feature is inherently non\-deterministic! The association of driver instance name to actual device may vary between runs! .sp If you only care to know that \fBat least\fR one of your no\-name UPSes is online, this option can help\&. .sp If you must really know \fBwhich\fR one, it will not! .sp .5v .RE .RE .PP \fBusb_set_altinterface =\fR \fIbAlternateSetting\fR .RS 4 Force redundant call to usb_set_altinterface(), especially if needed for devices serving multiple USB roles where the UPS is not represented by the interface number 0 (default)\&. .RE .PP \fBusb_config_index\fR, \fBusb_hid_rep_index\fR, \fBusb_hid_desc_index\fR, \fBusb_hid_ep_in\fR, \fBusb_hid_ep_out\fR .RS 4 Force use of specific interface, endpoint, descriptor index etc\&. numbers, rather than defaulting to \fI0\fR (rarely other values in certain drivers for some devices known to use non\-zero numbers)\&. Specified as a hexadecimal number\&. .sp As a rule of thumb for usb_hid_desc_index discovery, you can see larger wDescriptorLength values (roughly 600+ bytes) in reports of lsusb or similar tools\&. .RE .PP \fBLIBUSB_DEBUG =\fR \fIINTEGER\fR .RS 4 Run\-time troubleshooting of USB\-capable NUT drivers can involve not only raising the common NUT debug verbosity (e\&.g\&. using the DEBUG_MIN setting in \fBups.conf\fR(5) or protocol commands to change the driver\&.debug value), but may also benefit from LibUSB specific debugging\&. .sp For the latter, you can set the LIBUSB_DEBUG driver option; alternatively you can classically export the environment variable LIBUSB_DEBUG before starting a NUT driver program (may be set and "exported" in driver init script or service method, perhaps via \fBnut.conf\fR(5)), to a numeric value such as 4 ("All messages are emitted")\&. .sp For more details, including the currently supported values for your version of the library, see e\&.g\&.: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/group__libusb__lib\&.html .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x upsid="12345" .RE .sp Select a specific UPS by its unique UPS ID\&. The argument is a regular expression that must match the UPS ID string\&. This allows for precise identification of UPS devices when multiple devices of the same make and model are connected\&. See below regarding how to read and write the ups id (unit id) using \fBupsrw\fR(8)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNotes for tripplite_usb driver handling of common USB matching settings:\fR .ps -1 .br .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBproduct\fR is a regular expression to match the product string for the UPS\&. This would be useful if you have two different Tripp Lite UPS models connected to the same monitoring system, and you want to be sure that you shut them down in the correct order\&. .sp This regex is matched against the full USB product string as seen in lsusb(8)\&. The ups\&.model in the \fBupsc\fR(1) output only lists the name after TRIPP LITE, so to match a SMART2200RMXL2U, you could use the regex \&.*SMART2200\&.*\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBproductid\fR is a regular expression which matches the UPS PID as four hexadecimal digits\&. So far, the only known devices that work with this driver have PID 0001\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBserial\fR option may be or not be helpful: it does not appear that these particular Tripp Lite UPSes supported by this driver use the iSerial descriptor field to return a serial number\&. However, in case your unit does, you may specify it here\&. .RE .sp .5v .RE .PP \fBoffdelay\fR .RS 4 This setting controls the delay between receiving the "kill" command (\fI\-k\fR) and actually cutting power to the computer\&. .RE .PP \fBbattery_min\fR, \fBbattery_max\fR .RS 4 These floating\-point values correspond to the "empty" (10%) and "full" (100%) voltages of the battery\&. They are used for an approximation of the battery state\-of\-charge\&. The calculated battery\&.charge value will be clamped to the range of 10% through 100%, so the resting voltage of the charged battery can be used for \fBbattery_max\fR, and the higher float charge voltage should not cause problems\&. .RE .SH "RUNTIME VARIABLES" .PP \fBups\&.delay\&.shutdown\fR .RS 4 This variable is the same as the \fIoffdelay\fR setting, but it can be changed at runtime by \fBupsrw\fR(8)\&. .RE .PP \fBups\&.id\fR .RS 4 Some SMARTPRO models feature an Unit ID (ups\&.id) that can be set and retrieved\&. If your UPS supports this feature, this variable will be listed in the output of \fBupsrw\fR(8)\&. .RE .PP \fBoutlet\&.1\&.switch\fR .RS 4 Some Tripp Lite units have a switchable outlet (usually outlet #1) which can be turned on and off by writing \fI1\fR or \fI0\fR, respectively, to outlet\&.1\&.switch with \fBupsrw\fR(8)\&. .sp If your unit has multiple switchable outlets, substitute the outlet number for \fI1\fR in the variable name\&. Be sure to test this first \(em there is no other way to be certain that the number used by the driver matches the label on the unit\&. .RE .SH "KNOWN ISSUES AND BUGS" .sp The driver was not developed with any official documentation from Tripp Lite, so certain events may confuse the driver\&. If you observe any strange behavior, please re\-run the driver with \-DDD to increase the verbosity\&. .sp So far, the Tripp Lite UPSes do not seem to have a serial number or other globally unique identifier accessible through USB\&. Thus, when monitoring several Tripp Lite USB UPSes, you should use either the \fIbus\fR, \fIdevice\fR or \fIproduct\fR configuration options to uniquely specify which UPS a given driver instance should control\&. .sp For instance, you can easily monitor an OMNIVS1000 and a SMART1500RM2U at the same time, since they have different USB Product ID strings\&. If you have two SMART1500RM2U units, you would have to find which USB bus and device number each unit is on (via lsusb(8))\&. .sp Some of the SMART*2U models have a configurable Unit ID number, and you can now use the upsid config argument to uniquely specify which UPS a given driver instance should control\&. This allows for precise identification of UPS devices when multiple devices are connected\&. To retrieve or set the upsid use the \fBupsrw\fR(8) utility\&. .SH "AUTHORS" .sp Written by Charles Lepple, based on the \fBtripplite\fR(8) driver by Rickard E\&. (Rik) Faith and Nicholas Kain\&. .sp Please do not email the authors directly \(em use the nut\-upsdev mailing list\&. .sp A Tripp Lite OMNIVS1000 was graciously donated to the NUT project by Bradley Feldman (http://www\&.bradleyloritheo\&.com) .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Other drivers for Tripp\-Lite hardware:" .sp \fBtripplite\fR(8), \fBtripplitesu\fR(8), \fBusbhid-ups\fR(8) .SS "Other tools:" .sp regex(7), lsusb(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upsstats.cgi.txt0000644000200500020050000000306015001555412014127 00000000000000UPSSTATS.CGI(8) =============== NAME ---- upsstats.cgi - Web-based UPS status viewer SYNOPSIS -------- *upsstats.cgi* NOTE: As a CGI program, this should be invoked through your web server. If you run it from the command line, it will either complain about unauthorized access or spew a bunch of HTML at you. DESCRIPTION ----------- *upsstats.cgi* uses template files to build web pages containing status information from UPS hardware. It can repeat sections of those template files to monitor several UPSes simultaneously, or focus on a single UPS. These templates can also include references to linkman:upsimage.cgi[8] for graphical displays of battery charge levels, voltage readings, and the UPS load. ACCESS CONTROL -------------- upsstats will only talk to linkman:upsd[8] servers that have been defined in your linkman:hosts.conf[5]. If it complains that "Access to that host is not authorized", check that file first. TEMPLATES --------- The web page that is displayed is actually a template containing commands to `upsstats` which are replaced by status information. The default file used for the overview of devices is `upsstats.html`. When monitoring a single UPS, the file displayed is `upsstats-single.html`. The format of these files, including the possible commands, is documented in linkman:upsstats.html[5]. FILES ----- linkman:hosts.conf[5], linkman:upsstats.html[5], upsstats-single.html SEE ALSO -------- linkman:upsimage.cgi[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nut.conf.50000644000200500020050000002522615001555037012572 00000000000000'\" t .\" Title: nut.conf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUT\&.CONF" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nut.conf \- UPS definitions for Network UPS Tools .SH "DESCRIPTION" .sp This file attempts to standardize the various files being found in different installations, like /etc/default/nut on Debian based systems and /etc/sysconfig/ups on RedHat based systems\&. .sp Distribution\(cqs init script should source this file in order to determine which components have to be started\&. .sp Blank lines are ignored\&. Lines with a hash (#) character at the first position of the line are ignored, too\&. They can be used to add comments\&. .SH "IMPORTANT NOTES" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} This file is intended to be sourced by shell scripts as well as by service management frameworks like systemd on Linux: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} There is no guaranteed export VAR=VAL syntax .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} No guaranteed expansion of variables like VAR1="$VAR2\-something" \(em only verbatim assignments .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} You may need to export VAR when sourcing it into init\-scripts or other scripts, for eventual propagation of certain settings to NUT programs\&. Not\-exported variables can only be consumed by the script which "sourced" the file (and may choose to export them independently)\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} You MUST NOT use spaces around the equal sign! .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Practical support for this file and its settings currently varies between different OS packages and NUT sample scripts, but should converge over time\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message)\&. .RE .sp Refer to the EXAMPLE section for illustrations\&. .SH "DIRECTIVES" .PP \fBMODE\fR .RS 4 Required\&. Recognized values are \fInone\fR, \fIstandalone\fR, \fInetserver\fR and \fInetclient\fR\&. Defaults to \fInone\fR\&. .PP none .RS 4 Indicates that NUT should not get started automatically, possibly because it is not configured or that an Integrated Power Management or some external system, is used to startup the NUT components\&. .RE .PP standalone .RS 4 Addresses a local only configuration, with 1 UPS protecting the local system\&. This implies to start the 3 NUT layers (driver, upsd and upsmon), with the related configuration files\&. This mode can also address UPS redundancy\&. .RE .PP netserver .RS 4 Like the standalone configuration, but also possibly need one or more specific LISTEN directive(s) in upsd\&.conf\&. Since this MODE is open to the network, a special care should be applied to security concerns\&. .RE .PP netclient .RS 4 When only upsmon is required, possibly because there are other hosts that are more closely attached to the UPS, the MODE should be set to netclient\&. .RE .RE .PP \fBALLOW_NO_DEVICE\fR .RS 4 Optional, defaults to false\&. Set this to true to allow starting the upsd NUT data server service even if ups\&.conf has no device sections configured at the moment\&. This environment variable overrides the built\-in "false" flag value in the upsd program, and an optional same\-named default flag that can be set in upsd\&.conf\&. .sp If you want a data server always running and responding on the network, even if it initially has nothing to serve (may be live\-reloaded later, when devices become configured), this option is for you\&. .RE .PP \fBALLOW_NOT_ALL_LISTENERS\fR .RS 4 Optional, defaults to false\&. Set this to true to allow starting the upsd NUT data server even if not all LISTEN directives can be honoured at the moment\&. This environment variable overrides the built\-in "false" flag in the upsd program, and an optional same\-named default flag that can be set in upsd\&.conf\&. .sp If you want a data server always running, even if it would potentially not serve all clients on every uptime, this option is for you (note you would have to restart upsd to pick up the `LISTEN`ed IP address if it appears later)\&. .sp Probably configuring LISTEN * is a better choice in such cases\&. .RE .PP \fBUPSD_OPTIONS\fR .RS 4 Optional\&. Set upsd specific options\&. See \fBupsd\fR(8) for more details\&. It is ignored when \fIMODE\fR above indicates that no upsd should be running\&. .RE .PP \fBUPSMON_OPTIONS\fR .RS 4 Optional\&. Set upsmon specific options\&. See \fBupsmon\fR(8) for more details\&. It is ignored when \fIMODE\fR above indicates that no upsmon should be running\&. .RE .PP \fBPOWEROFF_WAIT\fR .RS 4 Optional\&. At the end of an emergency system halt, the upsmon primary will signal the UPS to switch off\&. This may fail for a number of reasons\&. Most notably is the case that mains power returns during the shutdown process\&. See the section "Power races" in /usr/share/doc/nut/FAQ\&.txt\&.gz\&. The system will wait this long for the UPS to cut power, and then reboot\&. It should be long enough to exhaust the batteries, in case line power continues to be unavailable\&. On the other hand, it should not be so long that the system remains offline for an unreasonable amount of time if line power has returned\&. See \fBsleep\fR(1) for compatible time syntax\&. If you specify the time in seconds, use the "s" suffix\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This workaround might be dangerous under some circumstances\&. Please read http://bugs\&.debian\&.org/358696 for more details\&. .sp .5v .RE .RE .PP \fBPOWEROFF_QUIET\fR .RS 4 Optional, defaults to false\&. This setting controls if the NUT shutdown integration scripts or service units would emit messages about their activity (or lack thereof)\&. By default they may be verbose, to aid in post\-mortem troubleshooting via logs or console captures\&. Set to true to avoid that trove of information, if you consider it noise\&. .RE .PP \fBNUT_DEBUG_LEVEL\fR .RS 4 Optional, defaults to 0\&. This setting controls the default debugging message verbosity passed to NUT daemons\&. As an environment variable, its priority sits between that of \fIDEBUG_MIN\fR setting of a driver and the command\-line options\&. .RE .PP \fBNUT_DEBUG_PID\fR .RS 4 Optionally add current process ID to tags with debug\-level identifiers\&. This may be useful when many NUT daemons write to the same console or log file, such as in containers/plugins for Home Assistant, storage appliances\&... .RE .PP \fBNUT_DEBUG_SYSLOG\fR .RS 4 Optional, unset by default\&. Normally NUT can (attempt to) use the syslog or Event Log (WIN32), but the environment variable \fINUT_DEBUG_SYSLOG\fR allows to bypass it, and perhaps keep the daemons logging to stderr (useful e\&.g\&. in NUT Integration Test suite to not pollute the OS logs, or in systemd where stderr and syslog both go into the same journal)\&. Recognized values: .TS allbox tab(:); ltB ltB. T{ Value T}:T{ Description T} .T& lt lt lt lt lt lt lt lt. T{ stderr T}:T{ .if n \{\ .RS 4 .\} .nf Disabled and `background()` keeps `stderr` attached .fi .if n \{\ .RE .\} T} T{ none T}:T{ .if n \{\ .RS 4 .\} .nf Disabled and `background()` detaches `stderr` as usual .fi .if n \{\ .RE .\} T} T{ default T}:T{ .if n \{\ .RS 4 .\} .nf Not disabled .fi .if n \{\ .RE .\} T} T{ unset/other T}:T{ .if n \{\ .RS 4 .\} .nf Not disabled .fi .if n \{\ .RE .\} T} .TE .sp 1 .RE .PP \fBNUT_IGNORE_CHECKPROCNAME\fR .RS 4 Optional, defaults to false\&. Normally NUT can (attempt to) verify that the program file name matches the name associated with a running process, when using PID files to send signals\&. .sp The NUT_IGNORE_CHECKPROCNAME boolean toggle allows to quickly skip such verification, in case it causes problems (e\&.g\&. NUT programs were renamed and do not match built\-in expectations)\&. .sp This environment variable can also be optionally set in init\-scripts or service methods for upsd, upsmon and NUT drivers/upsdrvctl\&. .RE .PP \fBNUT_QUIET_INIT_UPSNOTIFY\fR .RS 4 Optional flag to prevent daemons which can notify service management frameworks (such as systemd) about passing their lifecycle milestones, to not report loudly if they could NOT do so (e\&.g\&. running on a system without a framework, or misconfigured so they could not report and the OS could eventually restart the false\-positively identified "unresponsive" service\&. .sp Currently such reports, done by default, help troubleshoot service start\-up and highlight that NUT sources (or package build) did not take advantage of tighter OS service management framework integration (if one exists, so that developers could focus on adding that)\&. Reasons to set this flag could include platforms without such a framework and not expecting one, although nagging your favourite OS or contributing development to make it better is also a way\&. .RE .SH "EXAMPLE" .sp .if n \{\ .RS 4 .\} .nf # /etc/nut/nut\&.conf\&. See nut\&.conf(5) MODE=none UPSD_OPTIONS="" UPSMON_OPTIONS="" # POWEROFF_WAIT=15m .fi .if n \{\ .RE .\} .SH "INTEGRATION" .sp An init script, such as /etc/init\&.d/nut, is expected to source this file in order to determine which components have to be started\&. .SH "SEE ALSO" .sp \fBups.conf\fR(5), \fBupsd.conf\fR(5), \fBupsd.users\fR(5), \fBupsmon.conf\fR(5) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/skel.txt0000644000200500020050000000653115001555412012444 00000000000000SKEL(8) ======= NAME ---- skel - Skeleton driver man page SYNOPSIS -------- *skel* -h *skel* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *skel* driver. For information about the core driver, see linkman:nutupsdrv[8]. ////////////////////////////////////////// The following lines are comments. When copying this man page for your new driver, be sure to replace all occurrences of "skel" and "SKEL" by your actual driver name. If you have AsciiDoc installed, you can test the formatting of your man page by running: asciidoc --backend=xhtml11 -o skel.html skel.txt After writing a man page, be sure to add it to the appropriate variable in Makefile.am in this directory. In the "NAME" section, you must follow the format above, including separating the driver name from its description by "-". This is to ensure that the apropos(8) database is properly rebuilt. ////////////////////////////////////////// SUPPORTED HARDWARE ------------------ *skel* supports ... ////////////////////////////////////////// If the driver only works with certain cables, this is a good place to mention it: CABLING ------- ////////////////////////////////////////// EXTRA ARGUMENTS --------------- This driver also supports the following optional settings: *option1*='num':: Set the value of ... to 'num'. Contrast with *option2*. *option2*='string':: Some other option. ////////////////////////////////////////// Optional: list supported instant commands here: INSTANT COMMANDS ---------------- *instcmd1*:: Command 1. ////////////////////////////////////////// ////////////////////////////////////////// Optional: use INSTALLATION if you need special parameters to the configure script, or additional libraries as prerequisites. INSTALLATION ------------ ////////////////////////////////////////// ////////////////////////////////////////// Optional: use DIAGNOSTICS to describe troubleshooting techniques that are longer than what can be conveniently described in the driver error messages. DIAGNOSTICS ----------- ////////////////////////////////////////// ////////////////////////////////////////// You may leave this as "none known at this time", or describe any trouble encountered when implementing the protocol for your UPS. KNOWN ISSUES AND BUGS --------------------- *Got "EPERM: Operation not permitted" upon driver startup*:: You have forgotten to install the udev files, as explained in the INSTALLATION section above. Don't forget to restart udev so that it applies these changes. ////////////////////////////////////////// ////////////////////////////////////////// An email address is not strictly necessary, but you may wish to provide some form of contact information so that users can report bugs. ////////////////////////////////////////// AUTHORS ------- J Random User ////////////////////////////////////////// If this driver is ever made obsolete by another driver, mention the replacement driver in the "SEE ALSO" section. You may also wish to point the user to other drivers which may better support their hardware, if there is ambiguity based on the driver name. ////////////////////////////////////////// SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutclient_has_device.30000644000200500020050000000004015001555117015177 00000000000000.so man3/libnutclient_devices.3 nut-2.8.3/docs/man/al175.txt0000644000200500020050000000323315001555412012333 00000000000000AL175(8) ======== NAME ---- al175 - Driver for Eltek UPS models with AL175 alarm module SYNOPSIS -------- *al175* -h *al175* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *al175* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The *al175* driver is known to work with the following UPSes: * Eltek MPSU4000 with AL175 alarm module It may also work with other UPSes equipped with AL175 alarm module, but they have not been tested. AL175 have to be configured to operate in COMLI mode. See documentation supplied with your hardware on how to do it. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. INSTANT COMMANDS ---------------- This driver supports some extra commands (see linkman:upscmd[8]): *test.battery.start*:: Start a battery test. *test.battery.stop*:: Stop a battery test. VARIABLES --------- Besides status, this driver reads UPS state into following variables: - *ups.test.result* - *output.voltage.nominal* - *output.current* - *battery.voltage.nominal* - *battery.current* - *battery.temperature* - *input.transfer.boost.low* KNOWN ISSUES AND BUGS --------------------- * Shutdown is not supported. FIXME * The driver was reworked to meet the project code quality criteria, without testing on real hardware. Some bugs may have crept in. AUTHOR ------ Kirill Smelkov SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upsimage.cgi.80000644000200500020050000000520315001555050013402 00000000000000'\" t .\" Title: upsimage.cgi .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSIMAGE\&.CGI" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsimage.cgi \- Image\-generating helper for upsstats\&.cgi .SH "SYNOPSIS" .sp \fBupsimage\&.cgi\fR .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp As a CGI program, this should be invoked through your web server\&. If you run it from the command line, it will either complain about unauthorized access or spew a PNG at you\&. .sp .5v .RE .SH "DESCRIPTION" .sp \fBupsimage\&.cgi\fR generates the graphical bars that make up the right side of the page generated by \fBupsstats.cgi\fR(8)\&. These represent the current battery charge, utility voltage, and UPS load where available\&. .sp The images are in PNG format, and are created by linking to Boutell\(cqs excellent \fIgd\fR library\&. .SH "ACCESS CONTROL" .sp upsstats will only talk to \fBupsd\fR(8) servers that have been defined in your \fBhosts.conf\fR(5)\&. If it complains about "Access to that host is not authorized", check that file first\&. .SH "FILES" .sp \fBhosts.conf\fR(5) .SH "SEE ALSO" .sp \fBupsd\fR(8), \fBupsstats.cgi\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The gd home page: http://libgd\&.bitbucket\&.org .RE nut-2.8.3/docs/man/upscli_get_default_connect_timeout.txt0000644000200500020050000000134415001555412020624 00000000000000UPSCLI_GET_DEFAULT_CONNECT_TIMEOUT(3) ===================================== NAME ---- upscli_get_default_connect_timeout - Return the upsclient module default timeout for initial connections. SYNOPSIS -------- ------ #include int upscli_get_default_connect_timeout(struct timeval *ptv); ------ DESCRIPTION ----------- The *upscli_get_default_connect_timeout()* function takes the pointer 'ptv' to a 'struct timeval' and returns the default network timeout for initial connections last assigned with linkman:upscli_set_default_connect_timeout[3]. SEE ALSO -------- linkman:upscli_connect[3], linkman:upscli_tryconnect[3], linkman:upscli_init_default_connect_timeout[3], linkman:upscli_set_default_connect_timeout[3] nut-2.8.3/docs/man/pijuice.txt0000644000200500020050000000447215001555412013140 00000000000000PIJUICE(8) ========== NAME ---- pijuice - Driver for UPS in PiJuice HAT SYNOPSIS -------- *pijuice* -h *pijuice* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *pijuice* driver. For information about the core driver, see linkman:nutupsdrv[8]. NOTE: This manual page was hastily adapted from related `asem` driver man page based on information from the original pull request, and so may not fully apply to PiJuice HAT, patches from experts are welcome. SUPPORTED HARDWARE ------------------ The *pijuice* driver supports the portable PiJuice HAT UPS for Raspberry Pi embedded PCs. EXTRA ARGUMENTS --------------- The required parameter for this driver is the I2C bus name: *port*='dev-node':: On the PiJuice HAT, this should be `/dev/i2c-1`. INSTALLATION ------------ NOTE: This section was copied from `asem` driver man page and may not fully apply to PiJuice HAT, patches are welcome. This driver is specific to the Linux I2C API, and requires the lm_sensors libi2c-dev or its equivalent to compile. Beware that the SystemIO memory used by the I2C controller is reserved by ACPI. If only a native I2C driver (e.g. `i2c_i801`, as of 3.5.X Linux kernels) is available, then you'll need to relax the ACPI resources check. For example, you can boot with the `acpi_enforce_resources=lax` option. ////////////////////////////////////////// Optional: use DIAGNOSTICS to describe troubleshooting techniques that are longer than what can be conveniently described in the driver error messages. DIAGNOSTICS ----------- ////////////////////////////////////////// KNOWN ISSUES AND BUGS --------------------- NOTE: This section was copied from `asem` driver man page and may not fully apply to PiJuice HAT, patches are welcome. The driver shutdown function is not implemented, so other arrangements must be made to turn off the UPS. AUTHORS ------- Andrew Anderson SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * Initial pull requests adding this driver: ** https://github.com/networkupstools/nut/pull/730 ** https://github.com/PiSupply/PiJuice/issues/124 * Product home page: https://uk.pi-supply.com/products/pijuice-standard * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/tripplite_usb.txt0000644000200500020050000001455715001555412014402 00000000000000TRIPPLITE_USB(8) ================ NAME ---- tripplite_usb - Driver for older Tripp Lite USB UPSes (not PDC HID) SYNOPSIS -------- *tripplite_usb* -h *tripplite_usb* -a 'UPS_NAME' ['OPTIONS'] SUPPORTED HARDWARE ------------------ This driver should work with older Tripp Lite UPSes which are detected as USB HID-class devices, but are not true HID Power-Device Class devices. So far, the devices supported by `tripplite_usb` have product ID '0001', and the newer units (such as those with "LCD" in the model name) with product ID '2001' require the linkman:usbhid-ups[8] driver instead. Please report success or failure to the nut-upsuser mailing list. A key piece of information is the protocol number, returned in `ups.firmware.aux`. Also, be sure to turn on debugging (`-DDD`) for more informative log messages. If your Tripp Lite UPS uses a serial port, you may wish to investigate the linkman:tripplite[8] or linkman:tripplitesu[8] drivers. This driver has been tested with the following models: * INTERNETOFFICE700 * OMNIVS1000 * OMNIVS1500XL (some warnings) * SMART700USB * SMART1500RM2U * SMART2200RMXL2U * SMART3000RM2U If you have used Tripp Lite's PowerAlert software to connect to your UPS, there is a good chance that `tripplite_usb` will work if it uses one of the following protocols: * Protocol 0004 * Protocol 1001 * Protocol 2001 * Protocol 3003 * Protocol 3005 On the other hand, if the web page for your UPS on the Tripp-Lite website says "HID-compliant USB port also enables direct integration with built-in power management and auto-shutdown features of Windows and MAC OS X", then you should use the linkman:usbhid-ups[8] driver instead. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file (or with '-x' on the command line): include::nut_usb_addvars.txt[] - `-x upsid="12345"` Select a specific UPS by its unique UPS ID. The argument is a regular expression that must match the UPS ID string. This allows for precise identification of UPS devices when multiple devices of the same make and model are connected. See below regarding how to read and write the ups id (unit id) using linkman:upsrw[8]. [NOTE] .Notes for `tripplite_usb` driver handling of common USB matching settings: ====== * *product* is a regular expression to match the product string for the UPS. This would be useful if you have two different Tripp Lite UPS models connected to the same monitoring system, and you want to be sure that you shut them down in the correct order. + This regex is matched against the full USB product string as seen in lsusb(8). The `ups.model` in the linkman:upsc[1] output only lists the name after `TRIPP LITE`, so to match a SMART2200RMXL2U, you could use the regex `.*SMART2200.*`. * The *productid* is a regular expression which matches the UPS PID as four hexadecimal digits. So far, the only known devices that work with this driver have PID `0001`. * The *serial* option may be or not be helpful: it does not appear that these particular Tripp Lite UPSes supported by this driver use the `iSerial` descriptor field to return a serial number. However, in case your unit does, you may specify it here. ====== *offdelay*:: This setting controls the delay between receiving the "kill" command ('-k') and actually cutting power to the computer. *battery_min*, *battery_max*:: These floating-point values correspond to the "empty" (10%) and "full" (100%) voltages of the battery. They are used for an approximation of the battery state-of-charge. The calculated battery.charge value will be clamped to the range of 10% through 100%, so the resting voltage of the charged battery can be used for *battery_max*, and the higher float charge voltage should not cause problems. RUNTIME VARIABLES ----------------- *ups.delay.shutdown*:: This variable is the same as the 'offdelay' setting, but it can be changed at runtime by linkman:upsrw[8]. *ups.id*:: Some SMARTPRO models feature an Unit ID (ups.id) that can be set and retrieved. If your UPS supports this feature, this variable will be listed in the output of linkman:upsrw[8]. *outlet.1.switch*:: Some Tripp Lite units have a switchable outlet (usually outlet #1) which can be turned on and off by writing '1' or '0', respectively, to `outlet.1.switch` with linkman:upsrw[8]. + If your unit has multiple switchable outlets, substitute the outlet number for '1' in the variable name. Be sure to test this first -- there is no other way to be certain that the number used by the driver matches the label on the unit. KNOWN ISSUES AND BUGS --------------------- The driver was not developed with any official documentation from Tripp Lite, so certain events may confuse the driver. If you observe any strange behavior, please re-run the driver with `-DDD` to increase the verbosity. So far, the Tripp Lite UPSes do not seem to have a serial number or other globally unique identifier accessible through USB. Thus, when monitoring several Tripp Lite USB UPSes, you should use either the 'bus', 'device' or 'product' configuration options to uniquely specify which UPS a given driver instance should control. For instance, you can easily monitor an OMNIVS1000 and a SMART1500RM2U at the same time, since they have different USB Product ID strings. If you have two SMART1500RM2U units, you would have to find which USB bus and device number each unit is on (via lsusb(8)). Some of the SMART*2U models have a configurable Unit ID number, and you can now use the `upsid` config argument to uniquely specify which UPS a given driver instance should control. This allows for precise identification of UPS devices when multiple devices are connected. To retrieve or set the upsid use the linkman:upsrw[8] utility. AUTHORS ------- Written by Charles Lepple, based on the linkman:tripplite[8] driver by Rickard E. (Rik) Faith and Nicholas Kain. Please do not email the authors directly -- use the nut-upsdev mailing list. A Tripp Lite OMNIVS1000 was graciously donated to the NUT project by Bradley Feldman (http://www.bradleyloritheo.com) SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Other drivers for Tripp-Lite hardware: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ linkman:tripplite[8], linkman:tripplitesu[8], linkman:usbhid-ups[8] Other tools: ~~~~~~~~~~~~ regex(7), lsusb(8) Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/clone.80000644000200500020050000002564015001555070012140 00000000000000'\" t .\" Title: clone .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "CLONE" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" clone \- Clone an UPS, treating its outlet as if it were an UPS (with shutdown INSTCMD support) .SH "SYNOPSIS" .sp \fBclone\fR \-h .sp \fBclone\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the clone driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "DESCRIPTION" .sp This driver, which sits on top of another driver\(cqs local UNIX socket file (or Windows named pipe), allows users to group clients to a particular outlet of a device and deal with this output as if it were a normal UPS\&. .sp Unlike the \fBclone-outlet\fR(8) driver, this driver represents a manageable device that can be used both for monitoring and for client computer and UPS/ePDU outlet shutdowns (it supports sending relevant instant commands during run time)\&. .sp Unlike \fBdummy-ups\fR(8), this driver does not require a running upsd data server nor use the networked NUT protocol to talk to the "real" driver (which may be remote in case of dummy\-ups repeater mode)\&. .sp This driver does not create a completely new virtual device, but replaces or extends some of the original readings reported by the "real" driver using information from the specified outlet, and relays all other readings as they were\&. .sp Remote clients like upsmon can MONITOR the device entry presented by the data server with this driver (and the "real" driver) running and published\&. .sp A larger deployment with one or more lower\-priority devices collected on a manageable outlet of an UPS or ePDU would likely see several drivers set up on the system actually capable of interactions with the UPS and running the NUT data server \fBupsd\fR(8) (and likely powered by another outlet): .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a "real" driver talking to the UPS; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a clone driver talking to the "real" driver and issuing outlet power\-off (or power\-cycle) based on relatively high thresholds for remaining battery charge and/or runtime of the actual UPS (or explicit instant commands), with such operations first setting the respective timers for the outlet on the "real" driver, and the "FSD" flag among states of the virtual UPS status; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} possibly a clone\-outlet driver which is read\-only and interprets the outlet timer values as triggers for "FSD" or "OFF" flags reported among states of the virtual UPS status\&. .RE .sp With this approach, the lower\-priority systems collected on such outlet would run the NUT \fBupsmon\fR(8) client to MONITOR the virtual UPS presented by the read\-only clone\-outlet driver and shut down as soon as the "FSD" flag is raised (fairly early, based on charge and/or runtime thresholds configured for that driver) allowing the higher\-priority devices (likely including the NUT server) to enjoy a longer on\-battery life\&. .sp The clone driver responsible for outlet power state changes would not normally be monitored directly (e\&.g\&. to avoid unfortunate direct shutdown requests from those clients), although it can be (instead of clone\-outlet) in sufficiently trusted networks\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following settings: .PP \fBport\fR=\fIdrivername\-devicename\fR .RS 4 Required\&. The standard NUT driver port setting, here it provides the name of the local Unix socket file (or Windows named pipe) for connection to the "real" device driver\&. .RE .PP \fBload\&.off\fR=\fIcommand\fR .RS 4 Recommended\&. Set the command on the "real" UPS driver that will be used to switch off the outlet\&. You need both \fBload\&.off\fR and \fBload\&.on\fR in order to power cycle the outlet\&. Otherwise, shutting down the clients powered by an outlet is a one way street (see IMPORTANT)\&. .RE .PP \fBload\&.on\fR=\fIcommand\fR .RS 4 Recommended\&. Set the command on the "real" UPS driver that will be used to switch on the outlet\&. You need both \fBload\&.off\fR and \fBload\&.on\fR in order to power cycle the outlet\&. Otherwise, shutting down the clients powered by an outlet is a one way street (see IMPORTANT)\&. .RE .PP \fBload\&.status\fR=\fIvalue\fR .RS 4 Recommended\&. Set the variable on the "real" UPS driver that will be used to indicate the outlet status (i\&.e\&. on/off)\&. If not specified, the clone driver will attempt to keep track of the outlet status, but this is less reliable\&. .RE .PP \fBoffdelay\fR=\fInum\fR .RS 4 Set the timer (in seconds) before the outlet is turned off after the shutdown condition (OB LB) for this outlet is met or a command to shutdown was issued\&. Defaults to 120 seconds\&. .RE .PP \fBondelay\fR=\fInum\fR .RS 4 Set the timer (in seconds) for the outlet to switch on in case the power returns after the outlet has been switched off\&. Defaults to 30 seconds\&. .RE .PP \fBmincharge\fR=\fIvalue\fR .RS 4 Set the remaining battery level when the clone UPS switches to LB (percent)\&. .RE .PP \fBminruntime\fR=\fIvalue\fR .RS 4 Set the remaining battery runtime when the clone UPS switches to LB (seconds)\&. .RE .SH "IMPLEMENTATION" .sp The port specification in the \fBups.conf\fR(5) should reference the local driver socket (or Windows named pipe) that the "real" UPS driver is using\&. For example: .sp .if n \{\ .RS 4 .\} .nf [realups] driver = usbhid\-ups port = auto [clone\-outlet\-1] driver = clone port = usbhid\-ups\-realups load\&.on = outlet\&.1\&.load\&.on load\&.off = outlet\&.1\&.load\&.off load\&.status = outlet\&.1\&.status desc = "Outlet 1 of the Real UPS" [\&.\&.\&.] .fi .if n \{\ .RE .\} .sp This driver supports instant commands to initiate a forced shutdown for upsmon or similar clients which MONITOR this virtual UPS device, if the outlet status is currently \fIon\fR and no other shutdown was initiated yet (setting the virtual UPS shutdown delay timer to offdelay and issuing an FSD via ups\&.status): .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} shutdown\&.return \(em power the outlet back on after ondelay; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} shutdown\&.stayoff \(em keep the outlet \fIoff\fR\&. .RE .sp Such commands are propagated to the "real" driver using the NUT socket protocol (using command names specified in the load\&.off and load\&.on driver configuration options), if the shutdown or start timers are set at the moment, or if the "real" device is not "online" and its known battery charge or runtime are below the configured "low" thresholds\&. .sp The outlet status is determined using the name specified by the load\&.status driver option if set, or is just assumed by latest completed shutdown/start operation (using unknown outlet number)\&. .sp The driver does not support a common NUT device shutdown operation as such (clone \-k just prints an error and bails out)\&. .sp This driver also supports setting certain NUT variables at run\-time: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} battery\&.charge\&.low \(em see mincharge in driver options; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} battery\&.runtime\&.low \(em see minruntime in driver options\&. .RE .sp Compared to the "real" driver\(cqs readings, this driver also adds (or overrides) the following data points: ups\&.delay\&.shutdown, ups\&.delay\&.start, ups\&.timer\&.shutdown and ups\&.timer\&.start\&. It keeps track of "real" driver\(cqs values of battery\&.charge and battery\&.runtime (actual current readings) to decide on automated outlet shutdown later on\&. .SH "IMPORTANT" .sp Unlike a real UPS, you should \fBnot\fR configure a upsmon primary mode for this driver\&. When a \fBupsmon\fR(8) primary sees the OB LB flags and tells the \fBupsd\fR(8) data server that it is OK to initiate the shutdown sequence, the server will latch the FSD status, and it will not be possible to restart the systems connected without restarting the upsd server\&. .sp This will be a problem if the power returns after the clone UPS initiated the shutdown sequence on its outlet, but returns before the real UPS begins shutting down\&. The solution is in the clone driver itself, that will insert the FSD flag if needed without the help of an upsmon primary\&. .SH "CAVEATS" .sp The clone UPS will follow the status on the real UPS driver\&. You can only make the clone UPS shutdown earlier than the real UPS driver, not later\&. If the real UPS driver initiates a shutdown, the clone UPS driver will immediately follow\&. .sp Be aware that the commands to shutdown/restart an outlet on the real UPS drivers are not affected, so if you tell the real UPS driver to shutdown the outlet of the clone UPS driver, your clients will lose power without warning\&. .sp If you use service management frameworks like systemd or SMF to manage the dependencies between driver instances and other units, then you may have to set up special dependencies (e\&.g\&. with systemd "drop\-in" snippet files) to queue your clone drivers to start after the "real" device drivers\&. .SH "AUTHOR" .sp Arjen de Korte .SH "SEE ALSO" .sp \fBupscmd\fR(1), \fBupsrw\fR(1), \fBups.conf\fR(5), \fBclone-outlet\fR(8), \fBnutupsdrv\fR(8) .SS "Dummy driver:" .sp The "repeater" mode of \fIdummy\-ups\fR driver is in some ways similar to the \fIclone\fR and \fIclone\-outlet\fR drivers, by relaying information from a locally or remotely running "real" device driver (and NUT data server)\&. .sp \fBdummy-ups\fR(8) .SS "Internet Resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upscli_ssl.30000644000200500020050000000375615001555054013221 00000000000000'\" t .\" Title: upscli_ssl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_SSL" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_ssl \- Check SSL mode for current connection .SH "SYNOPSIS" .sp .nf #include int upscli_ssl(UPSCONN_t *ups); .fi .SH "DESCRIPTION" .sp The \fBupscli_ssl\fR() function takes the pointer \fIups\fR to a UPSCONN_t state structure\&. It only returns \fI1\fR if SSL support has been compiled into the \fBupsclient\fR(3) library, and if it was successfully enabled for this connection\&. .SH "RETURN VALUE" .sp The \fBupscli_ssl\fR() function returns \fI1\fR if SSL is running, and \fI0\fR if not\&. It returns \fI\-1\fR in the event of an error\&. .SH "SEE ALSO" .sp \fBupscli_fd\fR(3), \fBupscli_get\fR(3), \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/riello_ser.txt0000644000200500020050000000411315001555412013637 00000000000000RIELLO_SER(8) ============= NAME ---- riello_ser - Driver for Riello UPS Protocol UPS equipment via serial port connections SYNOPSIS -------- *riello_ser* -h *riello_ser* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the riello_ser driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ riello_ser supports all recent Riello UPS, Aros UPS models which use the Riello UPS GPSER and SENTR protocols. Older Riello UPS products are not supported. EXTRA ARGUMENTS --------------- You may need to tweak some settings, depending on the make and model of your UPS (see linkman:ups.conf[5]): *localcalculation*:: When enabled, driver will calculate values of `battery.runtime` and `battery.charge` "locally" in the driver. This is for some Riello models which provide incorrect values in hardware readings, or none at all. This "local calculation" is done according to nominal battery capacity, nominal battery voltage, actual battery charge, maximum and actual UPS load. + You may want to also configure 'default.battery.voltage.low' and 'default.battery.voltage.high' in case the built-in default range (from 10.7V to 12.9V) does not match your hardware, or give a shot to 'default.battery.voltage.nominal' (e.g. '24') if your device does not serve that either. + NOTE: Lead (PbAc) battery charge graph is not linear, so guesstimated charge value may not be perfectly accurate. However it should be good enough to determine battery actual status and roughly estimate the time it can still power the system. + WARNING: This keyword may be deprecated in future releases of the driver, in favor of `runtimecal` and other settings which it requires (as seen in linkman:nutdrv_qx[8], linkman:blazer_ser[8] and linkman:blazer_usb[8] drivers). AUTHOR ------ Massimo Zampieri SEE ALSO -------- Related drivers ~~~~~~~~~~~~~~~ linkman:riello_usb[8] The core driver ~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_strerror.30000644000200500020050000000402215001555054014265 00000000000000'\" t .\" Title: upscli_strerror .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_STRERROR" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_strerror \- Return a string describing error condition .SH "SYNOPSIS" .sp .nf #include const char *upscli_strerror(UPSCONN_t *ups); .fi .SH "DESCRIPTION" .sp The \fBupscli_strerror\fR() function takes the pointer \fIups\fR to a UPSCONN_t state structure and returns a string describing the last error which occurred on this connection\&. The string is valid until the next call to \fBupscli_strerror\fR()\&. .SH "RETURN VALUE" .sp The \fBupscli_strerror\fR() function returns a description of the error, or an "unknown error" message if the error code is not recognized\&. .SH "SEE ALSO" .sp \fBupscli_fd\fR(3), \fBupscli_get\fR(3), \fBupscli_readline\fR(3), \fBupscli_sendline\fR(3), \fBupscli_ssl\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/bestfcom.80000644000200500020050000000502315001555067012641 00000000000000'\" t .\" Title: bestfcom .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BESTFCOM" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" bestfcom \- Driver for Best Power Fortress/Ferrups .SH "SYNOPSIS" .sp \fBbestfcom\fR \-h .sp \fBbestfcom\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the bestfcom driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp Best Power Fortress/Ferrups implementing the Fortress UPS Protocol (f\-command set)\&. (For older Fortress units, see \fBbestfortress\fR(8)\&.) .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Kent Polk (bestfcom) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Andreas Wrede, John Stone (bestuferrups) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Grant Taylor (bestfort) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Russell Kroll (bestups) .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/powercom.txt0000644000200500020050000001733415001555412013344 00000000000000POWERCOM(8) =========== NAME ---- powercom - UPS driver for serial Powercom/Trust/Advice UPS equipment SYNOPSIS -------- *powercom* -h *powercom* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the powercom driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports many similar kinds of serial UPS hardware (as well as a few USB UPS models with USB-to-serial adapters). The most common ones are the Trust 425/625, Powercom, and Advice Partner/King PR750. Others using the same protocol may also work. For USB connections, you might need linkman:usbhid-ups[8]. For more specific guidance on which driver is applicable for a USB connection, see the NUT Hardware Compatibility List (HCL). EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file: *linevoltage*='value':: An integer specifying the line voltage. It can't be auto detected. Acceptable values are in the range of 110-120 or 220-240. The default is '230'. *manufacturer*='name':: Specify the manufacturer name, which also can't be auto detected. This is a user defined string, so any name is acceptable. The default is 'PowerCom'. *modelname*='name':: Specify the model name, which also can't be auto detected. This is a user defined string, so any name is acceptable. The default is 'Unknown'. *serialnumber*='value':: Like modelname above, but for the serial number. The default is 'Unknown'. *type*='name':: The exact type of the communication protocol within the powercom family, that will be used to communicate with the UPS. The type is named after the first modelname that was coded with that protocol. The acceptable names are 'Trust', 'Egys', 'KP625AP', 'IMP', 'KIN', 'BNT', 'BNT-other' and 'OPTI'. The default is 'Trust'. + 'BNT-other' is a special type for other BNT models (such as the 1500A at 120V and can be used to override ALL models using ALL of the following values. *shutdownArguments*={{'minutes','seconds'},'whether_minutes_should_be_used'}:: The minutes and seconds that the UPS should wait between receiving the shutdown command and actually shutting off. The other argument should be set to the character 'n' only when the minutes value should be skipped and not sent to the UPS. The default is type-dependent and is given below. The braces and commas are mandatory. Note that there should be no whitespace characters. *numOfBytesFromUPS*='value':: The number of bytes in a UPS frame: 16 is common, 11 for 'Trust'. The default is type-dependent and is given below. *methodOfFlowControl*='name':: The method of serial communication flow control that is engaged by the UPS. The default is type-dependent and is given below. Acceptable names are 'dtr0rts1', 'dtr1' or 'no_flow_control'. *validationSequence*={{'index1','value1'},{'index2','value2'},{'index3','value3'}}:: (Only for types KP625AP, Trust, Egys.) 3 pairs to be used for validating the UPS by comparing bytes of the raw data with constant values. The index selects the byte from the UPS (see numOfBytesFromUPS) and the value is for matching to the byte. The default is type-dependent and is given below. The braces and commas are mandatory, as the lack of white space characters. *frequency*={'A','B'}:: (Only for types KP625AP, Trust, Egys.) A pair to convert the raw frequency data to a human-readable frequency reading using the function 1/(A*x+B). If the raw value x IS the frequency, then set A=1/(x^2) and B=0. The default is type-dependent and is given below. Do note that the braces and commas are mandatory as well, as the lack of whitespace characters. *loadPercentage*={'BatteryA','BatteryB','LineA','LineB'}:: (Only for types KP625AP, Trust, Egys.) A quad to convert the raw load data to human readable load percentage reading using the function A*x+B. If the raw value x IS the Load Percent, then set A=1 and B=0. The default is type-dependent and is given below. Do note that the braces and commas are mandatory, as the lack of white space characters. *batteryPercentage*={'Battery1','Battery2','Battery3','Line4','Line5'}:: (Only for KP625AP, Trust, Egys.) A 5 tuple to convert the raw battery and line data to a human-readable battery and line percentage reading using the functions (Battery) A*x+B*y+C and (Line) D*x+E. If the raw value x IS the Battery Percent, then set A=1, B=0, C=0, D=1, E=0. The default is type-dependent and is given below. Do note that the braces and commas are mandatory, as the lack of white space characters. *voltage*={'240A','240B','120A','120B'}:: (Only for types KP625AP, Trust, Egys.) A quad that is used convert the raw voltage data to a human-readable voltage reading using the function A*x+B. If the raw value x IS HALF the Voltage, then set A=2, B=0. The default is type-dependent and is given below. Do note that the braces and commas are mandatory, as well as the lack of whitespace characters. *nobt*:: If this flag is present, the battery check on startup is skipped. This is useful for systems that tend to overload the UPS when testing the battery on system startup -- just when the power consumption tends to be high. DEFAULT VALUES FOR THE EXTRA ARGUMENTS -------------------------------------- linevoltage = 230 manufacturer = PowerCom modelname = Unknown serialnumber = Unknown type = Trust The rest of the default values for the extra arguments are type-dependent. However, 'BNT-other' is a special type that can be used to override ALL values for ALL models. Trust ~~~~~ numOfBytesFromUPS = 11 methodOfFlowControl = dtr0rts1 validationSequence = {{5,0},{7,0},{8,0}} shutdownArguments = {{0,10},n} frequency = {0.00020997,0.00020928} loadPercentage = {6.1343,-0.3808,4.3110,0.1811} batteryPercentage = {5.0000,0.3268,-825.00,4.5639,-835.82} voltage = {1.9216,-0.0977,0.9545,0.0000} KP625AP ~~~~~~~ numOfBytesFromUPS = 16 methodOfFlowControl = dtr0rts1 validationSequence = {{5,0x80},{7,0},{8,0}} shutdownArguments = {{0,10},n} frequency = {0.00020997,0.00020928} loadPercentage = {6.1343,-0.3808,4.3110,0.1811} batteryPercentage = {5.0000,0.3268,-825.00,4.5639,-835.82} voltage = {1.9216,-0.0977,0.9545,0.0000} Egys ~~~~ numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{5,0x80},{7,0},{8,0}} shutdownArguments = {{0,10},n} frequency = {0.00020997,0.00020928} loadPercentage = {6.1343,-0.3808,1.3333,0.6667} batteryPercentage = {5.0000,0.3268,-825.00,2.2105,-355.37} voltage = {1.9216,-0.0977,0.9545,0.0000} IMP ~~~ numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{5,0xFF},{7,0},{8,0}} shutdownArguments = {{1,30},y} KIN ~~~ numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{11,0x4b},{8,0},{8,0}} shutdownArguments = {{1,30},y} BNT ~~~ numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{11,0x42},{8,0},{8,0}} shutdownArguments = {{1,30},y} BNT-other ~~~~~~~~~ numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{8,0},{8,0},{8,0}} shutdownArguments = {{1,30},y} frequency = {0.00027778,0.0000} loadPercentage = {1.0000,0.0,1.0000,0.0} batteryPercentage = {1.0000,0.0000,0.0000,1.0000,0.0000} voltage = {2.0000,0.0000,2.0000,0.0000} OPTI ~~~~ numOfBytesFromUPS = 16 methodOfFlowControl = no_flow_control validationSequence = {{5,0xFF},{7,0},{8,0}} shutdownArguments = {{1,30},y} AUTHORS ------- * Peter Bieringer * Alexey Sidorov * Keven L. Ates * Rouben Tchakhmakhtchian SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/blazer_ser.80000644000200500020050000003021015001555070013155 00000000000000'\" t .\" Title: blazer_ser .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BLAZER_SER" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" blazer_ser \- Driver for Megatec/Q1 protocol serial based UPS equipment .SH "SYNOPSIS" .sp \fBblazer_ser\fR \-h .sp \fBblazer_ser\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .SH "NOTE" .sp This man page only documents the hardware\-specific features of the blazer driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .SH "NOTE" .sp Please note that this driver is deprecated and will not receive new development\&. If it works for managing your devices \(em fine, but if you are running it to try setting up a new device, please consider the newer \fBnutdrv_qx\fR(8) instead, which should handle all \fIQ*\fR protocol variants for NUT\&. .sp Please do also report if your device works with this driver, but \fBnutdrv_qx\fR(8) would not actually support it with any subdriver! .SH "SUPPORTED HARDWARE" .sp The blazer driver is known to work with various UPSes from Blazer, Energy Sistem, Fenton Technologies, General Electric, Mustek and many others\&. The NUT compatibility table lists all the known supported models\&. Keep in mind, however, that other models not listed there may also be supported, but haven\(cqt been tested\&. .sp All devices with a serial interface (use the \fBblazer_ser\fR driver) and many with a USB interface (use the \fBblazer_usb\fR driver) are supported\&. .SH "EXTRA ARGUMENTS" .sp You may need to override or provide defaults for some values, depending on the make and model of your UPS\&. The following are the ones that most likely will need changing (see \fBups.conf\fR(5)): .PP \fBdefault\&.battery\&.voltage\&.high =\fR \fIvalue\fR .RS 4 Maximum battery voltage that is reached after about 12 to 24 hours charging\&. If you want the driver to report a guesstimated \fBbattery\&.charge\fR, you need to specify this (see BATTERY CHARGE GUESSTIMATION)\&. .RE .PP \fBdefault\&.battery\&.voltage\&.low =\fR \fIvalue\fR .RS 4 Minimum battery voltage just before the UPS automatically shuts down\&. If you want the driver to report a guesstimated \fBbattery\&.charge\fR, you need to specify this (see BATTERY CHARGE GUESSTIMATION)\&. .RE .PP \fBdefault\&.battery\&.voltage\&.nominal =\fR \fIvalue\fR, \fBoverride\&.battery\&.voltage\&.nominal =\fR \fIvalue\fR .RS 4 Some devices show a wrong nominal battery voltage (or none at all), so you may need to override or set a default value\&. .RE .PP \fBoverride\&.battery\&.packs =\fR \fIvalue\fR .RS 4 Some devices report a part of the total battery voltage\&. For instance, if \fBbattery\&.voltage\&.nominal\fR is 24 V, but it reports a \fBbattery\&.voltage\fR of around 2 V, the number of \fBbattery\&.packs\fR to correct this reading would be 12\&. The driver will attempt to detect this automatically, but if this fails somehow, you may want to override this value\&. .RE .PP \fBondelay =\fR \fIvalue\fR .RS 4 Time to wait before switching on the UPS (minutes)\&. Note that a value below 3 minutes, may cause earlier firmware versions to not switch on automatically, so it defaults to 3 minutes\&. The acceptable range is 0\&.\&.9999 minutes\&. .RE .PP \fBoffdelay =\fR \fIvalue\fR .RS 4 Time to wait before shutting down the UPS (seconds)\&. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds)\&. Defaults to 30 seconds\&. The acceptable range is 12\&.\&.600 seconds\&. .RE .PP \fBnorating\fR .RS 4 Some UPSes will lock up if you attempt to read rating information from them\&. Setting this flag will make the driver skip this step\&. .RE .PP \fBnovendor\fR .RS 4 Some UPSes will lock up if you attempt to read vendor information from them\&. Setting this flag will make the driver skip this step\&. .RE .PP \fBprotocol =\fR \fIstring\fR .RS 4 Skip autodetection of the protocol to use and only use the one specified\&. Supported values are \fImegatec\fR, \fImegatec/old\fR, \fImustek\fR and \fIzinto\fR\&. .RE .PP \fBruntimecal =\fR \fIvalue,value,value,value\fR .RS 4 Parameter used in the (optional) runtime estimation\&. This takes two runtimes at different loads\&. Typically, this uses the runtime at full load and the runtime at half load\&. For instance, if your UPS has a rated runtime of 240 seconds at full load and 720 seconds at half load, you would enter .sp .if n \{\ .RS 4 .\} .nf runtimecal = 240,100,720,50 .fi .if n \{\ .RE .\} .sp The first load should always be higher than the second\&. If you have values available for loads other than 100 and 50 % respectively, you can use those too, but keep them spaced apart as far as reasonably possible\&. Just don\(cqt get too close to no load (prediction of runtime depends more on idle load for the battery then)\&. .RE .PP \fBchargetime =\fR \fIvalue\fR .RS 4 The time needed to fully recharge the battery after being fully discharged\&. If not specified, the driver defaults to 43200 seconds (12 hours)\&. Only used if \fBruntimecal\fR is also specified\&. .RE .PP \fBidleload =\fR \fIvalue\fR .RS 4 Minimum battery load used by the driver to estimate the runtime\&. If not specified, the driver defaults to 10%\&. Only used if \fBruntimecal\fR is also specified\&. .RE .SS "SERIAL INTERFACE ONLY" .PP \fBcablepower =\fR \fIstring\fR .RS 4 By default the driver will set DTR and clear RTS (\fInormal\fR)\&. If you find that your UPS isn\(cqt detected or the communication with the UPS is unreliable, you may try if clear DTR and set RTS (\fIreverse\fR), set DTR and RTS (\fIboth\fR) or clear DTR and RTS (\fInone\fR) improves this situation\&. .RE .SH "UPS COMMANDS" .sp This driver supports some instant commands (see \fBupscmd\fR(8)): .PP \fBbeeper\&.toggle\fR .RS 4 Toggle the UPS beeper\&. (Not available on some hardware\&.) .RE .PP \fBload\&.on\fR .RS 4 Turn on the load immediately\&. .RE .PP \fBload\&.off\fR .RS 4 Turn off the load immediately (see KNOWN PROBLEMS)\&. .RE .PP \fBshutdown\&.return\fR .RS 4 Turn off the load and return when power is back\&. Uses the timers defined by \fBondelay\fR and \fBoffdelay\fR\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Turn off the load and remain off (see KNOWN PROBLEMS)\&. Uses the timer defined by \fBoffdelay\fR\&. .RE .PP \fBshutdown\&.stop\fR .RS 4 Stop a shutdown in progress\&. .RE .PP \fBtest\&.battery\&.start\&.deep\fR .RS 4 Perform a long battery test (Not available on some hardware\&.) .RE .PP \fBtest\&.battery\&.start\&.quick\fR .RS 4 Perform a (10 second) battery test\&. .RE .PP \fBtest\&.battery\&.start\fR \fIvalue\fR .RS 4 Perform a battery test for the duration of \fIvalue\fR minutes\&. .RE .PP \fBtest\&.battery\&.stop\fR .RS 4 Stop a running battery test (not available on some hardware\&.) .RE .SH "BATTERY CHARGE GUESSTIMATION" .sp Due to popular demand, this driver will report a guesstimated \fBbattery\&.charge\fR value and optionally \fBbattery\&.runtime\fR, provided you specified a couple of the EXTRA ARGUMENTS listed above\&. .sp If you specify both \fBbattery\&.voltage\&.high\fR and \fBbattery\&.voltage\&.low\fR in \fBups.conf\fR(5), but don\(cqt enter \fBruntimecal\fR, it will guesstimate the state of charge by looking at the battery voltage alone\&. This is not reliable under load, as this only gives reasonably accurate readings if you disconnect the load, let the battery rest for a couple of minutes and then measure the open cell voltage\&. This just isn\(cqt practical if the power went out and the UPS is providing power for your systems\&. .sp .if n \{\ .RS 4 .\} .nf battery\&.voltage \- battery\&.voltage\&.low battery\&.charge = \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- x 100 % battery\&.voltage\&.high \- battery\&.voltage\&.low .fi .if n \{\ .RE .\} .sp There is a way to get better readings without disconnecting the load, but this requires one to keep track on how much (and how fast) current is going in\- and out of the battery\&. If you specified the \fBruntimecal\fR, the driver will attempt to do this\&. Note however, that this heavily relies on the values you enter and that the UPS must be able to report the load as well\&. There are quite a couple of devices that report 0% (or any other fixed value) at all times, in which case this obviously doesn\(cqt work\&. .sp The driver also has no way of determining the degradation of the battery capacity over time, so you\(cqll have to deal with this yourself (by adjusting the values in \fBruntimecal\fR)\&. Also note that the driver guesses the initial state of charge based on the battery voltage, so this may be less than 100%, even when you are certain that they are full\&. There is just no way to reliably measure this between 0 and 100% full charge\&. .sp This is better than nothing (but not by much)\&. If any of the above calculations are giving you incorrect readings, remember that you are the one who put in the values in \fBups.conf\fR(5), so don\(cqt complain to the author\&. If you need something better, consider buy an UPS that reports \fBbattery\&.charge\fR and \fBbattery\&.runtime\fR all by itself without the help of a NUT driver\&. .SH "NOTES FOR THE PREVIOUS USER OF MEGATEC DRIVERS" .sp The blazer drivers having replaced the megatec ones, some configuration changes may be required by users switching to blazer\&. .sp Part of this, the following megatec options, in ups\&.conf, have to be changed: .PP \fBbattvolts\fR .RS 4 You need to use \fIdefault\&.battery\&.voltage\&.high\fR and \fIdefault\&.battery\&.voltage\&.low\fR .RE .PP \fBdtr and rts\fR .RS 4 You need to use \fIcablepower\fR .RE .PP \fBignoreoff\fR .RS 4 This parameter can simply be discarded, since it was a wrong understanding of the specification\&. .RE .SH "KNOWN PROBLEMS" .sp Some UPS commands aren\(cqt supported by all models\&. In most cases, the driver will send a message to the system log when the user tries to execute an unsupported command\&. Unfortunately, some models don\(cqt even provide a way for the driver to check for this, so the unsupported commands will silently fail\&. .sp Both the \fBload\&.off\fR and \fBshutdown\&.stayoff\fR instant commands are meant to turn the load off indefinitely\&. However, some UPS models don\(cqt allow this\&. .sp Some models report a bogus value for the beeper status (will always be \fIenabled\fR or \fIdisabled\fR)\&. So, the \fBbeeper\&.toggle\fR command may appear to have no effect in the status reported by the driver when, in fact, it is working fine\&. .sp The temperature and load value is known to be bogus in some models\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arjen de Korte .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Alexander Gordeev .RE .SH "SEE ALSO" .sp \fBblazer_usb\fR(8), \fBnutupsdrv\fR(8), \fBupsc\fR(8), \fBupscmd\fR(8), \fBupsrw\fR(8) .SS "Internet Resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT HCL: https://www\&.networkupstools\&.org/stable\-hcl\&.html .RE nut-2.8.3/docs/man/nutscan_stringify_ip_ranges.txt0000644000200500020050000000222715001555412017304 00000000000000NUTSCAN_STRINGIFY_IP_RANGES(3) ============================== NAME ---- nutscan_stringify_ip_ranges - Collect contents of a `nutscan_ip_range_list_t` structure into a string buffer that can be further printed into logs. SYNOPSIS -------- ------ #include const char * nutscan_stringify_ip_ranges(nutscan_ip_range_list_t *irl); ------ DESCRIPTION ----------- The *nutscan_stringify_ip_ranges()* function can walk a `nutscan_ip_range_list_t` structure to report its contents: count of list items, and a comma-separated listing with each item as a single token (if `start_ip==end_ip` in that range) or a range as `start_ip .. end_ip`. Returns a pointer to internal statically allocated buffer which would be overwritten by subsequent calls, but does not have to be freed by caller. WARNING: Callers should use semaphores if accessing this function in multi-thread context! NOTES ----- Technically, the function is currently defined in 'nutscan-ip.h' file. SEE ALSO -------- linkman:nutscan_free_ip_ranges[3], linkman:nutscan_add_ip_range[3], linkman:nutscan_cidr_to_ip[3], linkman:nutscan_ip_ranges_iter_init[3], linkman:nutscan_ip_ranges_iter_inc[3] nut-2.8.3/docs/man/libnutclient_tcp.txt0000644000200500020050000000364715001555412015055 00000000000000LIBNUTCLIENT_TCP(3) =================== NAME ---- libnutclient_tcp, nutclient_tcp_create_client, nutclient_tcp_is_connected, nutclient_tcp_disconnect, nutclient_tcp_reconnect, nutclient_tcp_set_timeout, nutclient_tcp_get_timeout - TCP protocol related function for Network UPS Tools high-level client access library SYNOPSIS -------- ------ #include #include /* uint16_t */ #include /* time_t */ typedef NUTCLIENT_t NUTCLIENT_TCP_t; NUTCLIENT_TCP_t nutclient_tcp_create_client( const char* host, uint16_t port); int nutclient_tcp_is_connected(NUTCLIENT_TCP_t client); void nutclient_tcp_disconnect(NUTCLIENT_TCP_t client); int nutclient_tcp_reconnect(NUTCLIENT_TCP_t client); void nutclient_tcp_set_timeout(NUTCLIENT_TCP_t client, time_t timeout); time_t nutclient_tcp_get_timeout(NUTCLIENT_TCP_t client); ------ DESCRIPTION ----------- These functions allow to manage connections to linkman:upsd[8] using NUT TCP protocol. * The *nutclient_tcp_create_client()* function create the 'NUTCLIENT_TCP_t' context and intend to connect to upsd at 'host' and 'port'. + The context must be freed by 'nutclient_destroy()'. - 'host' can be a sever name or a valid IPv4 or IPv6 address like "localhost", "127.0.0.1" or "::1". - 'port' is a valid TCP port, generally '3493'. * The *nutclient_tcp_is_connected()* function test if the connection is valid. * The *nutclient_tcp_disconnect()* function force to disconnect the specified connection. * The *nutclient_tcp_reconnect()* function force to reconnect a connection, disconnecting it if needed. * The *nutclient_tcp_set_timeout()* function set the timeout duration for I/O operations. * The *nutclient_tcp_get_timeout()* function retrieve the timeout duration for I/O operations. + 'timeout' values are specified in seconds, use negative values for blocking. SEE ALSO -------- linkman:libnutclient[3] linkman:libnutclient_general[3] nut-2.8.3/docs/man/upscli_get_default_connect_timeout.30000644000200500020050000000367615001555052020161 00000000000000'\" t .\" Title: upscli_get_default_connect_timeout .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_GET_DEFAULT_C" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_get_default_connect_timeout \- Return the upsclient module default timeout for initial connections\&. .SH "SYNOPSIS" .sp .nf #include int upscli_get_default_connect_timeout(struct timeval *ptv); .fi .SH "DESCRIPTION" .sp The \fBupscli_get_default_connect_timeout()\fR function takes the pointer \fIptv\fR to a \fIstruct timeval\fR and returns the default network timeout for initial connections last assigned with \fBupscli_set_default_connect_timeout\fR(3)\&. .SH "SEE ALSO" .sp \fBupscli_connect\fR(3), \fBupscli_tryconnect\fR(3), \fBupscli_init_default_connect_timeout\fR(3), \fBupscli_set_default_connect_timeout\fR(3) nut-2.8.3/docs/man/belkin.txt0000644000200500020050000000300315001555412012741 00000000000000BELKIN(8) ========= NAME ---- belkin - Driver for Belkin serial UPS equipment SYNOPSIS -------- *belkin* -h *belkin* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the belkin driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The *belkin* driver is known to support the Regulator Pro 525 (F6C525-SER). Other similar models such as the 425 and 625 should also work. The Trust UPS and older Belkin units are not supported. This driver only supports serial connections. If your UPS has a USB port, please consult the Hardware Compatibility List (HCL) to see which of the USB drivers you should use. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. BUGS ---- There are dragons lurking within the protocol to this UPS. I have one that essentially behaves like a glorified power strip due to some invasive probing on my part. Don't mess with it directly. NOTE: the driver doesn't go anywhere near these character sequences, so it won't zap your UPS. I only mention this here as yet another reminder of the perils of closed hardware. SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Other Belkin drivers: ~~~~~~~~~~~~~~~~~~~~~ linkman:belkinunv[8], linkman:blazer_ser[8], linkman:blazer_usb[8], linkman:usbhid-ups[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_display_ups_conf.txt0000644000200500020050000000222315001555412016574 00000000000000NUTSCAN_DISPLAY_UPS_CONF(3) =========================== NAME ---- nutscan_display_ups_conf - Display the specified `nutscan_device_t` structure on stdout. SYNOPSIS -------- ------ #include void nutscan_display_ups_conf(nutscan_device_t * device); ------ DESCRIPTION ----------- The *nutscan_display_ups_conf()* function displays all NUT devices in 'device' to `stdout`. It displays them in a way that it can be directly copied into the `ups.conf` file. It is called from *nutscan_display_ups_conf_with_sanity_check()* to provide an aggregate content for `ups.conf` file in one shot. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/masterguard.txt0000644000200500020050000000235615001555412014025 00000000000000MASTERGUARD(8) ============== NAME ---- masterguard - Driver for Masterguard UPS equipment SYNOPSIS -------- *masterguard* -h *masterguard* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the masterguard driver. For information about the core driver, see linkman:nutupsdrv[8]. NOTE ---- Please note that this driver is deprecated and will not receive new development. If it works for managing your devices -- fine, but if you are running it to try setting up a new device, please consider the newer linkman:nutdrv_qx[8] instead, which should handle all 'Q*' protocol variants for NUT. Please do also report if your device works with this driver, but linkman:nutdrv_qx[8] would not actually support it with any subdriver! SUPPORTED HARDWARE ------------------ This driver supports Masterguard UPS equipment (serial connection only). EXTRA ARGUMENTS --------------- *CS*:: Cancel the shutdown procedure. AUTHOR ------ Michael Spanier SEE ALSO -------- Newer driver: ~~~~~~~~~~~~~ linkman:nutdrv_qx[8] The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_display_ups_conf.30000644000200500020050000000455115001555061016125 00000000000000'\" t .\" Title: nutscan_display_ups_conf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_DISPLAY_UPS_" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_display_ups_conf \- Display the specified `nutscan_device_t` structure on stdout\&. .SH "SYNOPSIS" .sp .nf #include void nutscan_display_ups_conf(nutscan_device_t * device); .fi .SH "DESCRIPTION" .sp The \fBnutscan_display_ups_conf()\fR function displays all NUT devices in \fIdevice\fR to stdout\&. It displays them in a way that it can be directly copied into the ups\&.conf file\&. .sp It is called from \fBnutscan_display_ups_conf_with_sanity_check()\fR to provide an aggregate content for ups\&.conf file in one shot\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/mge-utalk.80000644000200500020050000001165715001555073012734 00000000000000'\" t .\" Title: mge-utalk .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "MGE\-UTALK" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mge-utalk \- Driver for MGE UPS SYSTEMS UTalk protocol equipment .SH "SYNOPSIS" .sp \fBmge\-utalk\fR \-h .sp \fBmge\-utalk\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the mge\-utalk driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp mge\-utalk supports the following legacy units, using the MGE UTalk protocol: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Pulsar ESV+ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Pulsar ES+ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Pulsar EL .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Pulsar EX .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Pulsar EXtreme .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Comet EXtreme .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Comet (Utalk Serial Card, ref 66060) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Galaxy (Utalk Serial Card, ref 66060) .RE .sp This driver also support some newer models with backward UTalk compatibility, such as Pulsar Evolution and Pulsar EXtreme C\&. As these models also support the SHUT protocol, prefer \fBmge-shut\fR(8) for serial communication, or use the USB port, if available, with the \fBusbhid-ups\fR(8)] driver\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBlowbatt\fR=\fInum\fR .RS 4 Set the low battery warning threshold at which shutdown is initiated by \fBupsmon\fR(8)\&. .sp The factory default value is \fI30\fR (in percent), and can be settable depending on the exact model\&. .RE .PP \fBoffdelay\fR=\fInum\fR .RS 4 Set the timer before the UPS is turned off after the kill power command is sent (via the \-k switch)\&. .sp The default value is 20 (in seconds)\&. .RE .PP \fBondelay\fR=\fInum\fR .RS 4 Set the delay before the UPS is turned on, after the power returns\&. .sp The default value is 1 (in minutes)\&. .RE .PP \fBoldmac\fR .RS 4 Set this flag if you are running Linux on an Oldworld Macintosh box (all beige Apple Macintosh)\&. This might also be needed for other OSs (like *BSD) running on PowerMac\&. .RE .SH "KNOWN ISSUES" .SS "Repetitive timeout and staleness" .sp Older models, such as ES/ESV ones, might report repetitive "data stale" errors\&. This is due to the fact that these models don\(cqt support too much polling\&. To solve this problem, add pollinterval=20 in ups\&.conf, and change the value of MAXAGE to \fI25\fR in upsd\&.conf, and DEADTIME to \fI25\fR in upsmon\&.conf\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Hans Ekkehard Plesser .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arnaud Quette .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Martin Loyer .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Patrick Agrain .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Nicholas Reilly .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Dave Abbott .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Marek Kralewski .RE .SH "SEE ALSO" .SS "The core driver" .sp \fBnutupsdrv\fR(8) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutdrv_qx.txt0000644000200500020050000011114215001555412013533 00000000000000NUTDRV_QX(8) ============ NAME ---- nutdrv_qx - Driver for Q* protocol serial and USB based UPS equipment SYNOPSIS -------- *nutdrv_qx* -h *nutdrv_qx* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *nutdrv_qx* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ The protocol originates from Mega System Technologies, Inc. in Taiwan and was used by numerous vendors, as well as evolved over time, growing both in features and nuance incompatibilities. NUT documentation usually refers to this large family of similar dialects as the 'Megatec Q*' or 'Megatec Qx' protocol family. The *nutdrv_qx* driver is known to work with various UPSes from 'Armac', 'Blazer', 'Energy Sistem', 'Fenton Technologies', 'General Electric', 'Gtec', 'Hunnox', 'Masterguard', 'Mustek', 'Powercool', 'Voltronic Power', 'SKE' (rebranded by many, many -- have I said many? -- others... Long story short: if your UPS came with a software called 'Viewpower', chances are high that it works with this driver with one of the <<_extra_arguments,'voltronic*' protocols or with the 'mecer' one>>), and many others. NOTE: Due to historical reasons, two important tunables of this driver are somewhat inconveniently named *protocol* (for the Qx dialect) and *subdriver* (for USB to serial link conversion). Other multi-dialect drivers refer to their dialect modules as *subdrivers*, and actually the modular source code of `nutdrv_qx` also does. NOTE: Due to the amount of supported Qx dialects, and the time it takes to query for relevant combinations of commands and wait for a reply or absence thereof, in order to detect hardware/firmware support of some particular way for the driver to communicate with the device, automatic `nutdrv_qx` driver initialization may take about a minute. It is recommended to store the detected and reported `protocol` and/or `subdriver` values into your linkman:ups.conf[5] file to speed up later driver start-ups and avoid possible service timeouts. The <<_internet_resources,NUT compatibility table>> lists all the known supported models. Keep in mind, however, that other models not listed there may also be supported, but haven't been tested or reported back. All devices with a serial interface and many with a USB interface are supported. EXTRA ARGUMENTS --------------- You may need to override or provide defaults for some values, depending on the make and model of your UPS. The following are the ones that most likely will need changing (see linkman:ups.conf[5]): *ondelay =* 'value':: Time to wait before switching on the UPS (seconds). This value is truncated to units of 60 seconds. + Note that a value below 3 minutes, may cause earlier firmware versions to not switch on automatically, so it defaults to 3 minutes (i.e. 180 seconds). + This option provides a default value for *ups.delay.start* that will then be used by the driver in the automatic shutdown sequence (i.e. calling the driver with the *-k* option, calling linkman:upsdrvctl[8] with the *shutdown* option or when the +FSD+ flag is set and linkman:upsmon[8] enters its shutdown sequence): however you can change this value `on the fly' for the actual session, only for the use with instant commands, setting *ups.delay.start* with linkman:upsrw[8]. *offdelay =* 'value':: Time to wait before shutting down the UPS (seconds). This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds). Defaults to 30 seconds. + This option provides a default value for *ups.delay.shutdown* that will then be used by the driver in the automatic shutdown sequence (i.e. calling the driver with the *-k* option, calling linkman:upsdrvctl[8] with the *shutdown* option or when the +FSD+ flag is set and linkman:upsmon[8] enters its shutdown sequence): however you can change this value "on the fly" for the actual session, only for the use with instant commands, setting *ups.delay.shutdown* with linkman:upsrw[8]. *stayoff*:: If you set stayoff in linkman:ups.conf[5] when FSD arises the UPS will call a *shutdown.stayoff* shutting down after *ups.delay.shutdown* seconds and won't return (see <<_known_problems,KNOWN PROBLEMS>>), otherwise (standard behaviour) the UPS will call *shutdown.return* shutting down after *ups.delay.shutdown* seconds and then turn on after *ups.delay.start* seconds (if mains meanwhile returned). *protocol =* 'string':: Skip autodetection of the protocol to use and only use the one specified. Supported values: 'bestups', 'gtec', 'hunnox', 'innovart31', 'masterguard', 'mecer', 'megatec', 'megatec/old', 'mustek', 'q1', 'q2', 'q6', 'voltronic', 'voltronic-qs', 'voltronic-qs-hex' and 'zinto'. + Run the driver program with the `--help` option to see the exact list of `protocol` values it would currently recognize. + Note that if you end up using the 'q1' protocol, you may want to give a try to the 'mecer', 'megatec' and 'zinto' ones setting the <> (only one, or both). *pollfreq =* 'num':: Set polling interval for full updates, in seconds, to reduce the message traffic. Between two polling requests, the driver will do 'quick polls' dealing just with *ups.status* at an interval specified by the *pollinterval* driver option (details in linkman:ups.conf[5]). The default value is 30 (in seconds). If your UPS doesn't report either *battery.charge* or *battery.runtime* you may want to add the following ones in order to have guesstimated values: *default.battery.voltage.high =* 'value':: Maximum battery voltage that is reached after about 12 to 24 hours charging. If you want the driver to report a guesstimated *battery.charge*, you need to specify this (see <<_battery_charge_guesstimation,BATTERY CHARGE GUESSTIMATION>>). *default.battery.voltage.low =* 'value':: Minimum battery voltage just before the UPS automatically shuts down. If you want the driver to report a guesstimated *battery.charge*, you need to specify this (see <<_battery_charge_guesstimation,BATTERY CHARGE GUESSTIMATION>>). *default.battery.voltage.nominal =* 'value':: *override.battery.voltage.nominal =* 'value':: Some devices show a wrong nominal battery voltage (or none at all), so you may need to override or set a default value. *override.battery.packs =* 'value':: Some devices "natively" report just a part of the total battery voltage (see also *battery_voltage_reports_one_pack* below). + For instance, if *battery.voltage.nominal* is 24 V, but it reports a *battery.voltage* of around 2 V, the number of *battery.packs* to correct this reading would be 12. + The driver will attempt to detect this number automatically, but if this fails somehow, you may want to override this value. + Note that this is primarily useful for "guesstimation" of `battery.charge` and/or `battery.runtime` (with `runtimecal` setting), if those readings are not provided by the device directly. *battery_voltage_reports_one_pack*:: Some devices "natively" report just report a part of the total battery voltage (see also *override.battery.packs* above, if that value is not reported by the device or properly guessed by the driver otherwise). + If this flag is set, most of the subdrivers (except those which know about more complicated device-specific nuances, currently: *ablerex*, *masterguard* and *voltronic-qs-hex*) adjust their ultimately reported *battery.voltage* value as a multiple of *battery.packs* and "native" *battery.voltage*). + Note this is primarily useful for consistent diagnostics and graphing of the numbers, and should not impact the "guesstimation" of `battery.charge` and/or `battery.runtime` -- so rather a cosmetic adjustment, than critical. *runtimecal =* 'value,value,value,value':: Parameter used in the (optional) runtime estimation. This takes two runtimes at different loads. Typically, this uses the runtime at full load and the runtime at half load. For instance, if your UPS has a rated runtime of 240 seconds at full load and 720 seconds at half load, you would enter + runtimecal = 240,100,720,50 + The first load should always be higher than the second. If you have values available for loads other than 100 and 50 % respectively, you can use those too, but keep them spaced apart as far as reasonably possible. Just don't get too close to no load (prediction of runtime depends more on idle load for the battery then). *chargetime =* 'value':: The time needed to fully recharge the battery after being fully discharged. If not specified, the driver defaults to 43200 seconds (12 hours). Only used if *runtimecal* is also specified. *idleload =* 'value':: Minimum battery load used by the driver to estimate the runtime. If not specified, the driver defaults to 10%. Only used if *runtimecal* is also specified. BESTUPS, INNOVART31, MECER, MEGATEC, MEGATEC/OLD, MUSTEK, Q1, Q2, Q6, VOLTRONIC-QS, VOLTRONIC-QS-HEX, ZINTO PROTOCOLS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *ignoresab*:: Some UPSes incorrectly report the `Shutdown Active' bit as always on, consequently making the driver believe the UPS is nearing a shutdown (and, as a result, ups.status always contains +FSD+... and you know what this means). Setting this flag will make the driver ignore the `Shutdown Active' bit. [[old-blazer-protocols-options]] MECER, MEGATEC, MEGATEC/OLD, MUSTEK, ZINTO PROTOCOLS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *ondelay*:: The acceptable range is +0..599940+ seconds. *offdelay*:: The acceptable range is +12..600+ seconds. *norating*:: Some UPSes will lock up if you attempt to read rating information from them. Setting this flag will make the driver skip this step. *novendor*:: Some UPSes will lock up if you attempt to read vendor information from them. Setting this flag will make the driver skip this step. BESTUPS PROTOCOL ~~~~~~~~~~~~~~~~ *ondelay*:: The acceptable range is +60..599940+ seconds. *offdelay*:: The acceptable range is +12..5940+ seconds. *pins_shutdown_mode =* 'value':: Set https://www.networkupstools.org/protocols/sola.html#_shutdown_set_command[shutdown mode functionality of Pin 1 and Pin 7] on the UPS DB9 communication port (Per Best Power's EPS-0059) to 'value' [+0..6+]. MASTERGUARD PROTOCOL ~~~~~~~~~~~~~~~~~~~~ *slave_addr =* 'value':: Make the claim function verify it's talking to the specified 'slave address' (*ups.id*). Safeguard against talking to the wrong one of several identical UPSes on the same USB bus. Note that when changing *ups.id* (through linkman:upsrw[8]) the driver will continue to talk to the UPS with the new 'slave address', but won't claim it again on restart until the *slave_addr* parameter is adjusted. INNOVART31, Q1, Q2, Q6 PROTOCOLS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *ondelay*:: The acceptable range is +0..599940+ seconds. *offdelay*:: The acceptable range is +12..600+ seconds. Q2, Q6 PROTOCOLS ~~~~~~~~~~~~~~~~ *nooutstats*:: Some UPSes don't support `WA` command which returns output load stats. Using this flag will make the driver ignore these requests. VOLTRONIC-QS, VOLTRONIC-QS-HEX PROTOCOLS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *ondelay*:: The acceptable range is +60..599940+ seconds. *offdelay*:: The acceptable range is +12..540+ seconds. VOLTRONIC PROTOCOL ~~~~~~~~~~~~~~~~~~ The following options are supported only by the 'voltronic' protocol. Not all of them are available on all the UPSes supported by this protocol. *ondelay*:: The acceptable range is +0..599940+ seconds. *offdelay*:: The acceptable range is +12..5940+ seconds. *battery_number =* 'value':: Set number of batteries that make a pack to 'value' [+1..9+]. This setting will change the charge and runtime estimation reported by the UPS. *output_phase_angle =* 'value':: Changes output phase angle to the provided value [+000+, +120+, +180+, +240+]°. UPS CAPABILITY SETTINGS ^^^^^^^^^^^^^^^^^^^^^^^ *reset_to_default*:: Reset capability options and their voltage and frequency limits to safe default values. (*Doable only when the UPS is in Standby Mode*) + Note that setting this option will reset also *ups.start.auto*, *battery.protection*, *battery.energysave*, *ups.start.battery*, *outlet.0.switchable*, *input.transfer.high*, *input.transfer.low*, *input.frequency.high* and *input.frequency.low*. These UPSes can be fine-tuned to suit your needs enabling or disabling the following options (the driver should tell you which one the UPS is capable of on startup: the settable ones will be reported either are 'enabled' or 'disabled' in the logs): *alarm_control =* 'string':: Enable or disable alarm (BEEP!) [+enabled+/+disabled+]. Settable also `on the fly' with *beeper.enable* and *beeper.disable* instant commands. *bypass_alarm =* 'string':: Enable or disable alarm (BEEP!) at Bypass Mode [+enabled+/+disabled+]. *battery_alarm =* 'string':: Enable or disable alarm (BEEP!) at Battery Mode [+enabled+/+disabled+]. *bypass_when_off =* 'string':: Enable or disable bypass when the UPS is Off [+enabled+/+disabled+]. If enabled, AC will directly provide power to connected devices when the UPS is off. *bypass_forbidding =* 'string':: Enable or disable Bypass Forbidding [+enabled+/+disabled+]. If enabled, the UPS will not transfer to bypass mode under any condition. *converter_mode =* 'string':: Enable or disable Converter Mode [+enabled+/+disabled+]. When input frequency is within 40 Hz to 70 Hz, the UPS can be set at a constant output frequency, 50 Hz or 60 Hz. The UPS will still charge battery under this mode. *eco_mode =* 'string':: Enable or disable ECO Mode [+enabled+/+disabled+]. When input voltage/frequency are within acceptable range, the UPS will bypass voltage to output for energy saving. PFC and INVERTER are still active at this mode. Settable also `on the fly' with *bypass.start* and *bypass.stop* instant commands. *advanced_eco_mode =* 'string':: Enable or disable Advanced ECO Mode [+enabled+/+disabled+]. When input voltage/frequency are within acceptable range, the UPS will bypass voltage to output for energy saving. PFC and INVERTER are off at this mode. *battery_open_status_check =* 'string':: Enable or disable Battery Open Status Check [+enabled+/+disabled+]. If enabled, when the UPS is turned on, it will check if the battery is connected or not. *site_fault_detection =* 'string':: Enable or disable site fault detection [+enabled+/+disabled+]. If enabled, the UPS will beep when the input neutral and hot wires are reversed. *constant_phase_angle =* 'string':: Enable or disable Constant Phase Angle Function (output and input phase angles are not equal) [+enabled+/+disabled+]. *limited_runtime_on_battery =* 'string':: Enable or disable limited runtime on battery mode [+enabled+/+disabled+]. BYPASS MODE VOLTAGE/FREQUENCY LIMITS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Variables to fine-tune voltage and frequency limits for Bypass mode. These limits are reset to safe default values by *reset_to_default*. If AC voltage and frequency are within acceptable range, Bypass mode will be used (If the UPS is capable of and it's enabled). Since these values are device-specific, if your UPS support them, you will get their settable limits printed in the logs on startup. *max_bypass_volt =* 'value':: Maximum voltage for Bypass Mode (V). *min_bypass_volt =* 'value':: Minimum voltage for Bypass Mode (V). *max_bypass_freq =* 'value':: Maximum frequency for Bypass Mode (Hz). *min_bypass_freq =* 'value':: Minimum frequency for Bypass Mode (Hz). OPTIONS SPECIFIC FOR P31 UPSES ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following options are available only on P31 UPSes. *work_range_type =* 'string':: Device grid working range for P31 UPSes [+Appliance+/+UPS+]. TESTING ^^^^^^^ This protocol comes with a couple of functions that are not enabled by default because of the lack of knowledge of some part of the communication protocol used by these UPSes by your friendly neighborhood developer. Since these functions are supposed to be queries to the UPS for some kind of information, they _should_ not make your UPS go boom. So if you are brave enough to risk your UPS and attached devices' life to help the developers, this will be very appreciated. *Do it at your own risk*. *testing*:: If invoked the driver will exec also commands that still need testing. SERIAL INTERFACE ONLY ~~~~~~~~~~~~~~~~~~~~~ *cablepower =* 'string':: By default the driver will set DTR and clear RTS ('normal'). If you find that your UPS isn't detected or the communication with the UPS is unreliable, you may try if clear DTR and set RTS ('reverse'), set DTR and RTS ('both') or clear DTR and RTS ('none') improves this situation. USB INTERFACE ONLY ~~~~~~~~~~~~~~~~~~ include::nut_usb_addvars.txt[] *subdriver =* 'string':: Select a serial-over-USB subdriver to use. You have a choice between *ablerex*, *armac*, *cypress*, *fabula*, *fuji*, *gtec*, *hunnox*, *ippon*, *krauler*, *phoenix*, *phoenixtec*, *sgs* and *snr*. + Run the driver program with the `--help` option to see the exact list of `subdriver` values it would currently recognize. + NOTE: When using this option, it is mandatory to also specify the *vendorid* and *productid* matching parameters. *langid_fix =* 'value':: Apply the language ID workaround to the *krauler* subdriver. This is mandatory for some devices to work (LDLC, Dynamix and others). You must provide *value* (+0x409+ or +0x4095+), according to your device entry in NUT hardware compatibility list (HCL). *noscanlangid*:: If this flag is set, don't autoscan valid range for langid. IMPLEMENTATION NOTES ^^^^^^^^^^^^^^^^^^^^ *'armac' subdriver*:: The Armac communication subdriver reproduces a communication protocol used by an old release of "PowerManagerII" software, which doesn't seem to be Armac specific: its banner is "2004 Richcomm Technologies, Inc. Dec 27 2005 ver 1.1." Maybe other Richcomm UPSes would work with this -- maybe better than with the older standalone `richcomm_usb` driver. *'fabula' subdriver*:: This subdriver, meant to be used with the 'megatec' protocol, does *not* support the various *test.battery* commands. Plus, the *shutdown.return* command ignores the values set in 'ups.delay.start'/*ondelay* and makes the UPS turn on the load as soon as power is back. *'gtec' subdriver*:: Currently, the Gtec specific support is only known to work with USB devices (tested with a Gtec ZP120N), and was not seen with Serial port. + This mode is not automatically detected, and should be enabled manually in your 'ups.conf', e.g.: + ---- [gtec-ups] driver = "nutdrv_qx" port = "auto" subdriver = "gtec" protocol = "gtec" ---- + Other subdrivers and protocol implementations (including linkman:blazer_usb[8]) sort of work, but both have two problems: + * They use the simple "Q1" query, which doesn't report the result of the latest battery test. - For some reason the UPS reports normal battery voltage even when the battery is completely disconnected. So you won't know the battery is dead until a power failure. - This driver sends the more advanced "Q4" request instead. Here the answer includes status letters with more information than the Q1 binary flags, including battery status. * USB reply is read in 8-byte chunks, which causes the UPS to disconnect from USB. The UPS reconnects in a second, but it still breaks the initialization of `nutdrv_qx`, where the query is sent twice in a short time (unlike `blazer_usb`). - The solution is simple: read the whole reply at once. *'hunnox' subdriver*:: This protocol subdriver is closely related to 'fabula' one, with a few tweaks for devices not directly supported by that driver. *'fuji' subdriver*:: This subdriver, meant to be used with the 'megatec' protocol, does *not* support the *shutdown.stayoff* and *load.off* commands. Plus, the *shutdown.return* command ignores the values set in 'ups.delay.start'/*ondelay* and makes the UPS turn on the load as soon as power is back. *'krauler' subdriver*:: This subdriver, meant to be used with the 'megatec' protocol, does *not* support the shutdown commands, i.e.: *shutdown.return*, *shutdown.stayoff* and *load.off*. *'snr' subdriver*:: This subdriver, meant to be used with the 'megatec' protocol, does *not* support the shutdown commands, i.e.: *shutdown.return*, *shutdown.stayoff* and *load.off*. UPS COMMANDS ------------ This driver supports some instant commands (see linkman:upscmd[8]): *beeper.toggle*:: Toggle the UPS beeper. (Not available on some hardware) *load.on*:: Turn on the load immediately. (Not available on some hardware) *load.off*:: Turn off the load immediately (see <<_known_problems,KNOWN PROBLEMS>>). *shutdown.return*:: Turn off the load and return when power is back. Uses the timers defined by *ups.delay.start* and *ups.delay.shutdown*. *shutdown.stayoff*:: Turn off the load and remain off (see <<_known_problems,KNOWN PROBLEMS>>). Uses the timer defined by *ups.delay.shutdown*. *shutdown.stop*:: Stop a shutdown in progress. *test.battery.start.deep*:: Perform a long battery test. (Not available on some hardware) *test.battery.start.quick*:: Perform a quick (10 second) battery test. *test.battery.stop*:: Stop a running battery test. (Not available on some hardware) BESTUPS, INNOVART31, MECER, MEGATEC, MEGATEC/OLD, MUSTEK, Q1, Q2, Q6, ZINTO PROTOCOLS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *test.battery.start* 'value':: Perform a battery test for the duration of 'value' seconds (truncated to 60 seconds) [+60..5940+]. MASTERGUARD PROTOCOL ~~~~~~~~~~~~~~~~~~~~ *beeper.enable*:: Enable the UPS beeper. *beeper.disable*:: Disable the UPS beeper. *test.battery.start* 'value':: Perform a battery test for the duration of 'value' seconds (truncated to 60 seconds) [+0..5940+]. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds). *bypass.start*:: Put the UPS in bypass mode *bypass.stop*:: Take the UPS in normal mode VOLTRONIC POWER P98 UNITS (WITH MECER PROTOCOL) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *test.battery.start* 'value':: Perform a battery test for the duration of 'value' seconds (truncated to 60 seconds) [+12..5940+]. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds). VOLTRONIC PROTOCOL ~~~~~~~~~~~~~~~~~~ The following instant commands are available for the 'voltronic' protocol. Not all of them are available on all the UPSes supported by this protocol. *beeper.enable*:: Enable the UPS beeper. *beeper.disable*:: Disable the UPS beeper. *test.battery.start* 'value':: Perform a battery test for the duration of 'value' seconds [+12..5940+]. This value is truncated to units of 6 seconds (less than 60 seconds) or 60 seconds (more than 60 seconds). *outlet.1.load.off*:: Turn off outlet 1 load immediately. *outlet.1.load.on*:: Turn on outlet 1 load immediately. *outlet.2.load.off*:: Turn off outlet 2 load immediately. *outlet.2.load.on*:: Turn on outlet 2 load immediately. *outlet.3.load.off*:: Turn off outlet 3 load immediately. *outlet.3.load.on*:: Turn on outlet 3 load immediately. *outlet.4.load.off*:: Turn off outlet 4 load immediately. *outlet.4.load.on*:: Turn on outlet 4 load immediately. *bypass.start*:: Put the UPS in ECO Mode. *bypass.stop*:: Take the UPS out of ECO Mode. BATTERY CHARGE GUESSTIMATION ---------------------------- Due to popular demand, this driver will report a guesstimated *battery.charge* and optionally *battery.runtime*, provided you specified a couple of the <<_extra_arguments,EXTRA ARGUMENTS>> listed above. If you specify both *battery.voltage.high* and *battery.voltage.low* in linkman:ups.conf[5], but don't enter *runtimecal*, it will guesstimate the state of charge by looking at the battery voltage alone. This is not reliable under load, as this only gives reasonably accurate readings if you disconnect the load, let the battery rest for a couple of minutes and then measure the open cell voltage. This just isn't practical if the power went out and the UPS is providing power for your systems. battery.voltage - battery.voltage.low battery.charge = ------------------------------------------ x 100 % battery.voltage.high - battery.voltage.low There is a way to get better readings without disconnecting the load but this requires one to keep track on how much (and how fast) current is going in and out of the battery. If you specified the *runtimecal*, the driver will attempt to do this. Note however, that this heavily relies on the values you enter and that the UPS must be able to report the load as well. There are quite a couple of devices that report 0 % (or any other fixed value) at all times, in which case this obviously doesn't work. The driver also has no way of determining the degradation of the battery capacity over time, so you'll have to deal with this yourself (by adjusting the values in *runtimecal*). Also note that the driver guesses the initial state of charge based on the battery voltage, so this may be less than 100 %, even when you are certain that they are full. There is just no way to reliably measure this between 0 and 100 % full charge. This is better than nothing (but not by much). If any of the above calculations is giving you incorrect readings, you are the one that put in the values in linkman:ups.conf[5], so don't complain with the author. If you need something better, buy a UPS that reports *battery.charge* and *battery.runtime* all by itself without the help of a NUT driver. NOTES FOR THE PREVIOUS USER OF MEGATEC DRIVERS ---------------------------------------------- The *nutdrv_qx* driver having replaced the megatec ones, some configuration changes may be required by users switching to *nutdrv_qx*. Part of this, the following megatec options, in linkman:ups.conf[5], have to be changed: *battvolts*:: You need to use 'default.battery.voltage.high' and 'default.battery.voltage.low' *dtr* and *rts*:: You need to use 'cablepower' *ignoreoff*:: This parameter can simply be discarded, since it was a wrong understanding of the specification. NOTES FOR THE PREVIOUS USER OF BLAZER DRIVERS --------------------------------------------- The *nutdrv_qx* driver having replaced the blazer ones, some configuration changes may be required by users switching to *nutdrv_qx*. Part of this, the following blazer options, in linkman:ups.conf[5], have to be changed: *ondelay*:: While the previous blazer drivers expected minutes, the new *nutdrv_qx* driver wants seconds. The following instant command has also been changed: *test.battery.start* 'value':: While the old blazer drivers expected a 'value' in minutes, the *nutdrv_qx* driver wants a 'value' in seconds. NOTES FOR THE PREVIOUS USER OF BESTUPS DRIVER --------------------------------------------- The *nutdrv_qx* driver having replaced the bestups one, some configuration changes may be required by users switching to *nutdrv_qx*. Part of this, the following bestups options, in linkman:ups.conf[5], are no longer supported by this driver: *nombattvolt*:: *battvoltmult*:: See <<_battery_charge_guesstimation,BATTERY CHARGE GUESSTIMATION>>. *ID*:: Discarded. NOTES FOR THE PREVIOUS USER OF VOLTRONIC DRIVERS ------------------------------------------------ The *nutdrv_qx* driver having replaced the voltronic ones, some configuration changes may be required by users switching to *nutdrv_qx*. Part of this, the following voltronic options, in linkman:ups.conf[5], have to be changed: *ondelay*:: While the previous voltronic drivers expected minutes, the new *nutdrv_qx* driver wants seconds. It no longer defaults to 0 minutes but to 3 minutes (i.e. 180 seconds) for compatibility with the users switching from the old blazer drivers. *battnumb*:: This option has been renamed to *battery_number*. The following options are no longer supported by this driver, you can now change them more conveniently "on the fly" calling linkman:upsrw[8] with the appropriate NUT variable -- provided that your UPS supports them. [horizontal] *battpacks*:: -> *battery.packs* + Set number of battery packs in parallel [+1..99+]. This setting will change the charge and runtime estimation reported by the UPS. *battlow*:: -> *battery.voltage.low* + Set minimum battery voltage just before the UPS automatically shuts down. This setting will change the charge and runtime estimation reported by the UPS. *auto_reboot*:: -> *ups.start.auto* + Enable or disable auto reboot [+enabled+/+disabled+]. If enabled, the UPS will auto recover when AC power returns. *battery_protection*:: -> *battery.protection* + Enable or disable battery deep discharge protection [+enabled+/+disabled+]. *energy_saving*:: -> *battery.energysave* + Enable or disable Green power function [+enabled+/+disabled+]. If enabled, for energy saving, the UPS will auto off when there is no load. *cold_start*:: -> *ups.start.battery* + Enable or disable Cold Start [+enabled+/+disabled+]. If enabled, the UPS can be turned on also if AC is not connected to the UPS. *outlet_control*:: -> *outlet.0.switchable* + Enable or disable programmable outlets control at battery mode [+enabled+/+disabled+]. If enabled, the UPS will cut off programmable outlets after backup time (set through *outlet.*{*1*,*2*,*3*,*4*}**.delay.shutdown**) arrives. If disabled, the UPS will provide continuous power to programmable outlets until the battery is running out. *max_eco_volt*:: -> *input.transfer.high* + Maximum voltage for ECO Mode (V). If AC voltage is within acceptable range, ECO mode will be used (If the UPS is capable of and it's enabled). *min_eco_volt*:: -> *input.transfer.low* + Minimum voltage for ECO Mode (V). If AC voltage is within acceptable range, ECO mode will be used (If the UPS is capable of and it's enabled). *max_eco_freq*:: -> *input.frequency.high* + Maximum frequency for ECO Mode (Hz). If AC frequency is within acceptable range, ECO mode will be used (If the UPS is capable of and it's enabled). *min_eco_freq*:: -> *input.frequency.low* + Minimum frequency for ECO Mode (Hz). If AC frequency is within acceptable range, ECO mode will be used (If the UPS is capable of and it's enabled). *outlet1_delay*:: -> *outlet.1.delay.shutdown* + Delay time before programmable outlet 1 shuts down the load when on battery mode [+0..59940+] (seconds). *outlet2_delay*:: -> *outlet.2.delay.shutdown* + Delay time before programmable outlet 2 shuts down the load when on battery mode [+0..59940+] (seconds). *outlet3_delay*:: -> *outlet.3.delay.shutdown* + Delay time before programmable outlet 3 shuts down the load when on battery mode [+0..59940+] (seconds). *outlet4_delay*:: -> *outlet.4.delay.shutdown* + Delay time before programmable outlet 4 shuts down the load when on battery mode [+0..59940+] (seconds). *batt_type*:: -> *battery.type* + Battery type (for P31 UPSes only) [+Li+/+Flooded+/+AGM+]. KNOWN PROBLEMS -------------- Some UPS commands aren't supported by all models. In most cases, the driver will send a message to the system log when the user tries to execute an unsupported command. Unfortunately, some models don't even provide a way for the driver to check for this, so the unsupported commands will silently fail. Both the *load.off* and *shutdown.stayoff* instant commands are meant to turn the load off indefinitely. However, some UPS models don't allow this. Some models report a bogus value for the beeper status (will always be 'enabled' or 'disabled'). So, the *beeper.toggle* command may appear to have no effect in the status reported by the driver when, in fact, it is working fine. The temperature and load value is known to be bogus in some models. MASTERGUARD UNITS ~~~~~~~~~~~~~~~~~ The driver is supposed to support both "new" A series (A700/1000/2000/3000 and their -19 cousins) and E series (E60/100/200) but was tested only on A due to lack of E hardware. VOLTRONIC-QS UNITS ~~~~~~~~~~~~~~~~~~ Both *load.off* and *shutdown.stayoff* instant commands are known to work as expected (i.e. turn the load off indefinitely) only if mains is present, otherwise, as soon as mains returns the load will be powered. After issuing a *shutdown.return* instant command, the UPS won't wait *ondelay* before powering on the load, provided the following conditions are met: - if the load has been previously (no matter how long before) powered off through *load.off*/*shutdown.stayoff* _and_ powered on through *load.on*/*shutdown.stop* _and_ - if AC wasn't cut after issuing the *load.off*/*shutdown.stayoff* (i.e. the UPS didn't turn itself off) _and_ - if there's a power outage after issuing the *shutdown.return* command In this case, as soon as mains returns the load will be powered. VOLTRONIC-QS-HEX UNITS ~~~~~~~~~~~~~~~~~~~~~~ *shutdown.return*, *load.off*, and *shutdown.stayoff* instant commands are known to work as expected only if mains is present, otherwise, as soon as mains returns the load will be powered. UPS WARNINGS (VOLTRONIC PROTOCOL) --------------------------------- The UPSes supported by 'voltronic' protocol report warnings through a 64bit flag (bit1bit2...bit63bit64) where 1 means that a warning arose, while 0 means no warning. Since more than one warning at a time can be signaled, and because of the limited space in the ups.alarm variable, if the length of the warnings exceeds that of ups.alarms variable, they will be reported as bits. If you want to know the explanation of that bit you can either watch the log or see the next table (unlisted bits equal to unknown warnings). .UPS Warnings for 'voltronic' UPSes [cols="5,95",options="autowidth,header",frame="topbot",grid="rows",align="center",caption=""] |==== |# |Corresponding Warning |1 |Battery disconnected |2 |Neutral not connected |3 |Site fault |4 |Phase sequence incorrect |5 |Phase sequence incorrect in bypass |6 |Input frequency unstable in bypass |7 |Battery overcharged |8 |Low battery |9 |Overload alarm |10 |Fan alarm |11 |EPO enabled |12 |Unable to turn on UPS |13 |Over temperature alarm |14 |Charger alarm |15 |Remote auto shutdown |16 |L1 input fuse not working |17 |L2 input fuse not working |18 |L3 input fuse not working |19 |Positive PFC abnormal in L1 |20 |Negative PFC abnormal in L1 |21 |Positive PFC abnormal in L2 |22 |Negative PFC abnormal in L2 |23 |Positive PFC abnormal in L3 |24 |Negative PFC abnormal in L3 |25 |Abnormal in CAN-bus communication |26 |Abnormal in synchronous signal circuit |27 |Abnormal in synchronous pulse signal circuit |28 |Abnormal in host signal circuit |29 |Male connector of parallel cable not connected well |30 |Female connector of parallel cable not connected well |31 |Parallel cable not connected well |32 |Battery connection not consistent in parallel systems |33 |AC connection not consistent in parallel systems |34 |Bypass connection not consistent in parallel systems |35 |UPS model types not consistent in parallel systems |36 |Capacity of UPSs not consistent in parallel systems |37 |Auto restart setting not consistent in parallel systems |38 |Battery cell over charge |39 |Battery protection setting not consistent in parallel systems |40 |Battery detection setting not consistent in parallel systems |41 |Bypass not allowed setting not consistent in parallel systems |42 |Converter setting not consistent in parallel systems |43 |High loss point for frequency in bypass mode not consistent in parallel systems |44 |Low loss point for frequency in bypass mode not consistent in parallel systems |45 |High loss point for voltage in bypass mode not consistent in parallel systems |46 |Low loss point for voltage in bypass mode not consistent in parallel systems |47 |High loss point for frequency in AC mode not consistent in parallel systems |48 |Low loss point for frequency in AC mode not consistent in parallel systems |49 |High loss point for voltage in AC mode not consistent in parallel systems |50 |Low loss point for voltage in AC mode not consistent in parallel systems |51 |Warning for locking in bypass mode after 3 consecutive overloads within 30 min |52 |Warning for three-phase AC input current unbalance |53 |Warning for a three-phase input current unbalance detected in battery mode |54 |Warning for Inverter inter-current unbalance |55 |Programmable outlets cut off pre-alarm |56 |Warning for Battery replace |57 |Abnormal warning on input phase angle |58 |Warning!! Cover of maintain switch is open |62 |EEPROM operation error |==== AUTHORS ------- * Daniele Pezzini * Arnaud Quette * John Stamp * Peter Selinger * Arjen de Korte * Alexander Gordeev * Edgar Fuß SEE ALSO -------- linkman:blazer_ser[8], linkman:blazer_usb[8], linkman:nutupsdrv[8], linkman:ups.conf[5], linkman:upsc[8], linkman:upscmd[8], linkman:upsdrvctl[8], linkman:upsmon[8], linkman:upsrw[8] Internet Resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * The NUT HCL: https://www.networkupstools.org/stable-hcl.html nut-2.8.3/docs/man/nut-scanner.txt0000644000200500020050000003061215001555412013740 00000000000000NUT-SCANNER(8) ============== NAME ---- nut-scanner - Tool to scan communication buses for NUT devices SYNOPSIS -------- *nut-scanner* -h *nut-scanner* ['OPTIONS'] DESCRIPTION ----------- *nut-scanner* scans available communication buses and displays any NUT-compatible devices it has found. *nut-scanner* can also display the detected devices in various formats, including `ups.conf`, and ensures that the generated devices name are unique across buses. INSTALLATION ------------ *nut-scanner* is only built if libltdl (part of libtool development suite) is available. Available scanning options (USB, SNMP, IPMI, ...) will vary according to the available compile-time and run-time dependencies. For example, if Net-SNMP is installed, thus providing libsnmp libraries (`*.so` or `*.dll`) and header files during compilation, and at least the library files on the monitoring system, then SNMP discovery will be available. OPTIONS ------- *-h*:: Display the help text. DISPLAY OPTIONS --------------- *-Q* | *--disp_nut_conf_with_sanity_check*:: Display result in the `ups.conf` format with sanity-check warnings (if any) as comments (default). *-N* | *--disp_nut_conf*:: Display result in the `ups.conf` format. *-P* | *--disp_parsable*:: Display result in a parsable format. BUS OPTIONS ----------- *-C* | *--complete_scan*:: Scan all available communication buses (default behavior) *-U* | *--usb_scan*:: List all NUT-compatible USB devices currently plugged in. + This option can be specified several times, for more hardware link-specific details; these can be counter-productive in case of USB enumeration changes over time: + [options="header",cols="1,3a"] |=========================================================================== | Option count | Practical meaning | `-U` | do not report any `bus`/`device`/`busport` details | `-UU` | report `bus` and `busport`, if available | `-UUU` | report `bus`/`device`/`busport` details | `-UUUU` | report `bus`/`device`/`busport` details, and `bcdDevice` (limited use and benefit) |=========================================================================== + NOTE: For reliability, it is preferable to match just by vendor and product identification, and a serial number if available and unique. *-S* | *--snmp_scan*:: Scan SNMP devices. Requires at least a 'start IP', and optionally, an 'end IP'. See specific SNMP OPTIONS for community and security settings. *-M* | *--xml_scan*:: Scan XML/HTTP devices. Can broadcast a network message on the current network interface(s) to retrieve XML/HTTP capable devices. No IP required in this mode. If IP address ranges are specified, they would be scanned instead of a broadcast. *-O* | *--oldnut_scan*:: Scan NUT devices (i.e. `upsd` daemon) on IP ranging from 'start IP' to 'end IP'. *-n* | *--nut_simulation_scan*:: Scan NUT simulated devices (`.dev` files in the built-in "sysconfig" location). + WARNING: The `NUT_CONFPATH` environment variable override is not currently supported. *-A* | *--avahi_scan*:: Scan NUT servers using Avahi request on the current network interface(s). No IP address options are required or used. *-I* | *--ipmi_scan*:: Scan NUT compatible power supplies available via IPMI on the current host, or over the network if IP address ranges are specified. *-E* | *--eaton_serial* 'serial ports':: Scan Eaton devices (XCP and SHUT) available via serial bus on the current host. This option must be requested explicitly, even for a complete scan. 'serial ports' can be expressed in various forms: + - 'auto' to scan all serial ports. - a single character indicating a port number ('0' (zero) for `/dev/ttyS0` and `/dev/ttyUSB0` on Linux, '1' for `COM1` on Windows, 'a' for `/dev/ttya` on Solaris...) - a range of N characters, hyphen separated, describing the range of ports using `X-Y` syntax, where 'X' and 'Y' are characters referring to the port number. - a single port name. - a list of ports name, comma separated, like `/dev/ttyS1,/dev/ttyS4`. NETWORK OPTIONS --------------- [NOTE] ====== The networked buses (such as SNMP, NetXML, IPMI and "Old NUT") allow to specify several IP (IPv4 or IPv6) address ranges, down to individual single IP addresses. Normally a new range is specified by a set of one `-s` and one `-e` options following each other (in any order on the command line). Lone or consecutive `-s` or `-e` options present on the command line would translate to single-IP queries. Also, a `-m` option squashed between two `-s` and `-e` options would be a new range, turning those two into single-IP queries. This feature does not by itself recombine "neighboring" addresses into one range, nor even check for duplicate or overlapping specifications. A single-address range may be a host name which would be resolved into one IP address by the system resolver. A CIDR using a host name and netmask length would be resolved into an IP address and subjected to the mask application, to query hosts "near" the named one. ====== Also note that some buses require IP address(es) to scan, and others have a different behavior when exactly no addresses are specified (it is not currently possible to mix the two behaviors in one invocation of the `nut-scanner` tool). Finally note that currently even if multi-threaded support is available, each range specification is a separate fan-out of queries constrained by the timeout. Requests to scan many single IP addresses will take a while to complete, much longer than if they were a single range. This will be hopefully fixed in later releases. NOTE: Colon-separated IPv6 addresses must be passed in square brackets. *-t* | *--timeout* 'timeout':: Set the network timeout in seconds. Default timeout is 5 seconds. *-s* | *--start_ip* 'start IP':: Set the first IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut) or optional (XML/HTTP). *-e* | *--end_ip* 'end IP':: Set the last IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut) or optional (XML/HTTP). If this parameter is omitted, only the 'start IP' is scanned. If 'end IP' is less than 'start IP', both parameters are internally permuted. *-m* | *--mask_cidr* 'IP address/mask':: Set a range of IP addresses by using CIDR notation. + A special form `-m auto` allows `nut-scanner` to detect local IP address(es) and scan corresponding subnet(s) on supported platforms, and `-m auto4` or `-m auto6` limits the selected addresses to IPv4 and IPv6 respectively. Only the first "auto*" request would be honoured, others ignored with a warning. + An `/ADDRLEN` suffix can be added to the option, to filter out discovered subnets with too many bits available for the host address part (avoiding millions of scans in the extreme cases). For example, if your IPv4 LAN's network range is `10.2.3.0/24`, its address part is `(32-24)=8`. Note that while this is applied to IPv6 networks also, their typical `/64` subnets are not likely to have a NUT/SNMP/NetXML/... server *that* close nearby (in addressing terms), for a tight filter to find them. Default is `8`. NUT DEVICE OPTION ----------------- *-p* | *--port* 'port number':: Set the port number of scanned NUT devices (default 3493). SNMP V1 OPTION -------------- *-c* | *--community* 'community':: Set SNMP v1 community name (default = public). SNMP V3 OPTIONS --------------- *-l* | *--secLevel* 'security level':: Set the 'security level' used for SNMPv3 messages. Allowed values are: noAuthNoPriv, authNoPriv and authPriv. This parameter is mandatory if you use non-trivial authentication. *-u* | *--secName* 'security name':: Set the 'security name' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level'. *-w* | *--authProtocol* 'authentication protocol':: Set the 'authentication protocol' used for authenticated SNMPv3 messages. Allowed values are MD5, SHA, SHA256, SHA384 or SHA512 (depending on Net-SNMP library capabilities; check help of the `nut-scanner` binary program for the run-time supported list). Default value is MD5. *-W* | *--authPassword* 'authentication pass phrase':: Set the 'authentication pass phrase' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level' to authNoPriv or authPriv. *-x* | *--privProtocol* 'privacy protocol':: Set the 'privacy protocol' used for encrypted SNMPv3 messages. Allowed values are DES, AES, AES192 or AES256 (depending on Net-SNMP library capabilities; check help of the `nut-scanner` binary program for the run-time supported list). Default value is DES. *-X* | *--privPassword* 'privacy pass phrase':: Set the 'privacy pass phrase' used for encrypted SNMPv3 messages. This parameter is mandatory if you set 'security level' to authPriv. IPMI OPTIONS ------------ *-b* | *--username* 'username':: Set the username used for authenticating IPMI over LAN connections (mandatory for IPMI over LAN. No default). *-B* | *--password* 'password':: Specify the password to use when authenticating with the remote host (mandatory for IPMI over LAN. No default). *-d* | *--authType* 'authentication type':: Specify the IPMI 1.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5). This forces connection through the 'lan' IPMI interface , thus in IPMI 1.5 mode. *-L* | *--cipher_suite_id* 'cipher suite identifier':: Specify the IPMI 2.0 cipher suite ID to use. The Cipher Suite ID identifies a set of authentication, integrity, and confidentiality algorithms to use for IPMI 2.0 communication. + The authentication algorithm identifies the algorithm to use for session setup, the integrity algorithm identifies the algorithm to use for session packet signatures, and the confidentiality algorithm identifies the algorithm to use for payload encryption (default=3). + The following cipher suite ids are currently supported (Authentication; Integrity; Confidentiality): - *0*: None; None; None - *1*: HMAC-SHA1; None; None - *2*: HMAC-SHA1; HMAC-SHA1-96; None - *3*: HMAC-SHA1; HMAC-SHA1-96; AES-CBC-128 - *6*: HMAC-MD5; None; None - *7*: HMAC-MD5; HMAC-MD5-128; None - *8*: HMAC-MD5; HMAC-MD5-128; AES-CBC-128 - *11*: HMAC-MD5; MD5-128; None - *12*: HMAC-MD5; MD5-128; AES-CBC-128 - *15*: HMAC-SHA256; None; None - *16*: HMAC-SHA256; HMAC_SHA256_128; None - *17*: HMAC-SHA256; HMAC_SHA256_128; AES-CBC-128 MISCELLANEOUS OPTIONS --------------------- *-V* | *--version*:: Display NUT version. *-a* | *--available*:: Display available buses that can be scanned, depending on how the nut-scanner binary program has been compiled. (e.g. OLDNUT, USB, SNMP, XML, AVAHI, IPMI). *-q* | *--quiet*:: Display only scan result. No information on currently scanned bus is displayed. *-D* | *--nut_debug_level*:: Raise the debugging level. Use this multiple times to see more details. NOTE: The level of debugging needed depends both on `nut-scanner` and the problem you're trying to diagnose. Therefore, first explain the problem you have with `nut-scanner` to a developer/maintainer, before sending them debugging output. More often than not, if you just pick a level, the output may be either too limited or too verbose to be of any use. EXAMPLES -------- To scan USB devices only: ---- :; nut-scanner -U [nutdev-usb1] driver = "snmp-ups" port = "192.168.0.42" ---- To scan SNMP v1 device with 'public' (default) community on address range '192.168.0.0 to 192.168.0.255': ---- :; nut-scanner -S -s 192.168.0.0 -e 192.168.0.255 [nutdev-snmp1] driver = "snmp-ups" port = "192.168.0.42" ---- The same using CIDR notation: ---- :; nut-scanner -S -m 192.168.0.0/24 [nutdev-snmp1] driver = "snmp-ups" port = "192.168.0.42" ---- To scan NUT servers with a timeout of '10' seconds on IP range '192.168.0.0 to 192.168.0.127' using CIDR notation: ---- :; nut-scanner -O -t 10 -m 192.168.0.0/25 [nutdev-nut1] driver = "dummy-ups" port = "dummy-test@192.168.1.28" ---- To scan for power supplies, through IPMI (1.5 mode) over the network, on address range '192.168.0.0 to 192.168.0.255' using CIDR notation: ---- :; nut-scanner -I -m 192.168.0.0/24 -b username -B password ---- To scan for Eaton serial devices on ports '0' and '1' (`/dev/ttyS0`, `/dev/ttyUSB0`, `/dev/ttyS1` and `/dev/ttyUSB1` on Linux): ---- :; nut-scanner --eaton_serial 0-1 ---- To scan for Eaton serial devices on ports '1' and '2' (`COM1` and `COM2` on Windows): ---- :; nut-scanner --eaton_serial 1-2 ---- SEE ALSO -------- linkman:ups.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/hwmon_ina219.80000644000200500020050000001337215001555101013245 00000000000000'\" t .\" Title: hwmon_ina219 .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "HWMON_INA219" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" hwmon_ina219 \- Driver for UPS based on INA219 .SH "SYNOPSIS" .sp \fBhwmon_ina219\fR \-h .sp \fBhwmon_ina219\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the \fBhwmon_ina219\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .sp The driver implements reading of current and voltage from INA219 by using hwmon sysfs API of the Linux Kernel\&. There is no other UPS\-like logic in there\&. Based on the measurements of the battery voltage and charging current, the driver makes assumptions of the current state of the system\&. .SH "SUPPORTED HARDWARE" .sp The \fBhwmon_ina219\fR driver is based on setup with Raspberry PI Compute Module 4 and its baseboard Waveshare CM4\-POE\-UPS\-BASE\&. .SH "EXTRA ARGUMENTS" .sp The required parameter for this driver: .PP \fBport\fR=\fIhwmon\-dir\fR .RS 4 Path to appropriate /sys/hwmon/hwmonX or \fIauto\fR to detect automatically\&. .RE .sp Optional parameters: .PP \fBdefault\&.battery\&.charge\&.low\fR=\fIlow\-battery\-threshold\fR .RS 4 Threshold for low battery state (in percent)\&. .RE .PP \fBdefault\&.battery\&.voltage\&.nominal\fR=\fIvoltage\-value\fR .RS 4 Nominal voltage (V) value of utilized batteries, used to derive their low and high watermark settings (see below)\&. Default: 3\&.6\&. .sp Known pre\-sets include: 3\&.6, 3\&.7, 3\&.8, 3\&.85\&. .RE .PP \fBdefault\&.battery\&.voltage\&.low\fR=\fIvoltage\-value\fR .RS 4 Low voltage (V) value of used batteries\&. Practically, it denotes depleted batteries\&. If not given, it is derived from the \fBbattery\&.voltage\&.nominal\fR\&. .RE .PP \fBdefault\&.battery\&.voltage\&.high\fR=\fIvoltage\-value\fR .RS 4 High voltage (V) value of used batteries\&. Practically, it denotes fully charged batteries\&. If not given, it is derived from the \fBbattery\&.voltage\&.nominal\fR\&. .RE .SH "INSTALLATION" .sp This driver is specific to the Linux hwmon API\&. .sp When using with the Waveshare CM4\-POE\-UPS\-BASE baseboard, there are few steps to be done to enable access to the INA219 circuit: .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ .sp -1 .IP " 1." 4.2 .\} edit boot/config\&.txt: .sp .if n \{\ .RS 4 .\} .nf dtparam=i2c_vc=on dtoverlay=i2c\-ina219 .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ .sp -1 .IP " 2." 4.2 .\} create a new device tree overlay file i2c\-ina219\&.dts: .sp .if n \{\ .RS 4 .\} .nf /dts\-v1/; /plugin/; / { compatible = "brcm,bcm2835"; fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address\-cells = \fB(1)\fR; #size\-cells = \fB(2)\fR; ina219@43 { status = "okay"; compatible = "ti,ina219"; reg = <0x43>; shunt\-resistor = \fB(3)\fR; // R100 }; }; }; }; .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ .sp -1 .IP " 3." 4.2 .\} convert i2c\-ina219\&.dts to dtbo and place it into /boot/overlays: .sp .if n \{\ .RS 4 .\} .nf $ dtc \-@ \-I dts \-O dtb \-o /boot/overlays/i2c\-ina219\&.dtbo i2c\-ina219\&.dts .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ .sp -1 .IP " 4." 4.2 .\} configure hwmon_ina219 UPS driver for NUT (ups\&.conf): .sp .if n \{\ .RS 4 .\} .nf [ina219] driver = hwmon_ina219 port = auto .fi .if n \{\ .RE .\} .RE .SH "KNOWN ISSUES AND BUGS" .sp The driver shutdown function is not implemented\&. .SH "AUTHORS" .sp Andrew Anderson .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Initial pull requests adding this driver: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://github\&.com/networkupstools/nut/pull/2430 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://github\&.com/networkupstools/nut/issues/2378 .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Baseboard with INA219: https://www\&.waveshare\&.com/wiki/CM4\-POE\-UPS\-BASE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} TI INA219: https://www\&.ti\&.com/lit/ds/symlink/ina219\&.pdf .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE nut-2.8.3/docs/man/nutscan_scan_usb.txt0000644000200500020050000000430315001555412015031 00000000000000NUTSCAN_SCAN_USB(3) ==================== NAME ---- nutscan_scan_usb - Scan NUT compatible USB devices. SYNOPSIS -------- ------ #include nutscan_device_t * nutscan_scan_usb(nutscan_usb_t * scanopts); ------ [NOTE] ====== Before `libnutscan` version 2.5.0 there was no argument: nutscan_device_t * nutscan_scan_usb(void); After the API update to have an argument, equivalent default activity can be achieved by passing `NULL` value for the argument. ====== DESCRIPTION ----------- The *nutscan_scan_usb()* function tries to detect NUT compatible USB devices. The `scanopts` argument contains toggles about values that would be reported into the generated device section. Currently they regard physical link details which can change over time (e.g. USB re-enumeration due to software or hardware re-connections); see `nut-scan.h` for current details: ---- /* USB scan options structure */ typedef struct nutscan_usb { /* Hardware link related values below are not reliable for run-time * matching (they can change over time) but can be useful if e.g. * "serial" is not available or unique */ int report_bus; int report_busport; int report_device; /* The value is not currently used for device matching, but might be * used later, and it is available from discovery */ int report_bcdDevice; } nutscan_usb_t; ---- You MUST call linkman:nutscan_init[3] before using this function. RETURN VALUE ------------ The *nutscan_scan_usb()* function returns a pointer to a `nutscan_device_t` structure containing all found devices or NULL if an error occurs or no device is found. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3] nut-2.8.3/docs/man/upscli_strerror.txt0000644000200500020050000000145615001555412014750 00000000000000UPSCLI_STRERROR(3) ================== NAME ---- upscli_strerror - Return a string describing error condition SYNOPSIS -------- ------ #include const char *upscli_strerror(UPSCONN_t *ups); ------ DESCRIPTION ----------- The *upscli_strerror*() function takes the pointer 'ups' to a `UPSCONN_t` state structure and returns a string describing the last error which occurred on this connection. The string is valid until the next call to *upscli_strerror*(). RETURN VALUE ------------ The *upscli_strerror*() function returns a description of the error, or an "unknown error" message if the error code is not recognized. SEE ALSO -------- linkman:upscli_fd[3], linkman:upscli_get[3], linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_ssl[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/oneac.80000644000200500020050000001257115001555074012130 00000000000000'\" t .\" Title: oneac .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "ONEAC" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" oneac \- Driver for Oneac UPS equipment .SH "SYNOPSIS" .sp \fBoneac\fR \-h .sp \fBoneac\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the oneac driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports various Oneac UPS families: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} EG (late 80s, early 90s, plug\-in serial interface card) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} ON (early and mid\-90s, plug\-in serial interface card) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} OZ (mid\-90s on, DB\-25 std\&., interface slot) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} OB (early 2000\(cqs on, big cabinet, DB\-25 std\&., interface slot) .RE .sp If your UPS is equipped with the Basic Interface card, use the \fBgenericups\fR(8) driver\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file: .PP \fBtesttime\fR=\fInum\fR .RS 4 Change battery test time from the 2 minute default\&. .RE .PP \fBoffdelay\fR=\fInum\fR .RS 4 Change shutdown delay time from 0 second default\&. .RE .SH "INSTANT COMMANDS" .sp This driver supports the following Instant Commands\&. (See \fBupscmd\fR(8)) .SS "All UPS units" .PP \fBshutdown\&.return\fR .RS 4 Turn off the load possibly after a delay and return when power is back\&. .RE .PP \fBshutdown\&.stop\fR .RS 4 Stop a shutdown in progress\&. .RE .PP \fBshutdown\&.reboot\fR .RS 4 Shut down the load briefly while rebooting the UPS\&. .RE .PP \fBtest\&.failure\&.start\fR .RS 4 Starts a 15 second long simulation of an input power failure\&. .RE .PP \fBtest\&.battery\&.start\&.quick\fR .RS 4 Start a "quick" battery test\&. The default time is 2 minutes\&. This time can be set in the \fBups\&.conf\fR file\&. See \fBtestime\fR above\&. .RE .PP \fBtest\&.battery\&.stop\fR .RS 4 Stops a battery test that is in progress\&. .RE .SS "All ON UPS units" .PP \fBreset\&.input\&.minmax\fR .RS 4 Reset the minimum and maximum input line voltage values seen since the last reset or power on\&. .RE .SS "Newer ON UPS units" .PP \fBtest\&.panel\&.start\fR .RS 4 Start testing the UPS panel\&. .RE .PP \fBtest\&.battery\&.start\&.deep\fR .RS 4 Start a "deep" battery test\&. This test runs the UPS until the low battery point and then returns to the AC line\&. .RE .PP \fBreset\&.input\&.minmax\fR .RS 4 Reset the minimum and maximum input line voltage values seen since the last reset or power on\&. .RE .PP \fBbeeper\&.enable\fR .RS 4 Enable UPS beeper/buzzer\&. .RE .PP \fBbeeper\&.disable\fR .RS 4 Disable UPS beeper/buzzer\&. .RE .PP \fBbeeper\&.mute\fR .RS 4 Mutes the UPS beeper/buzzer for the current alarm condition(s)\&. .RE .SH "WRITABLE VARIABLES" .sp See \fBupsrw\fR(8) to see what variables are writable for the UPS\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp If your UPS supports writing battery\&.runtime\&.low, the new set value is to be entered in minutes (up to \fI99\fR) but the reported value is reported in seconds (set \fIvalue * 60\fR)\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp If your UPS supports input\&.transfer\&.low and input\&.transfer\&.high, those values are used to create an allowable output range\&. The UPS will do what it can to keep the output voltage value within the defined range (for example: tap change or switch to inverter)\&. .sp .5v .RE .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Bill Elliot .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Eric Lawson .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/tripplite.txt0000644000200500020050000000327115001555412013520 00000000000000TRIPPLITE(8) ============ NAME ---- tripplite - Driver for Tripp-Lite SmartPro UPS equipment SYNOPSIS -------- *tripplite* -h *tripplite* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the tripplite driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver should work on the SmartPro line, including the SMART700 and SMART700SER. It only supports SmartPro models that communicate using the serial port. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *offdelay*='num':: Time to wait before the UPS is turned off after the kill power command is sent. The default value is 64 (in seconds). *rebootdelay*='num':: Set the timer before the UPS is cycled after the reboot command is sent. The default value is 64 (in seconds). *startdelay*='num':: Set the time that the UPS waits before it turns itself back on after a reboot command. The default value is 60 (in seconds). KNOWN ISSUES AND BUGS --------------------- Battery charge information may not be correct for all UPSes. It is tuned to be correct for a SMART700SER. Other models may not provide correct information. Information from the manufacturer would be helpful. AUTHORS ------- * Rickard E. (Rik) Faith * Nicholas Kain SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Other drivers for Tripp-Lite hardware: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ linkman:tripplitesu[8], linkman:tripplite_usb[8], linkman:usbhid-ups[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/powerpanel.80000644000200500020050000001540315001555075013215 00000000000000'\" t .\" Title: powerpanel .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "POWERPANEL" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" powerpanel \- Driver for serial PowerPanel Plus compatible UPS equipment .SH "SYNOPSIS" .sp \fBpowerpanel\fR \-h .sp \fBpowerpanel\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the powerpanel driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports CyberPower BC1200, PR2200 and many other similar devices, both for the text and binary protocols\&. The driver will autodetect which protocol is used\&. .sp If your Cyber Power Systems UPS has a USB port, you may wish to use the \fBusbhid-ups\fR(8) driver\&. The \fBsnmp-ups\fR(8) driver supports several network cards via SNMP\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in \fBups.conf\fR(5): .PP \fBprotocol=\fR[\fItext,binary\fR] .RS 4 Override the default autodetection of the protocol\&. .RE .PP \fBmanufacturer=\fR\fIvalue\fR .RS 4 If you don\(cqt like the autodetected value, you can override this by setting it here\&. .RE .PP \fBmodel=\fR\fIvalue\fR .RS 4 Like manufacturer above\&. .RE .PP \fBserial=\fR\fIvalue\fR .RS 4 Like manufacturer above\&. .RE .PP \fBondelay=\fR\fIvalue\fR .RS 4 Time to wait before switching on the UPS (1 \- 9999 minutes, 0=indefinite)\&. Only available with the text protocol driver (see Support Status)\&. .RE .PP \fBoffdelay=\fR\fIvalue\fR .RS 4 Time to wait before shutting down the UPS (6 \- 600 seconds)\&. Values below 60 seconds will be truncated to 6 seconds intervals, values above 60 seconds to 60 seconds intervals\&. Only available with the text protocol driver (see Support Status)\&. .RE .SH "VARIABLES" .sp Depending on the type of your UPS unit, some of the following variables may be changed with \fBupsrw\fR(8)\&. If the driver can\(cqt read a variable from the UPS, it will not be made available\&. .PP \fBinput\&.transfer\&.high\fR .RS 4 writable: high transfer voltage point in V .RE .PP \fBinput\&.transfer\&.low\fR .RS 4 writable: low transfer voltage point in V .RE .PP \fBbattery\&.charge\&.low\fR .RS 4 writable: remaining battery charge percentage for low battery warning .RE .PP \fBoutput\&.voltage\&.nominal\fR .RS 4 writable: nominal output voltage in V .RE .PP \fBups\&.start\&.battery\fR .RS 4 writable: allow cold start from battery .RE .SH "COMMANDS" .sp Depending on the type of your UPS unit, some of the following commands may be available\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} test\&.battery\&.start\&.quick, test\&.battery\&.stop .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} beeper\&.enable, beeper\&.disable, beeper\&.toggle .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} shutdown\&.return, shutdown\&.reboot, shutdown\&.stayoff .RE .sp On many devices, these commands are unreliable, so before using them you must verify that these work as expected (see Shutdown Issues)\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} shutdown\&.stop .RE .SH "SUPPORT STATUS" .sp Vendor support is absent for this driver, so if you need some features that are currently not available, provide ample documentation on what the driver should sent to the UPS in order to make this work\&. If more information would be available on the binary protocol, it would probably be possible to make \fIondelay\fR and \fIoffdelay\fR configurable\&. So far, nobody has taken the time to investigate what we should tell the UPS to make this work, and CyberPower isn\(cqt willing to share this with us\&. .SH "SHUTDOWN ISSUES" .sp If the \fBshutdown\&.return\fR command on your UPS doesn\(cqt seem to work, chances are that your UPS is an older model\&. Try a couple of different settings for \fIoffdelay\fR\&. If no value in the range 6\&.\&.600 works, your UPS likely doesn\(cqt support this\&. In order to get the expected behaviour, it requires \fBshutdown\&.stayoff\fR (when on battery) and \fBshutdown\&.reboot\fR (when on mains)\&. The driver will automatically fallback to these commands if \fBshutdown\&.return\fR fails, and tries to detect which one should be used when called with the \fI\-k\fR option (or through \fBupsdrvctl shutdown\fR)\&. .sp This isn\(cqt bullet\-proof, however, and you should be prepared that the power will either not be shutdown or that it doesn\(cqt return when the power comes back\&. All models supported by the binary protocol and many supported through the text protocol are affected by this\&. .SH "KNOWN PROBLEMS" .sp The CyberPower OP series don\(cqt offer direct voltage, charge, frequency and temperature readings\&. Instead, they will return a binary value that needs conversion to the actual value\&. .sp The exact conversion needed is unknown at the time of this writing, hence an estimation was made based om readings from actual devices\&. This may (probably will) be off, possibly a lot\&. Unless you can tell us the exact mapping between values from the UPS and actual readings, don\(cqt bother to complain\&. We\(cqve done the best we can based on the limited information available\&. Remember, a UPS isn\(cqt a measuring instrument\&. .SH "AUTHORS" .sp Arjen de Korte , Doug Reynolds .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Other drivers:" .sp \fBusbhid-ups\fR(8), \fBsnmp-ups\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/bcmxcp_usb.txt0000644000200500020050000000675715001555412013645 00000000000000BCMXCP_USB(8) ============= NAME ---- bcmxcp_usb - Experimental driver for UPSes supporting the BCM/XCP protocol over USB SYNOPSIS -------- *bcmxcp_usb* -h *bcmxcp_usb* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the `bcmxcp_usb` driver. For information about the core driver, see linkman:nutupsdrv[8]. NOTE: This driver is a variant of the serial driver linkman:bcmxcp[8] and uses the same core code. SUPPORTED HARDWARE ------------------ This driver should recognize all BCM/XCP-compatible UPSes that are connected via USB. It has been developed and tested on Powerware PW3501 hardware. It also has been tested on PW5110 hardware. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]. *shutdown_delay =* 'delay':: The number of seconds that the UPS should wait between receiving the shutdown command and actually shutting off. NOTE: This driver does not currently support USB-matching settings common to other drivers, such as *vendor*, *vendorid*, *product*, *productid*, *serial*, *device* or *bus*. //////// The note above may be addressed by https://github.com/networkupstools/nut/issues/1764 When that happens, replace it by the following lines: USB INTERFACE ONLY ~~~~~~~~~~~~~~~~~~ include::nut_usb_addvars.txt[] //////// DEFAULT VALUES FOR THE EXTRA ARGUMENTS -------------------------------------- *shutdown_delay =*'120' INSTANT COMMANDS ---------------- This driver supports the following Instant Commands: *shutdown.return*:: Turn off the load and return when power is back. *shutdown.stayoff*:: Turn off the load and remain off. *test.battery.start*:: Start a battery test. TODO LIST --------- *Report UPS alarm status*:: BCM/XCP supports reporting a wide range of UPS alarm conditions. *Report UPS statistics information*:: BCM/XCP supports reporting of UPS statistics data. EXPERIMENTAL DRIVER ------------------- This driver has been tagged experimental, even if it has been reported to be stable. Thus it is not suitable for production systems and it may be not built by default. This is mainly due to the fact that it is a new driver. INSTALLATION ------------ This driver may be not built by default. You can require building it by using `./configure --with-usb=yes` (note that it will also install other USB drivers), or `./configure --with-drivers=bcmxcp_usb`. Either way, you would need libusb-dev (libraries and headers package) or equivalent for other platforms. You also need to install manually the hotplug files (libhidups and libhid.usermap), generally in etc/hotplug/usb/, to address the permission settings problem. Lastly note that the libhidups file must have execution flag set (ie using chmod +x ...). IMPLEMENTATION -------------- bcmxcp_usb only supports 1 UPS at this time. You can put the "auto" value for port in `ups.conf`, i.e.: [pw3105] driver = bcmxcp_usb port = auto KNOWN ISSUES AND BUGS --------------------- "Got EPERM: Operation not permitted upon driver startup" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You have forgotten to install the hotplug files, as explained in the INSTALLATION section above. Don't forget to restart hotplug so that it applies these changes. AUTHORS ------- * Tore Ørpetveit * Wolfgang Ocker SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_scan_nut_simulation.txt0000644000200500020050000000315115001555412017312 00000000000000NUTSCAN_SCAN_NUT_SIMULATION(3) ============================== NAME ---- nutscan_scan_nut_simulation - Scan your sysconfig directory for NUT simulation devices. SYNOPSIS -------- ------ #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_nut_simulation(); ------ DESCRIPTION ----------- The *nutscan_scan_nut_simulation()* function tries to detect available NUT simulation devices, by finding `*.dev` and `*.seq` files in your "sysconfig" directory. You MUST call linkman:nutscan_init[3] before using this function. BUGS ---- This function currently uses the built-in location of the "sysconfig" directory, and does not consider an override with `NUT_CONFPATH` environment variable accepted by most of the NUT code base. RETURN VALUE ------------ The *nutscan_scan_nut_simulation()* function returns a pointer to a `nutscan_device_t` structure containing all found devices or NULL if an error occurs or no device is found. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_nut[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/upsc.80000644000200500020050000001161315001555047012011 00000000000000'\" t .\" Title: upsc .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSC" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsc \- Lightweight read\-only NUT client .SH "SYNOPSIS" .sp \fBupsc\fR \-l | \-L [\fIhost\fR] .sp \fBupsc\fR \fIups\fR [\fIvariable\fR] .sp \fBupsc\fR \-c \fIups\fR .SH "DESCRIPTION" .sp \fBupsc\fR is provided as a quick way to poll the status of a UPS server\&. It can be used inside shell scripts and other programs that need UPS data but don\(cqt want to include the full interface\&. .SH "OPTIONS" .PP \fB\-l\fR \fIhost\fR .RS 4 List all UPS names configured at \fIhost\fR, one name per line\&. The hostname defaults to "localhost"\&. You may optionally add a colon and a port number\&. .RE .PP \fB\-L\fR \fIhost\fR .RS 4 As above, list all UPS names configured at \fIhost\fR, including their description provided by the remote \fBupsd\fR(8) from its \fBups.conf\fR(5)\&. The hostname defaults to "localhost"\&. You may optionally add a colon and a port number to override the default port\&. .RE .PP \fB\-c\fR \fIups\fR .RS 4 Lists each client connected on \fIups\fR, one name per line\&. .RE .PP \fIups\fR .RS 4 Display the status of that UPS\&. The format for this option is \fIupsname[@hostname[:port]]\fR\&. The default hostname is "localhost"\&. .RE .PP \fIvariable\fR .RS 4 Display the value of this variable only\&. By default, upsc retrieves the list of variables from the server and then displays the value for each\&. This option may be useful in shell scripts to save an additional pipe into grep\&. .RE .SH "COMMON OPTIONS" .PP \fB\-h\fR .RS 4 Show the command\-line help message\&. .RE .PP \fB\-V\fR .RS 4 Show NUT version banner\&. More details may be available if you also export NUT_DEBUG_LEVEL=1 or greater verbosity level\&. .RE .PP \fB\-W\fR \fIsecs\fR .RS 4 Set the timeout for initial network connections (by default they are indefinitely non\-blocking, or until the system interrupts the attempt)\&. Overrides the optional NUT_DEFAULT_CONNECT_TIMEOUT environment variable\&. .RE .SH "EXAMPLES" .sp To list all variables on an UPS named "myups" on a host called "mybox", with \fBupsd\fR(8) running on port \fI1234\fR: .sp .if n \{\ .RS 4 .\} .nf :; upsc myups@mybox:1234 battery\&.charge: 100\&.0 battery\&.voltage: 13\&.9 battery\&.voltage\&.nominal: 13\&.6 \&. \&. \&. .fi .if n \{\ .RE .\} .sp To list the UPSes configured on this system, along with their descriptions: .sp .if n \{\ .RS 4 .\} .nf :; upsc \-L apc: Back\-UPS 500 ppro2: Patriot Pro II .fi .if n \{\ .RE .\} .sp To retrieve the status for all UPSes connected to mybox, using Bourne\-shell syntax: .sp .if n \{\ .RS 4 .\} .nf :; for UPS in `upsc \-l mybox:1234`; do upsc $UPS ups\&.status done .fi .if n \{\ .RE .\} .sp To list clients connected on "myups": .sp .if n \{\ .RS 4 .\} .nf :; upsc \-c myups 127\&.0\&.0\&.1 ::1 192\&.168\&.1\&.2 .fi .if n \{\ .RE .\} .SH "SCRIPTED MODE" .sp If you run this program inside a shell script or similar to get the list of devices and variables, you should only consider using output from stdout, not stderr\&. .SH "DIAGNOSTICS" .sp upsc will either print a list of UPS names, a list of all supported variables and their values on the UPS, or an error message\&. If you do receive an error, make sure you have specified a valid UPS on the command line, that \fBupsd\fR(8) is really running on the other host, and that no firewalls are blocking you\&. .SH "HISTORY" .sp Earlier versions of this program used the \fIupsfetch\fR library and UDP sockets to talk to upsd\&. This version of upsc uses the new \fIupsclient\fR library, which only talks TCP\&. This is why \fIupsct\fR no longer exists\&. .SH "SEE ALSO" .sp \fBupslog\fR(8), \fBups.conf\fR(5), \fBupsd\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/snmp-ups.80000644000200500020050000002253715001555076012632 00000000000000'\" t .\" Title: snmp-ups .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "SNMP\-UPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" snmp-ups \- Multi\-MIB Driver for SNMP UPS equipment .SH "SYNOPSIS" .sp \fBsnmp\-ups\fR \-h .sp \fBsnmp\-ups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the snmp\-ups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The snmp\-ups driver automatically detects and supports a wide range of devices by loading various MIBS, such as: .PP \fBietf\fR .RS 4 UPS that is RFC 1628 (UPS MIB) compliant, e\&.g\&. MGE UPS SYSTEMS, Liebert, perhaps others (default) .RE .PP \fBmge\fR .RS 4 MGE UPS SYSTEMS and MGE Office Protection Systems devices with SNMP cards (ref 66062, 66045, 66074 and 66244) .RE .PP \fBapcc\fR .RS 4 APC AP9605, AP9606, AP9617, and AP9618 APC network management cards, as well as any others supporting the APC POWERNET MIB .RE .PP \fBnetvision\fR .RS 4 Socomec Sicon UPS with Netvision Web/SNMP management card/external box .RE .PP \fBeaton_pw_nm2\fR .RS 4 Powerware devices with ConnectUPS SNMP cards, as well as UPSes with Eaton Gigabit Network Cards (Network\-M2) (renamed from pw) .RE .PP \fBeaton_pxg_ups\fR .RS 4 Eaton devices with Power Xpert Gateway UPS Card (renamed from pxgx_ups) .RE .PP \fBaphel_genesisII\fR .RS 4 Eaton Powerware ePDU Monitored .RE .PP \fBaphel_revelation\fR .RS 4 Eaton Powerware ePDU Managed .RE .PP \fBraritan\fR .RS 4 Various Raritan PDUs (Dominion PX, PM, RPC) .RE .PP \fBraritan\-px2\fR .RS 4 Various Raritan PDUs (Dominion PX2) .RE .PP \fBbaytech\fR .RS 4 Various BayTech PDUs .RE .PP \fBcpqpower\fR .RS 4 HP/Compaq AF401A management card, perhaps others .RE .PP \fBcyberpower\fR .RS 4 Cyberpower RMCARD201\&. Should also support RMCARD100 (net version), RMCARD202 and RMCARD301 .RE .PP \fBhuawei\fR .RS 4 Huawei UPS5000\-E, perhaps others .RE .PP \fBtripplite\fR .RS 4 TrippLite UPSes; at this time this is the IETF MIB mapping with just the Tripplite entry point OID to verify the device vendor, and a real hardware\-specific configuration will be added in the future development\&. .RE .sp For a complete and up\-to\-date listing, you can query the driver by passing the \fBmibs=\-\-list\fR argument (see below)\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBport\fR=\fIhostname[:port]\fR .RS 4 Set SNMP hostname, or IP address, and port number of the peer SNMP agent\&. There is no default for the hostname, but the default port is 161\&. .RE .PP \fBmibs\fR=\fI\-\-list\fR .RS 4 A special option which allows to list the currently known MIB\-to\-NUT mappings and exit the driver binary, intended for command\-line usage like this: .sp .if n \{\ .RS 4 .\} .nf :; snmp\-ups \-a snmp\-test \-x mibs=\-\-list .fi .if n \{\ .RE .\} .RE .PP \fBmibs\fR=\fIname\fR .RS 4 Set MIB compliance (default=\fIauto\fR, allowed entries: refer to SUPPORTED HARDWARE above)\&. .sp With "auto", the driver will try a select set of SNMP objects until it finds one that the device responds to\&. .sp Note that since NUT 2\&.6\&.2, snmp\-ups has a new method that uses sysObjectID (which is a pointer to the preferred MIB of the device) to detect supported devices\&. This renders void the \fBrequirement\fR to use the "mibs" option\&. .RE .PP \fBcommunity\fR=\fIname\fR .RS 4 Set community name (default is \fIpublic\fR) for SNMPv1 and SNMPv2c connections\&. Note that an RW capable community name is required to change UPS settings and send commands (such as for a power\-down)\&. .RE .PP \fBsnmp_version\fR=\fIversion\fR .RS 4 Set SNMP version (default = v1, allowed: v2c, v3) .RE .PP \fBsnmp_retries\fR=\fIretries\fR .RS 4 Specifies the number of Net\-SNMP retries to be used in the requests (default=5) .RE .PP \fBsnmp_timeout\fR=\fItimeout\fR .RS 4 Specifies the Net\-SNMP timeout in seconds between retries (default=1) .RE .PP \fBsymmetrathreephase\fR .RS 4 Enable APCC three phase Symmetra quirks (use on APCC three phase Symmetras): Convert from three phase line\-to\-line voltage to line\-to\-neutral voltage (default: not enabled) .RE .PP \fBpollfreq\fR=\fInum\fR .RS 4 Set polling interval for full updates, in seconds, to reduce SNMP network traffic relative to the quick updates performed every "pollinterval" (the latter option is described in \fBups.conf\fR(5))\&. The default value is 30 (in seconds)\&. .RE .PP \fBnotransferoids\fR .RS 4 Disable the monitoring of the low and high voltage transfer OIDs in the hardware\&. This will remove input\&.transfer\&.low and input\&.transfer\&.high from the list of variables\&. This should only be used on APCC Symmetra equipment which has strangeness in the three\-phase power reporting\&. .RE .PP \fBsecLevel\fR=\fIvalue\fR .RS 4 Set the securityLevel used for SNMPv3 messages (default=noAuthNoPriv, allowed: authNoPriv,authPriv) This parameter is mandatory if you use non\-trivial authentication\&. .RE .PP \fBsecName\fR=\fIvalue\fR .RS 4 Set the securityName used for authenticated SNMPv3 messages (no default) .RE .PP \fBauthPassword\fR=\fIvalue\fR .RS 4 Set the authentication pass phrase used for authenticated SNMPv3 messages (no default) .RE .PP \fBprivPassword\fR=\fIvalue\fR .RS 4 Set the privacy pass phrase used for encrypted SNMPv3 messages (no default) .RE .PP \fBauthProtocol\fR=\fIvalue\fR .RS 4 Set the authentication protocol (MD5, SHA, SHA256, SHA384 or SHA512) used for authenticated SNMPv3 messages (default=MD5)\&. Note that the exact protocol list depends on Net\-SNMP library capabilities; check help of the snmp\-ups binary program for the run\-time supported list\&. .RE .PP \fBprivProtocol\fR=\fIvalue\fR .RS 4 Set the privacy protocol (DES, AES, AES192 or AES256) used for encrypted SNMPv3 messages (default=DES)\&. Note that the exact protocol list depends on Net\-SNMP library capabilities; check help of the snmp\-ups binary program for the run\-time supported list\&. .RE .SH "REQUIREMENTS" .sp You will need to install the Net\-SNMP package from http://www\&.net\-snmp\&.org/ before building this driver\&. .sp SNMP v3 also requires OpenSSL support from http://www\&.openssl\&.org\&. .SH "LIMITATIONS" .SS "Shutdown" .sp The shutdown sequence should be tested before relying on NUT to send a shutdown command to the UPS\&. The problem is that the host network stack may have been torn down by the time the driver is invoked to send the shutdown command\&. The driver attempts to send shutdown\&.return, shutdown\&.reboot, and load\&.off\&.delay commands to the UPS in sequence, stopping after the first supported command\&. .SH "INSTALLATION" .sp This driver is only built if the Net\-SNMP development files are present at configuration time\&. You can also force it to be built by using configure \-\-with\-snmp=yes before calling make\&. .SH "EXAMPLES" .sp The hostname of the UPS is specified with the "port" value in ups\&.conf, and may include a non\-standard (161) remote peer port: .sp .if n \{\ .RS 4 .\} .nf [snmpv1] driver = snmp\-ups port = snmp\-ups\&.example\&.com community = public snmp_version = v1 pollfreq = 15 desc = "Example SNMP v1 device" [snmpv3] driver = snmp\-ups port = 166\&.99\&.224\&.132:170 snmp_version = v3 secLevel = authPriv secName = mysecurityname authPassword = myauthenticationpassphrase privPassword = myprivatepassphrase desc = "Example SNMP v3 device, with the highest security level" .fi .if n \{\ .RE .\} .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Arnaud Quette .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Dmitry Frolov .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Jim Klimov .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "NUT SNMP Protocols Library" .sp Available at: https://www\&.networkupstools\&.org/ups\-protocols\&.html#_snmp .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upsmon.conf.50000644000200500020050000007410115001555047013302 00000000000000'\" t .\" Title: upsmon.conf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSMON\&.CONF" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsmon.conf \- Configuration for Network UPS Tools upsmon client .SH "DESCRIPTION" .sp This file\(cqs primary job is to define the systems that \fBupsmon\fR(8) will monitor, and to tell it how to shut down the system when necessary\&. It will contain passwords, so keep it secure\&. Ideally, only the upsmon process should be able to read it\&. .sp A minimal configuration should include at least one MONITOR instruction, MINSUPPLIES (may be \fI0\fR if this system is only monitoring other NUT servers), and a POWERDOWNFLAG if this machine is a "primary" system connected to the UPS and drives its late\-shutdown power\-off command in case of an emergency\&. .sp Additionally, other optional configuration values can be set in this file\&. .SH "IMPORTANT NOTES" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Balance the run\-time user permissions to access the file (and perhaps the directory it is in) for only upsmon to be able to read it; write access is not needed\&. It is common to use chown root:nut and chmod 640 to set up acceptable file permissions\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Packages (and build recipes) typically prepare one set of user and group accounts for NUT\&. Custom builds with minimal configuration might even use nobody:nogroup or similar, which is inherently insecure\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} On systems with extra security concerns, NUT drivers, data server, and any other monitoring, logging, etc\&. clients, should run as separate user accounts\&. This would need some daemons to use customized user, group, RUN_AS_USER and/or RUN_AS_GROUP settings to override the single built\-in value\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Keep in mind the security of also any backup copies of this file, e\&.g\&. the archive files it might end up in\&. .RE .RE .SH "CONFIGURATION DIRECTIVES" .PP \fBDEADTIME\fR \fIseconds\fR .RS 4 upsmon allows a UPS to go missing for this many seconds before declaring it "dead"\&. The default is 15 seconds\&. .sp upsmon requires a UPS to provide status information every few seconds (see POLLFREQ and POLLFREQALERT) to keep things updated\&. If the status fetch fails, the UPS is marked stale\&. If it stays stale for more than DEADTIME seconds, the UPS is marked dead\&. .sp A dead UPS that was last known to be on battery is assumed to have changed to a low battery condition\&. This may force a shutdown if it is providing a critical amount of power to your system\&. This seems disruptive, but the alternative is barreling ahead into oblivion and crashing when you run out of power\&. .sp Note: DEADTIME should be a multiple of POLLFREQ and POLLFREQALERT\&. Otherwise, you\(cqll have "dead" UPSes simply because upsmon isn\(cqt polling them quickly enough\&. Rule of thumb: take the larger of the two POLLFREQ values, and multiply by 3\&. .RE .PP \fBFINALDELAY\fR \fIseconds\fR .RS 4 When running in primary mode, upsmon waits this long after sending the NOTIFY_SHUTDOWN to warn the users\&. After the timer elapses, it then runs your SHUTDOWNCMD\&. By default this is set to 5 seconds\&. .sp If you need to let your users do something in between those events, increase this number\&. Remember, at this point your UPS battery is almost depleted, so don\(cqt make this too big\&. .sp Alternatively, you can set this very low so you don\(cqt wait around when it\(cqs time to shut down\&. Some UPSes don\(cqt give much warning for low battery and will require a value of 0 here for a safe shutdown\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br If FINALDELAY on the secondary is greater than HOSTSYNC on the primary, the primary will give up waiting for that secondary upsmon to disconnect\&. .sp .5v .RE .RE .PP \fBHOSTSYNC\fR \fIseconds\fR .RS 4 upsmon will wait up to this many seconds in primary mode for the secondaries to disconnect during a shutdown situation\&. By default, this is 15 seconds\&. .sp When a UPS goes critical (on battery + low battery, or "FSD": forced shutdown), the secondary systems are supposed to disconnect and shut down right away\&. The HOSTSYNC timer keeps the primary upsmon from sitting there forever if one of the secondaries gets stuck\&. .sp This value is also used to keep secondary systems from getting stuck if the primary fails to respond in time\&. After a UPS becomes critical, the secondary will wait up to HOSTSYNC seconds for the primary to set the FSD flag\&. If that timer expires, the secondary upsmon will assume that the primary (or communications path to it) is broken and will shut down anyway\&. .sp This keeps the secondaries from shutting down during a short\-lived status change to "OB LB" and back that the secondaries see but the primary misses\&. .RE .PP \fBMINSUPPLIES\fR \fInum\fR .RS 4 Set the number of power supplies that must be receiving power to keep this system running\&. Normal computers have just one power supply, so the default value of 1 is acceptable\&. .sp Large/expensive server type systems usually have more, and can run with a few missing\&. The HP NetServer LH4 can run with 2 out of 4, for example, so you\(cqd set it to 2\&. The idea is to keep the box running as long as possible, right? .sp Obviously you have to put the redundant supplies on different UPS circuits for this to make sense! See big\-servers\&.txt in the docs subdirectory for more information and ideas on how to use this feature\&. .sp Also see the section on "power values" in \fBupsmon\fR(8)\&. .RE .PP \fBMONITOR\fR \fIsystem\fR \fIpowervalue\fR \fIusername\fR \fIpassword\fR \fItype\fR .RS 4 Each UPS that you need to be monitor should have a MONITOR line\&. Not all of these need supply power to the system that is running upsmon\&. You may monitor other systems if you want to be able to send notifications about status changes on them\&. .sp You must have at least one MONITOR directive in upsmon\&.conf\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIsystem\fR is a UPS identifier\&. It is in this form: .sp [@[:]] .sp The default hostname is "localhost"\&. Some examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} "su700@mybox" means a UPS called "su700" on a system called "mybox"\&. This is the normal form\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} "fenton@bigbox:5678" is a UPS called "fenton" on a system called "bigbox" which runs \fBupsd\fR(8) on port "5678"\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIpowervalue\fR is an integer representing the number of power supplies that the UPS feeds on this system\&. Most normal computers have one power supply, and the UPS feeds it, so this value will be 1\&. You need a very large or special system to have anything higher here\&. .sp You can set the \fIpowervalue\fR to 0 if you want to monitor a UPS that doesn\(cqt actually supply power to this system\&. This is useful when you want to have upsmon do notifications about status changes on a UPS without shutting down when it goes critical\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fIusername\fR and \fIpassword\fR on this line must match an entry in the upsd server system\(cqs \fBupsd.users\fR(5) file\&. .sp If your username is "observer" and your password is "abcd", the MONITOR line might look like this (likely on a remote secondary system): .sp .if n \{\ .RS 4 .\} .nf MONITOR myups@bigserver 1 observer abcd secondary .fi .if n \{\ .RE .\} .sp Meanwhile, the upsd\&.users on bigserver would look like this: .sp .if n \{\ .RS 4 .\} .nf [observer] password = abcd upsmon secondary [upswired] password = blah upsmon primary .fi .if n \{\ .RE .\} .sp And the copy of upsmon on that bigserver would run with the primary configuration: .sp .if n \{\ .RS 4 .\} .nf MONITOR myups@bigserver 1 upswired blah primary .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fItype\fR refers to the relationship with \fBupsd\fR(8)\&. It can be either "primary" or "secondary"\&. See \fBupsmon\fR(8) for more information on the meaning of these modes\&. The mode you pick here also goes in the upsd\&.users file, as seen in the example above\&. .RE .RE .PP \fBNOCOMMWARNTIME\fR \fIseconds\fR .RS 4 upsmon will trigger a NOTIFY_NOCOMM after this many seconds if it can\(cqt reach any of the UPS entries in this configuration file\&. It keeps warning you until the situation is fixed\&. By default this is 300 seconds\&. .RE .PP \fBPOLLFAIL_LOG_THROTTLE_MAX\fR \fIcount\fR .RS 4 upsmon normally reports polling failures for each device that are in place for each POLLFREQ loop (e\&.g\&. "Data stale" or "Driver not connected") to system log as configured\&. If your devices are expected to be AWOL for an extended timeframe, you can use this throttle to reduce the stress on syslog traffic and storage, by posting these messages only once in every several loop cycles, and when the error condition has changed or cleared\&. .sp A negative value means standard behavior (log on every loop, effectively same as when max=1), and a zero value means to never repeat the message (log only on start and end/change of the failure state)\&. .sp Note that this throttle only applies to one latest\-active error state per monitored device\&. .RE .PP \fBNOTIFYCMD\fR \fIcommand\fR .RS 4 upsmon calls this to send messages when things happen\&. .sp This command is called with the full text of the message as one argument\&. The environment string NOTIFYTYPE will contain the type string of whatever caused this event to happen\&. .sp If you need to use \fBupssched\fR(8), then you must make it your NOTIFYCMD by listing it here\&. .sp Note that this is only called for NOTIFY events that have EXEC set with NOTIFYFLAG\&. See NOTIFYFLAG below for more details\&. .sp Making this some sort of shell script might not be a bad idea\&. For more information and ideas, see docs/scheduling\&.txt .sp Remember, this command also needs to be one element in the configuration file, so if your command has spaces, then wrap it in quotes\&. .sp NOTIFYCMD "/path/to/script \-\-foo \-\-bar" .sp This script is run in the background\(emthat is, upsmon forks before it calls out to start it\&. This means that your NOTIFYCMD may have multiple instances running simultaneously if a lot of stuff happens all at once\&. Keep this in mind when designing complicated notifiers\&. .RE .PP \fBNOTIFYMSG\fR \fItype\fR \fImessage\fR .RS 4 upsmon comes with a set of stock messages for various events\&. You can change them if you like\&. .sp .if n \{\ .RS 4 .\} .nf NOTIFYMSG ONLINE "UPS %s is getting line power" .fi .if n \{\ .RE .\} .sp .if n \{\ .RS 4 .\} .nf NOTIFYMSG ONBATT "Someone pulled the plug on %s" .fi .if n \{\ .RE .\} .sp Note that %s is replaced with the identifier of the UPS in question\&. .sp The message must be one element in the configuration file, so if it contains spaces, you must wrap it in quotes\&. .sp .if n \{\ .RS 4 .\} .nf NOTIFYMSG NOCOMM "Someone stole UPS %s" .fi .if n \{\ .RE .\} .sp Possible values for \fItype\fR: .PP ONLINE .RS 4 UPS is back online .RE .PP ONBATT .RS 4 UPS is on battery .RE .PP LOWBATT .RS 4 UPS is on battery and has a low battery (is critical) .RE .PP FSD .RS 4 UPS is being shutdown by the primary (FSD = "Forced Shutdown") .RE .PP COMMOK .RS 4 Communications established with the UPS .RE .PP COMMBAD .RS 4 Communications lost to the UPS .RE .PP SHUTDOWN .RS 4 The system is being shutdown .RE .PP REPLBATT .RS 4 The UPS battery is bad and needs to be replaced .RE .PP NOCOMM .RS 4 A UPS is unavailable (can\(cqt be contacted for monitoring) .RE .PP NOPARENT .RS 4 upsmon parent process died \- shutdown impossible .RE .PP CAL .RS 4 UPS calibration in progress .RE .PP NOTCAL .RS 4 UPS calibration finished .RE .PP OFF .RS 4 UPS administratively OFF or asleep .RE .PP NOTOFF .RS 4 UPS no longer administratively OFF or asleep .RE .PP BYPASS .RS 4 UPS on bypass (powered, not protecting) .RE .PP NOTBYPASS .RS 4 UPS no longer on bypass .RE .PP ECO .RS 4 UPS in ECO or similar mode (as defined and named by vendor); for more details see \fBupsmon\fR(8)\&. .RE .PP NOTECO .RS 4 UPS no longer in ECO mode (see above) .RE .PP ALARM .RS 4 UPS has one or more active alarms (check ups\&.alarm); for this notification, the message can contain a second %s placeholder to substitute the current value of ups\&.alarm\&. .RE .PP NOTALARM .RS 4 UPS is no longer in an alarm state (no active alarms) .RE .PP OVER .RS 4 UPS is overloaded .RE .PP NOTOVER .RS 4 UPS is no longer overloaded .RE .PP TRIM .RS 4 UPS is trimming incoming voltage .RE .PP NOTTRIM .RS 4 UPS is no longer trimming incoming voltage .RE .PP BOOST .RS 4 UPS is boosting incoming voltage .RE .PP NOTBOOST .RS 4 UPS is no longer boosting incoming voltage .RE .PP OTHER .RS 4 UPS has at least one unclassified ups\&.status token; for this notification, the message can contain a second %s placeholder to substitute the current collection of such tokens\&. .RE .PP NOTOTHER .RS 4 UPS has no unclassified status tokens anymore .RE .PP SUSPEND_STARTING .RS 4 OS is entering sleep/suspend/hibernate mode .RE .PP SUSPEND_FINISHED .RS 4 OS just finished sleep/suspend/hibernate mode, de\-activating obsolete UPS readings to avoid an unfortunate shutdown .RE .RE .PP \fBNOTIFYFLAG\fR \fItype\fR \fIflag\fR[+\fIflag\fR]\&... .RS 4 By default, upsmon sends walls global messages to all logged in users) via /bin/wall and writes to the syslog when things happen\&. Except for Windows where upsmon only writes to the Event Log by default\&. You can change this\&. .sp Examples: .sp .if n \{\ .RS 4 .\} .nf NOTIFYFLAG ONLINE SYSLOG NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC .fi .if n \{\ .RE .\} .sp Possible values for the flags: .PP SYSLOG .RS 4 Write the message to the syslog .RE .PP WALL .RS 4 Write the message to all users with /bin/wall .RE .PP EXEC .RS 4 Execute NOTIFYCMD (see above) with the message .RE .PP IGNORE .RS 4 Don\(cqt do anything .sp If you use IGNORE, don\(cqt use any other flags on the same line\&. .RE .RE .PP \fBPOLLFREQ\fR \fIseconds\fR .RS 4 Normally upsmon polls the \fBupsd\fR(8) server every 5 seconds\&. If this is flooding your network with activity, you can make it higher\&. You can also make it lower to get faster updates in some cases\&. .sp There are some catches\&. First, if you set the POLLFREQ too high, you may miss short\-lived power events entirely\&. You also risk triggering the DEADTIME (see above) if you use a very large number\&. .sp Second, there is a point of diminishing returns if you set it too low\&. While upsd normally has all of the data available to it instantly, most drivers only refresh the UPS status once every 2 seconds\&. Polling any more than that usually doesn\(cqt get you the information any faster\&. .RE .PP \fBPOLLFREQALERT\fR \fIseconds\fR .RS 4 This is the interval that upsmon waits between polls if any of its UPSes are on battery\&. You can use this along with POLLFREQ above to slow down polls during normal behavior, but get quicker updates when something bad happens\&. .sp This should always be equal to or lower than the POLLFREQ value\&. By default it is also set 5 seconds\&. .sp The warnings from the POLLFREQ entry about too\-high and too\-low values also apply here\&. .RE .PP \fBPOWERDOWNFLAG\fR \fIfilename\fR .RS 4 upsmon creates this file when running in primary mode when the UPS needs to be powered off\&. You should check for this file in your late shutdown scripts and call upsdrvctl shutdown if it exists; note that upsmon \-K may be called for this effect, if NUT configuration files remain readable at that point (file systems mostly unmounted or changed to read\-only)\&. .sp Historically it was often /etc/killpower but nowadays you may want it in a temporary filesystem (e\&.g\&. under /run or /run/nut location)\&. .sp Note that double backslashes must be used for Windows paths, e\&.g\&. C:\e\eTemp\e\ekillpower (modern Windows may also accept forward slashes like C:/Temp/killpower but YMMV)\&. .sp This is done to forcibly reset the secondary systems, so they don\(cqt get stuck at the "halted" stage even if the power returns during the shutdown process\&. This usually does not work well on contact\-closure UPSes that use the genericups driver\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br The upsmon binary program does not have a built\-in default, so this setting MUST be specified in the configuration, in order for the late shutdown integration to work on the particular primary\-mode system! .sp .5v .RE See the config\-notes\&.txt file in the docs subdirectory for more information\&. Refer to the section: "Configuring automatic shutdowns for low battery events", or refer to the online version\&. .RE .PP \fBOFFDURATION\fR \fIseconds\fR .RS 4 NUT supports an "administrative OFF" for power devices which can be managed to turn off their application workload, while the UPS or ePDU remains accessible for monitoring and management\&. This toggle allows to delay propagation of such state into a known loss of a feed (possibly triggering FSD on upsmon clients which MONITOR the device and are in fact still alive \(em e\&.g\&. with multiple power sources or because they as the load are not really turned off), because when some devices begin battery calibration, they report "OFF" for a few seconds and only then they might report "CAL" after switching all the power relays \(em thus causing false\-positives for upsmon FSD trigger\&. .sp A negative value means to disable decreasing the counter of working power supplies in such cases, and a zero makes the effect of detected "OFF" state immediate\&. Built\-in default value is 30 (seconds), to put an "OFF" state into effect (decrease known\-fed supplies count) if it persists for this many seconds\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br so far we support the device reporting an "OFF" state which usually means completely un\-powering the load; a bug\-tracker issue was logged to design similar support for just some manageable outlets or outlet groups\&. .sp .5v .RE .RE .PP \fBOVERDURATION\fR \fIseconds\fR .RS 4 This setting handles how a UPS that is overloaded should be treated in situations when it is not fully communicating\&. Because such a UPS may be in a potentially severe state, some users may want their systems to be shutdown either immediately or after a set timeout has elapsed\&. The OVERDURATION setting defines this timeout (in seconds), after which an overloaded UPS that is not communicating will be considered critical\&. .sp A negative value means an overloaded UPS will never be considered critical (at least not because of the overload itself)\&. A value of zero means the UPS will instantly be considered critical when overloaded and not communicating\&. Built\-in default value is \-1 (seconds)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This setting only affects the behavior when a UPS is both overloaded and not communicating\&. When the UPS is communicating normally, an overload condition may raise notifications but won\(cqt trigger a system shutdown on its own\&. .sp .5v .RE .RE .PP \fBOBLBDURATION\fR \fIseconds\fR .RS 4 NUT normally raises alarms for immediate shutdown (FSD) for consumers of an UPS known to be on battery ("OB") and achieving the low battery status ("LB"), if that is their last remaining power source to satisfy their MINSUPPLIES setting\&. In some special cases, users may want to delay raising the alarm (using the OBLBDURATION option) at their discretion and risk of an ungraceful shutdown\&. .sp A positive value puts "OB LB" state into effect only if it persists for this many seconds\&. A non\-positive value makes the FSD effect of detected "OB LB" state immediate\&. Built\-in default value is 0 (seconds)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br If both OBLBDURATION and HOSTSYNC options are set on the same (secondary) upsmon client system, and HOSTSYNC is shorter, it would be effectively ignored: upsmon would wait for up to OBLBDURATION seconds for the "OB LB" state to clear, and then the secondary client logic would fall through to immediate shutdown\&. If the primary system issues an FSD on this UPS, that would take an even higher\-priority effect as soon as seen\&. .sp .5v .RE .RE .PP \fBRBWARNTIME\fR \fIseconds\fR .RS 4 When a UPS says that it needs to have its battery replaced, upsmon will generate a NOTIFY_REPLBATT event\&. By default, this happens every 43200 seconds (12 hours)\&. .sp If you need another value, set it here\&. .RE .PP \fBALARMCRITICAL\fR \fI0 | 1\fR .RS 4 NUT normally considers UPS with active alarms as volatile, meaning they are observed more closely and may be considered critical/dead earlier than in other regular UPS statuses\&. This is especially true for no\-communication situations, where UPS in an ALARM status will be considered lost and system shutdowns may be triggered as a product\&. .sp As there is no common standard for what constitutes an alarm, such alarm states may in fact be mundane in nature and the behavior above unwanted due to possibly resulting in unwarranted system shutdowns\&. .sp When this setting is disabled, upsmon will consider a UPS in an alarm state as not volatile and make it treat the ALARM status as any other\&. .RE .PP \fBRUN_AS_USER\fR \fIusername\fR .RS 4 upsmon normally runs the bulk of the monitoring duties under another user ID after dropping root privileges\&. On most systems this means it runs as "nobody", since that\(cqs the default from compile\-time\&. .sp The catch is that "nobody" can\(cqt read your upsmon\&.conf, since by default it is installed so that only root can open it\&. This means you won\(cqt be able to reload the configuration file, since it will be unavailable\&. .sp The solution is to create a new user just for upsmon, then make it run as that user\&. I suggest "nutmon", but you can use anything that isn\(cqt already taken on your system\&. Just create a regular user with no special privileges and an impossible password\&. .sp Then, tell upsmon to run as that user, and make upsmon\&.conf readable by it\&. Your reloads will work, and your config file will stay secure\&. .sp This file should not be writable by the upsmon user, as it would be possible to exploit a hole, change the SHUTDOWNCMD to something malicious, then wait for upsmon to be restarted\&. .RE .PP \fBSHUTDOWNCMD\fR \fIcommand\fR .RS 4 upsmon runs this command when the system needs to be brought down\&. If it is a secondary, it will do that immediately whenever the current overall power value drops below the MINSUPPLIES value above\&. .sp When upsmon is a primary, it will allow any secondaries to log out before starting the local shutdown procedure\&. .sp Note that the command needs to be one element in the config file\&. If your shutdown command includes spaces, then put it in quotes to keep it together, i\&.e\&.: .sp .if n \{\ .RS 4 .\} .nf SHUTDOWNCMD "/sbin/shutdown \-h +0" .fi .if n \{\ .RE .\} .RE .PP \fBSHUTDOWNEXIT\fR \fIboolean|number\fR .RS 4 After initiating shutdown, should this upsmon daemon itself exit? By doing so NUT secondary systems can tell the NUT primary that it can proceed with its own shutdown and eventually tell the UPS to cut power for the load\&. ("Yes" by default) .sp Some "secondary" systems with workloads that take considerable time to stop (e\&.g\&. virtual machines or large databases) can benefit from reporting (by virtue of logging off the data server) that they are ready for the "primary" system to begin its own shutdown and eventually to tell the UPS to cut the power \(em not as soon as they have triggered their own shutdown, but at a later point (e\&.g\&. when the upsmon service is stopped AFTER the heavier workloads)\&. .sp Note that the actual ability to complete such shutdown depends on the remaining battery run\-time at the moment when UPS power state becomes considered critical and the shutdowns begin\&. You may also have to tune HOSTSYNC on the NUT primary to be long enough for those secondaries to stop their services\&. In practice, it may be worthwhile to investigate ways to trigger shutdowns earlier on these systems, e\&.g\&. by setting up upssched integration, or dummy\-ups driver with overrides for stricter battery\&.charge or battery\&.runtime triggers than used by the rest of your servers\&. .sp This option supports Boolean\-style strings (yes/on/true or no/off/false) or numbers to define a delay (in seconds) between calling SHUTDOWNCMD and exiting the daemon\&. Zero means immediate exit (default), negative values mean never exiting on its own accord\&. .RE .PP \fBCERTPATH\fR \fIcertificate file or database\fR .RS 4 When compiled with SSL support, you can enter the certificate path here\&. .PP With NSS: .RS 4 Certificates are stored in a dedicated database (data split in 3 files)\&. Specify the path of the database directory\&. .RE .PP With OpenSSL: .RS 4 Directory containing CA certificates in PEM format, used to verify the server certificate presented by the upsd server\&. The files each contain one CA certificate\&. The files are looked up by the CA subject name hash value, which must hence be available\&. .RE .RE .PP \fBCERTIDENT\fR \fIcertificate name\fR \fIdatabase password\fR .RS 4 When compiled with SSL support with NSS, you can specify the certificate name to retrieve from database to authenticate itself and the password required to access certificate related private key\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br Be sure to enclose "certificate name" in double\-quotes if you are using a value with spaces in it\&. .sp .5v .RE .RE .PP \fBCERTHOST\fR \fIhostname\fR \fIcertificate name\fR \fIcertverify\fR \fIforcessl\fR .RS 4 When compiled with SSL support with NSS, you can specify security directive for each server you can contact\&. .sp Each entry maps server name with the expected certificate name and flags indicating if the server certificate is verified and if the connection must be secure\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br Be sure to enclose "certificate name" in double\-quotes if you are using a value with spaces in it\&. .sp .5v .RE .RE .PP \fBCERTVERIFY\fR \fI0 | 1\fR .RS 4 When compiled with SSL support, make upsmon verify all connections with certificates\&. .sp Without this, there is no guarantee that the upsd is the right host\&. Enabling this greatly reduces the risk of man\-in\-the\-middle attacks\&. This effectively forces the use of SSL, so don\(cqt use this unless all of your upsd hosts are ready for SSL and have their certificates in order\&. .sp When compiled with NSS support of SSL, can be overridden for host specified with a CERTHOST directive\&. .RE .PP \fBFORCESSL\fR \fI0 | 1\fR .RS 4 When compiled with SSL, specify that a secured connection must be used to communicate with upsd\&. .sp If you don\(cqt use \fICERTVERIFY 1\fR, then this will at least make sure that nobody can sniff your sessions without a large effort\&. Setting this will make upsmon drop connections if the remote upsd doesn\(cqt support SSL, so don\(cqt use it unless all of them have it running\&. .sp When compiled with NSS support of SSL, can be overridden for host specified with a CERTHOST directive\&. .RE .PP \fBDEBUG_MIN\fR \fIINTEGER\fR .RS 4 Optionally specify a minimum debug level for upsmon daemon, e\&.g\&. for troubleshooting a deployment, without impacting foreground or background running mode directly\&. Command\-line option \-D can only increase this verbosity level\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br if the running daemon receives a reload command, presence of the DEBUG_MIN NUMBER value in the configuration file can be used to tune debugging verbosity in the running service daemon (it is recommended to comment it away or set the minimum to explicit zero when done, to avoid huge journals and I/O system abuse)\&. Keep in mind that for this run\-time tuning, the DEBUG_MIN value \fBpresent\fR in \fBreloaded\fR configuration files is applied instantly and overrides any previously set value, from file or CLI options, regardless of older logging level being higher or lower than the newly found number; a missing (or commented away) value however does not change the previously active logging verbosity\&. .sp .5v .RE .RE .SH "SEE ALSO" .sp \fBupsmon\fR(8), \fBupsd\fR(8), \fBnutupsdrv\fR(8)\&. .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/metasys.80000644000200500020050000000715515001555072012530 00000000000000'\" t .\" Title: metasys .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "METASYS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" metasys \- Driver for Meta System UPS equipment .SH "SYNOPSIS" .sp \fBmetasys\fR \-h .sp \fBmetasys\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the metasys driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The \fBmetasys\fR driver was written with the "Meta System UPS Protocol Rev\&.1\&.12" kindly supplied from Meta System\&. .sp The driver should support all the common features of the UPS models: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} HF Line (/2) 1\-8 boards .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} HF Millennium (810, 820) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} HF TOP Line (910, 920, 930, 940, 950, 970, 980) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} ECO Network (750, 1000, 1050, 1500, 1800, 2000, 2100, 2500, 3000) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} ECO (305, 308, 311, 511, 516, 519, 522, SX, SXI) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} ally HF (800, 1000, 1250, 1600, 2000, 2500) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Megaline (1250, 2500, 3750, 5000, 6250, 7500, 8750, 10000) .RE .SH "CABLING" .sp The needed cable is a standard pin\-to\-pin serial cable with at least pins 2, 3, and 5 (on DB9 connector) connected\&. .SH "EXTRA ARGUMENTS" .sp This driver supports no extra arguments from \fBups.conf\fR(5)\&. .SH "BUGS" .sp This driver has been tested on Meta System HF Millennium 820 and ally HF 1000 only\&. .sp Any information about the use of the driver with the other listed UPS are really welcome\&. .SH "AUTHOR" .sp Fabio Di Niro .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Meta System UPS protocol: https://networkupstools\&.org/ups\-protocols\&.html#_legrand .RE nut-2.8.3/docs/man/nut-scanner.80000644000200500020050000004215415001555050013272 00000000000000'\" t .\" Title: nut-scanner .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUT\-SCANNER" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nut-scanner \- Tool to scan communication buses for NUT devices .SH "SYNOPSIS" .sp \fBnut\-scanner\fR \-h .sp \fBnut\-scanner\fR [\fIOPTIONS\fR] .SH "DESCRIPTION" .sp \fBnut\-scanner\fR scans available communication buses and displays any NUT\-compatible devices it has found\&. .sp \fBnut\-scanner\fR can also display the detected devices in various formats, including ups\&.conf, and ensures that the generated devices name are unique across buses\&. .SH "INSTALLATION" .sp \fBnut\-scanner\fR is only built if libltdl (part of libtool development suite) is available\&. .sp Available scanning options (USB, SNMP, IPMI, \&...) will vary according to the available compile\-time and run\-time dependencies\&. For example, if Net\-SNMP is installed, thus providing libsnmp libraries (*\&.so or *\&.dll) and header files during compilation, and at least the library files on the monitoring system, then SNMP discovery will be available\&. .SH "OPTIONS" .PP \fB\-h\fR .RS 4 Display the help text\&. .RE .SH "DISPLAY OPTIONS" .PP \fB\-Q\fR | \fB\-\-disp_nut_conf_with_sanity_check\fR .RS 4 Display result in the ups\&.conf format with sanity\-check warnings (if any) as comments (default)\&. .RE .PP \fB\-N\fR | \fB\-\-disp_nut_conf\fR .RS 4 Display result in the ups\&.conf format\&. .RE .PP \fB\-P\fR | \fB\-\-disp_parsable\fR .RS 4 Display result in a parsable format\&. .RE .SH "BUS OPTIONS" .PP \fB\-C\fR | \fB\-\-complete_scan\fR .RS 4 Scan all available communication buses (default behavior) .RE .PP \fB\-U\fR | \fB\-\-usb_scan\fR .RS 4 List all NUT\-compatible USB devices currently plugged in\&. .sp This option can be specified several times, for more hardware link\-specific details; these can be counter\-productive in case of USB enumeration changes over time: .TS allbox tab(:); ltB ltB. T{ Option count T}:T{ Practical meaning T} .T& lt lt lt lt lt lt lt lt. T{ \-U T}:T{ .if n \{\ .RS 4 .\} .nf do not report any `bus`/`device`/`busport` details .fi .if n \{\ .RE .\} T} T{ \-UU T}:T{ .if n \{\ .RS 4 .\} .nf report `bus` and `busport`, if available .fi .if n \{\ .RE .\} T} T{ \-UUU T}:T{ .if n \{\ .RS 4 .\} .nf report `bus`/`device`/`busport` details .fi .if n \{\ .RE .\} T} T{ \-UUUU T}:T{ .if n \{\ .RS 4 .\} .nf report `bus`/`device`/`busport` details, and `bcdDevice` (limited use and benefit) .fi .if n \{\ .RE .\} T} .TE .sp 1 .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br For reliability, it is preferable to match just by vendor and product identification, and a serial number if available and unique\&. .sp .5v .RE .RE .PP \fB\-S\fR | \fB\-\-snmp_scan\fR .RS 4 Scan SNMP devices\&. Requires at least a \fIstart IP\fR, and optionally, an \fIend IP\fR\&. See specific SNMP OPTIONS for community and security settings\&. .RE .PP \fB\-M\fR | \fB\-\-xml_scan\fR .RS 4 Scan XML/HTTP devices\&. Can broadcast a network message on the current network interface(s) to retrieve XML/HTTP capable devices\&. No IP required in this mode\&. If IP address ranges are specified, they would be scanned instead of a broadcast\&. .RE .PP \fB\-O\fR | \fB\-\-oldnut_scan\fR .RS 4 Scan NUT devices (i\&.e\&. upsd daemon) on IP ranging from \fIstart IP\fR to \fIend IP\fR\&. .RE .PP \fB\-n\fR | \fB\-\-nut_simulation_scan\fR .RS 4 Scan NUT simulated devices (\&.dev files in the built\-in "sysconfig" location)\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br The NUT_CONFPATH environment variable override is not currently supported\&. .sp .5v .RE .RE .PP \fB\-A\fR | \fB\-\-avahi_scan\fR .RS 4 Scan NUT servers using Avahi request on the current network interface(s)\&. No IP address options are required or used\&. .RE .PP \fB\-I\fR | \fB\-\-ipmi_scan\fR .RS 4 Scan NUT compatible power supplies available via IPMI on the current host, or over the network if IP address ranges are specified\&. .RE .PP \fB\-E\fR | \fB\-\-eaton_serial\fR \fIserial ports\fR .RS 4 Scan Eaton devices (XCP and SHUT) available via serial bus on the current host\&. This option must be requested explicitly, even for a complete scan\&. \fIserial ports\fR can be expressed in various forms: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIauto\fR to scan all serial ports\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a single character indicating a port number (\fI0\fR (zero) for /dev/ttyS0 and /dev/ttyUSB0 on Linux, \fI1\fR for COM1 on Windows, \fIa\fR for /dev/ttya on Solaris\&...) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a range of N characters, hyphen separated, describing the range of ports using X\-Y syntax, where \fIX\fR and \fIY\fR are characters referring to the port number\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a single port name\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a list of ports name, comma separated, like /dev/ttyS1,/dev/ttyS4\&. .RE .RE .SH "NETWORK OPTIONS" .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The networked buses (such as SNMP, NetXML, IPMI and "Old NUT") allow to specify several IP (IPv4 or IPv6) address ranges, down to individual single IP addresses\&. .sp Normally a new range is specified by a set of one \-s and one \-e options following each other (in any order on the command line)\&. .sp Lone or consecutive \-s or \-e options present on the command line would translate to single\-IP queries\&. .sp Also, a \-m option squashed between two \-s and \-e options would be a new range, turning those two into single\-IP queries\&. This feature does not by itself recombine "neighboring" addresses into one range, nor even check for duplicate or overlapping specifications\&. .sp A single\-address range may be a host name which would be resolved into one IP address by the system resolver\&. A CIDR using a host name and netmask length would be resolved into an IP address and subjected to the mask application, to query hosts "near" the named one\&. .sp .5v .RE .sp Also note that some buses require IP address(es) to scan, and others have a different behavior when exactly no addresses are specified (it is not currently possible to mix the two behaviors in one invocation of the nut\-scanner tool)\&. .sp Finally note that currently even if multi\-threaded support is available, each range specification is a separate fan\-out of queries constrained by the timeout\&. Requests to scan many single IP addresses will take a while to complete, much longer than if they were a single range\&. This will be hopefully fixed in later releases\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Colon\-separated IPv6 addresses must be passed in square brackets\&. .sp .5v .RE .PP \fB\-t\fR | \fB\-\-timeout\fR \fItimeout\fR .RS 4 Set the network timeout in seconds\&. Default timeout is 5 seconds\&. .RE .PP \fB\-s\fR | \fB\-\-start_ip\fR \fIstart IP\fR .RS 4 Set the first IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut) or optional (XML/HTTP)\&. .RE .PP \fB\-e\fR | \fB\-\-end_ip\fR \fIend IP\fR .RS 4 Set the last IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut) or optional (XML/HTTP)\&. If this parameter is omitted, only the \fIstart IP\fR is scanned\&. If \fIend IP\fR is less than \fIstart IP\fR, both parameters are internally permuted\&. .RE .PP \fB\-m\fR | \fB\-\-mask_cidr\fR \fIIP address/mask\fR .RS 4 Set a range of IP addresses by using CIDR notation\&. .sp A special form \-m auto allows nut\-scanner to detect local IP address(es) and scan corresponding subnet(s) on supported platforms, and \-m auto4 or \-m auto6 limits the selected addresses to IPv4 and IPv6 respectively\&. Only the first "auto*" request would be honoured, others ignored with a warning\&. .sp An /ADDRLEN suffix can be added to the option, to filter out discovered subnets with too many bits available for the host address part (avoiding millions of scans in the extreme cases)\&. For example, if your IPv4 LAN\(cqs network range is 10\&.2\&.3\&.0/24, its address part is (32\-24)=8\&. Note that while this is applied to IPv6 networks also, their typical /64 subnets are not likely to have a NUT/SNMP/NetXML/\&... server \fBthat\fR close nearby (in addressing terms), for a tight filter to find them\&. Default is 8\&. .RE .SH "NUT DEVICE OPTION" .PP \fB\-p\fR | \fB\-\-port\fR \fIport number\fR .RS 4 Set the port number of scanned NUT devices (default 3493)\&. .RE .SH "SNMP V1 OPTION" .PP \fB\-c\fR | \fB\-\-community\fR \fIcommunity\fR .RS 4 Set SNMP v1 community name (default = public)\&. .RE .SH "SNMP V3 OPTIONS" .PP \fB\-l\fR | \fB\-\-secLevel\fR \fIsecurity level\fR .RS 4 Set the \fIsecurity level\fR used for SNMPv3 messages\&. Allowed values are: noAuthNoPriv, authNoPriv and authPriv\&. This parameter is mandatory if you use non\-trivial authentication\&. .RE .PP \fB\-u\fR | \fB\-\-secName\fR \fIsecurity name\fR .RS 4 Set the \fIsecurity name\fR used for authenticated SNMPv3 messages\&. This parameter is mandatory if you set \fIsecurity level\fR\&. .RE .PP \fB\-w\fR | \fB\-\-authProtocol\fR \fIauthentication protocol\fR .RS 4 Set the \fIauthentication protocol\fR used for authenticated SNMPv3 messages\&. Allowed values are MD5, SHA, SHA256, SHA384 or SHA512 (depending on Net\-SNMP library capabilities; check help of the nut\-scanner binary program for the run\-time supported list)\&. Default value is MD5\&. .RE .PP \fB\-W\fR | \fB\-\-authPassword\fR \fIauthentication pass phrase\fR .RS 4 Set the \fIauthentication pass phrase\fR used for authenticated SNMPv3 messages\&. This parameter is mandatory if you set \fIsecurity level\fR to authNoPriv or authPriv\&. .RE .PP \fB\-x\fR | \fB\-\-privProtocol\fR \fIprivacy protocol\fR .RS 4 Set the \fIprivacy protocol\fR used for encrypted SNMPv3 messages\&. Allowed values are DES, AES, AES192 or AES256 (depending on Net\-SNMP library capabilities; check help of the nut\-scanner binary program for the run\-time supported list)\&. Default value is DES\&. .RE .PP \fB\-X\fR | \fB\-\-privPassword\fR \fIprivacy pass phrase\fR .RS 4 Set the \fIprivacy pass phrase\fR used for encrypted SNMPv3 messages\&. This parameter is mandatory if you set \fIsecurity level\fR to authPriv\&. .RE .SH "IPMI OPTIONS" .PP \fB\-b\fR | \fB\-\-username\fR \fIusername\fR .RS 4 Set the username used for authenticating IPMI over LAN connections (mandatory for IPMI over LAN\&. No default)\&. .RE .PP \fB\-B\fR | \fB\-\-password\fR \fIpassword\fR .RS 4 Specify the password to use when authenticating with the remote host (mandatory for IPMI over LAN\&. No default)\&. .RE .PP \fB\-d\fR | \fB\-\-authType\fR \fIauthentication type\fR .RS 4 Specify the IPMI 1\&.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5)\&. This forces connection through the \fIlan\fR IPMI interface , thus in IPMI 1\&.5 mode\&. .RE .PP \fB\-L\fR | \fB\-\-cipher_suite_id\fR \fIcipher suite identifier\fR .RS 4 Specify the IPMI 2\&.0 cipher suite ID to use\&. The Cipher Suite ID identifies a set of authentication, integrity, and confidentiality algorithms to use for IPMI 2\&.0 communication\&. .sp The authentication algorithm identifies the algorithm to use for session setup, the integrity algorithm identifies the algorithm to use for session packet signatures, and the confidentiality algorithm identifies the algorithm to use for payload encryption (default=3)\&. .sp The following cipher suite ids are currently supported (Authentication; Integrity; Confidentiality): .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB0\fR: None; None; None .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB1\fR: HMAC\-SHA1; None; None .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB2\fR: HMAC\-SHA1; HMAC\-SHA1\-96; None .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB3\fR: HMAC\-SHA1; HMAC\-SHA1\-96; AES\-CBC\-128 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB6\fR: HMAC\-MD5; None; None .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB7\fR: HMAC\-MD5; HMAC\-MD5\-128; None .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB8\fR: HMAC\-MD5; HMAC\-MD5\-128; AES\-CBC\-128 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB11\fR: HMAC\-MD5; MD5\-128; None .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB12\fR: HMAC\-MD5; MD5\-128; AES\-CBC\-128 .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB15\fR: HMAC\-SHA256; None; None .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB16\fR: HMAC\-SHA256; HMAC_SHA256_128; None .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fB17\fR: HMAC\-SHA256; HMAC_SHA256_128; AES\-CBC\-128 .RE .RE .SH "MISCELLANEOUS OPTIONS" .PP \fB\-V\fR | \fB\-\-version\fR .RS 4 Display NUT version\&. .RE .PP \fB\-a\fR | \fB\-\-available\fR .RS 4 Display available buses that can be scanned, depending on how the nut\-scanner binary program has been compiled\&. (e\&.g\&. OLDNUT, USB, SNMP, XML, AVAHI, IPMI)\&. .RE .PP \fB\-q\fR | \fB\-\-quiet\fR .RS 4 Display only scan result\&. No information on currently scanned bus is displayed\&. .RE .PP \fB\-D\fR | \fB\-\-nut_debug_level\fR .RS 4 Raise the debugging level\&. Use this multiple times to see more details\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The level of debugging needed depends both on nut\-scanner and the problem you\(cqre trying to diagnose\&. Therefore, first explain the problem you have with nut\-scanner to a developer/maintainer, before sending them debugging output\&. More often than not, if you just pick a level, the output may be either too limited or too verbose to be of any use\&. .sp .5v .RE .SH "EXAMPLES" .sp To scan USB devices only: .sp .if n \{\ .RS 4 .\} .nf :; nut\-scanner \-U [nutdev\-usb1] driver = "snmp\-ups" port = "192\&.168\&.0\&.42" .fi .if n \{\ .RE .\} .sp To scan SNMP v1 device with \fIpublic\fR (default) community on address range \fI192\&.168\&.0\&.0 to 192\&.168\&.0\&.255\fR: .sp .if n \{\ .RS 4 .\} .nf :; nut\-scanner \-S \-s 192\&.168\&.0\&.0 \-e 192\&.168\&.0\&.255 [nutdev\-snmp1] driver = "snmp\-ups" port = "192\&.168\&.0\&.42" .fi .if n \{\ .RE .\} .sp The same using CIDR notation: .sp .if n \{\ .RS 4 .\} .nf :; nut\-scanner \-S \-m 192\&.168\&.0\&.0/24 [nutdev\-snmp1] driver = "snmp\-ups" port = "192\&.168\&.0\&.42" .fi .if n \{\ .RE .\} .sp To scan NUT servers with a timeout of \fI10\fR seconds on IP range \fI192\&.168\&.0\&.0 to 192\&.168\&.0\&.127\fR using CIDR notation: .sp .if n \{\ .RS 4 .\} .nf :; nut\-scanner \-O \-t 10 \-m 192\&.168\&.0\&.0/25 [nutdev\-nut1] driver = "dummy\-ups" port = "dummy\-test@192\&.168\&.1\&.28" .fi .if n \{\ .RE .\} .sp To scan for power supplies, through IPMI (1\&.5 mode) over the network, on address range \fI192\&.168\&.0\&.0 to 192\&.168\&.0\&.255\fR using CIDR notation: .sp .if n \{\ .RS 4 .\} .nf :; nut\-scanner \-I \-m 192\&.168\&.0\&.0/24 \-b username \-B password .fi .if n \{\ .RE .\} .sp To scan for Eaton serial devices on ports \fI0\fR and \fI1\fR (/dev/ttyS0, /dev/ttyUSB0, /dev/ttyS1 and /dev/ttyUSB1 on Linux): .sp .if n \{\ .RS 4 .\} .nf :; nut\-scanner \-\-eaton_serial 0\-1 .fi .if n \{\ .RE .\} .sp To scan for Eaton serial devices on ports \fI1\fR and \fI2\fR (COM1 and COM2 on Windows): .sp .if n \{\ .RS 4 .\} .nf :; nut\-scanner \-\-eaton_serial 1\-2 .fi .if n \{\ .RE .\} .SH "SEE ALSO" .sp \fBups.conf\fR(5) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/belkin.80000644000200500020050000000575115001555065012311 00000000000000'\" t .\" Title: belkin .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BELKIN" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" belkin \- Driver for Belkin serial UPS equipment .SH "SYNOPSIS" .sp \fBbelkin\fR \-h .sp \fBbelkin\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the belkin driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The \fBbelkin\fR driver is known to support the Regulator Pro 525 (F6C525\-SER)\&. Other similar models such as the 425 and 625 should also work\&. .sp The Trust UPS and older Belkin units are not supported\&. .sp This driver only supports serial connections\&. If your UPS has a USB port, please consult the Hardware Compatibility List (HCL) to see which of the USB drivers you should use\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "BUGS" .sp There are dragons lurking within the protocol to this UPS\&. I have one that essentially behaves like a glorified power strip due to some invasive probing on my part\&. Don\(cqt mess with it directly\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp the driver doesn\(cqt go anywhere near these character sequences, so it won\(cqt zap your UPS\&. I only mention this here as yet another reminder of the perils of closed hardware\&. .sp .5v .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Other Belkin drivers:" .sp \fBbelkinunv\fR(8), \fBblazer_ser\fR(8), \fBblazer_usb\fR(8), \fBusbhid-ups\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/generic_modbus.80000644000200500020050000002051515001555100014013 00000000000000'\" t .\" Title: generic_modbus .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "GENERIC_MODBUS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" generic_modbus \- Driver for contact (direct) signal UPS devices connected via modbus remote I/O gateways .SH "SYNOPSIS" .sp \fBgeneric_modbus\fR \-h .sp \fBgeneric_modbus\fR \-a \fIDEVICE_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the \fBgeneric_modbus\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This is a generic modbus driver expected to work with contact (direct) signal UPS devices, connected via modbus RIO (remote I/O) either serial or TCP/IP\&. .sp The driver has been tested against PULS UPS (model UB40\&.241) via MOXA ioLogikR1212 (RS485) and ioLogikE1212 (TCP/IP)\&. .PP More information about this UPS can be found here: .RS 4 https://products\&.pulspower\&.com/ca/ubc10\-241\-n1\&.html .RE .PP More information about Moxa ioLogik R1212, E1212 can be found here: .RS 4 https://www\&.moxa\&.com/en/products/industrial\-edge\-connectivity/controllers\-and\-ios .RE .sp The PULS UPS UB40\&.241 supports the following signals: .sp .if n \{\ .RS 4 .\} .nf Ready contact (DO) <\-\-> HB Buffering contact (DO) <\-\-> OL | OB Battery\-low (DO) <\-\-> LB Replace Battery (DO) <\-\-> RB Inhibit (DI) <\-\-> FSD .fi .if n \{\ .RE .\} .sp Digital port direction (DI/DO) assumes the device perspective .sp The driver\(cqs concept is to map the UPS states (as defined in NUT) onto UPS contacts\*(Aq states\&. The driver has an extended configuration interface implemented using variables defined in ups\&.conf\&. .SH "HARDWARE INTERCONNECTION" .sp The commission of modbus remote I/O server as well as UPS device is carried out following the corresponding instruction manuals\&. The following figure depicts the anticipated communication path and hardware interconnection: .sp .if n \{\ .RS 4 .\} .nf +\-\-\-\-\-\-+ +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+ +\-\-\-\-\-\-\-\-\-\-\-\-+ +\-\-\-\-\-\-\-\-\-\-\-\-+ | UPSD | <\-\-\-> | GENERIC_MODBUS | <\-\-\-> | MODBUS RIO | <\-\-\-> | UPS DEVICE | +\-\-\-\-\-\-+ (1) +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+ (2) +\-\-\-\-\-\-\-\-\-\-\-\-+ (3) +\-\-\-\-\-\-\-\-\-\-\-\-+ | | +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+ HOST CONTROLLER (1) Unix IPC (2) RS232 | TCP/IP (3) contacts .fi .if n \{\ .RE .\} .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file: .SS "Generic:" .PP \fBdevice_mfr\fR=\fIvalue\fR .RS 4 A string specifying the manufacturer of the UPS device (default UNKNOWN)\&. .RE .PP \fBdevice_model\fR=\fIvalue\fR .RS 4 A string specifying the model of the UPS device (default UNKNOWN)\&. .RE .SS "Serial:" .PP \fBser_baud_rate\fR=\fIvalue\fR .RS 4 A integer specifying the serial port baud rate (default 9600)\&. .RE .PP \fBser_data_bit\fR=\fIvalue\fR .RS 4 A integer specifying the serial port data bit (default 8)\&. .RE .PP \fBser_parity\fR=\fIvalue\fR .RS 4 A character specifying the serial port parity (default N)\&. .RE .PP \fBser_stop_bit\fR=\fIvalue\fR .RS 4 An integer specifying the serial port stop bit (default 1)\&. .RE .SS "Modbus:" .PP \fBrio_slave_id\fR=\fIvalue\fR .RS 4 An integer specifying the RIO modbus slave ID (default 1)\&. .RE .SS "States (X = OL, OB, LB, HB, RB, CHRG, DISCHRG, FSD)" .PP \fB_addr\fR=\fIvalue\fR .RS 4 A number specifying the modbus address for the X state\&. .RE .PP \fB_regtype\fR=\fIvalue\fR .RS 4 A number specifying the modbus register type for the X state .RE .PP Default values: .RS 4 .sp .if n \{\ .RS 4 .\} .nf 1 for X = OL, OB, LB ,HB, RB, CHRG, DISCHRG 0 for X = FSD .fi .if n \{\ .RE .\} .RE .PP Valid values: .RS 4 .sp .if n \{\ .RS 4 .\} .nf 0:COIL, 1:INPUT_B, 2:INPUT_R, 3:HOLDING .fi .if n \{\ .RE .\} .RE .PP \fB_noro\fR=\fIvalue\fR .RS 4 A number specifying the contact configuration for the X state (default 1)\&. .RE .PP Valid values: .RS 4 .sp .if n \{\ .RS 4 .\} .nf 0:NC, 1:NO .fi .if n \{\ .RE .\} .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br NO stands for normally open and NC for normally closed contact .sp .5v .RE .RE .SS "Shutdown" .PP \fBFSD_pulse_duration\fR=\fIvalue\fR .RS 4 A number specifying the duration in ms for the inhibit pulse\&. If it\(cqs not defined, signal has only one transition depending on FSD_noro configuration\&. .sp Examples for FSD signal configuration: .RE .sp .if n \{\ .RS 4 .\} .nf FSD_noro = 1 FSD_pulse_duration = 150 +\-\-\-\-\-+ | | inhibit pulse >\-\-\-\-\-+ +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-> <\-\-\-> 150ms FSD_noro = 0 inhibit pulse >\-\-\-\-\-+ | +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-> .fi .if n \{\ .RE .\} .SH "CONFIGURATION" .sp Here is an example of generic_modbus driver configuration in \fBups\&.conf\fR file: .sp .if n \{\ .RS 4 .\} .nf [generic_modbus] driver = generic_modbus port = /dev/ttyUSB0 desc = "generic ups driver" # device info device_mfr = "PULS" device_model = "UB40\&.241" # serial settings ser_baud_rate = 9600 ser_parity = N ser_data_bit = 8 ser_stop_bit = 1 # modbus slave id rio_slave_id = 5 # UPS signal state attributes OB_addr = 0x0 OB_regtype = 1 OB_noro = 0 LB_addr = 0x1 LB_regtype = 1 HB_addr = 0x2 HB_regtype = 1 RB_addr = 0x3 RB_regtype = 1 FSD_addr = 0x0 FSD_regtype = 0 FSD_pulse_duration = 150 .fi .if n \{\ .RE .\} .SH "INSTANT COMMANDS" .sp This driver support the following instant commands: .PP load\&.off .RS 4 executes "instant poweroff" .RE .SH "INSTALLATION" .sp This driver may be not built by default\&. You can build it by installing libmodbus and running configure \-\-with\-modbus=yes\&. .sp You also need to give proper permissions on the local serial device file (/dev/ttyUSB0 for example) to allow the run\-time NUT driver user account to access it\&. .SH "OTHER NOTES" .sp The generic_modbus driver intends to support generic UPS devices with contact signals through modbus TCP/RTU gateways (also known as RIO \(em remote I/Os)\&. The data and signal path looks like this: .sp .if n \{\ .RS 4 .\} .nf [UPSD] <\-\-\- IPC \-\-\-> [GENERIC_UPS] <\-\-\- modbus TCP/RTU \-\-\-> MODBUS\-RIO <\-\-\- contacts \-\-\-> [UPS DEVICE] .fi .if n \{\ .RE .\} .sp On the other hand, you can setup any kind of modbus server, and configure the generic_modbus driver to connect and read or write specific registers\&. Your application / modbus server could then drive NUT statuses (e\&.g\&. OL, OB, HB etc) by writing over those registers\&. .SH "AUTHOR" .sp Dimitris Economou .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8), \fBups.conf\fR(5) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} libmodbus home page: http://libmodbus\&.org .RE nut-2.8.3/docs/man/nutscan_add_ip_range.txt0000644000200500020050000000465615001555412015643 00000000000000NUTSCAN_ADD_IP_RANGE(3) ======================= NAME ---- nutscan_add_ip_range - Add an entry with IP address range (starting and ending addresses) to a `nutscan_ip_range_list_t` structure. SYNOPSIS -------- ------ #include /* One IP address range: */ typedef struct nutscan_ip_range_s { char * start_ip; char * end_ip; struct nutscan_ip_range_s * next; } nutscan_ip_range_t; /* List of IP address ranges and helper data: */ typedef struct nutscan_ip_range_list_s { nutscan_ip_range_t * ip_ranges; /* Actual linked list of entries, first entry */ nutscan_ip_range_t * ip_ranges_last; /* Pointer to end of list for quicker additions */ size_t ip_ranges_count; /* Counter of added entries */ } nutscan_ip_range_list_t; size_t nutscan_add_ip_range( nutscan_ip_range_list_t *irl, char * start_ip, char * end_ip); ------ DESCRIPTION ----------- The *nutscan_add_ip_range()* function can create and add a `nutscan_ip_range_t` entry based on provided inputs to the specified `nutscan_ip_range_list_t` structure. The resulting amount of entries in the structure is returned, or 0 in case of non-fatal errors. This function skips work if: * the structure pointer is `NULL` ('0' is returned); * neither `start_ip` nor `end_ip` were provided, i.e. they both have `NULL` values (current list length from the structure is returned); * failed to allocate the entry (fatal). If only one of `start_ip` or `end_ip` values was provided (not `NULL`), a single-address range is created with both addresses set to the same pointer value. The structure should be initialized before use by `nutscan_init_ip_ranges()`. The caller must free the contents of the structure after completing its use by calling `nutscan_free_ip_ranges()` (after which the structure can be re-used for a new list), and explicitly `free()` the structure object itself if it was allocated dynamically (e.g. by calling `nutscan_init_ip_ranges(NULL)`). NOTES ----- Technically, the function is currently defined in 'nutscan-ip.h' file. Currently there are no checks for duplicate or overlapping entries, so the same IP addresses and whole IP address ranges can be added to the list (and would eventually be scanned) many times. SEE ALSO -------- linkman:nutscan_init_ip_ranges[3], linkman:nutscan_free_ip_ranges[3], linkman:nutscan_stringify_ip_ranges[3], linkman:nutscan_cidr_to_ip[3], linkman:nutscan_ip_ranges_iter_init[3], linkman:nutscan_ip_ranges_iter_inc[3] nut-2.8.3/docs/man/richcomm_usb.80000644000200500020050000000564615001555077013525 00000000000000'\" t .\" Title: richcomm_usb .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "RICHCOMM_USB" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" richcomm_usb \- Driver UPS equipment using Richcomm dry\-contact to USB solution .SH "SYNOPSIS" .sp \fBrichcomm_usb\fR \-h .sp \fBrichcomm_usb\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the richcomm_usb driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The Richcomm dry\-contact to USB solution is a generic interface that is used to upgrade an existing (RS\-232) contact closure UPS interface to USB\&. As such, all the limitations of the underlying contact closure interface apply\&. This means that you will only get the essentials in ups\&.status: OL, OB, and LB\&. See also \fBgenericups\fR(8)\&. .SH "BUGS" .sp Most contact\-closure UPSes will not power down the load if the line power is present\&. This can create a race when using secondary \fBupsmon\fR(8) systems\&. See the \fBupsmon\fR(8) man page for more information\&. .sp The solution to both of these problems is to upgrade to a smart protocol UPS of some kind that allows detection and proper load cycling on command\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Peter van Valderen .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Dirk Teurlings .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "The generic serial driver:" .sp \fBgenericups\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/phoenixcontact_modbus.txt0000644000200500020050000000635615001555412016112 00000000000000PHOENIXCONTACT_MODBUS(8) ======================== NAME ---- phoenixcontact_modbus - Driver for Phoenix Contact SYNOPSIS -------- *phoenixcontact_modbus* -h *phoenixcontact_modbus* -a 'DEVICE_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the phoenixcontact_modbus driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver should support the PhoenixContact QUINT-UPS industrial DC UPS, model 2320461 and all compatible models. More information about this UPS can be found among <<_internet_resources,Internet resources>> below. phoenixcontact_modbus uses the libmodbus project, for Modbus implementation. How to configure the UPS ------------------------ Note: this UPS and its manual refers to Low-Batt as "Shutdown Event". You need the "IFS-RS232-DATACABLE" to communicate with the UPS in Linux as the IFS-USB cable doesn't seem to be supported. FYI communication parameters are: `115200,E,8,1`. You also need the UPS-CONF Windows software (free; download from their site), to configure the UPS signals and timers. 1. Run the UPS-CONF 2. Go to Settings->Time Setting 3. Choose "state of charge shutdown delay" 4. Choose Remote starts PC-Shutdown in Mains and Battery mode 5. On the PC-Shutdown enter the maximum value (5 minutes) 6. On the PC-Restart delay enter the time you want the UPS to leave the output power off before restarting (e.g. 60 seconds), after mains power is restored. 7. On the UPS, turn the screw to the "PC-MODE" position Configuring the above way ensures that: * When power is lost, UPS constantly calculates remaining battery time * When remaining battery time is less than 5 minutes (PC-Shutdown setting), it will raise the "Shutdown" event (seen as LOW-BATT in NUT) * From that moment even if input power is restored, the UPS will cut the output power to its load after 5 minutes * When the input power is restored, the UPS will restore output power after 60 seconds (PC-RESTART delay setting). Meaning of settings: * PC-Shutdown: How long before output cutoff the UPS will raise the "shutdown event" signal. Max value for this is 5 minutes. So PC should be able to shutdown within 5 minutes. * PC-Restart: How long to delay output power after power is restored. Max is 60 seconds. EXTRA ARGUMENTS --------------- This driver doesn't support any optional settings. INSTALLATION ------------ This driver may be not built by default. You can build it by installing libmodbus and running `configure --with-modbus=yes`. You also need to give proper permissions on the local serial device file (`/dev/ttyS0` for example) to allow the NUT user to access it. INSTANT COMMANDS ---------------- This driver doesn't support any instant commands. AUTHOR ------ Spiros Ioannou SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * libmodbus home page: http://libmodbus.org * More information about PhoenixContact QUINT-UPS industrial DC UPS, model 2320461 UPS series can be found here: https://www.phoenixcontact.com/online/portal/us?uri=pxc-oc-itemdetail:pid=2320461 nut-2.8.3/docs/man/upscli_str_add_unique_token.txt0000644000200500020050000000426415001555412017274 00000000000000UPSCLI_STR_ADD_UNIQUE_TOKEN(3) ============================== NAME ---- upscli_str_add_unique_token - Add a unique token into a string buffer, with optional callbacks as needed by implementation SYNOPSIS -------- ------ #include int upscli_str_add_unique_token(char *tgt, size_t tgtsize, const char *token, int (*callback_always)(char *, size_t, const char *), int (*callback_unique)(char *, size_t, const char *) ); ------ DESCRIPTION ----------- The *upscli_str_add_unique_token*() function takes the pointer 'tgt' to a caller-provided `char *` buffer of size 'tgtsize', and the pointer 'token' to a contiguous token that should be added to the end of 'tgt' buffer, if it is not there yet. The 'token' contents are stripped of surrounding space characters, and the method recurses to independently process each space-separated token inside (if there are any spaces left). The resulting 'tgt' buffer would eventually collect a string comprised of unique 'token' values in order of first mention, separated by single space characters (ASCII '0x20'). Optionally calls 'callback_always' (if not `NULL`) after checking the input for spaces (and maybe recursing) and before checking if the token is already there, and/or 'callback_unique' (if not `NULL`) after checking for uniqueness and just before going to add a newly seen token. * If such callback returns '0', abort the addition of 'token' and return '-3'. It is up to the caller to dynamically or statically allocate the 'tgt' buffer and *free*() it if needed. As far as this method is concerned, the buffer may be recycled (in data processing loops) by setting the initial character to `'\0'`, making it an empty string again. RETURN VALUE ------------ The *upscli_str_add_unique_token*() function returns a numeric code: * '0' if the 'token' value was already there in 'tgt' buffer; * '1' if 'token' was added successfully; * '-1' if we needed to add the 'token', but it did not fit under the 'tgtsize' limit; * '-2' if either 'token' or 'tgt' string was `NULL`, or if 'token' was empty; * '-3' if the 'token' was rejected by the optional callback method returning '0'. SEE ALSO -------- linkman:upscli_str_contains_token[3] nut-2.8.3/docs/man/index.txt0000644000200500020050000000627215001555412012617 00000000000000NUT manual pages ================ [[User_man]] User manual pages ----------------- Configuration files ~~~~~~~~~~~~~~~~~~~ - linkman:nut.conf[5] - linkman:ups.conf[5] - linkman:upsd.conf[5] - linkman:upsd.users[5] - linkman:upsmon.conf[5] - linkman:upssched.conf[5] - linkman:hosts.conf[5] - linkman:upsset.conf[5] - linkman:upsstats.html[5] Daemons ~~~~~~~ - linkman:upsd[8] - linkman:upsmon[8] - linkman:upssched[8] - linkman:upslog[8] Clients commands ~~~~~~~~~~~~~~~~ - linkman:upsc[8] - linkman:upscmd[8] - linkman:upsrw[8] - linkman:NUT-Monitor[8] Configuration commands ~~~~~~~~~~~~~~~~~~~~~~ - linkman:nutconf[8] - linkman:nut-scanner[8] CGI programs ~~~~~~~~~~~~ - linkman:upsimage.cgi[8] - linkman:upsset.cgi[8] - linkman:upsstats.cgi[8] Platform management ~~~~~~~~~~~~~~~~~~~ Windows ^^^^^^^ - linkman:nut.exe[8] [[Drivers]] Driver control: ~~~~~~~~~~~~~~~ include::{builddir}linkman-drivertool-names.txt[] Drivers: ~~~~~~~~ - linkman:nutupsdrv[8] include::{builddir}linkman-driver-names.txt[] [[Developer_man]] Developer manual pages ---------------------- - linkman:libupsclient-config[1] - linkman:nut-recorder[8] - linkman:skel[8] - linkman:sockdebug[8] [[devclient]] Client library ~~~~~~~~~~~~~~ - linkman:libnutclient[3] - linkman:libnutclient_commands[3] - linkman:libnutclient_devices[3] - linkman:libnutclient_general[3] - linkman:libnutclient_misc[3] - linkman:libnutclient_tcp[3] - linkman:libnutclient_variables[3] - linkman:upsclient[3] - linkman:upscli_add_host_cert[3] - linkman:upscli_cleanup[3] - linkman:upscli_connect[3] - linkman:upscli_tryconnect[3] - linkman:upscli_disconnect[3] - linkman:upscli_fd[3] - linkman:upscli_get[3] - linkman:upscli_init[3] - linkman:upscli_set_default_connect_timeout[3] - linkman:upscli_get_default_connect_timeout[3] - linkman:upscli_init_default_connect_timeout[3] - linkman:upscli_list_next[3] - linkman:upscli_list_start[3] - linkman:upscli_readline[3] - linkman:upscli_sendline[3] - linkman:upscli_splitaddr[3] - linkman:upscli_splitname[3] - linkman:upscli_ssl[3] - linkman:upscli_strerror[3] - linkman:upscli_upserror[3] - linkman:upscli_str_add_unique_token[3] - linkman:upscli_str_contains_token[3] [[devscan]] Device discovery library ~~~~~~~~~~~~~~~~~~~~~~~~ - linkman:nutscan[3] - linkman:nutscan_add_device_to_device[3] - linkman:nutscan_add_ip_range[3] - linkman:nutscan_add_option_to_device[3] - linkman:nutscan_cidr_to_ip[3] - linkman:nutscan_display_parsable[3] - linkman:nutscan_display_sanity_check[3] - linkman:nutscan_display_sanity_check_serial[3] - linkman:nutscan_display_ups_conf[3] - linkman:nutscan_display_ups_conf_with_sanity_check[3] - linkman:nutscan_free_device[3] - linkman:nutscan_free_ip_ranges[3] - linkman:nutscan_get_serial_ports_list[3] - linkman:nutscan_init[3] - linkman:nutscan_init_ip_ranges[3] - linkman:nutscan_ip_ranges_iter_inc[3] - linkman:nutscan_ip_ranges_iter_init[3] - linkman:nutscan_new_device[3] - linkman:nutscan_scan_avahi[3] - linkman:nutscan_scan_eaton_serial[3] - linkman:nutscan_scan_ipmi[3] - linkman:nutscan_scan_nut[3] - linkman:nutscan_scan_nut_simulation[3] - linkman:nutscan_scan_snmp[3] - linkman:nutscan_scan_usb[3] - linkman:nutscan_scan_xml_http_range[3] - linkman:nutscan_stringify_ip_ranges[3] nut-2.8.3/docs/man/nutclient_tcp_get_timeout.30000644000200500020050000000003415001555117016303 00000000000000.so man3/libnutclient_tcp.3 nut-2.8.3/docs/man/nutscan_add_ip_range.30000644000200500020050000001012115001555062015147 00000000000000'\" t .\" Title: nutscan_add_ip_range .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_ADD_IP_RANGE" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_add_ip_range \- Add an entry with IP address range (starting and ending addresses) to a `nutscan_ip_range_list_t` structure\&. .SH "SYNOPSIS" .sp .nf #include /* One IP address range: */ typedef struct nutscan_ip_range_s { char * start_ip; char * end_ip; struct nutscan_ip_range_s * next; } nutscan_ip_range_t; /* List of IP address ranges and helper data: */ typedef struct nutscan_ip_range_list_s { nutscan_ip_range_t * ip_ranges; /* Actual linked list of entries, first entry */ nutscan_ip_range_t * ip_ranges_last; /* Pointer to end of list for quicker additions */ size_t ip_ranges_count; /* Counter of added entries */ } nutscan_ip_range_list_t; size_t nutscan_add_ip_range( nutscan_ip_range_list_t *irl, char * start_ip, char * end_ip); .fi .SH "DESCRIPTION" .sp The \fBnutscan_add_ip_range()\fR function can create and add a nutscan_ip_range_t entry based on provided inputs to the specified nutscan_ip_range_list_t structure\&. The resulting amount of entries in the structure is returned, or 0 in case of non\-fatal errors\&. .sp This function skips work if: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the structure pointer is NULL (\fI0\fR is returned); .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} neither start_ip nor end_ip were provided, i\&.e\&. they both have NULL values (current list length from the structure is returned); .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} failed to allocate the entry (fatal)\&. .RE .sp If only one of start_ip or end_ip values was provided (not NULL), a single\-address range is created with both addresses set to the same pointer value\&. .sp The structure should be initialized before use by nutscan_init_ip_ranges()\&. .sp The caller must free the contents of the structure after completing its use by calling nutscan_free_ip_ranges() (after which the structure can be re\-used for a new list), and explicitly free() the structure object itself if it was allocated dynamically (e\&.g\&. by calling nutscan_init_ip_ranges(NULL))\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-ip\&.h\fR file\&. .sp Currently there are no checks for duplicate or overlapping entries, so the same IP addresses and whole IP address ranges can be added to the list (and would eventually be scanned) many times\&. .SH "SEE ALSO" .sp \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_stringify_ip_ranges\fR(3), \fBnutscan_cidr_to_ip\fR(3), \fBnutscan_ip_ranges_iter_init\fR(3), \fBnutscan_ip_ranges_iter_inc\fR(3) nut-2.8.3/docs/man/upssched.conf.50000644000200500020050000001266515001555046013605 00000000000000'\" t .\" Title: upssched.conf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSSCHED\&.CONF" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upssched.conf \- Configuration for upssched timer program .SH "DESCRIPTION" .sp This file controls the operations of \fBupssched\fR(8), the timer\-based helper program for \fBupsmon\fR(8)\&. .SH "IMPORTANT NOTES" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message)\&. .RE .SH "CONFIGURATION DIRECTIVES" .PP \fBCMDSCRIPT\fR \fIscriptname\fR .RS 4 Required\&. This must be above any AT lines\&. This script is used to invoke commands when your timers are triggered\&. It receives a single argument which is the name of the timer that caused it to trigger\&. .RE .PP \fBPIPEFN\fR \fIfilename\fR .RS 4 Required\&. This sets the file name of the socket which will be used for interprocess communications\&. This should be in a directory where normal users can\(cqt create the file, due to the possibility of symlinking and other evil\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBCaution\fR .ps -1 .br .sp if you are running Solaris or similar, the permissions that upssched sets on this file \fBare not enough\fR to keep you safe\&. If your OS ignores the permissions on a FIFO, then you MUST put this in a protected directory! .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp by default, \fBupsmon\fR(8) will run upssched as whatever user you have defined with RUN_AS_USER in \fBupsmon.conf\fR(8)\&. Make sure that user can create files and write to files in the path you use for PIPEFN and LOCKFN\&. .sp .5v .RE .sp My recommendation: create a special directory for upssched, make it owned by your upsmon user, then use it for both\&. .sp The stock version of the upssched\&.conf ships with PIPEFN disabled to make you visit this portion of the documentation and think about how your system works before potentially opening a security hole\&. .PP \fBLOCKFN\fR \fIfilename\fR .RS 4 Required\&. upssched attempts to create this file in order to avoid a race condition when two events are dispatched from upsmon at nearly the same time\&. This file will only exist briefly\&. It must not be created by any other process\&. .sp You should put this in the same directory as PIPEFN\&. .RE .PP \fBAT\fR \fInotifytype\fR \fIupsname\fR \fIcommand\fR .RS 4 Define a handler for a specific event \fInotifytype\fR on UPS \fIupsname\fR\&. \fIupsname\fR can be the special value * to apply this handler to every UPS\&. .sp This will perform the command \fIcommand\fR when the \fInotifytype\fR and \fIupsname\fR match the current activity\&. Possible values for \fIcommand\fR are: .PP \fBSTART\-TIMER\fR \fItimername\fR \fIinterval\fR .RS 4 Start a timer of \fIinterval\fR seconds\&. When it triggers, it will pass the argument \fItimername\fR as an argument to your CMDSCRIPT\&. .sp Example: .sp Start a timer that will execute when any UPS (*) has been gone for 10 seconds .sp .if n \{\ .RS 4 .\} .nf AT COMMBAD * START\-TIMER upsgone 10 .fi .if n \{\ .RE .\} .RE .PP \fBCANCEL\-TIMER\fR \fItimername\fR [\fIcmd\fR] .RS 4 Cancel a running timer called \fItimername\fR, if possible\&. If the timer has passed then pass the optional argument \fIcmd\fR to CMDSCRIPT\&. .sp Example: .sp If a specific UPS (myups@localhost) comes back online, then stop the timer before it triggers .sp .if n \{\ .RS 4 .\} .nf AT COMMOK myups@localhost CANCEL\-TIMER upsgone .fi .if n \{\ .RE .\} .RE .PP \fBEXECUTE\fR \fIcommand\fR .RS 4 Immediately pass \fIcommand\fR as an argument to CMDSCRIPT\&. .sp Example: .sp If any UPS (*) reverts to utility power, then execute ups\-back\-on\-line via CMDSCRIPT\&. .sp .if n \{\ .RS 4 .\} .nf AT ONLINE * EXECUTE ups\-back\-on\-line .fi .if n \{\ .RE .\} .RE .RE .sp Note that any AT that matches both the \fInotifytype\fR and the \fIupsname\fR for the current event will be used\&. .sp For a complete list of \fInotifytype\fR possible values, refer to the section NOTIFY EVENTS in \fBupsmon\fR(8)\&. .SH "SEE ALSO" .sp \fBupssched\fR(8), \fBupsmon\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/adelsystem_cbi.txt0000644000200500020050000000444515001555412014477 00000000000000ADELSYSTEM_CBI(8) ================= NAME ---- adelsystem_cbi - Driver for the ADELSYSTEM CB/CBI DC-UPS SYNOPSIS -------- *adelsystem_cbi* -h *adelsystem_cbi* -a 'DEVICE_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the *adelsystem_cbi* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This is the driver for the adelsystem cb/cbi dc-ups devices. The driver has been tested against CBI2801224A, all in one 12/24Vdc DC-UPS. More information about this UPS can be found here: :: https://www.adelsystem.com/en/products/dc-ups-/ EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file: Serial: ~~~~~~ *ser_baud_rate*='value':: A integer specifying the serial port baud rate (default 9600). *ser_data_bit*='value':: A integer specifying the serial port data bit (default 8). *ser_parity*='value':: A character specifying the serial port parity (default N). *ser_stop_bit*='value':: An integer specifying the serial port stop bit (default 1). Modbus: ~~~~~~ *dev_slave_id*='value':: An integer specifying the device modbus slave ID (default 1). CONFIGURATION ------------- Here is an example of adelsystem_cbi driver configuration in *ups.conf* file: ---- [adelsystem_cbi] driver = adelsystem_cbi port = /dev/ttyUSB0 desc = "adelsystem cb/cbi ups driver" # serial settings ser_baud_rate = 9600 ser_parity = N ser_data_bit = 8 ser_stop_bit = 1 # modbus slave id dev_slave_id = 5 ---- INSTANT COMMANDS ---------------- This driver support the following instant commands: load.off:: executes "instant poweroff" INSTALLATION ------------ This driver may be not built by default. You can build it by installing libmodbus and running `configure --with-modbus=yes`. You also need to give proper permissions on the local serial device file (`/dev/ttyUSB0` for example) to allow the run-time NUT driver user account to access it. AUTHOR ------ Dimitris Economou SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8], linkman:ups.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * libmodbus home page: http://libmodbus.org nut-2.8.3/docs/man/nutdrv_atcl_usb.txt0000644000200500020050000000577415001555412014714 00000000000000NUTDRV_ATCL_USB(8) ================== NAME ---- nutdrv_atcl_usb - Driver for 'ATCL FOR UPS' equipment SYNOPSIS -------- *nutdrv_atcl_usb* -h *nutdrv_atcl_usb* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the nutdrv_atcl_usb driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver is for UPS hardware which identifies itself as USB idVendor +0001+ and idProduct +0000+, and iManufacturer +ATCL FOR UPS+. Known manufacturers include Kanji and Plexus. The UPS interface seems to be a generic USB-to-serial chip, and for hardware manufactured by Kanji and Plexus, the microcontroller appears to emulate a traditional contact-closure interface. This translates into only three states in ups.status: *OL*, *OB* and *OB LB* (similar to linkman:genericups[8]), with no other dynamic status values reported. Note that these USB identifiers (including the iManufacturer string) have also been seen on devices that are supported by the `fuji` subdriver of linkman:nutdrv_qx[8], and some others. EXTRA ARGUMENTS --------------- This driver supports the following optional setting: *vendor =* 'name':: In case your iManufacturer (Vendor) string does not exactly match +ATCL FOR UPS+, you may provide an alternate string here (or specify "NULL" if the device does not provide a vendor string but you want this driver to match). + Note that a more likely case for mismatch is that your device is handled by another driver for +0001:0000+ devices, such as linkman:nutdrv_qx[8]. + NOTE: This driver does not intend to support USB-matching settings common to other drivers, such as *vendorid*, *product*, *productid*, *serial*, *device* or *bus*; also the *vendor* setting supported here is not a regular expression. BUGS ---- The UPS returns the same code for "load power is off" as for "on line power". This condition will not be observed if the NUT `upsmon` in primary mode runs on the box powered by the UPS, but may be an issue if the UPS is monitored by a remote (secondary) system. The time between the shutdown command and removal of power seems to be fixed at 30 seconds. Ensure that the NUT shutdown script is invoked as late as possible in the shutdown procedure (in case some services take longer than others to clean up). Most contact-closure UPSes will not power down the load if the line power is present. This can create a race when using secondary linkman:upsmon[8] systems. See the linkman:upsmon[8] man page for more information. The solution to this problem is to upgrade to a smart protocol UPS of some kind that allows detection and proper load cycling on command. AUTHOR ------ Charles Lepple SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] The generic serial driver: ~~~~~~~~~~~~~~~~~~~~~~~~~~ linkman:genericups[8] The Qx driver: ~~~~~~~~~~~~~~ linkman:nutdrv_qx[8] (`fuji` subdriver) Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/mge-shut.80000644000200500020050000001044015001555073012564 00000000000000'\" t .\" Title: mge-shut .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "MGE\-SHUT" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" mge-shut \- Driver for SHUT Protocol UPS equipment .SH "SYNOPSIS" .sp \fBmge\-shut\fR \-h .sp \fBmge\-shut\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the mge\-shut driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp mge\-shut supports all recent Eaton, MGE and Dell UPS models which use the SHUT (Serial HID UPS Transfer) protocol\&. .sp Older MGE models, such as Pulsar ESV+, Pulsar EX and Pulsar ES+, use the U\-Talk protocol and should use the mge\-utalk driver\&. .SH "EXTRA ARGUMENTS" .sp This driver also supports the following optional settings: .PP \fBlowbatt\fR=\fInum\fR .RS 4 Set the low battery warning threshold at which shutdown is initiated by \fBupsmon\fR(8)\&. .sp The factory default value is 30 (in percent), and can be settable depending on the exact model\&. .RE .PP \fBoffdelay\fR=\fInum\fR .RS 4 Set the timer before the UPS is turned off after the kill power command is sent (via the \-k switch)\&. .sp The default value is 20 (in seconds)\&. Usually this \fBmust be lower\fR than \fIondelay\fR, but the driver will \fBnot\fR warn you upon startup if it isn\(cqt\&. .RE .PP \fBondelay\fR=\fInum\fR .RS 4 Set the timer for the UPS to switch on in case the power returns after the kill power command had been sent but before the actual switch off\&. This ensures the machines connected to the UPS are, in all cases, rebooted after a power failure\&. .sp The default value is 30 (in seconds)\&. Usually this \fBmust be greater\fR than offdelay, but the driver will \fBnot\fR warn you upon startup if it isn\(cqt\&. Some UPSes will restart no matter what, even if the power is (still) out at the moment this timer elapses\&. In that case, you could try if setting \fIondelay = \-1\fR in \fBups\&.conf\fR helps\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br ondelay parameter was set in ten seconds unit in the legacy mge\-shut driver ( 3 for 30 seconds) \&. It is now set in seconds ( 30 for 30 seconds)\&. Make sure you use the correct unit in your configuration\&. .sp .5v .RE .RE .PP \fBnotification\fR=\fInum\fR .RS 4 Set notification type to \fI1\fR (no), \fI2\fR (light) or \fI3\fR (yes)\&. .sp This argument is ignored\&. It is only here for backward compatibility\&. .RE .SH "KNOWN ISSUES" .SS "Repetitive timeout and staleness" .sp Some models tend to be unresponsive with the default polling frequency\&. The result is that you have some "data stale" errors in your system log\&. .sp In this case, simply modify the general parameter pollinterval to a higher value (like \fI10\fR for 10 seconds)\&. This should solve the issue\&. .sp Using \fInotification=3\fR might also help\&. .SH "AUTHOR" .sp Arnaud Quette .SH "SEE ALSO" .SS "The core driver" .sp \fBnutupsdrv\fR(8) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan_display_sanity_check_serial.30000644000200500020050000000525515001555060020315 00000000000000'\" t .\" Title: nutscan_display_sanity_check_serial .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_DISPLAY_SANI" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_display_sanity_check_serial \- Display sanity check warnings about "serial" (serial number/code string) optional values in the specified `nutscan_device_t` structure on stdout\&. .SH "SYNOPSIS" .sp .nf #include void nutscan_display_sanity_check_serial(nutscan_device_t * device); .fi .SH "DESCRIPTION" .sp The \fBnutscan_display_sanity_check_serial()\fR function analyzes "serial" optional field in all NUT devices in \fIdevice\fR, and in case of duplicate or otherwise seemingly invalid values, prints comments to stdout\&. It displays them in a way that it can be directly copied into the ups\&.conf file\&. .sp It is called from \fBnutscan_display_ups_conf_with_sanity_check()\fR to provide an aggregate content for ups\&.conf file in one shot\&. .SH "SEE ALSO" .sp \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/upsstats.html.50000644000200500020050000002134115001555050013656 00000000000000'\" t .\" Title: upsstats.html .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSSTATS\&.HTML" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsstats.html \- HTML template for web\-based Network UPS Tools upsstats .SH "DESCRIPTION" .sp This file is used by \fBupsstats.cgi\fR(8) to generate status pages\&. Certain commands are recognized, and will be replaced with various status elements on the fly\&. .SH "FORMATTING" .sp Commands can be placed anywhere on a line, but must start and end with @\&. .sp Any extra characters before or after the commands will be passed through unchanged\&. .sp It is allowed to use more than one command on a single line, as long as each command has its own start and end character\&. .sp If you need to use the @ sign, use HTML entity @ to prevent it from being treated as a start character\&. .SH "BLOCK CONTROL" .sp Some commands begin blocks \(em sections of the template that will be included, excluded, or repeated depending on certain parameters\&. .SS "BLOCK CONTROL \- ITERATION" .PP \fB@FOREACHUPS@\fR .RS 4 Starts a block that will be repeated for each MONITOR directive in the \fBhosts.conf\fR(5)\&. This is how you can generate pages that monitor all of your systems simultaneously\&. .RE .PP \fB@ENDFOR@\fR .RS 4 Ends a FOREACHUPS block\&. .RE .SS "BLOCK CONTROL \- MATCHING SPECIFIC CASES" .PP \fB@IFSUPP \fR\fB\fIvar\fR\fR@* .RS 4 Starts a block that will only be printed if the variable var is supported by the current UPS\&. This is generally used to suppress "not supported" messages by avoiding the label and variable call entirely\&. .RE .PP \fB@IFEQ\fR \fIvar\fR \fIvalue\fR\fB@\fR .RS 4 Starts a block if the value returned from the variable \fIvar\fR matches \fIvalue\fR\&. .RE .PP \fB@IFBETWEEN\fR \fIvarlow\fR \fIvarhigh\fR \fIvarvalue\fR\fB@\fR .RS 4 Starts a block if the value returned by the variable \fIvarvalue\fR is between the values returned by the variables \fIvarlow\fR and \fIvarhigh\fR\&. .RE .PP \fB@ELSE@\fR .RS 4 If the previous IF\-command did not match, perform this instead\&. .RE .PP \fB@ENDIF@\fR .RS 4 Ends an IF/ELSE\-block\&. .RE .SS "BLOCK CONTROL \- ADVANCED EXPRESSIONS" .sp Even though the parser is pretty limited, it\(cqs still possible to create rather advanced expressions\&. The key to this is the fact that multiple block control commands are AND:ed\&. This is illustrated with an example (more examples are available in upsstats\&.html)\&. .sp .if n \{\ .RS 4 .\} .nf @IFSUPP ambient\&.humidity@ @IFSUPP ambient\&.temperature@ This UPS knows both ambient temperature and humidity\&. @ELSE@ @IFSUPP ambient\&.humidity@ This UPS only knows ambient humidity\&. @ELSE@ @IFSUPP ambient\&.temperature@ This UPS only knows ambient temperature\&. @ELSE@ This UPS knows nothing, how annoying\&. @ENDIF@ .fi .if n \{\ .RE .\} .SH "OTHER COMMANDS" .PP \fB@AMBTEMP@\fR .RS 4 Insert the ambient temperature in the current temperature scale\&. .RE .PP \fB@DATE\fR \fIformat\fR\fB@\fR .RS 4 Insert the current date and time\&. The format string is passed to strftime, so almost anything is possible\&. See \fBstrftime\fR(3) for possible values\&. .RE .PP \fB@DEGREES@\fR .RS 4 Insert the entity for degrees (\(de) and either C or F depending on the current temperature scale\&. .RE .PP \fB@HOST@\fR .RS 4 Insert the designation of the host being monitored, like myups@localhost\&. .RE .PP \fB@HOSTDESC@\fR .RS 4 Insert the host\(cqs description from \fBhosts.conf\fR(5)\&. .RE .PP \fB@HOSTLINK@\fR .RS 4 Insert a link to upsstats\&.cgi with the "host" variable set to the current UPS\&. This is only useful within a FOREACHUPS block\&. .RE .PP \fB@IMG\fR \fIvarname\fR \fB@\fR .RS 4 Insert an IMG SRC to \fBupsimage.cgi\fR(8) for one of these status variables: .PP battery\&.charge .RS 4 Battery charge \(em a percentage .RE .PP battery\&.voltage .RS 4 The charge on the battery in volts .RE .PP input\&.frequency .RS 4 Incoming utility frequency (Hz) .RE .PP input\&.voltage .RS 4 Incoming utility voltage .RE .PP input\&.L1\-L2\&.voltage .RS 4 Incoming voltage, L1\-L2 (3phase) .RE .PP input\&.L2\-L3\&.voltage .RS 4 Incoming voltage, L2\-L3 (3phase) .RE .PP input\&.L3\-L1\&.voltage .RS 4 Incoming voltage, L3\-L1 (3phase) .RE .PP output\&.frequency .RS 4 Outgoing utility frequency (Hz) .RE .PP output\&.voltage .RS 4 Outgoing voltage (from the UPS) .RE .PP output\&.L1\-L2\&.voltage .RS 4 Outgoing voltage, L1\-L2 (3phase) .RE .PP output\&.L2\-L3\&.voltage .RS 4 Outgoing voltage, L2\-L3 (3phase) .RE .PP output\&.L3\-L1\&.voltage .RS 4 Outgoing voltage, L3\-L1 (3phase) .RE .PP output\&.L1\&.power\&.percent .RS 4 UPS load, L1 (3phase) .RE .PP output\&.L2\&.power\&.percent .RS 4 UPS load, L2 (3phase) .RE .PP output\&.L3\&.power\&.percent .RS 4 UPS load, L3 (3phase) .RE .PP ups\&.load .RS 4 UPS load \(em percentage .RE .PP ups\&.temperature .RS 4 UPS temperature .RE .RE .sp \fIextra\fR is where you can put additional definitions\&. Right now the valid definitions are colors for various parts of the bars drawn by \fBupsimage.cgi\fR(8)\&. Possible color names are: .PP back_col .RS 4 background color .RE .PP scale_num_col .RS 4 scale number color .RE .PP summary_col .RS 4 summary color (number at the bottom) .RE .PP ok_zone_maj_col .RS 4 major scale color for the normal ("ok") zone .RE .PP ok_zone_min_col .RS 4 minor scale color for the normal ("ok") zone .RE .PP neutral_zone_maj_col .RS 4 major scale color for the neutral zone .RE .PP neutral_zone_min_col .RS 4 minor scale color for the neutral zone .RE .PP warn_zone_maj_col .RS 4 major scale color for the warning zone .RE .PP warn_zone_min_col .RS 4 minor scale color for the warning zone .RE .PP bar_col .RS 4 the color of the bar in the middle .RE .sp All colors are hex triplets \(em e\&.g\&. 0xff0000 is red, 0x00ff00 is green, and 0x0000ff is blue\&. .sp Examples: .sp .if n \{\ .RS 4 .\} .nf @IMG battery\&.charge@ @IMG battery\&.charge back_col=0xff00ff bar_col=0xaabbcc@ @IMG input\&.voltage ok_zone_maj_col=0x123456@ .fi .if n \{\ .RE .\} .PP \fB@REFRESH@\fR .RS 4 Insert the META header magic for refreshing the page if that variable has been set by the browser\&. This needs to be in the HEAD section of the page\&. .RE .PP \fB@STATUS@\fR .RS 4 Expand the abbreviations in the ups\&.status variable \(em OL becomes "On line", OB becomes "On battery", and so on\&. .RE .PP \fB@STATUSCOLOR@\fR .RS 4 Insert red, green, or yellow color triplets depending on the severity of the current UPS status\&. Normal operations are green, warnings like voltage trim/boost or "off" are yellow, and other events like being on battery or having a low battery are red\&. .RE .PP \fB@VAR\fR \fIvarname\fR\fB@\fR .RS 4 Insert the current value of the status variable varname on the host being monitored, or "Not supported"\&. .RE .PP \fB@RUNTIME@\fR .RS 4 Inserts the current runtime, in hh:mm:ss format\&. .RE .PP \fB@TEMPC@\fR .RS 4 Use the Celsius scale for temperature data (default)\&. .RE .PP \fB@TEMPF@\fR .RS 4 Use the Fahrenheit scale for temperature data\&. .RE .PP \fB@UPSTEMP@\fR .RS 4 Insert the UPS temperature in the current scale\&. .RE .PP \fB@BATTTEMP@\fR .RS 4 Insert the battery temperature in the current scale\&. .RE .PP \fB@UTILITYCOLOR@\fR .RS 4 Obsoleted\&. Use IFBETWEEN instead (see example in upsstats\&.html)\&. .RE .PP \fB@VERSION@\fR .RS 4 Insert the version number of the software\&. .RE .SH "OTHER TEMPLATES" .sp \fBupsstats.cgi\fR(8) will also open a file called upsstats\-single\&.html if you call it with host= set in the query URL\&. That file uses the same rules and techniques as documented here\&. .SH "SEE ALSO" .sp \fBupsstats.cgi\fR(8), \fBupsimage.cgi\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upsset.conf.txt0000644000200500020050000000522715001555412013756 00000000000000UPSSET.CONF(5) ============== NAME ---- upsset.conf - Configuration for Network UPS Tools upsset.cgi DESCRIPTION ----------- This file only does one job -- it lets you convince linkman:upsset.cgi[8] that your system's CGI directory is secure. The program will not run until this file has been properly defined. IMPORTANT NOTES --------------- * Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message). SECURITY REQUIREMENTS --------------------- linkman:upsset.cgi[8] allows you to try login name and password combinations. There is no rate limiting, as the program shuts down between every request. Such is the nature of CGI programs. Credentials are provided to `upsset.cgi` as part of your browsing session, so it is highly recommended to set up HTTPS on the web server; ways to do so are outside the scope of this document. Normally, attackers would not be able to access your linkman:upsd[8] server directly, as it would be protected by the LISTEN directives in your linkman:upsd.conf[5] file, tcp-wrappers (if available when NUT was built), and hopefully local firewall settings in your OS. *upsset* runs on your web server, so `upsd` will see it as a connection from a host on an internal network. It doesn't know that the connection is actually initiated by someone further outside. This is why you must secure it. On Apache, you can use the `.htaccess` file or put the directives in your `httpd.conf`. It looks something like this, assuming the `.htaccess` method for older Apache releases: deny from all allow from your.network.addresses You will probably have to set `AllowOverride Limit` for this directory in your server-level configuration file as well. Modern Apache enjoys a more detailed syntax, like this: ScriptAlias /upsstats.cgi /usr/share/nut/cgi/upsstats.cgi ScriptAlias /upsset.cgi /usr/share/nut/cgi/upsset.cgi Options +Includes +ExecCGI AllowOverride Limit Require local Require ip aa.bb.cc.dd/nn If this doesn't make sense, then stop reading and leave this program alone. It's not something you absolutely need to have anyway. Assuming you have all this done, and it actually works (test it!), then you may add the following directive to this file: I_HAVE_SECURED_MY_CGI_DIRECTORY If you lie to the program and someone beats on your `upsd` through your web server, don't blame me. SEE ALSO -------- linkman:upsset.cgi[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_init_ip_ranges.txt0000644000200500020050000000250315001555412016226 00000000000000NUTSCAN_INIT_IP_RANGES(3) ========================= NAME ---- nutscan_init_ip_ranges - Initialize contents of a `nutscan_ip_range_list_t` structure (and optionally create one in the first place). SYNOPSIS -------- ------ #include nutscan_ip_range_list_t * nutscan_init_ip_ranges(nutscan_ip_range_list_t *irl); ------ DESCRIPTION ----------- The *nutscan_init_ip_ranges()* function can prepare a `nutscan_ip_range_list_t` structure by zeroing out its fields. If the argument is `NULL`, the structure is dynamically allocated. Either way, a pointer to it is returned. A structure passed by caller is not assumed to have any valid contents to free, as it may have garbage from stack after allocation. The caller must free the contents of the structure after completing its use by calling `nutscan_free_ip_ranges` (after which the structure can be re-used), and explicitly `free()` the structure object itself if it was allocated dynamically (e.g. by originally calling `nutscan_init_ip_ranges(NULL)`). NOTES ----- Technically, the function is currently defined in 'nutscan-ip.h' file. SEE ALSO -------- linkman:nutscan_free_ip_ranges[3], linkman:nutscan_add_ip_range[3], linkman:nutscan_stringify_ip_ranges[3], linkman:nutscan_cidr_to_ip[3], linkman:nutscan_ip_ranges_iter_init[3], linkman:nutscan_ip_ranges_iter_inc[3] nut-2.8.3/docs/man/optiups.80000644000200500020050000001074715001555074012551 00000000000000'\" t .\" Title: optiups .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "OPTIUPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" optiups \- Driver for Opti\-UPS (Viewsonic) UPS and Zinto D (ONLINE\-USV) equipment .SH "SYNOPSIS" .sp \fBoptiups\fR \-h .sp \fBoptiups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the optiups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp \fBoptiups\fR was originally written against a PowerES 280es in nut\-0\&.45\&. It was revised for nut\-2\&.0\&.1 and tested against a PowerES 420E\&. It is expected to work with at least the PowerES, PowerPS, and PowerVS models\&. .sp This driver additionally supports a Zinto D from ONLINE USV\-Systeme AG because of their very similar commands, but it is unknown if it also works with other UPS from them\&. .sp This driver will not work with the PowerES stock serial cable\&. You will need to construct your own three conductor cable: .sp .if n \{\ .RS 4 .\} .nf UPS 6 \-> PC 3 UPS 9 \-> PC 2 UPS 4 \-> PC 5 .fi .if n \{\ .RE .\} .sp The cable for Online\-USV uses pin UPS 7 (not UPS 4) → PC 5\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file: .PP \fBstatus_only\fR .RS 4 Only poll for critical status information\&. Without this, \fBoptiups\fR (and all NUT drivers) poll all sorts of information from the UPS fairly often\&. It is probably not often enough to hurt anything, so this option probably is not very useful, unless you have a flaky serial connection or a highly loaded machine\&. .RE .PP \fBnowarn_noimp\fR .RS 4 Does not print warnings when the UPS reports that a variable is not implemented or not pollable\&. Without the option you will get a message sent to your system logs each time NUT polls the UPS\&. If you specify \fBnowarn_noimp\fR, this message will only be logged once\&. .RE .PP \fBfake_lowbatt\fR .RS 4 This forces the low battery flag true\&. Without it, if you want to test your UPS, you will have to unplug it and wait until the battery drops to a low/critical voltage level before NUT will respond and power down your system\&. With the flag, NUT should power down the system soon after you pull the plug\&. When you are done testing, you should remove this flag\&. .sp For basic shutdown configuration testing, the command \fIupsmon \-c fsd\fR is preferred\&. .RE .PP \fBpowerup\fR .RS 4 Zinto D from ONLINE\-USV cannot be identified when switched to standby\&. Set this flag to allow the driver to power\-up your Zinto UPS\&. This will also power\-up your equipment connected to the UPS! .RE .SH "BUGS" .sp On the 420E, ups\&.serial and ups\&.temperature are unsupported features\&. This is not a bug in NUT or the NUT driver, just the way things are with this UPS\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Russell Kroll .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Scott Heavner .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Matthias Goebl .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/everups.txt0000644000200500020050000000165715001555412013203 00000000000000EVERUPS(8) ========== NAME ---- everups - Driver for Ever UPS models SYNOPSIS -------- *everups* -h *everups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the everups driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver should recognize the NET *-DPC and AP *-PRO models. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. BUGS ---- This UPS can only switch off the load if it's running on battery. This means you may be vulnerable to power races if your shutdown scripts don't sleep and force a reboot. AUTHOR ------ Bartek Szady SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_ip_ranges_iter_init.30000644000200500020050000000544215001555062016602 00000000000000'\" t .\" Title: nutscan_ip_ranges_iter_init .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_IP_RANGES_IT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_ip_ranges_iter_init \- Begin iteration of an IP address range using a `nutscan_ip_range_list_iter_t` structure\&. .SH "SYNOPSIS" .sp .nf #include char * nutscan_ip_ranges_iter_init( nutscan_ip_range_list_iter_t *irliter, const nutscan_ip_range_list_t *irl); .fi .SH "DESCRIPTION" .sp The \fBnutscan_ip_ranges_iter_init()\fR function can prepare an iterator from the specified nutscan_ip_range_list_t structure, saving it into the caller\-provided nutscan_ip_range_list_iter_t helper object\&. .sp Different iterators may be created to walk the same nutscan_ip_range_list_t list from different scans independently, but the list and its contents should not be freed while anyone references it\&. .sp This function skips work if: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the structure pointer is NULL (NULL is returned); .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} the structure pointer\(cqs ip_range list is NULL (NULL is returned)\&. .RE .sp Returns the first IP address from the first registered IP address range\&. Subsequent addresses can be returned by nutscan_ip_ranges_iter_inc()\&. The caller SHOULD NOT free this string while iterating\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-ip\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_cidr_to_ip\fR(3), \fBnutscan_ip_ranges_iter_inc\fR(3) nut-2.8.3/docs/man/libupsclient-config.txt0000644000200500020050000000323215001555412015441 00000000000000LIBUPSCLIENT-CONFIG(1) ====================== NAME ---- libupsclient-config - Script to get information about the installed version of libupsclient SYNOPSIS -------- *libupsclient-config* [--version] [--libs] [--cflags] DESCRIPTION ----------- *libupsclient-config* is a tool that is used to determine the compiler and linker flags that should be used to compile and link programs that use the *libupsclient* from the Network UPS Tools project (also known as the "upscli" API). It allows to simplify build automation for systems without a `pkg-config` implementation which would instead use the `libupsclient.pc` file installed with the NUT development files. Note that to rebuild current NUT with same settings as the installed NUT v2.8.1 or newer, you can use `lib/libupsclient-config --config-flags`, where supported. Note that the `pkg-config` manifest `libupsclient.pc` does not easily convey this information. OPTIONS ------- *libupsclient-config* accepts the following options: *--version*:: Print the currently installed version of *libupsclient* on the standard output. *--libs*:: Print the linker flags that are necessary to link a *libupsclient* program. *--cflags*:: Print the compiler flags that are necessary to compile a *libupsclient* program. *--config-flags*:: Print the flags passed to `configure` script when this installation of NUT was originally built (supported since release v2.8.1). AUTHORS ------- This manual page was written by Arnaud Quette . SEE ALSO -------- linkman:upsclient[3], linkman:nutclient[3] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upscli_fd.30000644000200500020050000000367015001555051013001 00000000000000'\" t .\" Title: upscli_fd .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_FD" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_fd \- Get file descriptor for connection .SH "SYNOPSIS" .sp .nf #include int upscli_fd(UPSCONN_t *ups); .fi .SH "DESCRIPTION" .sp The \fBupscli_fd()\fR function takes the pointer \fIups\fR to a UPSCONN_t state structure and returns the value of the file descriptor for that connection, if any\&. .sp This may be useful for determining if the connection to \fBupsd\fR(8) has been lost\&. .SH "RETURN VALUE" .sp The \fBupscli_fd()\fR function returns the file descriptor, which may be any non\-negative number\&. .sp It returns \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_connect\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/bcmxcp.80000644000200500020050000000747015001555065012321 00000000000000'\" t .\" Title: bcmxcp .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BCMXCP" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" bcmxcp \- Driver for UPSes supporting the serial BCM/XCP protocol .SH "SYNOPSIS" .sp \fBbcmxcp\fR \-h .sp \fBbcmxcp\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the bcmxcp driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver should recognize all serial BCM/XCP\-compatible UPSes\&. It has been developed and tested on Powerware PW5115 and PW9120 hardware\&. .sp If your UPS has a USB connection, you may also consult the \fBbcmxcp_usb\fR(8) driver documentation\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5)\&. .PP \fBshutdown_delay=\fR\fIdelay\fR .RS 4 The number of seconds that the UPS should wait between receiving the shutdown command (upsdrvctl shutdown) and actually shutting off\&. .RE .PP \fBbaud_rate=\fR\fIrate\fR .RS 4 Communication speed for the UPS\&. If this is set to 9600, it tries to connect to the UPS at 9600bps\&. If it fails to communicate, it will go into baud\-hunting\&. It starts at 1200 and goes up to 19200\&. If it succeeds, it tell you the speed it connected with\&. If not included in the config, it defaults to baud\-hunting\&. .RE .SH "DEFAULT VALUES FOR THE EXTRA ARGUMENTS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBshutdown_delay =\fR \fI120\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbaud_rate =\fR \fInone\fR .RE .SH "INSTANT COMMANDS" .sp This driver supports the following Instant Commands: .PP \fBshutdown\&.return\fR .RS 4 Turn off the load and return when power is back\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Turn off the load and remain off\&. .RE .PP \fBtest\&.battery\&.start\fR .RS 4 Start a battery test\&. .RE .PP \fBoutlet\&.n\&.shutdown\&.return\fR .RS 4 Turn off the load on outlet \fIn\fR and return when power is back\&. (\fIn\fR is the outlet number reported by the upsc command) .RE .SH "TODO LIST" .PP Report UPS statistics information .RS 4 BCM/XCP supports reporting of UPS statistics data\&. .RE .PP Change settings .RS 4 Access the config register to change settings\&. .RE .SH "BUGS" .sp None known\&. .SH "AUTHOR" .sp Tore Ørpetveit .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "The USB BCM/XCP driver:" .sp \fBbcmxcp_usb\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/libnutclient_misc.txt0000644000200500020050000000343015001555412015210 00000000000000LIBNUTCLIENT_MISC(3) ==================== NAME ---- libnutclient_misc, nutclient_authenticate, nutclient_logout, nutclient_device_login, nutclient_get_device_num_logins, nutclient_device_master, nutclient_device_forced_shutdown - Miscellaneous functions in Network UPS Tools high-level client access library SYNOPSIS -------- ------ #include typedef void* NUTCLIENT_t; void nutclient_authenticate( NUTCLIENT_t client, const char* login, const char* passwd); void nutclient_logout(NUTCLIENT_t client); void nutclient_device_login(NUTCLIENT_t client, const char* dev); int nutclient_get_device_num_logins(NUTCLIENT_t client, const char* dev); void nutclient_device_primary(NUTCLIENT_t client, const char* dev); /* OBSOLETED name: */ void nutclient_device_master(NUTCLIENT_t client, const char* dev); void nutclient_device_forced_shutdown(NUTCLIENT_t client, const char* dev); ------ DESCRIPTION ----------- * The *nutclient_authenticate()* function authenticates the user. - 'login' is the user name. - 'passwd' is the user password. * The *nutclient_logout()* function disconnects gracefully from the server. * The *nutclient_device_login()* function logs the fact that a system is drawing power from this UPS. * The *nutclient_get_device_num_logins()* function retrieves the number of clients which have been logged for this device. * The *nutclient_device_master()* and *nutclient_device_primary()* (note: the former is obsoleted since NUT v2.8.0 in favor of the latter) functions make sure that primary-mode functions like FSD are available if necessary. * The *nutclient_device_forced_shutdown()* function sets the "forced shutdown" (FSD) flag on the device. Common arguments: * 'dev' is the device name. SEE ALSO -------- linkman:libnutclient[3] nut-2.8.3/docs/man/nutdrv_siemens_sitop.txt0000644000200500020050000001466515001555412016000 00000000000000NUTDRV_SIEMENS_SITOP(8) ======================= NAME ---- nutdrv_siemens_sitop - Driver for the Siemens SITOP UPS500 series UPS SYNOPSIS -------- *nutdrv_siemens_sitop* -h *nutdrv_siemens_sitop* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *nutdrv_siemens_sitop* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ *nutdrv_siemens_sitop* supports Siemens UPS models from the SITOP UPS500 series. Some models have a serial port, others have a USB port. The models with USB port actually contain a serial-over-USB chip, so as far as this driver is concerned, all models are serial models. This driver should work with all models in the SITOP UPS500 series, as long as your kernel has support for the serial port device (see section *USB driver* below). NOTE: This driver has only been tested with the SITOP UPS500S-2.5 with USB port (Siemens product number 6EP1933-2EC41). DEVICE SETTINGS --------------- The UPS is configured via DIP-switches. For correct functioning in combination with NUT, set the DIP-switches to the following: *switch 1-4*:: Choose whatever suits your situation. Any combination will work with NUT. *switch 5* (=> / t):: Set to OFF (t). This ensures that the UPS will not cut power unless NUT tells it to do so (or unless the batteries are exhausted). *switch 6-10* (delay):: Set to OFF (minimum delay). Setting a higher delay will actually also work, but any command from NUT will be delayed as well before being executed by the UPS. With the minimum setting, it will already take 5 seconds before a command from NUT is executed. *switch 11* (INTERR.):: Set to ON (interrupt the output after the timer expires). This ensures that the UPS briefly interrupts the output power in response to the shutdown.return command. See the section *Instant Commands* below. *switch 12* (ON/OFF):: set to ON (enable the UPS functionality). Without this, the UPS will never supply power from its batteries. USB driver ---------- The USB-versions of the UPS contain an FTDI USB-to-serial converter chip. It is programmed with a non-standard product ID (for example _0403:e0e3_), but can still be used with the normal `ftdi_sio` driver. NOTE: The following hints may be specific to GNU/Linux. Use *lsusb* to figure out which product ID is used in your model, and replace all occurrences of _e0e3_ in the following examples with the actual Product ID. .... modprobe ftdi_sio echo 0403 e0e3 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id .... If your system uses *udev*, this can be automated via an *udev* rule: ---- ACTION=="add", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="e0e3", \ RUN+="/sbin/modprobe ftdi_sio", \ RUN+="/bin/sh -c 'echo 0403 e0e3 > /sys/bus/usb-serial/drivers/ftdi_sio/new_id'" ---- You can use the following udev rule to obtain a predictable device name, for example `/dev/ttyUPS`: ---- SUBSYSTEM=="tty" ATTRS{idVendor}=="0403", ATTRS{idProduct}=="e0e3" SYMLINK+="ttyUPS" ---- POLLING ------- The UPS does not have a special 'get status' command. Instead, it continuously sends out status update messages (tens of messages per second). Every *pollinterval*, these messages are read from the serial port buffer. In order to react quickly on status changes from the UPS, and to prevent the serial buffer from overflowing, *pollinterval* should be set to a relatively low value. The recommended value is 1 (second). EXTRA ARGUMENTS --------------- This driver supports the following optional settings: *max_polls_without_data*='num':: The serial port is polled periodically for new data (see *Polling*). If there is no valid new data after 'num' polls, it is assumed that communication with the UPS is lost. + The default value is '2'. Lower values may cause spurious 'Data stale' messages, especially at startup. INSTANT COMMANDS ---------------- *shutdown.return*:: The behavior of this command depends on the line state: * *on line*: after 5 seconds (or longer, if DIP switches 6-10 are not OFF), the UPS will shut off its output. After another 5 seconds, the output is activated again. * *on battery*: after 5 seconds (or longer, if DIP switches 6-10 are not OFF), the UPS will shut off its output. The output will stay off, until the line voltage has returned. *shutdown.stayoff*:: The behavior of this command depends on the line state: * *on line*: after 5 seconds (or longer, if DIP switches 6-10 are not OFF), the UPS will shut off its output. The output stays off, until the line voltage has been removed for at least 1 second, and has been re-applied. * *on battery*: this command behaves the same as *shutdown.return*. INSTALLATION ------------ Make sure that your operating system has created a serial device for the UPS. See the section *USB driver* for more information. Next, make sure that NUT has access rights to this device file. For example, by creating an udev rule that grants permission to the NUT user, or by adding the NUT user to a user group that can access serial devices (e.g. the *dialout* group on Debian-based systems). DIAGNOSTICS ----------- You can verify the correct functioning of the hardware, by monitoring the serial port with a terminal program, for example `picocom`: .... :; picocom -b 9600 -d 8 -p n /dev/ttyUPS .... NUT must not be running when you do this. You should now see a continuous stream of 5-character texts coming in, for example: .... BUFRD BA>85 DC_OK .... To exit picocom, use Ctrl-A Ctrl-X. KNOWN ISSUES AND BUGS --------------------- *Untested models*:: As mentioned under *Supported hardware*, this driver has not been tested with all models in the SITOP UPS500 series. *Data stale messages*:: The firmware in these UPSes is quite buggy. After sending data to the UPS, it sometimes stops sending status updates. This driver tries to prevent this (e.g. by sending commands twice, and by sending additional LF characters after each command). + Once the UPS is in this state, communication can only be restored by rebooting the UPS, or by unplugging and reconnecting the USB cable. + During normal operation, no commands are sent to the UPS at all (only at shutdown), so this issue is expected to have little impact on usability. + It is not certain if the serial models are affected by this issue as well. AUTHOR ------ Matthijs H. ten Berge SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upsmon.conf.txt0000644000200500020050000006263415001555412013761 00000000000000UPSMON.CONF(5) ============== NAME ---- upsmon.conf - Configuration for Network UPS Tools upsmon client DESCRIPTION ----------- This file's primary job is to define the systems that linkman:upsmon[8] will monitor, and to tell it how to shut down the system when necessary. It will contain passwords, so keep it secure. Ideally, only the `upsmon` process should be able to read it. A minimal configuration should include at least one `MONITOR` instruction, `MINSUPPLIES` (may be '0' if this system is only monitoring other NUT servers), and a `POWERDOWNFLAG` if this machine is a "primary" system connected to the UPS and drives its late-shutdown power-off command in case of an emergency. Additionally, other optional configuration values can be set in this file. IMPORTANT NOTES --------------- * Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message). * Balance the run-time user permissions to access the file (and perhaps the directory it is in) for only `upsmon` to be able to read it; write access is not needed. It is common to use `chown root:nut` and `chmod 640` to set up acceptable file permissions. - Packages (and build recipes) typically prepare one set of user and group accounts for NUT. Custom builds with minimal configuration might even use `nobody:nogroup` or similar, which is inherently insecure. - On systems with extra security concerns, NUT drivers, data server, and any other monitoring, logging, etc. clients, should run as separate user accounts. This would need some daemons to use customized `user`, `group`, `RUN_AS_USER` and/or `RUN_AS_GROUP` settings to override the single built-in value. - Keep in mind the security of also any backup copies of this file, e.g. the archive files it might end up in. CONFIGURATION DIRECTIVES ------------------------ *DEADTIME* 'seconds':: upsmon allows a UPS to go missing for this many seconds before declaring it "dead". The default is 15 seconds. + upsmon requires a UPS to provide status information every few seconds (see POLLFREQ and POLLFREQALERT) to keep things updated. If the status fetch fails, the UPS is marked stale. If it stays stale for more than DEADTIME seconds, the UPS is marked dead. + A dead UPS that was last known to be on battery is assumed to have changed to a low battery condition. This may force a shutdown if it is providing a critical amount of power to your system. This seems disruptive, but the alternative is barreling ahead into oblivion and crashing when you run out of power. + Note: DEADTIME should be a multiple of POLLFREQ and POLLFREQALERT. Otherwise, you'll have "dead" UPSes simply because upsmon isn't polling them quickly enough. Rule of thumb: take the larger of the two POLLFREQ values, and multiply by 3. *FINALDELAY* 'seconds':: When running in primary mode, upsmon waits this long after sending the NOTIFY_SHUTDOWN to warn the users. After the timer elapses, it then runs your SHUTDOWNCMD. By default this is set to 5 seconds. + If you need to let your users do something in between those events, increase this number. Remember, at this point your UPS battery is almost depleted, so don't make this too big. + Alternatively, you can set this very low so you don't wait around when it's time to shut down. Some UPSes don't give much warning for low battery and will require a value of 0 here for a safe shutdown. + NOTE: If FINALDELAY on the secondary is greater than HOSTSYNC on the primary, the primary will give up waiting for that secondary upsmon to disconnect. *HOSTSYNC* 'seconds':: upsmon will wait up to this many seconds in primary mode for the secondaries to disconnect during a shutdown situation. By default, this is 15 seconds. + When a UPS goes critical (on battery + low battery, or "FSD": forced shutdown), the secondary systems are supposed to disconnect and shut down right away. The HOSTSYNC timer keeps the primary upsmon from sitting there forever if one of the secondaries gets stuck. + This value is also used to keep secondary systems from getting stuck if the primary fails to respond in time. After a UPS becomes critical, the secondary will wait up to HOSTSYNC seconds for the primary to set the FSD flag. If that timer expires, the secondary upsmon will assume that the primary (or communications path to it) is broken and will shut down anyway. + This keeps the secondaries from shutting down during a short-lived status change to "OB LB" and back that the secondaries see but the primary misses. *MINSUPPLIES* 'num':: Set the number of power supplies that must be receiving power to keep this system running. Normal computers have just one power supply, so the default value of 1 is acceptable. + Large/expensive server type systems usually have more, and can run with a few missing. The HP NetServer LH4 can run with 2 out of 4, for example, so you'd set it to 2. The idea is to keep the box running as long as possible, right? + Obviously you have to put the redundant supplies on different UPS circuits for this to make sense! See big-servers.txt in the docs subdirectory for more information and ideas on how to use this feature. + Also see the section on "power values" in linkman:upsmon[8]. *MONITOR* 'system' 'powervalue' 'username' 'password' 'type':: Each UPS that you need to be monitor should have a MONITOR line. Not all of these need supply power to the system that is running upsmon. You may monitor other systems if you want to be able to send notifications about status changes on them. + You must have at least one MONITOR directive in `upsmon.conf`. + * 'system' is a UPS identifier. It is in this form: + +[@[:]]+ + The default hostname is "localhost". Some examples: + - "su700@mybox" means a UPS called "su700" on a system called "mybox". This is the normal form. - "fenton@bigbox:5678" is a UPS called "fenton" on a system called "bigbox" which runs linkman:upsd[8] on port "5678". + * 'powervalue' is an integer representing the number of power supplies that the UPS feeds on this system. Most normal computers have one power supply, and the UPS feeds it, so this value will be 1. You need a very large or special system to have anything higher here. + You can set the 'powervalue' to 0 if you want to monitor a UPS that doesn't actually supply power to this system. This is useful when you want to have upsmon do notifications about status changes on a UPS without shutting down when it goes critical. + * The 'username' and 'password' on this line must match an entry in the `upsd` server system's linkman:upsd.users[5] file. + If your username is "observer" and your password is "abcd", the MONITOR line might look like this (likely on a remote secondary system): + ---- MONITOR myups@bigserver 1 observer abcd secondary ---- + Meanwhile, the `upsd.users` on `bigserver` would look like this: + ---- [observer] password = abcd upsmon secondary [upswired] password = blah upsmon primary ---- + And the copy of upsmon on that bigserver would run with the primary configuration: + ---- MONITOR myups@bigserver 1 upswired blah primary ---- + * The 'type' refers to the relationship with linkman:upsd[8]. It can be either "primary" or "secondary". See linkman:upsmon[8] for more information on the meaning of these modes. The mode you pick here also goes in the `upsd.users` file, as seen in the example above. *NOCOMMWARNTIME* 'seconds':: upsmon will trigger a NOTIFY_NOCOMM after this many seconds if it can't reach any of the UPS entries in this configuration file. It keeps warning you until the situation is fixed. By default this is 300 seconds. *POLLFAIL_LOG_THROTTLE_MAX* 'count':: upsmon normally reports polling failures for each device that are in place for each POLLFREQ loop (e.g. "Data stale" or "Driver not connected") to system log as configured. If your devices are expected to be AWOL for an extended timeframe, you can use this throttle to reduce the stress on syslog traffic and storage, by posting these messages only once in every several loop cycles, and when the error condition has changed or cleared. + A negative value means standard behavior (log on every loop, effectively same as when `max=1`), and a zero value means to never repeat the message (log only on start and end/change of the failure state). + Note that this throttle only applies to one latest-active error state per monitored device. *NOTIFYCMD* 'command':: upsmon calls this to send messages when things happen. + This command is called with the full text of the message as one argument. The environment string NOTIFYTYPE will contain the type string of whatever caused this event to happen. + If you need to use linkman:upssched[8], then you must make it your NOTIFYCMD by listing it here. + Note that this is only called for NOTIFY events that have EXEC set with NOTIFYFLAG. See NOTIFYFLAG below for more details. + Making this some sort of shell script might not be a bad idea. For more information and ideas, see docs/scheduling.txt + Remember, this command also needs to be one element in the configuration file, so if your command has spaces, then wrap it in quotes. + +NOTIFYCMD "/path/to/script --foo --bar"+ + This script is run in the background--that is, upsmon forks before it calls out to start it. This means that your NOTIFYCMD may have multiple instances running simultaneously if a lot of stuff happens all at once. Keep this in mind when designing complicated notifiers. *NOTIFYMSG* 'type' 'message':: upsmon comes with a set of stock messages for various events. You can change them if you like. NOTIFYMSG ONLINE "UPS %s is getting line power" NOTIFYMSG ONBATT "Someone pulled the plug on %s" + Note that +%s+ is replaced with the identifier of the UPS in question. + The message must be one element in the configuration file, so if it contains spaces, you must wrap it in quotes. NOTIFYMSG NOCOMM "Someone stole UPS %s" + Possible values for 'type': ONLINE;; UPS is back online ONBATT;; UPS is on battery LOWBATT;; UPS is on battery and has a low battery (is critical) FSD;; UPS is being shutdown by the primary (FSD = "Forced Shutdown") COMMOK;; Communications established with the UPS COMMBAD;; Communications lost to the UPS SHUTDOWN;; The system is being shutdown REPLBATT;; The UPS battery is bad and needs to be replaced NOCOMM;; A UPS is unavailable (can't be contacted for monitoring) NOPARENT;; `upsmon` parent process died - shutdown impossible CAL;; UPS calibration in progress NOTCAL;; UPS calibration finished OFF;; UPS administratively OFF or asleep NOTOFF;; UPS no longer administratively OFF or asleep BYPASS;; UPS on bypass (powered, not protecting) NOTBYPASS;; UPS no longer on bypass ECO;; UPS in ECO or similar mode (as defined and named by vendor); for more details see linkman:upsmon[8]. NOTECO;; UPS no longer in ECO mode (see above) ALARM;; UPS has one or more active alarms (check ups.alarm); for this notification, the `message` can contain a second `%s` placeholder to substitute the current value of `ups.alarm`. NOTALARM;; UPS is no longer in an alarm state (no active alarms) OVER;; UPS is overloaded NOTOVER;; UPS is no longer overloaded TRIM;; UPS is trimming incoming voltage NOTTRIM;; UPS is no longer trimming incoming voltage BOOST;; UPS is boosting incoming voltage NOTBOOST;; UPS is no longer boosting incoming voltage OTHER;; UPS has at least one unclassified `ups.status` token; for this notification, the `message` can contain a second `%s` placeholder to substitute the current collection of such tokens. NOTOTHER;; UPS has no unclassified status tokens anymore SUSPEND_STARTING;; OS is entering sleep/suspend/hibernate mode SUSPEND_FINISHED;; OS just finished sleep/suspend/hibernate mode, de-activating obsolete UPS readings to avoid an unfortunate shutdown *NOTIFYFLAG* 'type' 'flag'[+'flag']...:: By default, upsmon sends walls global messages to all logged in users) via `/bin/wall` and writes to the syslog when things happen. Except for Windows where upsmon only writes to the Event Log by default. You can change this. + Examples: + NOTIFYFLAG ONLINE SYSLOG NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC + Possible values for the flags: + SYSLOG;; Write the message to the syslog WALL;; Write the message to all users with /bin/wall EXEC;; Execute NOTIFYCMD (see above) with the message IGNORE;; Don't do anything + If you use IGNORE, don't use any other flags on the same line. *POLLFREQ* 'seconds':: Normally upsmon polls the linkman:upsd[8] server every 5 seconds. If this is flooding your network with activity, you can make it higher. You can also make it lower to get faster updates in some cases. + There are some catches. First, if you set the POLLFREQ too high, you may miss short-lived power events entirely. You also risk triggering the DEADTIME (see above) if you use a very large number. + Second, there is a point of diminishing returns if you set it too low. While upsd normally has all of the data available to it instantly, most drivers only refresh the UPS status once every 2 seconds. Polling any more than that usually doesn't get you the information any faster. *POLLFREQALERT* 'seconds':: This is the interval that upsmon waits between polls if any of its UPSes are on battery. You can use this along with POLLFREQ above to slow down polls during normal behavior, but get quicker updates when something bad happens. + This should always be equal to or lower than the POLLFREQ value. By default it is also set 5 seconds. + The warnings from the POLLFREQ entry about too-high and too-low values also apply here. *POWERDOWNFLAG* 'filename':: upsmon creates this file when running in primary mode when the UPS needs to be powered off. You should check for this file in your late shutdown scripts and call `upsdrvctl shutdown` if it exists; note that `upsmon -K` may be called for this effect, if NUT configuration files remain readable at that point (file systems mostly unmounted or changed to read-only). + Historically it was often `/etc/killpower` but nowadays you may want it in a temporary filesystem (e.g. under `/run` or `/run/nut` location). + Note that double backslashes must be used for Windows paths, e.g. `C:\\Temp\\killpower` (modern Windows may also accept forward slashes like `C:/Temp/killpower` but YMMV). + This is done to forcibly reset the secondary systems, so they don't get stuck at the "halted" stage even if the power returns during the shutdown process. This usually does not work well on contact-closure UPSes that use the genericups driver. + WARNING: The `upsmon` binary program does not have a built-in default, so this setting MUST be specified in the configuration, in order for the late shutdown integration to work on the particular primary-mode system! + See the config-notes.txt file in the docs subdirectory for more information. Refer to the section: [[UPS_shutdown]] "Configuring automatic shutdowns for low battery events", or refer to the online version. *OFFDURATION* 'seconds':: NUT supports an "administrative OFF" for power devices which can be managed to turn off their application workload, while the UPS or ePDU remains accessible for monitoring and management. This toggle allows to delay propagation of such state into a known loss of a feed (possibly triggering FSD on `upsmon` clients which `MONITOR` the device and are in fact still alive -- e.g. with multiple power sources or because they as the load are not really turned off), because when some devices begin battery calibration, they report "OFF" for a few seconds and only then they might report "CAL" after switching all the power relays -- thus causing false-positives for `upsmon` FSD trigger. + A negative value means to disable decreasing the counter of working power supplies in such cases, and a zero makes the effect of detected "OFF" state immediate. Built-in default value is 30 (seconds), to put an "OFF" state into effect (decrease known-fed supplies count) if it persists for this many seconds. + NOTE: so far we support the device reporting an "OFF" state which usually means completely un-powering the load; a bug-tracker issue was logged to design similar support for just some manageable outlets or outlet groups. *OVERDURATION* 'seconds':: This setting handles how a UPS that is overloaded should be treated in situations when it is not fully communicating. Because such a UPS may be in a potentially severe state, some users may want their systems to be shutdown either immediately or after a set timeout has elapsed. The OVERDURATION setting defines this timeout (in seconds), after which an overloaded UPS that is not communicating will be considered critical. + A negative value means an overloaded UPS will never be considered critical (at least not because of the overload itself). A value of zero means the UPS will instantly be considered critical when overloaded and not communicating. Built-in default value is -1 (seconds). + NOTE: This setting only affects the behavior when a UPS is both overloaded and not communicating. When the UPS is communicating normally, an overload condition may raise notifications but won't trigger a system shutdown on its own. *OBLBDURATION* 'seconds':: NUT normally raises alarms for immediate shutdown (FSD) for consumers of an UPS known to be on battery ("OB") and achieving the low battery status ("LB"), if that is their last remaining power source to satisfy their `MINSUPPLIES` setting. In some special cases, users may want to delay raising the alarm (using the `OBLBDURATION` option) at their discretion and risk of an ungraceful shutdown. + A positive value puts "OB LB" state into effect only if it persists for this many seconds. A non-positive value makes the FSD effect of detected "OB LB" state immediate. Built-in default value is 0 (seconds). + NOTE: If both `OBLBDURATION` and `HOSTSYNC` options are set on the same (secondary) `upsmon` client system, and `HOSTSYNC` is shorter, it would be effectively ignored: `upsmon` would wait for up to `OBLBDURATION` seconds for the "OB LB" state to clear, and then the secondary client logic would fall through to immediate shutdown. If the primary system issues an FSD on this UPS, that would take an even higher-priority effect as soon as seen. *RBWARNTIME* 'seconds':: When a UPS says that it needs to have its battery replaced, upsmon will generate a NOTIFY_REPLBATT event. By default, this happens every 43200 seconds (12 hours). + If you need another value, set it here. *ALARMCRITICAL* '0 | 1':: NUT normally considers UPS with active alarms as volatile, meaning they are observed more closely and may be considered critical/dead earlier than in other regular UPS statuses. This is especially true for no-communication situations, where UPS in an `ALARM` status will be considered lost and system shutdowns may be triggered as a product. + As there is no common standard for what constitutes an alarm, such alarm states may in fact be mundane in nature and the behavior above unwanted due to possibly resulting in unwarranted system shutdowns. + When this setting is disabled, `upsmon` will consider a UPS in an alarm state as not volatile and make it treat the `ALARM` status as any other. *RUN_AS_USER* 'username':: upsmon normally runs the bulk of the monitoring duties under another user ID after dropping root privileges. On most systems this means it runs as "nobody", since that's the default from compile-time. + The catch is that "nobody" can't read your upsmon.conf, since by default it is installed so that only root can open it. This means you won't be able to reload the configuration file, since it will be unavailable. + The solution is to create a new user just for upsmon, then make it run as that user. I suggest "nutmon", but you can use anything that isn't already taken on your system. Just create a regular user with no special privileges and an impossible password. + Then, tell upsmon to run as that user, and make `upsmon.conf` readable by it. Your reloads will work, and your config file will stay secure. + This file should not be writable by the upsmon user, as it would be possible to exploit a hole, change the SHUTDOWNCMD to something malicious, then wait for upsmon to be restarted. *SHUTDOWNCMD* 'command':: upsmon runs this command when the system needs to be brought down. If it is a secondary, it will do that immediately whenever the current overall power value drops below the MINSUPPLIES value above. + When upsmon is a primary, it will allow any secondaries to log out before starting the local shutdown procedure. + Note that the command needs to be one element in the config file. If your shutdown command includes spaces, then put it in quotes to keep it together, i.e.: SHUTDOWNCMD "/sbin/shutdown -h +0" *SHUTDOWNEXIT* 'boolean|number':: After initiating shutdown, should this upsmon daemon itself exit? By doing so NUT secondary systems can tell the NUT primary that it can proceed with its own shutdown and eventually tell the UPS to cut power for the load. ("Yes" by default) + Some "secondary" systems with workloads that take considerable time to stop (e.g. virtual machines or large databases) can benefit from reporting (by virtue of logging off the data server) that they are ready for the "primary" system to begin its own shutdown and eventually to tell the UPS to cut the power -- not as soon as they have triggered their own shutdown, but at a later point (e.g. when the upsmon service is stopped AFTER the heavier workloads). + Note that the actual ability to complete such shutdown depends on the remaining battery run-time at the moment when UPS power state becomes considered critical and the shutdowns begin. You may also have to tune `HOSTSYNC` on the NUT primary to be long enough for those secondaries to stop their services. In practice, it may be worthwhile to investigate ways to trigger shutdowns earlier on these systems, e.g. by setting up `upssched` integration, or `dummy-ups` driver with overrides for stricter `battery.charge` or `battery.runtime` triggers than used by the rest of your servers. + This option supports Boolean-style strings (yes/on/true or no/off/false) or numbers to define a delay (in seconds) between calling `SHUTDOWNCMD` and exiting the daemon. Zero means immediate exit (default), negative values mean never exiting on its own accord. *CERTPATH* 'certificate file or database':: When compiled with SSL support, you can enter the certificate path here. + With NSS:;; Certificates are stored in a dedicated database (data split in 3 files). Specify the path of the database directory. With OpenSSL:;; Directory containing CA certificates in PEM format, used to verify the server certificate presented by the upsd server. The files each contain one CA certificate. The files are looked up by the CA subject name hash value, which must hence be available. *CERTIDENT* 'certificate name' 'database password':: When compiled with SSL support with NSS, you can specify the certificate name to retrieve from database to authenticate itself and the password required to access certificate related private key. + NOTE: Be sure to enclose "certificate name" in double-quotes if you are using a value with spaces in it. *CERTHOST* 'hostname' 'certificate name' 'certverify' 'forcessl':: When compiled with SSL support with NSS, you can specify security directive for each server you can contact. + Each entry maps server name with the expected certificate name and flags indicating if the server certificate is verified and if the connection must be secure. + NOTE: Be sure to enclose "certificate name" in double-quotes if you are using a value with spaces in it. *CERTVERIFY* '0 | 1':: When compiled with SSL support, make upsmon verify all connections with certificates. + Without this, there is no guarantee that the upsd is the right host. Enabling this greatly reduces the risk of man-in-the-middle attacks. This effectively forces the use of SSL, so don't use this unless all of your upsd hosts are ready for SSL and have their certificates in order. + When compiled with NSS support of SSL, can be overridden for host specified with a CERTHOST directive. *FORCESSL* '0 | 1':: When compiled with SSL, specify that a secured connection must be used to communicate with upsd. + If you don't use 'CERTVERIFY 1', then this will at least make sure that nobody can sniff your sessions without a large effort. Setting this will make upsmon drop connections if the remote upsd doesn't support SSL, so don't use it unless all of them have it running. + When compiled with NSS support of SSL, can be overridden for host specified with a CERTHOST directive. *DEBUG_MIN* 'INTEGER':: Optionally specify a minimum debug level for `upsmon` daemon, e.g. for troubleshooting a deployment, without impacting foreground or background running mode directly. Command-line option `-D` can only increase this verbosity level. + NOTE: if the running daemon receives a `reload` command, presence of the `DEBUG_MIN NUMBER` value in the configuration file can be used to tune debugging verbosity in the running service daemon (it is recommended to comment it away or set the minimum to explicit zero when done, to avoid huge journals and I/O system abuse). Keep in mind that for this run-time tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files is applied instantly and overrides any previously set value, from file or CLI options, regardless of older logging level being higher or lower than the newly found number; a missing (or commented away) value however does not change the previously active logging verbosity. SEE ALSO -------- linkman:upsmon[8], linkman:upsd[8], linkman:nutupsdrv[8]. Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/tripplitesu.80000644000200500020050000000476215001555076013434 00000000000000'\" t .\" Title: tripplitesu .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "TRIPPLITESU" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" tripplitesu \- Driver for Tripp\-Lite SmartOnline (SU) UPS equipment .SH "SYNOPSIS" .sp \fBtripplitesu\fR \-h .sp \fBtripplitesu\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the tripplitesu driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports the Tripp Lite SmartOnline family (via the serial port)\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBlowbatt\fR=\fInum\fR .RS 4 Set the low battery warning threshold in percent at which shutdown is initiated by \fBupsmon\fR(8)\&. By default, the UPS may not report low battery until there are only a few seconds left\&. Common values are around 25\(em30\&. .RE .SH "AUTHOR" .sp Allan N\&. Hessenflow .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Other drivers for Tripp\-Lite hardware:" .sp \fBtripplite\fR(8), \fBtripplite_usb\fR(8), \fBusbhid-ups\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/solis.txt0000644000200500020050000000340115001555412012630 00000000000000SOLIS(8) ======== NAME ---- solis - Driver for Brazilian Microsol SOLIS UPS equipment SYNOPSIS -------- *solis* -h *solis* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the solis driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver has been tested with: * Solis 1000 VA * Solis 1500 VA * Solis 2000 VA * Solis 3000 VA * Back-UPS BZ1200-BR * Back-UPS BZ2200BI-BR All Solis models are sinusoidal on-line. In 2009, Schneider Electric acquired Microsol Technologies, and by 2012, the entire Microsol line of equipment was being sold under the APC brand. Newer devices may be better supported by linkman:microsol-apc[8] driver instead. EXTRA ARGUMENTS --------------- This driver support the following extra optional settings in the linkman:ups.conf[5]. *battext=*'n':: Default = 0, no extra battery, where `n` = Ampere*hour. *prgshut=*'n':: Default = 0, no programmable shutdown; `1` to enable one. COMMANDS -------- *shutdown.return*:: Shut down in .3 minutes and restart in .3 minutes after that. *shutdown.stayoff*:: Shut down in .3 minutes and do not return. ISSUES ------ The APC version of the Microsol protocol is slightly incompatible with the *solis* driver. As of version 0.62 of the *solis* driver, the driver will connect to the UPS, but some values are read incorrectly. AUTHOR ------ Silvino B. Magalhães SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Driver for newer devices under same brand: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ linkman:microsol-apc[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/ups.conf.txt0000644000200500020050000004301315001555412013235 00000000000000UPS.CONF(5) =========== NAME ---- ups.conf - UPS definitions for Network UPS Tools DESCRIPTION ----------- This file is read by the driver controller linkman:upsdrvctl[8], the UPS drivers which use the common core (see linkman:nutupsdrv[8]), linkman:nut-driver-enumerator[8], and the NUT data server linkman:upsd[8]. The file begins with global directives, and then each UPS has a section which contains a number of directives that set parameters for that UPS. A UPS section begins with the name of the UPS in brackets, and continues until the next UPS name in brackets or until EOF. The name "default" is used internally in linkman:upsd[8], so you can't use it in this file. You must define the 'driver' and 'port' elements for each entry. Anything after that in a section is optional. A simple example might look like this: [myups] driver = blazer_ser port = /dev/ttyS0 desc = "Web server UPS" A slightly more complicated version includes some extras for the hardware-specific part of the driver: [bigups] driver = apcsmart port = /dev/cua00 cable = 940-0095B sdtype = 2 desc = "Database server UPS" In this case, the linkman:apcsmart[8] driver will receive variables called "cable" and "sdtype" which have special meanings. See the man pages of your driver(s) to learn which variables are supported and what they do. Here is another example, when connecting a serial UPS on Windows: [windows-ups] driver = mge-shut port = "\\\\.\\COM10" desc = "UPS on a Windows machine" IMPORTANT NOTES --------------- * Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message). * Balance the run-time user permissions to access the file (and perhaps the directory it is in) for only `upsd` and the drivers to be able to read it; write access is not needed. It is common to use `chown root:nut` and `chmod 640` to set up acceptable file permissions. - Packages (and build recipes) typically prepare one set of user and group accounts for NUT. Custom builds with minimal configuration might even use `nobody:nogroup` or similar, which is inherently insecure. - On systems with extra security concerns, NUT drivers, data server should run as separate user accounts which would be members of one same group for shared access to local Unix socket files and the directory they are in, as well for reading `ups.conf`, but different groups for other configuration file access. This would need some daemons to use customized `user`, `group`, `RUN_AS_USER` and/or `RUN_AS_GROUP` settings to override the single built-in value. - Note that the monitoring, logging, etc. clients are networked-only. They do not need access to these files and directories, and can run as an independent user and group altogether. - Keep in mind the security of also any backup copies of this file, e.g. the archive files it might end up in. GLOBAL DIRECTIVES ----------------- *chroot*:: Optional. The driver will chroot(2) to this directory during initialization. This can be useful when securing systems. *driverpath*:: Optional. Path name of the directory in which the UPS driver executables reside. If you don't specify this, the programs look in a built-in default directory, which is often /usr/local/ups/bin. *statepath*:: Optional. Path name of the directory in which the UPS drivers should place their state sockets for local communication with `upsd` data server, rather than the default location that was compiled into the program, which is often /var/state/ups. + Note that the drivers must use the same path as `upsd`, so the data server would prefer this setting from `ups.conf` global section, if present, over its own in `upsd.conf`. + Environment variable `NUT_STATEPATH` set by caller can override this setting. *maxstartdelay*:: Optional. Same as the UPS field of the same name, but this is the default for UPSes that don't have the field. *maxretry*:: Optional. Specify the number of attempts to start the driver(s), in case of failure, before giving up. A delay of 'retrydelay' is inserted between each attempt. Caution should be taken when using this option, since it can impact the time taken by your system to start. + The default is 1 attempt. *nowait*:: Optional. Specify to upsdrvctl to not wait at all for the driver(s) to execute the request command. + The default (omission) is to wait. + It can be overridden by `NUT_IGNORE_NOWAIT` environment variable (e.g. used to work around certain issues with systemd otherwise). *retrydelay*:: Optional. Specify the delay between each restart attempt of the driver(s), as specified by 'maxretry'. Caution should be taken when using this option, since it can impact the time taken by your system to start. + The default is 5 seconds. *pollinterval*:: Optional. The status of the UPS will be refreshed after a maximum delay which is controlled by this setting. This is normally 2 seconds. This setting may be useful if the driver is creating too much of a load on your monitoring system or network. + Note that some drivers (such as linkman:usbhid-ups[8], linkman:snmp-ups[8] and linkman:nutdrv_qx[8]) also have an option called *pollfreq* which controls how frequently some of the less critical parameters are polled. Details are provided in the respective driver man pages. *synchronous*:: Optional. The drivers work by default in asynchronous mode initially but can fall back to synchronous mode if writes to server socket failed (i.e *synchronous=auto*). This means that all data are pushed by the driver on the communication socket to upsd (Unix socket on Unix, Named pipe on Windows) without waiting for these data to be actually consumed. With some HW, such as ePDUs, that can produce a lot of data, asynchronous mode may cause some congestion, resulting in the socket to be full, and the driver to appear as not connected. In such case, the driver will provide the following debug message: + write XX bytes to socket Y failed + By enabling the 'synchronous' flag (value = 'yes'), the driver will wait for data to be consumed by upsd, prior to publishing more. This can be enabled either globally or per driver. + The default of 'auto' acts like 'no' (i.e. asynchronous mode) for backward compatibility of the driver behavior, until communications fail with a "Resource temporarily unavailable" condition, which happens when the driver has many data points to send in a burst, and the server can not handle that quickly enough so the buffer fills up. *user*:: Optional. Overrides the compiled-in default unprivileged username for all NUT device drivers. See the discussion of the `-u` option in linkman:nutupsdrv[8] for details. *group*:: Optional. Overrides the compiled-in (and/or global-section) default unprivileged group name for all NUT device drivers, used for the socket file access. See the discussion of the `-g` option in linkman:nutupsdrv[8] for details. This may be specifically useful for ensuring access to dynamic device filesystem nodes, such as USB (or serial-over-USB) hot-plug support, or with device filesystems re-generated by an OS for every reboot. *debug_min* 'INTEGER':: Optional. Specify a minimum debug level for all driver daemons, e.g. for troubleshooting a deployment, without impacting foreground or background running mode directly. Command-line option `-D` can only increase this verbosity level. *LIBUSB_DEBUG* 'INTEGER':: Optional. For run-time troubleshooting of USB-capable NUT drivers, you can specify verbosity of LibUSB specific debugging as a numeric value such as `4` ("All messages are emitted"). Should not have any practical impact on other NUT drivers. + For more details, including the currently supported values for your version of the library, see e.g.: * https://libusb.sourceforge.io/api-1.0/ * link:https://libusb.sourceforge.io/api-1.0/group\__libusb\__lib.html[https://libusb.sourceforge.io/api-1.0/group\__libusb__lib.html] /////////////////// // EDITOR NOTE: There are no backslashes in the URL above, just that // asciidoc sees them as "emphasis" markup, they had to be escaped. // If a link from this asciidoc source file is needed, please visit: // https://libusb.sourceforge.io/api-1.0/group__libusb__lib.html /////////////////// UPS FIELDS ---------- *driver*:: Required. This specifies which program will be monitoring this UPS. You need to specify the one that is compatible with your hardware. See linkman:nutupsdrv[8] for more information on drivers in general and pointers to the man pages of specific drivers. *port*:: Required. This is the serial port where the UPS is connected. On a Linux system, the first serial port usually is '/dev/ttyS0'. On FreeBSD and similar systems, it probably will be '/dev/cuaa0'. On Windows, the first serial port will be "\\\\.\\COM1" (note the escaped slashes). *user*:: Optional. Overrides the compiled-in (and/or global-section) default unprivileged username for a particular NUT device driver. See the discussion of the `-u` option in linkman:nutupsdrv[8] for details. This may be specifically useful for ensuring access to dynamic device filesystem nodes, such as USB (or serial-over-USB) hot-plug support, or with device filesystems re-generated by an OS for every reboot. *group*:: Optional. Overrides the compiled-in (and/or global-section) default unprivileged group name for a particular NUT device driver, used for the socket file access. See the discussion of the `-g` option in linkman:nutupsdrv[8] for details. This may be specifically useful for ensuring access to dynamic device filesystem nodes, such as USB (or serial-over-USB) hot-plug support, or with device filesystems re-generated by an OS for every reboot. *sdorder*:: Optional. When you have multiple UPSes on your system, you usually need to turn them off in a certain order. upsdrvctl shuts down all the 0s, then the 1s, 2s, and so on. To exclude a UPS from the shutdown sequence, set this to -1. + The default value for this parameter is 0. *sdcommands*:: Optional. Comma-separated list of instant command name(s) to send to the UPS when you request its shutdown. + Default logic is built into each driver (where supported) and can be referenced here as the `shutdown.default` value. + The primary use-case is for devices whose drivers "natively" support trying several commands, but the built-in order of those calls a command that is mis-handled by the specific device model (so the handling is reported as successful and the loop stops, but nothing happens as far as the load power-down is concerned). + Another use-case is differentiation of automated power-off scenarios where the UPS and its load should stay "OFF" (e.g. by building emergency power-off) vs. those where the load should return to work automatically when it is safe to do so. NOTE: This would *currently* need editing of `ups.conf` for such cases before `nutshutdown` sees the file; but could be better automated in future NUT releases. + NOTE: User-provided commands may be something other than actual shutdown, e.g. a beeper to test that the INSTCMD happened such and when expected, and the device was contacted, without impacting the load fed by the UPS. *allow_killpower*:: Optional. This allows you to request `driver.killpower` instant command, to immediately call the driver-specific default implementation of `upsdrv_shutdown()` method, for same effect as when a NUT driver is started with `-k` command-line flag. This option can be toggled with linkman:upsrw[8] as `driver.flag.allow_killpower` during run-time. *desc*:: Optional. This allows you to set a brief description that upsd will provide to clients that ask for a list of connected equipment. *nolock*:: Optional. When you specify this, the driver skips the port locking routines every time it starts. This may allow other processes to seize the port if you start more than one accidentally. + You should only use this if your system won't work without it. + This may be needed on Mac OS X systems. *ignorelb*:: Optional. When you specify this, the driver ignores a low battery condition flag that is reported by the UPS (some devices will switch off almost immediately after setting this flag, or will report this as soon as the mains fails). Instead it will use either of the following conditions to determine when the battery is low: battery.charge < battery.charge.low battery.runtime < battery.runtime.low + The idea is to set the battery.charge.low and/or battery.runtime.low levels in *ups.conf* to a value that gives enough time to cleanly shutdown your system: override.battery.charge.low = 30 override.battery.runtime.low = 180 + In order for this to work, your UPS should be able to (reliably) report charge and/or runtime remaining on battery. Use with caution! *maxstartdelay*:: Optional. This can be set as a global variable above your first UPS definition and it can also be set in a UPS section. This value controls how long upsdrvctl will wait for the driver to finish starting. This keeps your system from getting stuck due to a broken driver or UPS. + Note that after this time `upsdrvctl` would just move along with its business (whether retrying the same driver if `maxretry>1`, or trying another driver if starting them all, or just eventually exit); however, each such most recently started "stuck" driver process may be further initializing in the background, and might even succeed eventually. + They would not be actively killed by `upsdrvctl` after this timeout expires. + The default is 75 seconds. *maxretry*:: Optional. This can be set as a global variable above your first UPS definition and it can also be set in a UPS section. See explanation above, in the global section. *retrydelay*:: Optional. This can be set as a global variable above your first UPS definition and it can also be set in a UPS section. See explanation above, in the global section. *synchronous*:: Optional. Same as the global directive of the same name, but this is for a specific device. *usb_set_altinterface*[='altinterface']:: Optional. Force the USB code to call `usb_set_altinterface(0)`, as was done in NUT 2.7.2 and earlier. This should not be necessary, since the default for `bAlternateSetting` (as shown in lsusb) is zero on all USB devices seen to date. However, this redundant call to `usb_set_altinterface()` prevents certain UPSes from working on Mac OS X. If your UPS requires explicitly setting the alternate interface, include this flag, and email the nut-upsdev list with details about your UPS and operating system. *usb_config_index*:: *usb_hid_rep_index*:: *usb_hid_desc_index*:: *usb_hid_ep_in*:: *usb_hid_ep_out*:: Optional. Force use of specific interface, endpoint, descriptor index etc. numbers, rather than defaulting to 0 (rarely other values in certain drivers for some devices known to use non-zero numbers). Specified as a hexadecimal number. + As a rule of thumb for `usb_hid_desc_index` discovery, you can see larger `wDescriptorLength` values (roughly 600+ bytes) in reports of `lsusb` or similar tools. *default.*:: Optional. Set a default value for which is used in case the UPS doesn't provide a value, but will be overwritten if a value is available from the UPS: default.input.voltage.nominal = 230 + The above will report the nominal input voltage to be 230, unless the UPS tells us differently. *override.*:: Optional. Set a value for that overrides any value that may be read from the UPS. Used for overriding values from the UPS that are clearly wrong (some devices report wrong values for battery voltage for instance): override.battery.voltage.nominal = 12 + Use with caution! This will only change the appearance of the variable to the outside world, internally in the UPS the original value is used. All other fields are passed through to the hardware-specific part of the driver. See those manuals for the list of what is allowed. *debug_min* 'INTEGER':: Optional. Specify a minimum debug level for this driver daemon, e.g. for troubleshooting a deployment, without impacting foreground or background running mode directly. If the global `debug_min` is also set, this driver-level setting overrides it. Command-line option `-D` can only increase this verbosity level. *LIBUSB_DEBUG* 'INTEGER':: Optional. For run-time troubleshooting of USB-capable NUT drivers, you can specify verbosity of LibUSB specific debugging as a numeric value such as `4` ("All messages are emitted"). + For more details, including the currently supported values for your version of the library, see e.g.: * https://libusb.sourceforge.io/api-1.0/ * link:https://libusb.sourceforge.io/api-1.0/group\__libusb\__lib.html[https://libusb.sourceforge.io/api-1.0/group\__libusb__lib.html] /////////////////// // EDITOR NOTE: There are no backslashes in the URL above, just that // asciidoc sees them as "emphasis" markup, they had to be escaped. // If a link from this asciidoc source file is needed, please visit: // https://libusb.sourceforge.io/api-1.0/group__libusb__lib.html /////////////////// INTEGRATION ----------- linkman:upsdrvctl[8] uses this file to start and stop the drivers. The drivers themselves also obtain configuration data from this file. Each driver looks up its section and uses that to configure itself. linkman:upsd[8] learns about which UPSes are installed on this system by reading this file. If this system is called "doghouse" and you have defined a UPS in your *ups.conf* called "snoopy", then you can monitor it from linkman:upsc[8] or similar as "snoopy@doghouse". SEE ALSO -------- linkman:upsd[8], linkman:nutupsdrv[8], linkman:upsdrvctl[8], linkman:upsdrvsvcctl[8] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_get_serial_ports_list.30000644000200500020050000000762115001555063017167 00000000000000'\" t .\" Title: nutscan_get_serial_ports_list .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_GET_SERIAL_P" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_get_serial_ports_list \- Get a port list name from a range of port\&. .SH "SYNOPSIS" .sp .nf #include char ** nutscan_get_serial_ports_list(const char *ports_range); .fi .SH "DESCRIPTION" .sp The \fBnutscan_get_serial_ports_list()\fR function returns a null terminated array of strings generated from a port range\&. .sp The \fIports_range\fR may be one of: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a single character from 0 to 9 or a to z, representing a serial communication port depending on the operating system\&. For instance: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 0 is converted to /dev/ttyS0 and /dev/ttyUSB0 on Linux; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 1 is converted to COM1 on Windows; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} c is converted to /dev/ttyc on Solaris\&... .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a range of character in the form X\-Y\&. For instance .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 0\-1 will be converted to /dev/ttyS0, /dev/ttyS1, /dev/ttyUSB0 and /dev/ttyUSB1 on Linux; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} 1\-3 will be converted to COM1, COM2 and COM3 on Windows; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a\-c will be converted to /dev/ttya, /dev/ttyb and /dev/ttyc on Solaris\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a single port name (/dev/ttyS5, COM4\&...)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a list of port names separated with commas: /dev/ttyS0,/dev/ttyS2,/dev/ttyS4 or COM1,COM3\&... .RE .sp The returned array can be used in a call to \fBnutscan_scan_eaton_serial\fR to get the serial\-port device on a system\&. .SH "RETURN VALUE" .sp The \fBnutscan_get_serial_ports_list()\fR function returns NULL if an error occurred (invalid port range) or a pointer to a NULL\-terminated array of strings on success\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-serial\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_eaton_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_display_ups_conf\fR(3) nut-2.8.3/docs/man/upsset.cgi.txt0000644000200500020050000000626315001555412013574 00000000000000UPSSET.CGI(8) ============= NAME ---- upsset.cgi - Web-based UPS administration program SYNOPSIS -------- *upsset.cgi* NOTE: As a CGI program, this should be invoked through your web server. If you run it from the command line, it will sit there until you give it input resembling a POST request. DESCRIPTION ----------- *upsset.cgi* lets you access many administrative functions within the UPS software from your web browser. You can change settings and invoke instant commands where available. CHANGING SETTINGS ----------------- Some UPS hardware allows you to change certain variables to other values. To see what's available, pick a UPS from the chooser and select "settings", then select "View" to update the page. You should see a list of items with the descriptions on the left side and the possible options or input spaces on the right. After changing something, be sure to "Save changes" to update the values in your UPS. If your UPS doesn't support any read/write variables, there will be nothing to do on this page. Setting values in read/write variables can also be done from the command line with linkman:upsrw[8]. INSTANT COMMANDS ---------------- Some UPS hardware also has provisions for performing certain actions at the user's command. These include battery tests, battery calibration, front panel tests (beep!) and more. To access this section, do as above, but pick "Commands" as the function. If your UPS supports any instant commands, they will be listed in a chooser widget. Pick the one you like and "Issue command" to make it happen. NOTE: some dangerous commands like "Turn off load" may not happen right away. This is a feature, not a bug. The apcsmart driver and some others require that you send this command twice within a short window in order to make it happen. This is to keep you from accidentally killing your systems by picking the wrong one. To actually turn off the load, you have to send the command once, then send it again after 3 seconds elapse but before 15 seconds pass. If you do it too quickly or slowly, you have to wait at least 3 seconds but not 15 seconds again. You can also invoke instant commands from the command line with linkman:upscmd[8]. ACCESS CONTROL -------------- It sends commands and settings via the server linkman:upsd[8] to your driver, which manages the hardware for you. You must use credentials defined in linkman:upsd.users[5] file on that data server with appropriate permissions. upsset will only talk to linkman:upsd[8] servers that have been defined in your linkman:hosts.conf[8]. If it complains about "Access to that host is not authorized", check your hosts.conf first. SECURITY -------- upsset will not run until you convince it that your CGI directory has been secured. This is due to the possibility of someone using upsset to try password combinations against your linkman:upsd[8] server. See the example `upsset.conf` file for more information on how you do this. The short explanation is--if you can't lock it down, don't try to run it. FILES ----- linkman:hosts.conf[5], linkman:upsset.conf[5] SEE ALSO -------- Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/microsol-apc.80000644000200500020050000000741515001555074013434 00000000000000'\" t .\" Title: microsol-apc .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "MICROSOL\-APC" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" microsol-apc \- Driver for APC Back\-UPS BR UPS equipment .SH "SYNOPSIS" .sp \fBmicrosol\-apc\fR \-h .sp \fBmicrosol\-apc\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the microsol\-apc driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports the following UPS models: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} APC Back\-UPS BZ1500\-BR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} APC Back\-UPS BZ2200I\-BR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} APC Back\-UPS BZ2200BI\-BR .RE .sp In 2009, Schneider Electric acquired Microsol Technologies, and by 2012, the entire Microsol line was being sold under the APC brand\&. This driver supports these newer, APC\-branded models\&. Older equipment should use \fBsolis\fR(8)\&. .SH "EXTRA ARGUMENTS" .sp This driver support the following extra optional settings in the \fBups.conf\fR(5)\&. .PP \fBbattext=\fR\fIn\fR .RS 4 Default = 0, no extra battery, where n = Ampere*hour\&. .RE .PP \fBprgshut=\fR\fIn\fR .RS 4 Default = 0, no programmable shutdown; 1 to enable one\&. .RE .SH "COMMANDS" .PP \fBshutdown\&.return\fR .RS 4 Shut down in \&.3 minutes and restart in \&.3 minutes after that\&. .RE .PP \fBshutdown\&.stayoff\fR .RS 4 Shut down in \&.3 minutes and do not return\&. .RE .SH "ISSUES" .sp For other APC\-Microsol models, the reported voltages, currents and power will be incorrect, as the communication protocol reports unprocessed data instead of real values, needing model\-specific post\-processing by the driver\&. Monitoring of UPS state (on\-battery/on\-line, critical battery) should work for other models, but is untested\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Ygor A\&. S\&. Regados .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Roberto P\&. Velloso .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Silvino B\&. Magalhães .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Driver for older devices under same brand:" .sp \fBsolis\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/libnutclient_misc.30000644000200500020050000000747415001555056014553 00000000000000'\" t .\" Title: libnutclient_misc .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIBNUTCLIENT_MISC" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libnutclient_misc, nutclient_authenticate, nutclient_logout, nutclient_device_login, nutclient_get_device_num_logins, nutclient_device_master, nutclient_device_forced_shutdown \- Miscellaneous functions in Network UPS Tools high\-level client access library .SH "SYNOPSIS" .sp .nf #include typedef void* NUTCLIENT_t; void nutclient_authenticate( NUTCLIENT_t client, const char* login, const char* passwd); void nutclient_logout(NUTCLIENT_t client); void nutclient_device_login(NUTCLIENT_t client, const char* dev); int nutclient_get_device_num_logins(NUTCLIENT_t client, const char* dev); void nutclient_device_primary(NUTCLIENT_t client, const char* dev); /* OBSOLETED name: */ void nutclient_device_master(NUTCLIENT_t client, const char* dev); void nutclient_device_forced_shutdown(NUTCLIENT_t client, const char* dev); .fi .SH "DESCRIPTION" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_authenticate()\fR function authenticates the user\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIlogin\fR is the user name\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIpasswd\fR is the user password\&. .RE .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_logout()\fR function disconnects gracefully from the server\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_device_login()\fR function logs the fact that a system is drawing power from this UPS\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_device_num_logins()\fR function retrieves the number of clients which have been logged for this device\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_device_master()\fR and \fBnutclient_device_primary()\fR (note: the former is obsoleted since NUT v2\&.8\&.0 in favor of the latter) functions make sure that primary\-mode functions like FSD are available if necessary\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_device_forced_shutdown()\fR function sets the "forced shutdown" (FSD) flag on the device\&. .RE .sp Common arguments: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIdev\fR is the device name\&. .RE .SH "SEE ALSO" .sp \fBlibnutclient\fR(3) nut-2.8.3/docs/man/libnutclient_general.30000644000200500020050000000543515001555056015230 00000000000000'\" t .\" Title: libnutclient_general .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIBNUTCLIENT_GENERAL" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libnutclient_general, nutclient_destroy, strarr_alloc, strarr_free \- General and utility functions in Network UPS Tools high\-level client access library .SH "SYNOPSIS" .sp .nf #include typedef void* NUTCLIENT_t; void nutclient_destroy(NUTCLIENT_t client); typedef char** strarr; strarr strarr_alloc(unsigned short count); void strarr_free(strarr arr); .fi .SH "DESCRIPTION" .sp The \fBnutclient_destroy()\fR function destroys a \fINUTCLIENT_t\fR or derived (like \fINUTCLIENT_TCP_t\fR) connection object, and frees allocated memory\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBstrarr\fR type represents an array of C strings (array of char pointer)\&. The array must always be terminated by a NULL pointer\&. .sp Pointed strings must be allocated by (x)calloc or (x)strdup\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBstrarr_alloc()\fR function allocates a \fIstrarr\fR array with the specified number of (non\-initialized) string pointers\&. .sp Another additional pointer set to NULL is added at the end of the array\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBstrarr_free\fR function frees a \fIstrarr\fR array\&. It also frees all pointed strings\&. .RE .sp Common arguments: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIdev\fR is the device name\&. .RE .SH "SEE ALSO" .sp \fBlibnutclient\fR(3) nut-2.8.3/docs/man/tripplite.80000644000200500020050000000624115001555075013055 00000000000000'\" t .\" Title: tripplite .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "TRIPPLITE" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" tripplite \- Driver for Tripp\-Lite SmartPro UPS equipment .SH "SYNOPSIS" .sp \fBtripplite\fR \-h .sp \fBtripplite\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the tripplite driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver should work on the SmartPro line, including the SMART700 and SMART700SER\&. It only supports SmartPro models that communicate using the serial port\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5): .PP \fBoffdelay\fR=\fInum\fR .RS 4 Time to wait before the UPS is turned off after the kill power command is sent\&. The default value is 64 (in seconds)\&. .RE .PP \fBrebootdelay\fR=\fInum\fR .RS 4 Set the timer before the UPS is cycled after the reboot command is sent\&. The default value is 64 (in seconds)\&. .RE .PP \fBstartdelay\fR=\fInum\fR .RS 4 Set the time that the UPS waits before it turns itself back on after a reboot command\&. The default value is 60 (in seconds)\&. .RE .SH "KNOWN ISSUES AND BUGS" .sp Battery charge information may not be correct for all UPSes\&. It is tuned to be correct for a SMART700SER\&. Other models may not provide correct information\&. Information from the manufacturer would be helpful\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Rickard E\&. (Rik) Faith .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Nicholas Kain .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Other drivers for Tripp\-Lite hardware:" .sp \fBtripplitesu\fR(8), \fBtripplite_usb\fR(8), \fBusbhid-ups\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan_ip_ranges_iter_init.txt0000644000200500020050000000257515001555412017262 00000000000000NUTSCAN_IP_RANGES_ITER_INIT(3) ============================== NAME ---- nutscan_ip_ranges_iter_init - Begin iteration of an IP address range using a `nutscan_ip_range_list_iter_t` structure. SYNOPSIS -------- ------ #include char * nutscan_ip_ranges_iter_init( nutscan_ip_range_list_iter_t *irliter, const nutscan_ip_range_list_t *irl); ------ DESCRIPTION ----------- The *nutscan_ip_ranges_iter_init()* function can prepare an iterator from the specified `nutscan_ip_range_list_t` structure, saving it into the caller-provided `nutscan_ip_range_list_iter_t` helper object. Different iterators may be created to walk the same `nutscan_ip_range_list_t` list from different scans independently, but the list and its contents should not be freed while anyone references it. This function skips work if: * the structure pointer is `NULL` (`NULL` is returned); * the structure pointer's `ip_range` list is `NULL` (`NULL` is returned). Returns the first IP address from the first registered IP address range. Subsequent addresses can be returned by `nutscan_ip_ranges_iter_inc()`. The caller SHOULD NOT free this string while iterating. NOTES ----- Technically, the function is currently defined in 'nutscan-ip.h' file. SEE ALSO -------- linkman:nutscan_init_ip_ranges[3], linkman:nutscan_free_ip_ranges[3], linkman:nutscan_cidr_to_ip[3], linkman:nutscan_ip_ranges_iter_inc[3] nut-2.8.3/docs/man/safenet.80000644000200500020050000001040315001555075012461 00000000000000'\" t .\" Title: safenet .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "SAFENET" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" safenet \- Driver for SafeNet compatible UPS equipment .SH "SYNOPSIS" .sp \fBsafenet\fR \-h .sp \fBsafenet\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the safenet driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports UPS equipment which can be controlled via SafeNet v1\&.0 for Windows (serial interface only)\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional settings in the \fBups.conf\fR(5) file: .PP \fBmanufacturer=\fR\fIvalue\fR .RS 4 Autodetection of this parameter is not possible yet (and it probably never will be)\&. Therefore, this user\-defined string accepts any name\&. The default is \fIunknown\fR\&. .RE .PP \fBmodelname=\fR\fIvalue\fR .RS 4 Like manufacturer above\&. The default is \fIunknown\fR\&. .RE .PP \fBserialnumber=\fR\fIvalue\fR .RS 4 Like manufacturer above\&. The default is \fIunknown\fR\&. .RE .PP \fBondelay=\fR\fIvalue\fR .RS 4 Time to wait before switching on the UPS (minutes)\&. Defaults to 1 minute\&. .RE .PP \fBoffdelay=\fR\fIvalue\fR .RS 4 Time to wait before shutting down the UPS (seconds)\&. Defaults to 30 seconds\&. .RE .SH "INSTANT COMMANDS" .sp This driver supports some instant commands (see \fBupscmd\fR(8)): .PP \fBtest\&.battery\&.start\fR .RS 4 Start UPS self test .RE .PP \fBtest\&.battery\&.stop\fR .RS 4 Cancel UPS self test .RE .PP \fBtest\&.failure\&.start\fR .RS 4 Start simulated power failure .RE .PP \fBtest\&.failure\&.stop\fR .RS 4 Cancel simulated power failure .RE .PP \fBbeeper\&.enable\fR .RS 4 Enable the UPS beeper .RE .PP \fBbeeper\&.mute\fR .RS 4 Temporarily mute the UPS beeper .RE .PP \fBbeeper\&.toggle\fR .RS 4 Toggle the UPS beeper .RE .PP \fBshutdown\&.return\fR .RS 4 Turn off the load and wait for the power to return\&. Uses the timer defined by \fBoffdelay\fR\&. .RE .PP \fBshutdown\&.reboot\fR .RS 4 Turn off the load and return\&. Uses the timers defined by \fBoffdelay\fR and \fBondelay\fR\&. .RE .SH "KNOWN PROBLEMS" .sp If you run the \fBshutdown\&.return\fR command with mains present, the output may stay on or switch off and not back on again\&. The \fBshutdown\&.reboot\fR command will unconditionally switch on the load again (with or without mains present)\&. .sp If the driver is called with the \fI\-k\fR option (or through \fBupsdrvctl shutdown\fR) it tries to detect which command should be used in an attempt to stay off until mains is present again or to cycle the output if the power returned in the mean time\&. This isn\(cqt bullet\-proof, and you should be prepared that the power will either not be shutdown, or that it doesn\(cqt return when the power comes back\&. .SH "AUTHOR" .sp Arjen de Korte .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/blazer_ser.txt0000644000200500020050000000034715001555412013635 00000000000000BLAZER_SER(8) ============= :blazer_usb!: NAME ---- blazer_ser - Driver for Megatec/Q1 protocol serial based UPS equipment SYNOPSIS -------- *blazer_ser* -h *blazer_ser* -a 'UPS_NAME' ['OPTIONS'] include::blazer-common.txt[] nut-2.8.3/docs/man/genericups.80000644000200500020050000003635415001555071013211 00000000000000'\" t .\" Title: genericups .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "GENERICUPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" genericups \- Driver for contact\-closure UPS equipment .SH "SYNOPSIS" .sp \fBgenericups\fR \-h .sp \fBgenericups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the genericups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports hardware from many different manufacturers as it only uses the very simplest of signaling schemes\&. Contact closure refers to a kind of interface where basic high/low signals are provided to indicate status\&. This kind of UPS can only report line power and battery status\&. .sp This means that you will only get the essentials in ups\&.status: OL, OB, and LB (some UPSes may also support RB and BYPASS)\&. Anything else requires a smarter UPS\&. .SH "CABLING" .sp Cabling is different for every kind of UPS\&. See the table below for information on what is known to work with a given UPS type\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following settings in the \fBups.conf\fR(5): .PP upstype=\fItype\fR .RS 4 Required\&. Configures the driver for a specific kind of UPS\&. See the UPS Types section below for more information on which entries are available\&. .RE .PP mfr=\fIstring\fR .RS 4 Optional\&. The very nature of a generic UPS driver sometimes means that the stock manufacturer data has no relation to the actual hardware that is attached\&. With the mfr setting, you can change the value that is seen by clients that monitor this UPS\&. .RE .PP model=\fIstring\fR .RS 4 Optional\&. This is like mfr above, but it overrides the model string instead\&. .RE .PP serial=\fIstring\fR .RS 4 Optional\&. This is like mfr above and intended to record the identification string of the UPS\&. It is titled "serial" because usually this string is referred to as the serial number\&. .RE .PP sdtime=\fIvalue\fR .RS 4 Optional\&. The driver will sleep for this many seconds after setting the shutdown signal\&. This is necessary for some hardware which requires a sustained level to activate the shutdown sequence\&. .sp The default behavior of the driver is to exit immediately\&. If this doesn\(cqt reliably trigger a shutdown in your UPS hardware, use this setting to give it more time to react\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp very large values for sdtime may create warnings from upsdrvctl if it gets tired of waiting for the driver to return\&. .sp .5v .RE .SH "CUSTOM CONFIGURATIONS" .sp You may override the values for CP, OL, LB, and SD by defining them in the \fBups.conf\fR(5) after the upstype setting\&. .sp For example, to set the cable power to DTR and the low battery value to DCD, it would look like this: .sp .if n \{\ .RS 4 .\} .nf CP = DTR LB = DCD .fi .if n \{\ .RE .\} .sp Recognized values for input lines are CTS, DCD, and RNG\&. Recognized values for output lines are DTR, RTS, and ST\&. See below for more about what these signals mean\&. .sp These values may be negated for active low signals\&. That is, LB=\-DCD recognizes a low battery condition when DCD is not held high\&. .SH "TYPE INFORMATION" .sp The essence of a UPS definition in this driver is how it uses the serial lines that are available\&. These are the abbreviations you will see below: .PP OL .RS 4 On line (no power failure) (opposite of \fIOB\fR \(em on battery) .RE .PP LB .RS 4 Low battery .RE .PP RB .RS 4 Replace battery .RE .PP BYPASS .RS 4 Battery bypass active or no battery installed .RE .PP SD .RS 4 Shutdown load .RE .PP CP .RS 4 Cable power (must be present for cable to have valid reading) .RE .PP CTS .RS 4 Clear to Send\&. Received from the UPS\&. .RE .PP RTS .RS 4 Ready to Send\&. Sent by the PC\&. .RE .PP DCD .RS 4 Data Carrier Detect\&. Received from the UPS\&. .RE .PP RNG .RS 4 Ring indicate\&. Received from the UPS\&. .RE .PP DTR .RS 4 Data Terminal Ready\&. Sent by the PC\&. .RE .PP DSR .RS 4 Data Set Ready\&. Received from the UPS\&. .RE .PP ST .RS 4 Send a BREAK on the transmit data line .RE .PP NULL .RS 4 Disable this signal\&. Disabled signal will always be low except for \fIOL\fR which will always be high\&. .RE .PP none .RS 4 Alias to NULL which matches some other documentation\&. .RE .sp A \- in front of a signal name (like \-RNG) means that the indicated condition is signaled with an active low signal\&. For example, [LB=\-RNG] means the battery is low when the ring indicate line goes low, and that the battery is OK when that line is held high\&. .SH "UPS TYPES" .sp 0 = UPSonic LAN Saver 600 .sp .if n \{\ .RS 4 .\} .nf [CP=DTR+RTS] [OL=\-CTS] [LB=DCD] [SD=DTR] .fi .if n \{\ .RE .\} .sp 1 = APC Back\-UPS/Back\-UPS Pro/Smart\-UPS with 940\-0095A/C cable .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=\-RNG] [LB=DCD] [SD=RTS] .fi .if n \{\ .RE .\} .sp 2 = APC Back\-UPS/Back\-UPS Pro/Smart\-UPS with 940\-0020B cable (Note: Type 2 has also been reported to work with the 940\-0020C cable)\&. .sp .if n \{\ .RS 4 .\} .nf [CP=RTS] [OL=\-CTS] [LB=DCD] [SD=DTR+RTS] .fi .if n \{\ .RE .\} .sp 3 = PowerTech Comp1000 with DTR cable power .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=CTS] [LB=DCD] [SD=DTR+RTS] .fi .if n \{\ .RE .\} .sp 4 = Generic RUPS Model .sp .if n \{\ .RS 4 .\} .nf [CP=RTS] [OL=CTS] [LB=\-DCD] [SD=\-RTS] .fi .if n \{\ .RE .\} .sp 5 = Tripp Lite UPS with Lan2\&.2 interface (black 73\-0844 cable) .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=CTS] [LB=\-DCD] [SD=DTR+RTS] .fi .if n \{\ .RE .\} .sp 6 = Best Patriot with INT51 cable .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=CTS] [LB=\-DCD] [SD=RTS] .fi .if n \{\ .RE .\} .sp 7 = CyberPower Power99 Also Upsonic Power Guardian PG\-500, Belkin Belkin Home Office, F6H350\-SER, F6H500\-SER, F6H650\-SER, Eaton Management Card Contact \(em Config3 with cable 66033 (shutdown does not work) .sp .if n \{\ .RS 4 .\} .nf [CP=RTS] [OL=CTS] [LB=\-DCD] [SD=DTR] .fi .if n \{\ .RE .\} .sp 8 = Nitram Elite 500 .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=CTS] [LB=\-DCD] [SD=???] .fi .if n \{\ .RE .\} .sp 9 = APC Back\-UPS/Back\-UPS Pro/Smart\-UPS with 940\-0023A cable .sp .if n \{\ .RS 4 .\} .nf [CP=none] [OL=\-DCD] [LB=CTS] [SD=RTS] .fi .if n \{\ .RE .\} .sp 10 = Victron Lite with crack cable .sp .if n \{\ .RS 4 .\} .nf [CP=RTS] [OL=CTS] [LB=\-DCD] [SD=DTR] .fi .if n \{\ .RE .\} .sp 11 = Powerware 3115 .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=\-CTS] [LB=\-DCD] [SD=ST] .fi .if n \{\ .RE .\} .sp 12 = APC Back\-UPS Office with 940\-0119A cable .sp .if n \{\ .RS 4 .\} .nf [CP=RTS] [OL=\-CTS] [LB=DCD] [SD=DTR] .fi .if n \{\ .RE .\} .sp 13 = RPT Repoteck RPT\-800A/RPT\-162A .sp .if n \{\ .RS 4 .\} .nf [CP=DTR+RTS] [OL=DCD] [LB=\-CTS] [SD=ST] .fi .if n \{\ .RE .\} .sp 14 = Online P\-series .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=DCD] [LB=\-CTS] [SD=RTS] .fi .if n \{\ .RE .\} .sp 15 = Powerware 5119, 5125 .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=CTS] [LB=\-DCD] [SD=ST] .fi .if n \{\ .RE .\} .sp 16 = Nitram Elite 2002 .sp .if n \{\ .RS 4 .\} .nf [CP=DTR+RTS] [OL=CTS] [LB=\-DCD] [SD=???] .fi .if n \{\ .RE .\} .sp 17 = PowerKinetics 9001 .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=CTS] [LB=\-DCD] [SD=???] .fi .if n \{\ .RE .\} .sp 18 = TrippLite Omni 450LAN with Martin\(cqs cabling .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=CTS] [LB=DCD] [SD=none] .fi .if n \{\ .RE .\} .sp 19 = Fideltronic Ares Series .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=CTS] [LB=\-DCD] [SD=RTS] .fi .if n \{\ .RE .\} .sp 20 = Powerware 5119 RM (check docs/cables/powerware\&.txt in NUT sources) .sp .if n \{\ .RS 4 .\} .nf [CP=DTR] [OL=\-CTS] [LB=DCD] [SD=ST] .fi .if n \{\ .RE .\} .sp 21 = Generic RUPS 2000 (Megatec M2501 cable) .sp .if n \{\ .RS 4 .\} .nf [CP=RTS] [OL=CTS] [LB=\-DCD] [SD=RTS+DTR] .fi .if n \{\ .RE .\} .sp 22 = Gamatronic All models with alarm interface (also CyberPower SL series) .sp .if n \{\ .RS 4 .\} .nf [CP=RTS] [OL=CTS] [LB=\-DCD] [SD=DTR] .fi .if n \{\ .RE .\} .sp 23 = Generic FTTx (Fiber to the x) battery backup with 4\-wire telemetry interface .sp .if n \{\ .RS 4 .\} .nf [CP=RTS] [OL=CTS] [LB=\-DCD] [RB=\-RNG] [BYPASS=\-DSR] [SD=none] .fi .if n \{\ .RE .\} .SH "SIMILAR MODELS" .sp Many different UPS companies make models with similar interfaces\&. The RUPS cable seems to be especially popular in the "power strip" variety of UPS found in office supply stores\&. If your UPS works with an entry in the table above, but the model or manufacturer information don\(cqt match, don\(cqt despair\&. You can fix that easily by using the mfr and model variables documented above in your \fBups.conf\fR(5)\&. .SH "TESTING COMPATIBILITY" .sp If your UPS isn\(cqt listed above, you can try going through the list until you find one that works\&. There is a lot of cable and interface reuse in the UPS world, and you may find a match\&. .sp To do this, first make sure nothing important is plugged into the outlets on the UPS, as you may inadvertently switch it off\&. Definitely make sure that the computer you\(cqre using is not plugged into that UPS\&. Plug in something small like a lamp so you know when power is being supplied to the outlets\&. .sp Now, you can either attempt to make an educated guess based on the documentation your manufacturer has provided (if any), or just start going down the list\&. .SS "Step 1" .sp Pick a driver to try from the list (run genericups \-h) and go to step 2\&. .SS "Step 2" .sp Start the driver with the type you want to try, e\&.g\&.: .sp .if n \{\ .RS 4 .\} .nf genericups \-x upstype=n /dev/port .fi .if n \{\ .RE .\} .sp Let \fBupsd\fR(8) sync up (watch the syslog), and then run \fBupsc\fR(8) to see what it found\&. If the STATUS is correct (should be "OL" for online), continue to Step 3, otherwise go back to step 1\&. .sp Alternatively, you can run genericups in debug mode, e\&.g\&.: .sp .if n \{\ .RS 4 .\} .nf genericups \-DDDDD \-x upstype=n /dev/port .fi .if n \{\ .RE .\} .sp In this mode it will be running in the foreground and continuously display the line and battery status of the UPS\&. .SS "Step 3" .sp Disconnect the UPS from the wall/mains power\&. This is easiest if you have a switched outlet in between it and the wall, but you can also just pull the plug to test\&. The lamp should stay lit, and the status should switch to "OB"\&. If the lamp went out or the status didn\(cqt go to "OB" within about 15 seconds, go to Step 1\&. Otherwise, continue to Step 4\&. .SS "Step 4" .sp At this point, we know that OL and OB work\&. If nothing else beyond this point works, you at least know what your OL/OB value should be\&. .sp Wait for the UPS to start complaining about a low battery\&. Depending on the size of your UPS battery and the lamp\(cqs bulb, this could take awhile\&. It should start complaining audibly at some point\&. When this happens, STATUS should show "OB LB" within 15 seconds\&. If not, go to Step 1, otherwise continue to Step 5\&. .SS "Step 5" .sp So far: OL works, OB works, and LB works\&. .sp With the UPS running on battery, run the genericups driver with the \-k switch to shut it down\&. .sp .if n \{\ .RS 4 .\} .nf genericups \-x upstype=n \-k /dev/port .fi .if n \{\ .RE .\} .sp If the UPS turns off the lamp, you\(cqre done\&. At this point, you have verified that the shutdown sequence actually does what you want\&. You can start using the genericups driver with this type number for normal operations\&. .sp You should use your findings to add a section to your ups\&.conf\&. Here is a quick example: .sp .if n \{\ .RS 4 .\} .nf [myups] driver = genericups port = /dev/ttyS0 upstype = 1 .fi .if n \{\ .RE .\} .sp Change the port and upstype values to match your system\&. .SH "NEW SUPPORT" .sp If the above testing sequence fails, you will probably need to create a new entry to support your hardware\&. All UPS types are determined from the table in the genericups\&.h file in the source tree\&. .sp On a standard 9 pin serial port, there are 6 lines that are used as the standard "high/low" signal levels\&. 4 of them are incoming (to the PC, from the UPS), and the other 2 are outgoing (to the UPS, from the PC)\&. The other 3 are the receive/transmit lines and the ground\&. .sp Be aware that many manufacturers remap pins within the cable\&. If you have any doubts, a quick check with a multimeter should confirm whether the cable is straight\-through or not\&. Another thing to keep in mind is that some cables have electronics in them to do special things\&. Some have resistors and transistors on board to change behavior depending on what\(cqs being supplied by the PC\&. .SH "SPECIFIC MODEL NOTES" .sp These have been contributed by users of this driver\&. .sp The Centralion CL series may power down the load if the driver starts up with the UPS running on battery as the default line settings contain the shutdown sequence\&. \- Neil Muller .sp The Tripp\-Lite Internet Office 700 must be used with the black 73\-0844 cable instead of the gray 73\-0743 cable\&. This entry should work with any of their models with the Lan 2\&.2 interface \(em see the sticker by the DB9 connector on the UPS\&. \- Stephen Brown .sp Type 5 should work with the Tripp\-Lite Lan 2\&.1 interface and the 73\-0724 cable\&. This was tested with the OmniSmart 675 PNP on Red Hat 7\&.2\&. \- Q Giese .sp Types 7 and 10 should both work with the PhoenixTec A1000\&. .SH "BUGS" .sp There is no way to reliably detect a contact\-closure UPS\&. This means the driver will start up happily even if no UPS is detected\&. It also means that if the connection between the UPS and computer is interrupted, you may not be able to sense this in software\&. .sp Most contact\-closure UPSes will not power down the load if the line power is present\&. This can create a race when using secondary \fBupsmon\fR(8) systems\&. See the \fBupsmon\fR(8) man page for more information\&. .sp The solution to both of these problems is to upgrade to a smart protocol UPS of some kind that allows detection and proper load cycling on command\&. .SH "SEE ALSO" .SS "The core driver" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/apc_modbus.txt0000644000200500020050000001315215001555412013617 00000000000000APC_MODBUS(8) ============= NAME ---- apc_modbus - Driver for APC Smart-UPS Modbus protocol SYNOPSIS -------- *apc_modbus* -h *apc_modbus* -a 'UPS_NAME' ['OPTIONS'] SUPPORTED HARDWARE ------------------ Generally this driver should work for all the APC Modbus UPS devices. Some devices might expose more than is currently supported, like multiple phases. A general rule of thumb is that APC devices (or firmware versions) released after 2010 are more likely to support Modbus than the USB HID standard. Tested with the following hardware: - SMT1500 (Smart-UPS 1500, Firmware 9.6) - SMX750 (Smart-UPS X 750, Firmware 10.1) - SMX1500 (Smart-UPS X 1500, Firmware 15.0) Note that you will have to enable Modbus communication. In the front panel of the UPS, go to Advanced Menu mode, under Configuration and enable Modbus. NOTE: This driver was tested with Serial, TCP and USB interfaces for Modbus. Notably, the Serial ports are not available on all devices nowadays; the TCP support may require a purchase of an additional network management card; and the USB support *currently* requires a non-standard build of libmodbus (pull request against the upstream library is pending, as of at the time of this publication) as a pre-requisite to building NUT with this part of the support. For more details (including how to build the custom library and NUT with it) please see link:https://github.com/networkupstools/nut/pull/2063[NUT PR #2063] NOTE: As currently published, this driver supports reading information from the UPS. Implementation of support to write (set modifiable variables or send commands) is expected with a later release. This can impact the host shutdown routines in particular (no ability to actively tell the UPS to power off or cycle in the end). As a workaround, you can try integrating `apctest` (from the "apcupsd" project) with a "Test to kill power" into your late-shutdown procedure, if needed. EXTRA ARGUMENTS --------------- This driver also supports the following optional settings: include::nut_usb_addvars.txt[] *porttype*='value':: Set the type of the port used. Available values are serial for RS232/485 based connections, tcp for TCP/IP connections and usb for USB connections. *port*='value':: Depending on the port type you can select a port here. For usb only auto is supported, for serial you can pass a device path like /dev/ttyS0 and for tcp you can pass a hostname with optional port like example.com:502. *baudrate*='num':: Set the speed of the serial connection. The default baudrate is 9600. *parity*='value':: Set the parity of the serial connection. Available values are N for none, E for even and O for odd. The default parity is N (none). *databits*='num':: Set the data bits of the serial connection. The default databits is 8. *stopbits*='num':: Set the stop bits of the serial connection. The default stopbits is 1. *slaveid*='num':: Set the Modbus slave id. The default slave id is 1. *response_timeout_ms*='num':: Set the Modbus response timeout. The default timeout is set by libmodbus. It can be good to set a higher timeout on TCP connections with high latency. BUGS ---- This driver relies on advanced features of `libmodbus` to talk Modbus protocol over USB specifically (Serial and TCP are part of common library codebase). At the time of this writing, the common library project is just expecting a merge of the pull request with this ability. For the time being, if your OS distribution does not ship the required feature set, you may have to build your own `libmodbus` and subsequently (re-)build NUT against this library, as detailed in the NUT GitHub Wiki at https://github.com/networkupstools/nut/wiki/APC-UPS-with-Modbus-protocol The short sequence may be like follows: ------ cd ~/ git clone -b rtu_usb https://github.com/networkupstools/libmodbus cd libmodbus ./autogen.sh ./configure --with-libusb --prefix=/path/to/prefix make install ------ [NOTE] ====== * you may need to `make && sudo make install` if you want to place this library files' variant into a system path (like `--prefix=/usr/local/ups` to match NUT defaults -- this activity would need privilege elevation via `sudo`), and not into your home directory or some `/tmp` location. * conversely, you may want to `./configure --with-libusb --enable-static --disable-shared --prefix=/path/to/prefix` and only build and install a static `libmodbus.a` (can well be installed into `/tmp` or similarly short-lived location), so that the customized Modbus+USB logic gets built directly into `apc_modbus` binary program and there would be no potential run-time conflict with a dynamic library file available elsewhere in the system. ====== ------ cd ~/ git clone https://github.com/networkupstools/nut cd nut ./autogen.sh ./configure --with-drivers=apc_modbus --with-usb --with-modbus \ --with-modbus-includes=-I/path/to/prefix/include/modbus \ --with-modbus-libs="-L/path/to/prefix/lib -lmodbus" make ------ [NOTE] ====== * Other NUT `configure` options may be needed for proper behavior, such as `--prefix`, `--with-sysconfdir`, `--with-user` and `--with-group` to match your packaged or otherwise preceding NUT installation. ====== The `./configure --enable-inplace-runtime` may be a good start to inherit build configuration from an existing NUT deployment, as further detailed at https://github.com/networkupstools/nut/wiki/Building-NUT-for-in%E2%80%90place-upgrades-or-non%E2%80%90disruptive-tests AUTHORS ------- * Axel Gembe SEE ALSO -------- The core driver ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8], linkman:ups.conf[5] Internet resources ~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_init.txt0000644000200500020050000000341315001555412014200 00000000000000NUTSCAN_INIT(3) =============== NAME ---- nutscan_init - Initialize the nutscan library. SYNOPSIS -------- ------ #include void nutscan_init(void); ------ DESCRIPTION ----------- The *nutscan_init()* function must be called at least once before using any other function of the nutscan library. It updates the following global variables which can be used by nutscan library user to know which scan methods are available at run-time. This depends on further libraries installed on the system: * `nutscan_avail_avahi = 1`: AVAHI NUT scan is available * `nutscan_avail_ipmi = 1`: IPMI scan is available * `nutscan_avail_nut = 1`: "Old" NUT method is available * `nutscan_avail_nut_simulation = 1`: NUT simulation devices method is available * `nutscan_avail_snmp = 1`: SNMP method is available * `nutscan_avail_usb = 1`: USB method is available * `nutscan_avail_xml_http = 1`: XML HTTP method is available Note that if a method is reported as unavailable by those variables, the call to the corresponding `nutscan_scan_*` function will always return NULL. NOTES ----- Technically, the function is currently defined in 'nutscan-init.h' file. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_nut_simulation[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3] nut-2.8.3/docs/man/libnutclient_devices.30000644000200500020050000000550415001555055015231 00000000000000'\" t .\" Title: libnutclient_devices .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "LIBNUTCLIENT_DEVICES" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" libnutclient_devices, nutclient_get_devices, nutclient_has_device, nutclient_get_device_description \- Device related functions in Network UPS Tools high\-level client access library .SH "SYNOPSIS" .sp .nf #include typedef void* NUTCLIENT_t; typedef char** strarr; strarr nutclient_get_devices(NUTCLIENT_t client); int nutclient_has_device(NUTCLIENT_t client, const char* dev); char* nutclient_get_device_description(NUTCLIENT_t client, const char* dev); .fi .SH "DESCRIPTION" .sp These functions allow to manage devices\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_devices()\fR function retrieves the list of devices monitored by a client\&. .sp The returned strarr must be freed by \fIstrarr_free\fR (see \fBlibnutclient_general\fR(3))\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_has_device()\fR function tests if a device is monitored by a client\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The \fBnutclient_get_device_description()\fR function retrieves the device description\&. .sp The returned description string must be freed by \fBfree\fR(3)\&. .RE .sp Common arguments: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIdev\fR is the device name\&. .RE .SH "SEE ALSO" .sp \fBlibnutclient\fR(3) \fBlibnutclient_commands\fR(3) \fBlibnutclient_devices\fR(3) \fBlibnutclient_general\fR(3) \fBlibnutclient_variables\fR(3) nut-2.8.3/docs/man/nutclient_logout.30000644000200500020050000000003515001555117014422 00000000000000.so man3/libnutclient_misc.3 nut-2.8.3/docs/man/upscli_list_next.txt0000644000200500020050000000375015001555412015076 00000000000000UPSCLI_LIST_NEXT(3) =================== NAME ---- upscli_list_next - Retrieve list items from a UPS SYNOPSIS -------- ------ #include int upscli_list_next( UPSCONN_t *ups, size_t numq, const char **query, size_t *numa, char ***answer) ------ DESCRIPTION ----------- The *upscli_list_next()* function takes the pointer 'ups' to a `UPSCONN_t` state structure, and the pointer 'query' to an array of 'numq' query elements. It performs a read from the network and expects to find either another list item or the end of a list. You must call linkman:upscli_list_start[3] before calling this function. This function will return '1' and set values in 'numa' and 'answer' if a list item is received. If the list is done, it will return '0', and the values in 'numa' and 'answer' are undefined. Calling this function after it returns something other than '1' is undefined behavior. QUERY FORMATTING ---------------- You may not change the values of 'numq' or 'query' between the call to linkman:upscli_list_start[3] and the first call to this function. You also may not change the values between calls to this function. ANSWER FORMATTING ----------------- The contents of 'numa' and 'answer' work just like a call to linkman:upscli_get[3]. The values returned by linkman:upsd[8] are identical to a single item request, so this is not surprising. ERROR CHECKING -------------- This function checks the response from linkman:upsd[8] against your query. If the response is not part of the list you have requested, it will return an error code. When this happens, linkman:upscli_upserror[3] will return `UPSCLI_ERR_PROTOCOL`. RETURN VALUE ------------ The *upscli_list_next()* function returns '1' when list data is present, '0' if the list is finished, or '-1' if an error occurs. It is possible to have an empty list. The function will return '0' for its first call in that case. SEE ALSO -------- linkman:upscli_list_start[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/nutscan_cidr_to_ip.30000644000200500020050000000467515001555062014707 00000000000000'\" t .\" Title: nutscan_cidr_to_ip .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_CIDR_TO_IP" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_cidr_to_ip \- Convert a CIDR IP to a range of IP address\&. .SH "SYNOPSIS" .sp .nf #include int nutscan_cidr_to_ip(const char * cidr, char ** start_ip, char ** stop_ip); .fi .SH "DESCRIPTION" .sp The \fBnutscan_cidr_to_ip()\fR function converts a range of IP address in the CIDR format given as a string in \fIcidr\fR, to two IPs in strings pointed by \fIstart_ip\fR and \fIstop_ip\fR which can be used as input parameters in the scanning functions of the libnutscan API\&. .sp It is the caller\(cqs responsibility to \fBfree\fR(3) the \fIstart_ip\fR and \fIstop_ip\fR strings\&. .SH "RETURN VALUE" .sp The \fBnutscan_cidr_to_ip()\fR function returns \fI0\fR if an error occurred (invalid \fIcidr\fR address) or \fI1\fR if successful\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-ip\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_display_ups_conf\fR(3) nut-2.8.3/docs/man/upsstats.html.txt0000644000200500020050000001524515001555412014341 00000000000000UPSSTATS.HTML(5) ================ NAME ---- upsstats.html - HTML template for web-based Network UPS Tools upsstats DESCRIPTION ----------- This file is used by linkman:upsstats.cgi[8] to generate status pages. Certain commands are recognized, and will be replaced with various status elements on the fly. FORMATTING ---------- Commands can be placed anywhere on a line, but must start and end with `@`. Any extra characters before or after the commands will be passed through unchanged. It is allowed to use more than one command on a single line, as long as each command has its own start and end character. If you need to use the `@` sign, use HTML entity ++\@++ to prevent it from being treated as a start character. BLOCK CONTROL ------------- Some commands begin blocks -- sections of the template that will be included, excluded, or repeated depending on certain parameters. BLOCK CONTROL - ITERATION ~~~~~~~~~~~~~~~~~~~~~~~~~ *@FOREACHUPS@*:: Starts a block that will be repeated for each MONITOR directive in the linkman:hosts.conf[5]. This is how you can generate pages that monitor all of your systems simultaneously. *@ENDFOR@*:: Ends a FOREACHUPS block. BLOCK CONTROL - MATCHING SPECIFIC CASES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *@IFSUPP 'var'*@*:: Starts a block that will only be printed if the variable var is supported by the current UPS. This is generally used to suppress "not supported" messages by avoiding the label and variable call entirely. *@IFEQ* 'var' 'value'*@*:: Starts a block if the value returned from the variable 'var' matches 'value'. *@IFBETWEEN* 'varlow' 'varhigh' 'varvalue'*@*:: Starts a block if the value returned by the variable 'varvalue' is between the values returned by the variables 'varlow' and 'varhigh'. *@ELSE@*:: If the previous IF-command did not match, perform this instead. *@ENDIF@*:: Ends an IF/ELSE-block. BLOCK CONTROL - ADVANCED EXPRESSIONS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Even though the parser is pretty limited, it's still possible to create rather advanced expressions. The key to this is the fact that multiple block control commands are AND:ed. This is illustrated with an example (more examples are available in upsstats.html). @IFSUPP ambient.humidity@ @IFSUPP ambient.temperature@ This UPS knows both ambient temperature and humidity. @ELSE@ @IFSUPP ambient.humidity@ This UPS only knows ambient humidity. @ELSE@ @IFSUPP ambient.temperature@ This UPS only knows ambient temperature. @ELSE@ This UPS knows nothing, how annoying. @ENDIF@ OTHER COMMANDS -------------- *@AMBTEMP@*:: Insert the ambient temperature in the current temperature scale. *@DATE* 'format'*@*:: Insert the current date and time. The format string is passed to `strftime`, so almost anything is possible. See linkmanext:strftime[3] for possible values. *@DEGREES@*:: Insert the entity for degrees (°) and either C or F depending on the current temperature scale. *@HOST@*:: Insert the designation of the host being monitored, like `myups@localhost`. *@HOSTDESC@*:: Insert the host's description from linkman:hosts.conf[5]. *@HOSTLINK@*:: Insert a link to upsstats.cgi with the "host" variable set to the current UPS. This is only useful within a FOREACHUPS block. *@IMG* 'varname' ['extra']*@*:: Insert an IMG SRC to linkman:upsimage.cgi[8] for one of these status variables: battery.charge;; Battery charge -- a percentage battery.voltage;; The charge on the battery in volts input.frequency;; Incoming utility frequency (Hz) input.voltage;; Incoming utility voltage input.L1-L2.voltage;; Incoming voltage, L1-L2 (3phase) input.L2-L3.voltage;; Incoming voltage, L2-L3 (3phase) input.L3-L1.voltage;; Incoming voltage, L3-L1 (3phase) output.frequency;; Outgoing utility frequency (Hz) output.voltage;; Outgoing voltage (from the UPS) output.L1-L2.voltage;; Outgoing voltage, L1-L2 (3phase) output.L2-L3.voltage;; Outgoing voltage, L2-L3 (3phase) output.L3-L1.voltage;; Outgoing voltage, L3-L1 (3phase) output.L1.power.percent;; UPS load, L1 (3phase) output.L2.power.percent;; UPS load, L2 (3phase) output.L3.power.percent;; UPS load, L3 (3phase) ups.load;; UPS load -- percentage ups.temperature;; UPS temperature 'extra' is where you can put additional definitions. Right now the valid definitions are colors for various parts of the bars drawn by linkman:upsimage.cgi[8]. Possible color names are: back_col;; background color scale_num_col;; scale number color summary_col;; summary color (number at the bottom) ok_zone_maj_col;; major scale color for the normal ("ok") zone ok_zone_min_col;; minor scale color for the normal ("ok") zone neutral_zone_maj_col;; major scale color for the neutral zone neutral_zone_min_col;; minor scale color for the neutral zone warn_zone_maj_col;; major scale color for the warning zone warn_zone_min_col;; minor scale color for the warning zone bar_col;; the color of the bar in the middle All colors are hex triplets -- e.g. `0xff0000` is red, `0x00ff00` is green, and `0x0000ff` is blue. Examples: @IMG battery.charge@ @IMG battery.charge back_col=0xff00ff bar_col=0xaabbcc@ @IMG input.voltage ok_zone_maj_col=0x123456@ *@REFRESH@*:: Insert the META header magic for refreshing the page if that variable has been set by the browser. This needs to be in the HEAD section of the page. *@STATUS@*:: Expand the abbreviations in the ups.status variable -- OL becomes "On line", OB becomes "On battery", and so on. *@STATUSCOLOR@*:: Insert red, green, or yellow color triplets depending on the severity of the current UPS status. Normal operations are green, warnings like voltage trim/boost or "off" are yellow, and other events like being on battery or having a low battery are red. *@VAR* 'varname'*@*:: Insert the current value of the status variable varname on the host being monitored, or "Not supported". *@RUNTIME@*:: Inserts the current runtime, in `hh:mm:ss` format. *@TEMPC@*:: Use the Celsius scale for temperature data (default). *@TEMPF@*:: Use the Fahrenheit scale for temperature data. *@UPSTEMP@*:: Insert the UPS temperature in the current scale. *@BATTTEMP@*:: Insert the battery temperature in the current scale. *@UTILITYCOLOR@*:: Obsoleted. Use IFBETWEEN instead (see example in upsstats.html). *@VERSION@*:: Insert the version number of the software. OTHER TEMPLATES --------------- linkman:upsstats.cgi[8] will also open a file called `upsstats-single.html` if you call it with `host=` set in the query URL. That file uses the same rules and techniques as documented here. SEE ALSO -------- linkman:upsstats.cgi[8], linkman:upsimage.cgi[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/victronups.80000644000200500020050000000613015001555076013253 00000000000000'\" t .\" Title: victronups .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "VICTRONUPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" victronups \- Driver for IMV/Victron UPS unit Match, Match Lite, NetUps .SH "SYNOPSIS" .sp \fBvictronups\fR \-h .sp \fBvictronups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the the victronups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The victronups driver should recognize all Victron models that use a serial protocol at 1200 bps\&. These include Match Lite, Match and the NetUps line\&. .sp The Match Lite line may only report a handful of variables\&. This is usually not a bug \(em they just don\(cqt support anything else\&. .SH "CABLING" .sp If your Victron cable is broken or missing, use this diagram to build a clone: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://github\&.com/networkupstools/nut/blob/master/docs/cables/ge\-imv\-victron\&.txt .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} docs/cables/ge\-imv\-victron\&.txt .RE .SH "EXTRA ARGUMENTS" .sp This driver supports the following optional setting in the \fBups.conf\fR(5): .PP \fBmodelname\fR=\fIname\fR .RS 4 Set model name .RE .PP \fBusd\fR=\fIdelay\fR .RS 4 Set delay before shutdown on UPS .RE .SH "BUGS" .sp The protocol for this UPS is not officially documented\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Radek Benedikt .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Daniel Prynych .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/dummy-ups.80000644000200500020050000003301715001555071012776 00000000000000'\" t .\" Title: dummy-ups .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "DUMMY\-UPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" dummy-ups \- Driver for multi\-purpose UPS emulation or relay .SH "SYNOPSIS" .sp \fBdummy\-ups\fR \-h .sp \fBdummy\-ups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the \fBdummy\-ups\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "DESCRIPTION" .sp This program is a multi\-purpose UPS emulation tool\&. Its general behavior depends on the running mode: "dummy" ("dummy\-once" or "dummy\-loop"), or "repeater"\&. .SS "Dummy Mode" .sp In this mode, \fBdummy\-ups\fR looks like a standard NUT device driver to \fBupsd\fR(8) and allows one to change any value for testing purposes\&. .sp It is both interactive, controllable through the \fBupsrw\fR(1) and \fBupscmd\fR(1) commands (or equivalent graphical tool), and batchable through script files\&. .sp It can be configured, launched and used as any other "real" NUT driver\&. This mode is mostly useful for development and testing purposes\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp See below about the differences of dummy\-once vs\&. dummy\-loop modes \(em the former may be more suitable for "interactive" uses and tests\&. .sp .5v .RE .SS "Repeater Mode" .sp In this mode, \fBdummy\-ups\fR acts as a NUT client, simply forwarding data\&. .sp This can be useful for supervision purposes\&. This mode can also allow some load sharing between several upsd instances communicating with ultimate NUT clients, with a "central" one using a point\-to\-point communication with the actual UPS or ePDU device\&. .sp This arrangement can also help with networked UPSes, whose network management cards can be overwhelmed with a whole farm of servers directly polling SNMP or other networked protocols every few seconds\&. .SH "IMPLEMENTATION" .sp The port specification in ups\&.conf depends on the running mode, and allows the driver to select the right mode of operation\&. .sp Since NUT v2\&.8\&.0, the mode specification in ups\&.conf allows users to override the mode of operation which would be otherwise guessed by the driver\&. .SS "Dummy Mode" .sp In this context, port in the ups\&.conf block specifies a "definition file" name for the \fBdummy\-ups\fR to read data from\&. This can either be an absolute or a relative path name\&. In the latter case the NUT sysconfig directory (i\&.e\&. /etc/nut, /usr/local/ups/etc, \&...) is prepended\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp The "sysconfig" location is built\-in according to configure script arguments, but can be tuned at run time by NUT_CONFPATH environment variable\&. See the tests/NIT/nit\&.sh script in NUT sources, which heavily relies on this driver, for more examples\&. .sp .5v .RE .sp Since NUT v2\&.8\&.0 two aspects of this mode are differentiated: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} dummy\-once reads the specified file once to the end (interrupting for TIMER lines, etc\&.) and does not re\-process it until the filesystem timestamp of the data file is changed; this reduces run\-time stress if you test with a lot of dummy devices, and allows use/test cases to upsrw variables into the driver instance \(em and they remain in memory until the driver is restarted (or the file is touched or modified); .sp Since NUT v2\&.8\&.0 dummy\-once is assigned by default to files with a *\&.dev naming pattern\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} dummy\-loop reads the specified file again and again, with a short sleep between the processing cycles; for sequence files using a TIMER keyword (see below), or for use/test cases which modify file contents with external means, this allows an impression of a device whose state changes over time\&. .sp Before NUT v2\&.8\&.0 this was the only aspect, so a simple dummy mode value maps to this behavior for backwards compatibility\&. .sp Since NUT v2\&.8\&.0 dummy\-loop is assigned by default to files with a *\&.seq naming pattern, and dummy is assigned by default to files with other naming patterns that the driver could not classify\&. .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Said defaulting based on filename pattern can break third\-party test scripts which earlier expected *\&.dev files to work as a looping sequence with a TIMER keywords to change values slowly\&. Now such files should get processed to the end once\&. .sp Specify mode=dummy\-loop driver option or rename the data file used in the port option for legacy behavior\&. .sp Use/Test\-cases which modified such files content externally should not be impacted\&. .sp .5v .RE .sp For instance: .sp .if n \{\ .RS 4 .\} .nf [dummy1] driver = dummy\-ups port = evolution500\&.seq desc = "dummy\-ups in dummy\-loop mode" [dummy2] driver = dummy\-ups port = epdu\-managed\&.dev desc = "dummy\-ups in dummy\-once mode" .fi .if n \{\ .RE .\} .sp This definition file, specified by the port argument in the example above, is generally named something\&.dev or something\&.seq\&. It contains a list of all valid variables and associated values (you can later use upsrw only to modify values of these variables), and has the same format as an \fBupsc\fR(8) data dump (: )\&. This means you can easily create definition files from an existing UPS using upsc > file\&.dev\&. .sp Note that the Network UPS project provides an extensive DDL (Devices Dumps Library) with files which can be used for modelling real devices\&. Entries for the DDL library are best prepared with the tools/nut\-ddl\-dump\&.sh script from NUT sources instead of plain upsc, to provide some additional data points from other NUT clients as well\&. .sp The file can also be empty, in which case only a basic set of data is available: device\&.*, driver\&.*, ups\&.mfr, ups\&.model, ups\&.status as filled by the driver itself\&. .sp Some sample definition files are available in the data directory of the NUT source tree, and generally in the "sysconfig" or "share" directory of your system distribution\&. .sp Since \fBdummy\-ups\fR will usually loop on reading this file, you can dynamically modify it with some external process to "interact" with the driver\&. This will avoid message spam into your system log files, if you are using NUT default configuration\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp By default since NUT v2\&.8\&.0, it will not loop on files in dummy\-once mode, e\&.g\&. those with a \&.dev extension, unless their timestamp changes\&. .sp .5v .RE .sp You can also use the TIMER instruction to create scheduled event sequences (such files are traditionally named with the \&.seq extension)\&. For example, the following sequence will loop on switching ups\&.status between "OL", "OB" and "OB LB" every minute: .sp .if n \{\ .RS 4 .\} .nf ups\&.status: OL TIMER 60 ups\&.status: OB TIMER 60 ups\&.status: OB LB TIMER 60 .fi .if n \{\ .RE .\} .sp It is wise to end the script for dummy\-loop mode with a TIMER keyword\&. Otherwise dummy\-ups will directly go back to the beginning of the file and, in particular, forget any values you could have just set with upsrw\&. .sp Note that to avoid CPU overload with an infinite loop, the driver "sleeps" a bit between file\-reading cycles (currently this delay is hardcoded to one second), independently of (and/or in addition to) any TIMER keywords and possibly the common pollinterval setting\&. .SS "Repeater Mode" .sp In this context, port in the ups\&.conf block is the name of the target UPS, using the NUT format, i\&.e\&.: .sp .if n \{\ .RS 4 .\} .nf @[:] .fi .if n \{\ .RE .\} .sp For instance: .sp .if n \{\ .RS 4 .\} .nf [repeater] driver = dummy\-ups port = ups1@remotehost desc = "dummy\-ups in repeater mode" .fi .if n \{\ .RE .\} .sp Unlike UPS specifications in the rest of NUT, the @hostname portion is not optional \(em it is the @ character which enables Repeater Mode\&. To refer to an UPS on the same host as \fBdummy\-ups\fR, use port = upsname@localhost\&. .sp Note that to avoid CPU overload with an infinite loop, the driver "sleeps" a bit between data\-requesting cycles (currently this delay is hardcoded to one second), so propagation of data updates available to a remote upsd may lag by this much\&. .sp Beware that any error encountered at repeater mode startup (e\&.g\&. when not all target UPS to be repeated or their upsd instances are connectable yet) will by default cause the \fBdummy\-ups\fR driver to terminate prematurely\&. This behaviour can be changed by setting the repeater_disable_strict_start flag, making such errors non\-fatal\&. .SH "INTERACTION" .sp Once the driver is loaded in dummy mode, you can change any variables, except those of the driver\&.* and server\&.* collections\&. You can do this by either editing the definition file, or use the \fBupsrw\fR(1) and \fBupscmd\fR(1) commands\&. .sp Note that in simulation mode, new variables can be added on the fly, but only by adding these to the definition file (and waiting for it to be re\-read)\&. That is, the driver should not allow to define a new variable via upsrw\&. .sp Conversely, if you need to remove a variable (such as transient ones, like ups\&.alarm), simply update these by setting an empty value\&. As a result, they will get removed from the data\&. .sp In repeater mode, the driver acts according to the capabilities of the UPS, and so supports the same instant commands and settable values\&. .SH "BACKGROUND" .sp Dummy Mode was originally written in one evening to replace the previous \fIdummycons\fR testing driver, which was too limited, and required a terminal for interaction\&. .sp \fBdummy\-ups\fR is useful for NUT client development, and other testing purposes\&. .sp It also helps the NUT Quality Assurance effort, by automating some tests on the NUT framework and the NIT (NUT Integration Test suite)\&. See the tests/NIT/nit\&.sh script in NUT sources, which heavily relies on this driver, for more examples\&. .sp It now offers a repeater mode\&. This will help in building the Meta UPS approach, which allows one to build a virtual device, composed of several other devices (either UPS, PDUs), or perhaps represent the same device which supports several communication protocols and different media (Serial, USB, SNMP\&...) .SH "BUGS" .sp Instant commands are not yet supported in Dummy Mode, and data need name/value checking enforcement, as well as boundaries or enumeration definition\&. .SH "CAVEATS" .sp If you use service management frameworks like systemd or SMF to manage the dependencies between driver instances and the data server, and some of these drivers are dummy\-ups in repeater mode representing data from another driver running on the same system, then you may have to set up special dependencies (e\&.g\&. with systemd "drop\-in" snippet files) to allow your nut\-server to start after the "real" device drivers and before such repeater drivers (without a responding server, they would fail to start anyway)\&. This may also need special care in upsd\&.conf and/or ups\&.conf files to not block the system start\-up for too long while the repeater driver has not started\&. .SH "AUTHOR" .sp Arnaud Quette .SH "SEE ALSO" .sp \fBupscmd\fR(1), \fBupsrw\fR(1), \fBups.conf\fR(5), \fBnutupsdrv\fR(8) .SS "Clone drivers:" .sp The "repeater" mode of \fIdummy\-ups\fR driver is in some ways similar to the \fIclone\fR and \fIclone\-outlet\fR drivers, which sit on top of another driver socket (or named Windows pipe) locally, and allow users to group clients to a particular outlet of a device and deal with this output as if it were a normal UPS\&. Notably, in this mode the \fIdummy\-ups\fR driver is a client to the networked NUT protocol and can relay information of local or remotely served devices, and requires a running NUT data server \fIupsd\fR to represent the "real" device for this to work\&. .sp \fBclone\fR(8), \fBclone-outlet\fR(8) .SS "Internet Resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutclient_execute_device_command.30000644000200500020050000000004115001555117017565 00000000000000.so man3/libnutclient_commands.3 nut-2.8.3/docs/man/upscli_get.txt0000644000200500020050000000667115001555412013651 00000000000000UPSCLI_GET(3) ============= NAME ---- upscli_get - Retrieve data from an UPS SYNOPSIS -------- ------ #include int upscli_get( UPSCONN_t *ups, size_t numq, const char **query, size_t *numa, char ***answer) ------ DESCRIPTION ----------- The *upscli_get()* function takes the pointer 'ups' to a `UPSCONN_t` state structure, and the pointer 'query' to an array of 'numq' query elements. It builds a properly-formatted request from those elements and transmits it to linkman:upsd[8]. Upon success, the response will be split into separate components. A pointer to those components will be returned in 'answer'. The number of usable answer components will be returned in 'numa'. USES ---- This function implements the "GET" command in the NUT protocol. As a result, you can use it to request many different things from the server. Some examples are: * GET NUMLOGINS * GET UPSDESC * GET VAR * GET TYPE * GET DESC * GET CMDDESC QUERY FORMATTING ---------------- To generate a request for `GET NUMLOGINS su700`, you would populate query and numq as follows: ------ size_t numq; const char *query[2]; query[0] = "NUMLOGINS"; query[1] = "su700"; numq = 2; ------ All escaping of special characters and quoting of elements with spaces is handled for you inside this function. ANSWER FORMATTING ----------------- The raw response from `upsd` to the above query would be `NUMLOGINS su700 1`. Since this is split up for you, the values work out like this: ------ size_t numa; numa = 3; answer[0] = "NUMLOGINS" answer[1] = "su700" answer[2] = "1" ------ Notice that the value which you seek typically starts at `answer[numq]`. ERROR CHECKING -------------- This function will check your query against the response from linkman:upsd[8] data server. For example, if you send `"VAR"` `"su700"` `"ups.status"`, it will expect to see those at the beginning of the response. If the results from `upsd` do not pass this case-insensitive test against your request, this function will return an error. When this happens, linkman:upscli_upserror[3] will return 'UPSCLI_ERR_PROTOCOL'. ANSWER ARRAY LIFETIME --------------------- The pointers contained within the 'answer' array are only valid until the next call to an 'upsclient' function which references them. If you need to use data from multiple calls, you must copy it somewhere else first. The 'answer' array and its elements may change locations, so you must not rely on previous addresses. You must only use the addresses which were returned by the most recent call. You also must not attempt to use more than 'numa' elements in 'answer'. Such behavior is undefined, and may yield bogus data or a crash. The array will be deleted after calling linkman:upscli_disconnect[3]. Any access after that point is also undefined. RETURN VALUE ------------ The *upscli_get()* function returns '0' on success, or '-1' if an error occurs. If *upsd* disconnects, you may need to handle or ignore `SIGPIPE` in order to prevent your program from terminating the next time that the library writes to the disconnected socket. The following code in your initialization function will allow the *upscli_get()* call to return an error in that case: ------ #include ... signal (SIGPIPE, SIG_IGN); ... ------ SEE ALSO -------- linkman:upscli_list_start[3], linkman:upscli_list_next[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/upscli_str_add_unique_token.30000644000200500020050000001006615001555054016616 00000000000000'\" t .\" Title: upscli_str_add_unique_token .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_STR_ADD_UNIQU" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_str_add_unique_token \- Add a unique token into a string buffer, with optional callbacks as needed by implementation .SH "SYNOPSIS" .sp .nf #include int upscli_str_add_unique_token(char *tgt, size_t tgtsize, const char *token, int (*callback_always)(char *, size_t, const char *), int (*callback_unique)(char *, size_t, const char *) ); .fi .SH "DESCRIPTION" .sp The \fBupscli_str_add_unique_token\fR() function takes the pointer \fItgt\fR to a caller\-provided char * buffer of size \fItgtsize\fR, and the pointer \fItoken\fR to a contiguous token that should be added to the end of \fItgt\fR buffer, if it is not there yet\&. .sp The \fItoken\fR contents are stripped of surrounding space characters, and the method recurses to independently process each space\-separated token inside (if there are any spaces left)\&. .sp The resulting \fItgt\fR buffer would eventually collect a string comprised of unique \fItoken\fR values in order of first mention, separated by single space characters (ASCII \fI0x20\fR)\&. .sp Optionally calls \fIcallback_always\fR (if not NULL) after checking the input for spaces (and maybe recursing) and before checking if the token is already there, and/or \fIcallback_unique\fR (if not NULL) after checking for uniqueness and just before going to add a newly seen token\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If such callback returns \fI0\fR, abort the addition of \fItoken\fR and return \fI\-3\fR\&. .RE .sp It is up to the caller to dynamically or statically allocate the \fItgt\fR buffer and \fBfree\fR() it if needed\&. As far as this method is concerned, the buffer may be recycled (in data processing loops) by setting the initial character to \*(Aq\e0\*(Aq, making it an empty string again\&. .SH "RETURN VALUE" .sp The \fBupscli_str_add_unique_token\fR() function returns a numeric code: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI0\fR if the \fItoken\fR value was already there in \fItgt\fR buffer; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI1\fR if \fItoken\fR was added successfully; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI\-1\fR if we needed to add the \fItoken\fR, but it did not fit under the \fItgtsize\fR limit; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI\-2\fR if either \fItoken\fR or \fItgt\fR string was NULL, or if \fItoken\fR was empty; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI\-3\fR if the \fItoken\fR was rejected by the optional callback method returning \fI0\fR\&. .RE .SH "SEE ALSO" .sp \fBupscli_str_contains_token\fR(3) nut-2.8.3/docs/man/nutscan_scan_nut.txt0000644000200500020050000000423015001555412015045 00000000000000NUTSCAN_SCAN_NUT(3) =================== NAME ---- nutscan_scan_nut - Scan network for available NUT services. SYNOPSIS -------- ------ #include #include /* useconds_t */ nutscan_device_t * nutscan_scan_nut( const char * startIP, const char * stopIP, const char * port, useconds_t usec_timeout); nutscan_device_t * nutscan_scan_ip_range_nut( nutscan_ip_range_list_t * irl, const char * port, useconds_t usec_timeout); ------ DESCRIPTION ----------- The *nutscan_scan_nut()* and *nutscan_scan_ip_range_nut()* functions try to detect available NUT services and their associated devices. The former issues a NUT request on every IP ranging from 'startIP' to 'stopIP', where 'startIP' is mandatory and 'stopIP' is optional (one 'startIP' address is scanned if 'stopIP' is NULL); while the latter can walk several IP address ranges represented by a `nutscan_ip_range_list_t` structure. Those IP arguments may be either IPv4 or IPv6 addresses or host names. You MUST call linkman:nutscan_init[3] before using this function. A specific 'port' number may be passed, or NULL to use the default NUT port. This function waits up to 'usec_timeout' microseconds before considering an IP address does not respond to NUT queries. RETURN VALUE ------------ The *nutscan_scan_nut()* function returns a pointer to a `nutscan_device_t` structure containing all found devices or NULL if an error occurs or no device is found. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_scan_eaton_serial[3], linkman:nutscan_init_ip_ranges[3], linkman:nutscan_free_ip_ranges[3], linkman:nutscan_add_ip_range[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/ivtscd.txt0000644000200500020050000000133215001555412012774 00000000000000IVTSCD(8) ========= NAME ---- ivtscd - Driver for the IVT Solar Controller Device SYNOPSIS -------- *ivtscd* -h *ivtscd* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the *ivtscd* driver. For information about the core driver, see linkman:nutupsdrv[8]. DESCRIPTION ----------- This driver allows to access the IVT SCD-series devices. EXTRA ARGUMENTS --------------- This driver does not support any extra argument. AUTHOR ------ Arjen de Korte SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutclient_tcp_is_connected.30000644000200500020050000000003415001555117016413 00000000000000.so man3/libnutclient_tcp.3 nut-2.8.3/docs/man/upscli_init.txt0000644000200500020050000000600215001555412014021 00000000000000UPSCLI_INIT(3) ============== NAME ---- upscli_init - Initialize upsclient module specifying security properties. SYNOPSIS -------- ------ #include int upscli_init( int certverify, const char *certpath, const char *certname, const char *certpasswd); ------ DESCRIPTION ----------- The *upscli_init()* function initializes upsclient module and sets many TLS/SSL-related properties: 'certverify' to 1 makes certificate verification required for all SSL connections and 'certpath' is the location of certificate database. * If compiled with OpenSSL, 'certpath' refers to directory containing certificates where the certificates must be named according to their hash values ending in a ".0" extension. If two certificates result in the same hash value (thus file name), the ".0" can be incremented to ".1" and so on, as needed. The shell command for creating links in this manner would be: + ---- :; ln -s ca.pem ./$(openssl x509 -hash -noout -in ca.pem).0 ---- + Alternatively, the `c_rehash` utility (provided by e.g. `openssl-perl` package) can take a directory and iterate it to link all certificates found in that directory, in the manner described above. * If compiled with NSS, 'certpath' refers to a directory containing its database files. If compiled with NSS and using SSL, you can specify 'certname' with the name of the certificate to send to `upsd`, and 'certpasswd' with the password used to decrypt certificate private key. If compiled with NSS, it would normally log either the infamous message "Init SSL without certificate database" if no 'certpath' was provided, or "Init SSL with certificate database located at %s" otherwise. Since some programmatic consumers become confused by such extra text on the `stderr` of tools they call (such as monitoring systems doing `upsc` queries), you can export an environment variable `NUT_QUIET_INIT_SSL` with string values `"true"`, `"TRUE"` or `"1"`, to avoid logging these messages and just emit them as debug stream (at verbosity 1 or higher). As part of general initialization, *upscli_init()* function can call the linkman:upscli_init_default_connect_timeout[3] method (if it was never used before): this allows unmodified (legacy) NUT clients to consistently benefit from presence of the `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable for linkman:upscli_connect[3] attempts to be not blocking (as per default). You can call linkman:upscli_add_host_cert[3] to register specific host security policy before initialize connections to them. You must call linkman:upscli_cleanup[3] when exiting application. RETURN VALUE ------------ The *upscli_init()* function returns '1' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_add_host_cert[3], linkman:upscli_cleanup[3], linkman:upscli_connect[3], linkman:upscli_disconnect[3], linkman:upscli_init_default_connect_timeout[3], linkman:upscli_fd[3], linkman:upscli_splitaddr[3], linkman:upscli_splitname[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/upscli_tryconnect.30000644000200500020050000000003215001555117014570 00000000000000.so man3/upscli_connect.3 nut-2.8.3/docs/man/apcupsd-ups.txt0000644000200500020050000000677715001555412013766 00000000000000APCUPSD-UPS(8) ============== NAME ---- apcupsd-ups - Driver for apcupsd client access SYNOPSIS -------- *apcupsd-ups* -h *apcupsd-ups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the *apcupsd-ups* driver. For information about the core driver, see linkman:nutupsdrv[8]. DESCRIPTION ----------- This driver is a client to *apcupsd* (another UPS monitoring project). *apcupsd-ups* acts as an *apcupsd* client, simply forwarding data. This can be useful in cases where both protocols are required in a network, or in case `apcupsd` code base has a required UPS access mode missing from NUT. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in linkman:nut.conf[5]: *port*=[:]:: This is the name of a remote host running apcupsd (plus an optional port). For instance: [apcupsd] driver = apcupsd-ups port = localhost desc = "apcupsd client" BACKGROUND ---------- This driver was originally written in one evening to allow interoperating with *apcupsd*. SUPPORTED VARIABLES ------------------- The following variables are translated from *apcupsd* to NUT. All times should be converted to seconds (please file a bug if you notice a mismatch in units). [width="50%",cols="m,m",options="header"] |=============================== | apcupsd variable | NUT variable(s) | BCHARGE | battery.charge | MBATTCHG | battery.charge.low | RETPCT | battery.charge.restart | BATTDATE | battery.date | TIMELEFT | battery.runtime | MINTIMEL | battery.runtime.low | BATTV | battery.voltage | NOMBATTV | battery.voltage.nominal | LINEFREQ | input.frequency | SENSE | input.sensitivity | HITRANS | input.transfer.high | LOTRANS | input.transfer.low | LASTXFER | input.transfer.reason | LINEV | input.voltage | MAXLINEV | input.voltage.maximum | MINLINEV | input.voltage.minimum | NOMINV | input.voltage.nominal | LINEFREQ | output.frequency | OUTPUTV | output.voltage | NOMOUTV | output.voltage.nominal | DATE | ups.date, ups.time | DSHUTD | ups.delay.shutdown | DWAKE | ups.delay.start | FIRMWARE | ups.firmware, ups.firmware.aux | UPSNAME | ups.id | LOADPCT | ups.load | MANDATE | ups.mfr.date | NOMPOWER | ups.realpower.nominal | SERIALNO | ups.serial | STATUS | ups.status | ITEMP | ups.temperature | STESTI | ups.test.interval | SELFTEST | ups.test.result |=============================== LIMITATIONS ----------- Access to *apcupsd* is strictly read only: no commands can be issued. This stems from the design of *apcupsd*, where the settings are changed in *apctest*. In order to run *apctest*, *apcupsd* must be stopped (and it is *apcupsd* that exposes the UPS to the network and to this NUT driver as its client). AUTHOR ------ Andreas Steinmetz SEE ALSO -------- linkman:ups.conf[5], linkman:nutupsdrv[8] Internet Resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * The apcupsd home page: http://www.apcupsd.org/ - Development of *apcupsd* project itself seems to have stalled in 2016/2017, with release 3.14.14 being the latest official tag. Its community discussions do remain quite active, however. - Just in case, a replica of its sources is stored at https://github.com/networkupstools/apcupsd nut-2.8.3/docs/man/clone-outlet.80000644000200500020050000002234315001555070013447 00000000000000'\" t .\" Title: clone-outlet .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "CLONE\-OUTLET" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" clone-outlet \- Clone an UPS, treating its outlet as if it were an UPS (monitoring only) .SH "SYNOPSIS" .sp \fBclone\-outlet\fR \-h .sp \fBclone\-outlet\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the specific features of the clone\-outlet driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "DESCRIPTION" .sp This driver, which sits on top of another driver\(cqs local UNIX socket file (or Windows named pipe), allows users to group clients to a particular outlet of a device and deal with this output as if it were a normal UPS\&. .sp Unlike the \fBclone\fR(8) driver or \fBdummy-ups\fR(8) driver running in repeater mode, this driver represents a read\-only device for monitoring and shutdowns (it does not accept setting any values or sending instant commands during run time)\&. .sp Unlike \fBdummy-ups\fR(8) generally, this driver does not require a running upsd data server nor use the networked NUT protocol to talk to the "real" driver (which may be remote in case of dummy\-ups repeater mode)\&. .sp This driver does not create a completely new virtual device, but replaces or extends some of the original readings reported by the "real" driver using information from the specified outlet, and relays all other readings as they were\&. .sp Remote clients like upsmon can MONITOR the device entry presented by the data server with this driver (and the "real" driver) running and published\&. .sp A larger deployment with one or more lower\-priority devices collected on a manageable outlet of an UPS or ePDU would likely see several drivers set up on the system actually capable of interactions with the UPS and running the NUT data server \fBupsd\fR(8) (and likely powered by another outlet): .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a "real" driver talking to the UPS; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} a clone driver talking to the "real" driver and issuing outlet power\-off (or power\-cycle) based on relatively high thresholds for remaining battery charge and/or runtime of the actual UPS (or explicit instant commands), with such operations first setting the respective timers for the outlet on the "real" driver, and the "FSD" flag among states of the virtual UPS status; .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} possibly a clone\-outlet driver which is read\-only and interprets the outlet timer values as triggers for "FSD" or "OFF" flags reported among states of the virtual UPS status\&. .RE .sp With this approach, the lower\-priority systems collected on such outlet would run the NUT \fBupsmon\fR(8) client to MONITOR the virtual UPS presented by the read\-only clone\-outlet driver and shut down as soon as the "FSD" flag is raised (fairly early, based on charge and/or runtime thresholds configured for that driver) allowing the higher\-priority devices (likely including the NUT server) to enjoy a longer on\-battery life\&. .sp The clone driver responsible for outlet power state changes would not normally be monitored directly (e\&.g\&. to avoid unfortunate direct shutdown requests from those clients), although it can be (instead of clone\-outlet) in sufficiently trusted networks\&. .SH "EXTRA ARGUMENTS" .sp This driver supports the following settings: .PP \fBport\fR=\fIdrivername\-devicename\fR .RS 4 Required\&. The standard NUT driver port setting, here it provides the name of the local Unix socket (or named Windows pipe) for connection to the "real" driver\&. .RE .PP \fBprefix\fR=\fIoutlet\&.N\fR .RS 4 Required\&. Specify the outlet prefix as known on the original driver\&. The subset of data points reported by the "real" UPS driver for the actual device on this prefix would be reported as data points of the virtual UPS maintained by this driver\&. .RE .SH "IMPLEMENTATION" .sp The port specification in the \fBups.conf\fR(5) should reference the local driver socket (or Windows named pipe) that the "real" UPS driver is using\&. For example: .sp .if n \{\ .RS 4 .\} .nf [realups] driver = usbhid\-ups port = auto [clone\-outlet\-1] driver = clone\-outlet port = usbhid\-ups\-realups prefix = outlet\&.1 desc = "Outlet 1 of the Real UPS" [\&.\&.\&.] .fi .if n \{\ .RE .\} .sp The driver internally interprets "real" driver\(cqs information about shutdown delay and shutdown timer, whole UPS status and this outlet\(cqs status, and relays other data points as they were\&. .sp If the outlet supports and reports a delayed power\-off, the virtual UPS would issue an FSD via ups\&.status for its clients to shut down safely\&. .sp In more detail: .sp Given the (required) prefix value such as outlet\&.1, the driver would specifically keep track of \&.status, \&.delay\&.shutdown, and \&.timer\&.shutdown data points reported by the "real" driver\&. Numeric values of the *\&.shutdown readings would be noted by this driver, and the boolean outlet status ("off" or otherwise) will be remembered\&. These values will also be re\-published by this driver "as is"\&. .sp The ups\&.status from the "real" driver would be remembered, but not re\-published by this driver immediately\&. Instead, it would be published during regular "update info" loop cycles either: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} with the "OFF" state added (if \&.status indicates the outlet is "off"), .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} or with the "FSD" state prepended (if \&.timer\&.shutdown is non\-negative and does not exceed the \&.delay\&.shutdown value), .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} or "as is" if the outlet power state is "not critical"\&. .RE .SH "IMPORTANT" .sp Unlike a real UPS, you should \fBnot\fR configure a upsmon primary mode for this driver\&. When a \fBupsmon\fR(8) primary sees the OB LB flags and tells the \fBupsd\fR(8) server it is OK to initiate the shutdown sequence, the server will latch the FSD status, and it will not be possible to restart the systems connected without restarting the upsd server\&. .sp This will be a problem if the power returns after the clone UPS initiated the shutdown sequence on its outlet, but returns before the real UPS begins shutting down\&. The solution is in the clone driver, that will insert the FSD flag if needed without the help of an upsmon primary\&. .SH "CAVEATS" .sp The clone UPS will follow the status on the real UPS driver\&. You can only make the clone UPS shutdown earlier than the real UPS driver, not later\&. If the real UPS driver initiates a shutdown, the clone\-outlet UPS driver will immediately follow\&. .sp Be aware that the commands to shutdown/restart an outlet on the real UPS drivers are not affected, so if you tell the real UPS driver to shutdown the outlet of the clone UPS driver immediately, your clients will lose power without warning\&. A delayed outlet power\-off should propagate as FSD, and the delay should be sufficiently long to allow for client shutdowns\&. .sp If you use service management frameworks like systemd or SMF to manage the dependencies between driver instances and other units, then you may have to set up special dependencies (e\&.g\&. with systemd "drop\-in" snippet files) to queue your clone drivers to start after the "real" device drivers\&. .SH "AUTHOR" .sp Arjen de Korte .SH "SEE ALSO" .sp \fBupscmd\fR(1), \fBupsrw\fR(1), \fBups.conf\fR(5), \fBclone\fR(8), \fBnutupsdrv\fR(8) .SS "Dummy driver:" .sp The "repeater" mode of \fIdummy\-ups\fR driver is in some ways similar to the \fIclone\fR and \fIclone\-outlet\fR drivers, by relaying information from a locally or remotely running "real" device driver (and NUT data server)\&. .sp \fBdummy-ups\fR(8) .SS "Internet Resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/powerman-pdu.80000644000200500020050000000700415001555100013442 00000000000000'\" t .\" Title: powerman-pdu .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "POWERMAN\-PDU" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" powerman-pdu \- Driver for Powerman PDU .SH "SYNOPSIS" .sp \fBpowerman\-pdu\fR \-h .sp \fBpowerman\-pdu\fR \-a \fIPDU_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the powerman\-pdu driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver supports a wide range of PDUs through the Powerman project\&. .sp This includes various models from APC, Baytech, Cyclades, but also support IPMI and various blade management modules from HP, IBM and Sun\&. .SH "EXTRA ARGUMENTS" .sp This driver doesn\(cqt support any optional settings\&. .SH "INSTALLATION" .sp This driver may be not built by default\&. You can build it by installing prerequisites and using configure \-\-with\-powerman=yes\&. .SH "UPS COMMANDS" .sp The following instant commands (see \fBupscmd\fR(8)) are available for each outlet of the PDU, with \fBX\fR standing for the outlet number: .PP \fBoutlet\&.X\&.load\&.on\fR .RS 4 Power on the outlet\&. .RE .PP \fBoutlet\&.X\&.load\&.off\fR .RS 4 Power off the outlet\&. .RE .PP \fBoutlet\&.X\&.load\&.cycle\fR .RS 4 Cycle the outlet (power off then power on, possibly with a delay)\&. .RE .SH "IMPLEMENTATION" .sp The hostname of the Powerman server is specified using the "port" value in \fBups\&.conf\fR, i\&.e\&.: .sp .if n \{\ .RS 4 .\} .nf [pdu] driver = powerman\-pdu port = host\&.example\&.com:port .fi .if n \{\ .RE .\} .sp The port used to reach \fIpowermand\fR is optional if the default port is used\&. .SH "KNOWN ISSUES" .sp In the current NUT version as of this writing (2\&.4\&.1), ups\&.status is still exposed, with the value "WAIT"\&. Some other values from the ups collection are also exposed\&. .SH "AUTHOR" .sp Arnaud Quette .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The PowerMan home page: https://github\&.com/chaos/powerman .RE nut-2.8.3/docs/man/bestuferrups.80000644000200500020050000000457215001555066013577 00000000000000'\" t .\" Title: bestuferrups .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "BESTUFERRUPS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" bestuferrups \- Driver for Best Power Micro\-Ferrups .SH "SYNOPSIS" .sp \fBbestuferrups\fR \-h .sp \fBbestuferrups\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the bestuferrups driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp Best Power Micro\-Ferrups ME3100, probably other similar models too\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Andreas Wrede, John Stone (bestuferrups) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Grant Taylor (bestfort) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Russell Kroll (bestups) .RE .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upscli_fd.txt0000644000200500020050000000130515001555412013450 00000000000000UPSCLI_FD(3) ============ NAME ---- upscli_fd - Get file descriptor for connection SYNOPSIS -------- ------ #include int upscli_fd(UPSCONN_t *ups); ------ DESCRIPTION ----------- The *upscli_fd()* function takes the pointer 'ups' to a `UPSCONN_t` state structure and returns the value of the file descriptor for that connection, if any. This may be useful for determining if the connection to linkman:upsd[8] has been lost. RETURN VALUE ------------ The *upscli_fd()* function returns the file descriptor, which may be any non-negative number. It returns '-1' if an error occurs. SEE ALSO -------- linkman:upscli_connect[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/upscli_add_host_cert.30000644000200500020050000000460715001555051015213 00000000000000'\" t .\" Title: upscli_add_host_cert .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_ADD_HOST_CERT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_add_host_cert \- Register a security rule for an host\&. .SH "SYNOPSIS" .sp .nf #include void upscli_add_host_cert( const char* hostname, const char* certname, int certverify, int forcessl); .fi .SH "DESCRIPTION" .sp The \fBupscli_add_host_cert()\fR function registers a security rule associated to the \fIhostname\fR\&. All connections to this host use this rule\&. .sp The rule is composed of the certificate name \fIcertname\fR expected for the host, \fIcertverify\fR if the certificate must be validated for the host and \fIforcessl\fR if a secured connection must be used to connect to the host\&. .sp Note: This call only functions if upsclient has been compiled with NSS support\&. If instead it was compiled with OpenSSL support, this function contains an empty definition and will take no action when called\&. .SH "RETURN VALUE" .sp \fBupscli_add_host_cert()\fR returns no value\&. .SH "SEE ALSO" .sp \fBupscli_init\fR(3), \fBupscli_connect\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/nutscan_free_device.30000644000200500020050000000426015001555063015023 00000000000000'\" t .\" Title: nutscan_free_device .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_FREE_DEVICE" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_free_device \- Free a `nutscan_device_t` structure created by `nutscan_new_device`\&. .SH "SYNOPSIS" .sp .nf #include void nutscan_free_device(nutscan_device_t * device); .fi .SH "DESCRIPTION" .sp The \fBnutscan_free_device()\fR function can free a nutscan_device_type_t structure\&. Doing so, it frees the whole linked list, not only the given device\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-device\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3) nut-2.8.3/docs/man/upscli_str_contains_token.30000644000200500020050000000461015001555055016315 00000000000000'\" t .\" Title: upscli_str_contains_token .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_STR_CONTAINS_" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_str_contains_token \- Verify that an unique token is present in the string .SH "SYNOPSIS" .sp .nf #include int upscli_str_contains_token(const char *string, const char *token); .fi .SH "DESCRIPTION" .sp The \fBupscli_str_contains_token\fR() function takes the pointer \fItgt\fR to a caller\-provided const char * buffer, comprised of unique tokens separated by single space characters (ASCII \fI0x20\fR), and the pointer \fItoken\fR to a presumed\-contiguous token value that should be found in the \fItgt\fR buffer\&. .SH "RETURN VALUE" .sp The \fBupscli_str_contains_token\fR() function returns a numeric code: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fInon\-zero\fR if the \fItoken\fR value was found in \fItgt\fR buffer (possibly surrounded by space characters, or being at start/end of the string); .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fI0\fR if \fItoken\fR was not found, or if either \fItoken\fR or \fItgt\fR string was NULL or empty\&. .RE .SH "SEE ALSO" .sp \fBupscli_str_add_unique_token\fR(3) nut-2.8.3/docs/man/sms_ser.80000644000200500020050000000464215001555075012517 00000000000000'\" t .\" Title: sms_ser .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "SMS_SER" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" sms_ser \- Driver for SMS UPS Protocol 1Phase\&. .SH "SYNOPSIS" .sp \fBsms_ser\fR \-h .sp \fBsms_ser\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the sms_ser driver\&. For information about the core driver, see \fBnutupsdrv\fR(8), and for the technical background check the docs/sms\-brazil\-protocol\&.txt file in NUT sources\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp Given the proximity of this protocol to Megatec Qx family, this driver may later become part of nutdrv_qx collection\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp sms_ser supports only the "sms 1phase" SMS Product, as described in the monofasico\&.xml file delivered with the device\&. .sp Other SMS protocols (for their other products) are not supported by this driver\&. .SH "AUTHOR" .sp Alex W\&. Baulé .SH "SEE ALSO" .SS "The core driver" .sp \fBnutupsdrv\fR(8) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/huawei-ups2000.txt0000644000200500020050000003647315001555412014107 00000000000000HUAWEI_UPS2000(8) ================= NAME ---- huawei-ups2000 - Driver for Huawei UPS2000 (1kVA-3kVA) UPS with USB or RS-232 serial Modbus connection. SYNOPSIS -------- *huawei-ups2000* -h *huawei-ups2000* -a 'DEVICE_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the huawei-ups2000 driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports Huawei UPS2000 series, online (double conversion) UPS with the following characteristics. 1. Output power: 1 kVA to 3 kVA (higher power models are unsupported). 2. Connection: USB or RS-232 (for most UPS models, USB is only supported on Linux 5.12 and newer kernels, but there are exceptions, read the section *Cabling* carefully). The UPS2000 series has two variants: UPS2000-A with a tower chassis, and UPS2000-G with a rack-mount chassis. Within these two variants, there are also two sub-variants: a standard runtime model powered by an internal battery pack denoted by an "S" suffix, and a long runtime model powered by an external battery pack denoted by an "L" suffix. All of these models should be equally supported, but more testers are needed. Currently, it has been tested on the following models. * UPS2000-A-1KTTS (firmware: UPS2000A, V2R1C1SPC40, P1.0-D1.0) * UPS2000-A-1KTTS (firmware: UPS2000A, V2R1C1SPC50, P1.0-D1.0) * UPS2000-A-2KTTS (firmware: UPS2000A, V2R1C1SPC50, P1.0-D1.0) * UPS2000-G-1KRTS (firmware: UPS2000A, V2R1C1SPC40, P1.0-D1.0) * UPS2000-G-1KRTS (firmware: UPS2000G, V2R1C1SPC50, P1.0-D1.0) * UPS2000-G-3KRTS (firmware: UPS2000A, V2R1C1SPC40, P1.0-D1.0) * UPS2000-G-3KRTS (firmware: UPS2000G, V2R1C1SPC50, P1.0-D1.0) * UPS2000-G-3KRTL (firmware: UPS2000A, V2R1C1SPC40, P1.0-D1.0) If your model is not in the list, we encourage you to report successful or unsuccessful results to the bug tracker or the mailing list. Make sure to include the full model number of your UPS manually in your report, because many units only report themselves as "UPS2000-A" regardless of their models, including the G series. As of 2022, there is also a new hardware variant with a WCH CH341 USB-to-serial chip instead of a MaxLinear/Exar RX21V1410 chip and reports itself as "UPS2000G". Driver support has been added since v0.03. huawei-ups2000 uses the libmodbus project, for Modbus implementation. CABLING ------- The UPS has a USB port and a RS-232 port. Both are supported, but on most UPS models, USB is only usable on Linux 5.12 and later, via the *xr_serial* kernel module. But for the newer hardware variant with a WCH CH341 chip, it should have better compatibility via the *ch341* kernel module. See subsection *USB* for details. On the other hand, RS-232 is always supported on all operating systems. Only one port can be used at a time. When USB is used, RS-232 should be unplugged from the UPS, and vice versa. Further, optional adapter cards, such as RS-485 or SNMP, are not supported. They should be removed from the UPS. Because the UPS port can be unresponsive under certain circumstances, it's recommended to power cycle your UPS after making a cabling change, especially after changing the port type. That is, turn off the UPS power output via the front panel, then unplug the UPS from line power input. Wait for the LCD screen to go black. Finally reconnect line power and restart your UPS. USB ~~~~ The USB port on the UPS2000 is originally powered by a MaxLinear/Exar RX21V1410 USB-to-serial converter chip, it's only supported by Linux 5.12 or newer, via the *xr_serial* kernel module. Its *lsusb* report is: 04e2:1410 Exar Corp. XR21V1410 USB-UART IC However, a recent hardware variant switched to the WCH CH341 serial chip: 1a86:5523 QinHeng Electronics CH341 in serial mode, usb to serial port converter If your unit has a WCH CH341 chip (likely only found in units made after 2022), when the UPS2000 is connected via USB, you should see the following logs in *dmesg*. ch341 2-1.2:1.0: ch341-uart converter detected usb 2-1.2: ch341-uart converter now attached to ttyUSB0 If so, you should be able to proceed without worrying about kernel compatibility. This CH341 chip has been around for a decade and should be compatible with your system. On the other hand, if your unit has a MaxLinear/Exar XR21V1410 chip, like most users do, when the UPS2000 is connected via USB to a supported Linux system, you should see the following logs in *dmesg*. xr_serial 1-1.2:1.1: xr_serial converter detected usb 1-1.2: xr_serial converter now attached to ttyUSB0 The driver must be *xr_serial*. If your system doesn't have the necessary device driver, you will get this message instead: cdc_acm 1-1.2:1.0: ttyACM0: USB ACM device The generic driver *cdc_acm* is incompatible and cannot be used. You should upgrade your Linux kernel to Linux 5.12 or newer. WARNING: On an unsupported system, the XR21V1410 USB device can still be recognized as a USB ACM device, but communication is impossible, please don't waste your time on *cdc_acm*. If you're already running on Linux 5.12 or newer kernels, but still cannot see the *xr_serial* driver, it means the driver is not enabled in your kernel build. If you're a regular user, you should file a bug report to your Linux distro maintainers and ask them to enable *xr_serial* (kernel option `CONFIG_USB_SERIAL_XR`). When upgrading the Linux kernel isn't an option, or when you are using another operating system (e.g. FreeBSD), RS-232 must be used. Even for CH341 users, one can try this option if USB somehow refuses to work. RS-232 ~~~~~~ RS-232 is supported on all operating systems, either via a built-in serial port on your computer, or by using an external USB-to-RS-232 converter. If you plan to use an USB-to-RS-232 converter, make sure it's supported by your operating system. INSTALLATION ------------ This driver may be not built by default. You can build it by installing libmodbus (with development packages) and running configure --with-serial=yes --with-modbus=yes You also need to give proper (R/W) permissions on the local serial device file to allow the NUT driver run-time user to access it. This may need additional setup for start-up scripting, udev or upower rules, to apply the rights on every boot -- especially if your device nodes are tracked by a virtual filesystem. For example, a USB-to-serial converter can be identified as `/dev/ttyACM0` or `/dev/ttyUSB0` on Linux, or `/dev/ttyU0` on FreeBSD (note the capital "U"). A built-in serial port can be identified as `/dev/ttyS0` on Linux or one of `/dev/cua*` names on FreeBSD. EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file: *offdelay=*'value':: Time to wait before shutting down the UPS (seconds), acceptable range is 6 seconds (0.1 minutes) to 5940 seconds (99 minutes). Defaults to 60 seconds. Must be a multiple of 6 seconds. To ensure your system has adequate time to shut down after a power failure, it's highly recommended to adjust *offdelay*. *rebootdelay=*'value':: Time to wait before rebooting the UPS (seconds), acceptable range is 6 seconds (0.1 minutes) to 5940 seconds (99 minutes). Defaults to 60 seconds. Must be a multiple of 6 seconds. This is used by the *shutdown.reboot.graceful* instant command. If you've adjusted *offdelay*, you should also adjust *rebootdelay*. *ondelay=*'value':: Time to wait before switching on the UPS (seconds), acceptable range is 60 seconds (1 minutes) to 5940 seconds (99 minutes). Defaults to 60 seconds. Must be a multiple of 60 seconds (not 6 seconds). You don't need to adjust this delay unless you have special requirements. NOTE: Due to hardware limitation, in this driver, *ondelay* is respected only when line power is available. If a power failure has occurred, the UPS and the load is always immediately switched on, as soon (or as late) as line power is restored. INSTANT COMMANDS ---------------- This driver supports some instant commands (see linkman:upscmd[8]): *shutdown.stayoff*:: After an *offdelay*, turn off the load. When line power is back, remain off. *shutdown.return*:: After an *offdelay*, turn off the load. When line power is back, turn on the load, possibly after an *ondelay*. NOTE: Normally, the load is turned on as soon as line power is back. But if line power is never lost, or has came back unexpectedly in the middle of an ongoing shutdown (an undesirable "power race" condition that many entry-level products on the market fail to recover from), the load is turned on after an *ondelay*. Thus, UPS2000 is unaffected by a power race, the load is guaranteed to always restart. *shutdown.reboot*:: Like *shutdown.return*, except that the load is turned off immediately (6 seconds in this implementation). *shutdown.reboot.graceful*:: Like *shutdown.return*, except that the load is turned off after a *rebootdelay*, not an *offdelay*. *beeper.enable*:: Enable the UPS beeper. *beeper.disable*:: Disable the UPS beeper. *beeper.toggle*:: Toggle the UPS beeper. *bypass.start*:: Put the UPS in bypass mode. Use with caution. It exposes your equipment to unregulated line power and provides no protection from power failures. Also, the UPS may shut down whenever the bypass input voltage is out of the nominal range. As a warning, the UPS beeps once every 10 seconds in bypass mode. NOTE: The driver has a basic foolproof mechanism. If the bypass input is already abnormal due to a power failure, the driver refuses to enter bypass mode by aborting the command and logging an error. However, it offers no protection after the UPS has entered (or in the middle of entering) bypass mode. Thus, again, use with caution. *bypass.stop*:: Put the UPS out of bypass mode. *load.on*:: Turn on the load immediately. *load.off*:: Turn off the load immediately. Use with caution, everything on the UPS will lost power. *test.battery.start.quick*:: Perform a short battery test. *test.battery.start.deep*:: Perform a long battery test. *test.battery.stop*:: Stop a running battery test. VARIABLES --------- This driver supports some writable runtime variables (see linkman:upsrw[8]): **ups.beeper.status**:: Enable or disable the UPS beeper, *disabled* or *enabled*. NOTE: The beeper can only be disabled completely, it cannot be temporally muted until the next alarm, but the option *muted* is also accepted for convenience, *muted* is treated as an alias of *disabled*. **ups.delay.shutdown**:: Seconds to wait after shutdown with delay command. It's the runtime equivalent of *offdelay*. See description of *offdelay*. **ups.delay.reboot**:: Seconds to wait before rebooting the UPS, it's the runtime equivalent of *rebootdelay*. See description of *rebootdelay*. **ups.delay.start**:: Seconds to wait before restarting the load, it's the runtime equivalent of *ondelay*. See description of *ondelay*. KNOWN ISSUES AND BUGS --------------------- Battery status has a non-fatal read failure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's usually harmless and can be safely ignored. It's only logged for informative purposes (*LOG_INFO*), not as a warning or error. Data stale ~~~~~~~~~~~ Under certain circumstances, some registers can return invalid values and trigger a "data stale" error. Once a data stale error has occurred, you should see error messages similar to the example below in the system log. huawei-ups2000: register 2002 has invalid value a000, upsd: Data for UPS [huawei] is stale - check driver upsd: UPS [huawei] data is no longer stale So far all known problems have been fixed by the author, but an unknown one cannot be ruled out. If you have encountered "data stale" problems during normal uses, please file a bug report with full logs attached. Before troubleshooting or reporting a problem, it's important to check your *dmesg* log for USB connect and disconnect events to avoid wasting time on the NUT driver when the actual problem is USB. For example, if someone yanks the cable out of the USB port, or if a new USB device is plugged into a USB host/hub that is struggling to power its ports (common on single-board computers like Raspberry Pi), or if you have flaky cabling or EMI noise, due to all these and similar reasons the serial converter can get disconnected from USB, at least briefly. This creates a permanent data stale situation, and the driver must be restarted (plugging the USB back won't fix it, since the driver is still using the nonexistent serial device, if the system kernel initializes a new device driver instance internally). These USB problems usually have nothing to do with NUT. If it's the case, you should solve the underlying USB problem -- check the cable, check the converter, try a powered USB hub, try a full-speed USB isolator, etc. Serial port becomes unresponsive ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some malformed commands are known to lock up the serial port (including USB, which is a USB-to-serial device). Upon receiving them, UPS2000 stops all serial communications. The result is a completely unresponsive UPS, regardless of what you do -- restarting NUT, rebooting the computer -- can not restore connectivity, as if someone has unplugged the RS-232 cable. To recover, simply power cycle the UPS: Turn off the UPS output via the front panel, then unplug the UPS from line power. Wait for the LCD front screen to go black. Finally reconnect line power and restart your UPS. That being said, a serial port lockup is unlikely to happen. To our best knowledge, this driver never sends malformed commands to the UPS (it was only a problem during early development). Furthermore, due to a CRC checksum, they're unlikely to be accidentally generated. Still, we recommend to power cycle your UPS after making a cabling change, especially after changing from RS-485/USB to RS-232, just to ensure the UPS selects the correct communication interface. Also, if you have discovered a reproducible serial port lockup problem, it can be a previously unknown bug, so please make sure to file a bug report. USB chip (MaxLinear/Exar RX21V1410) is unsupported ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As previously stated, only RS-232 is supported on all systems. On most UPS units, the USB chip RX21V1410 is used, and it requires a device-specific driver *xr_serial*, which is only available on Linux 5.12 and newer kernels. On an unsupported system, the USB device can still be recognized as a USB ACM device, but in reality, communication is impossible. It can only be fixed by implementing a driver for your system, nothing can be done within NUT. Please use the RS-232 port instead. Alternatively, if your unit has a WCH CH341 chip (likely only found in units made after 2022), it should have better compatibility. See the previous section *Cabling* for more information. Finally, in the unlike scenario that you are using NUT on Microsoft Windows, you should be able to install the USB device driver following the steps in the Huawei UPS2000 (1 kVA-3 kVA) Modbus Protocol Development Guide. AUTHOR ------ Yifeng Li SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * Huawei UPS2000-A (1 kVA-3 kVA) User Manual: https://support.huawei.com/enterprise/en/doc/EDOC1000084260 * Huawei UPS2000 (1 kVA-3 kVA) Modbus Protocol Development Guide: https://support.huawei.com/enterprise/en/doc/EDOC1000110696 * libmodbus home page: http://libmodbus.org nut-2.8.3/docs/man/upscli_readline.txt0000644000200500020050000000266215001555412014651 00000000000000UPSCLI_READLINE(3) ================== NAME ---- upscli_readline, upscli_readline_timeout - Read a single response from a UPS SYNOPSIS -------- ------ #include #include /* or on some platforms */ int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen); int upscli_readline_timeout(UPSCONN_t *ups, char *buf, size_t buflen, const time_t timeout); ------ DESCRIPTION ----------- The *upscli_readline()* and *upscli_readline_timeout()* functions take the pointer 'ups' to a `UPSCONN_t` state structure, receive a single line from the server, and copy up to 'buflen' bytes of the response into the buffer 'buf'. Some parsing of the string occurs during reception. In particular, ERR messages from linkman:upsd[8] are detected and will cause this function to return '-1'. The difference between the two functions is that *upscli_readline_timeout()* lets the caller decide the amount of time ('timeout' seconds) after which it should give up and return, whereas *upscli_readline()* does not offer this freedom, and uses NUT default network timeout (5 seconds). RETURN VALUE ------------ The *upscli_readline()* and *upscli_readline_timeout()* functions return '0' on success, or '-1' if an error occurs. SEE ALSO -------- linkman:upscli_fd[3], linkman:upscli_get[3], linkman:upscli_readline[3], linkman:upscli_sendline[3], linkman:upscli_ssl[3], linkman:upscli_strerror[3], linkman:upscli_upserror[3] nut-2.8.3/docs/man/nut-recorder.80000644000200500020050000000564215001555050013447 00000000000000'\" t .\" Title: nut-recorder .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUT\-RECORDER" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nut-recorder \- Utility to record device status and values changes .SH "SYNOPSIS" .sp \fBnut\-recorder\fR \fIdevice\-name\fR [output\-file] [interval] .SH "DESCRIPTION" .sp \fBnut\-recorder\fR is an utility to record sequences from running devices (such as power failures, or any other value changes) from \fBupsd\fR(8) data server, and dump it in a \&.seq format\&. .sp The \&.seq file can then be used by the \fBdummy-ups\fR(8) driver to replay the sequence\&. .SH "OPTIONS" .PP \fIdevice\-name\fR .RS 4 Record the changes of this device\&. The format for this option is \fIdevname[@hostname[:port]]\fR\&. The default hostname is "localhost"\&. .RE .PP \fIoutput\-file\fR .RS 4 Optional\&. Data will be saved to this file\&. The default is \fIdummy\-device\&.seq\fR\&. .RE .PP \fIinterval\fR .RS 4 Optional\&. The status of the device will be checked every \fIinterval\fR\&. The default is 5 seconds\&. .RE .SH "EXAMPLES" .sp To record data from \fIups1@host1\fR every 10 seconds: .sp .if n \{\ .RS 4 .\} .nf :; nut\-recorder ups1@host1\*(Aq ups1\-output\&.seq 10 \&. \&. \&. battery\&.charge: 100\&.0 battery\&.voltage: 13\&.9 battery\&.voltage\&.nominal: 13\&.6 ups\&.status: OL \&. \&. \&. battery\&.charge: 90\&.0 ups\&.status: OB \&. \&. \&. .fi .if n \{\ .RE .\} .sp You can then define a dummy device in \fBups.conf\fR(5): .sp .if n \{\ .RS 4 .\} .nf [ups\-test] driver = dummy\-ups port = ups1\-output\&.seq .fi .if n \{\ .RE .\} .SH "AUTHOR" .sp Arnaud Quette .SH "SEE ALSO" .SS "The dummy\-ups driver:" .sp \fBdummy-ups\fR(8) .SS "The logging daemon:" .sp \fBupslog\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan.30000644000200500020050000001040315001555056012501 00000000000000'\" t .\" Title: nutscan .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan \- Network UPS Tools (NUT) device discovery library .SH "DESCRIPTION" .sp The Network UPS Tools (NUT) \fBnutscan\fR library provides the same discovery related features that are also offered by \fBnut-scanner\fR(8)\&. .sp It enables the discovery of supported NUT devices (USB, SNMP, Eaton XML/HTTP and IPMI) and NUT servers (either using Avahi, or the classic connection method)\&. .SH "DISCOVERY FUNCTIONS" .sp First, include the required header file: .sp .if n \{\ .RS 4 .\} .nf #include .fi .if n \{\ .RE .\} .sp Then, to discover new devices, use the appropriate function: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_scan_usb\fR(3) for supported USB devices, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_scan_snmp\fR(3) for supported SNMP agents, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_scan_xml_http_range\fR(3) for Eaton Network Management Card, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_scan_nut\fR(3) for NUT servers (upsd), using the classic method (search for port), .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_scan_avahi\fR(3) for NUT servers (upsd), using the mDNS (Avahi) method, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_scan_ipmi\fR(3) for supported IPMI PSU\&. .RE .sp All of these functions return a list of devices found, using the nutscan_device_t structure\&. This structure is described in \fBnutscan_add_device_to_device\fR(3)\&. .sp Helper functions are also provided to output data using standard formats: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_display_parsable\fR(3) for parsable output, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_display_ups_conf\fR(3) for ups\&.conf style, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBnutscan_display_ups_conf_with_sanity_check\fR(3) for ups\&.conf style with comments for warnings about possible configuration problems (if any)\&. .RE .SH "ERROR HANDLING" .sp There is currently no specific mechanism for error handling\&. .SH "SEE ALSO" .sp \fBnut-scanner\fR(8), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_add_ip_range\fR(3), \fBnutscan_cidr_to_ip\fR(3) .SS "Internet resources:" .sp http://avahi\&.org/ nut-2.8.3/docs/man/nutscan_add_commented_option_to_device.30000644000200500020050000000005015001555117020750 00000000000000.so man3/nutscan_add_option_to_device.3 nut-2.8.3/docs/man/nutclient_device_master.30000644000200500020050000000003515001555117015723 00000000000000.so man3/libnutclient_misc.3 nut-2.8.3/docs/man/safenet.txt0000644000200500020050000000517415001555412013135 00000000000000SAFENET(8) ========== NAME ---- safenet - Driver for SafeNet compatible UPS equipment SYNOPSIS -------- *safenet* -h *safenet* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the safenet driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver supports UPS equipment which can be controlled via SafeNet v1.0 for Windows (serial interface only). EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file: *manufacturer=*'value':: Autodetection of this parameter is not possible yet (and it probably never will be). Therefore, this user-defined string accepts any name. The default is 'unknown'. *modelname=*'value':: Like manufacturer above. The default is 'unknown'. *serialnumber=*'value':: Like manufacturer above. The default is 'unknown'. *ondelay=*'value':: Time to wait before switching on the UPS (minutes). Defaults to 1 minute. *offdelay=*'value':: Time to wait before shutting down the UPS (seconds). Defaults to 30 seconds. INSTANT COMMANDS ---------------- This driver supports some instant commands (see linkman:upscmd[8]): *test.battery.start*:: Start UPS self test *test.battery.stop*:: Cancel UPS self test *test.failure.start*:: Start simulated power failure *test.failure.stop*:: Cancel simulated power failure *beeper.enable*:: Enable the UPS beeper *beeper.mute*:: Temporarily mute the UPS beeper *beeper.toggle*:: Toggle the UPS beeper *shutdown.return*:: Turn off the load and wait for the power to return. Uses the timer defined by *offdelay*. *shutdown.reboot*:: Turn off the load and return. Uses the timers defined by *offdelay* and *ondelay*. KNOWN PROBLEMS -------------- If you run the *shutdown.return* command with mains present, the output may stay on or switch off and not back on again. The *shutdown.reboot* command will unconditionally switch on the load again (with or without mains present). If the driver is called with the '-k' option (or through *upsdrvctl shutdown*) it tries to detect which command should be used in an attempt to stay off until mains is present again or to cycle the output if the power returned in the mean time. This isn't bullet-proof, and you should be prepared that the power will either not be shutdown, or that it doesn't return when the power comes back. AUTHOR ------ Arjen de Korte SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/generic_modbus.txt0000644000200500020050000001374015001555412014473 00000000000000GENERIC_MODBUS(8) ================= NAME ---- generic_modbus - Driver for contact (direct) signal UPS devices connected via modbus remote I/O gateways SYNOPSIS -------- *generic_modbus* -h *generic_modbus* -a 'DEVICE_NAME' ['OPTIONS'] NOTE: This man page only documents the specific features of the *generic_modbus* driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This is a generic modbus driver expected to work with contact (direct) signal UPS devices, connected via modbus RIO (remote I/O) either serial or TCP/IP. The driver has been tested against PULS UPS (model UB40.241) via MOXA ioLogikR1212 (RS485) and ioLogikE1212 (TCP/IP). More information about this UPS can be found here: :: https://products.pulspower.com/ca/ubc10-241-n1.html More information about Moxa ioLogik R1212, E1212 can be found here: :: https://www.moxa.com/en/products/industrial-edge-connectivity/controllers-and-ios The PULS UPS UB40.241 supports the following signals: ---- Ready contact (DO) <--> HB Buffering contact (DO) <--> OL | OB Battery-low (DO) <--> LB Replace Battery (DO) <--> RB Inhibit (DI) <--> FSD ---- Digital port direction (DI/DO) assumes the device perspective The driver's concept is to map the UPS states (as defined in NUT) onto UPS contacts' states. The driver has an extended configuration interface implemented using variables defined in ups.conf. HARDWARE INTERCONNECTION ------------------------ The commission of modbus remote I/O server as well as UPS device is carried out following the corresponding instruction manuals. The following figure depicts the anticipated communication path and hardware interconnection: ---- +------+ +----------------+ +------------+ +------------+ | UPSD | <---> | GENERIC_MODBUS | <---> | MODBUS RIO | <---> | UPS DEVICE | +------+ (1) +----------------+ (2) +------------+ (3) +------------+ | | +-------------------+ HOST CONTROLLER (1) Unix IPC (2) RS232 | TCP/IP (3) contacts ---- EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5] file: Generic: ~~~~~~~~ *device_mfr*='value':: A string specifying the manufacturer of the UPS device (default UNKNOWN). *device_model*='value':: A string specifying the model of the UPS device (default UNKNOWN). Serial: ~~~~~~~ *ser_baud_rate*='value':: A integer specifying the serial port baud rate (default 9600). *ser_data_bit*='value':: A integer specifying the serial port data bit (default 8). *ser_parity*='value':: A character specifying the serial port parity (default N). *ser_stop_bit*='value':: An integer specifying the serial port stop bit (default 1). Modbus: ~~~~~~~ *rio_slave_id*='value':: An integer specifying the RIO modbus slave ID (default 1). States (X = OL, OB, LB, HB, RB, CHRG, DISCHRG, FSD) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *_addr*='value':: A number specifying the modbus address for the X state. *_regtype*='value':: A number specifying the modbus register type for the X state Default values: :: + ---- 1 for X = OL, OB, LB ,HB, RB, CHRG, DISCHRG 0 for X = FSD ---- Valid values: :: + ---- 0:COIL, 1:INPUT_B, 2:INPUT_R, 3:HOLDING ---- *_noro*='value':: A number specifying the contact configuration for the X state (default 1). Valid values: :: + ---- 0:NC, 1:NO ---- + NOTE: NO stands for normally open and NC for normally closed contact Shutdown ~~~~~~~~ *FSD_pulse_duration*='value':: A number specifying the duration in ms for the inhibit pulse. If it's not defined, signal has only one transition depending on FSD_noro configuration. + Examples for FSD signal configuration: ---- FSD_noro = 1 FSD_pulse_duration = 150 +-----+ | | inhibit pulse >-----+ +------------------> <---> 150ms FSD_noro = 0 inhibit pulse >-----+ | +------------------------> ---- CONFIGURATION ------------- Here is an example of generic_modbus driver configuration in *ups.conf* file: ---- [generic_modbus] driver = generic_modbus port = /dev/ttyUSB0 desc = "generic ups driver" # device info device_mfr = "PULS" device_model = "UB40.241" # serial settings ser_baud_rate = 9600 ser_parity = N ser_data_bit = 8 ser_stop_bit = 1 # modbus slave id rio_slave_id = 5 # UPS signal state attributes OB_addr = 0x0 OB_regtype = 1 OB_noro = 0 LB_addr = 0x1 LB_regtype = 1 HB_addr = 0x2 HB_regtype = 1 RB_addr = 0x3 RB_regtype = 1 FSD_addr = 0x0 FSD_regtype = 0 FSD_pulse_duration = 150 ---- INSTANT COMMANDS ---------------- This driver support the following instant commands: load.off:: executes "instant poweroff" INSTALLATION ------------ This driver may be not built by default. You can build it by installing libmodbus and running `configure --with-modbus=yes`. You also need to give proper permissions on the local serial device file (`/dev/ttyUSB0` for example) to allow the run-time NUT driver user account to access it. OTHER NOTES ----------- The `generic_modbus` driver intends to support generic UPS devices with contact signals through modbus TCP/RTU gateways (also known as RIO -- remote I/Os). The data and signal path looks like this: ---- [UPSD] <--- IPC ---> [GENERIC_UPS] <--- modbus TCP/RTU ---> MODBUS-RIO <--- contacts ---> [UPS DEVICE] ---- On the other hand, you can setup any kind of modbus server, and configure the `generic_modbus` driver to connect and read or write specific registers. Your application / modbus server could then drive NUT statuses (e.g. OL, OB, HB etc) by writing over those registers. AUTHOR ------ Dimitris Economou SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8], linkman:ups.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ * The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ * libmodbus home page: http://libmodbus.org nut-2.8.3/docs/man/hosts.conf.50000644000200500020050000000560315001555050013114 00000000000000'\" t .\" Title: hosts.conf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "HOSTS\&.CONF" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" hosts.conf \- Access control for Network UPS Tools CGI programs .SH "DESCRIPTION" .sp The CGI programs (\fBupsset.cgi\fR(8), \fBupsstats.cgi\fR(8), \fBupsimage.cgi\fR(8)) use this file to determine if they are allowed to talk to a host\&. This keeps random visitors from using your web server to annoy others by creating outgoing connections\&. .SH "IMPORTANT NOTES" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} This file does not contain passwords\&. Read\-only monitoring in NUT is anonymous, and the \fBupsset\fR(8) program asks for credentials in the browser session when commanding a particular UPS (web\-server should be secured, as reported to the program by \fBupsset.conf\fR(5) file)\&. .RE .SH "DIRECTIVES" .PP \fBMONITOR\fR \fIups\fR \fIdescription\fR .RS 4 The \fIups\fR element is in the form upsname[@hostname[:port]]\&. .sp To allow connections to an UPS called "snoopy" on a system called "doghouse" that runs upsd on port 7877, it would look like this: .sp .if n \{\ .RS 4 .\} .nf MONITOR snoopy@doghouse:7877 "Joe Cool" .fi .if n \{\ .RE .\} .sp The description must be one element, so if it has spaces, then it must be wrapped with quotes as shown above\&. The default hostname is "localhost"\&. .RE .SH "SEE ALSO" .sp \fBupsset.cgi\fR(8), \fBupsstats.cgi\fR(8), \fBupsimage.cgi\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upscli_init_default_connect_timeout.txt0000644000200500020050000000550715001555412021015 00000000000000UPSCLI_INIT_DEFAULT_CONNECT_TIMEOUT(3) ====================================== NAME ---- upscli_init_default_connect_timeout - Initialize upsclient module aspect of default timeout for initial connections. SYNOPSIS -------- ------ #include int upscli_init_default_connect_timeout( const char *cli_secs, const char *config_secs, const char *default_secs); ------ DESCRIPTION ----------- The *upscli_init_default_connect_timeout()* function initializes upsclient module aspect of default connection timeout for linkman:upscli_connect[3], which may be important when e.g. linkman:upsc[8] scripting or linkman:upsmon[8] configuration refers to unresponsive hosts, or when the host name resolution lags, etc. By default, linkman:upscli_connect[3] blocks indefinitely in its attempts to connect (or until the system transport layer interrupts such an attempt). It populates the value from different sources, mostly C strings which represent a floating-point non-negative number (invalid parsing is logged and may impact the return value), any or all of them may be `NULL` to skip, and in specific order (last valid hit wins): * built-in '0' meaning indefinitely blocking (NUT default for this method over at least 20 years); * the number from `default_secs` as a particular NUT or third-party client program's built-in preferred (low-priority) default; * the number from `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable as a site-local preference (generally pre-set in linkman:nut.conf[5]); * the number from `config_secs` as a particular NUT or third-party client program's configuration file default; * the number from `cli_secs` as a particular NUT or third-party client program's setting from command line (highest priority). Internally, calls linkman:upscli_set_default_connect_timeout[3] for most of the string related processing. The upsclient module tracks if *upscli_init_default_connect_timeout()* function was called and succeeded, in order to call it once (if never used) from the linkman:upscli_connect[3] or linkman:upscli_init[3] methods. This allows unmodified (legacy) NUT clients to consistently benefit from presence of the `NUT_DEFAULT_CONNECT_TIMEOUT` environment variable. This tracking does not preclude programs from explicitly calling the method any amount of times. RETURN VALUE ------------ The *upscli_init_default_connect_timeout()* function returns '0' on success (either if all strings were `NULL` so the built-in default is applied, or at least one of those strings that were set was valid and its value got applied), or '-1' if an error occurs (at least one string was not `NULL`, and none of the strings was valid). SEE ALSO -------- linkman:upscli_connect[3], linkman:upscli_tryconnect[3], linkman:upscli_set_default_connect_timeout[3], linkman:upscli_get_default_connect_timeout[3], linkman:upscli_init[3] nut-2.8.3/docs/man/nutscan_display_sanity_check.30000644000200500020050000000473015001555060016753 00000000000000'\" t .\" Title: nutscan_display_sanity_check .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_DISPLAY_SANI" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_display_sanity_check \- Display sanity check warnings about the specified `nutscan_device_t` structure on stdout\&. .SH "SYNOPSIS" .sp .nf #include void nutscan_display_sanity_check(nutscan_device_t * device); .fi .SH "DESCRIPTION" .sp The \fBnutscan_display_sanity_check()\fR function calls all sanity\-check analyzers against displays all NUT devices in \fIdevice\fR, and they may print comments to stdout\&. It displays them in a way that it can be directly copied into the ups\&.conf file\&. .sp It is called from \fBnutscan_display_ups_conf_with_sanity_check()\fR to provide an aggregate content for ups\&.conf file in one shot\&. .SH "SEE ALSO" .sp \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_add_device_to_device\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/nutscan_scan_ipmi.30000644000200500020050000000673215001555060014530 00000000000000'\" t .\" Title: nutscan_scan_ipmi .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_SCAN_IPMI" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_scan_ipmi \- Scan local IPMI devices\&. .SH "SYNOPSIS" .sp .nf #include nutscan_device_t * nutscan_scan_ipmi( const char * startIP, const char * stopIP, nutscan_ipmi_t * sec); nutscan_device_t * nutscan_scan_ip_range_ipmi( nutscan_ip_range_list_t * irl, nutscan_ipmi_t * sec); .fi .SH "DESCRIPTION" .sp The \fBnutscan_scan_ipmi()\fR and \fBnutscan_scan_ip_range_ipmi()\fR functions try to detect IPMI manageable devices\&. .sp If \fIstart_ip\fR for the former or \fIirl\fR for the latter are NULL, the respective function searches for a local PSU\&. .sp Otherwise, it searches for remote hosts that would serve IPMI protocols, and would try to authenticate using the data in \fIsec\fR structure\&. .sp The former issues an IPMI request on every IP ranging from \fIstartIP\fR to \fIstopIP\fR, where \fIstartIP\fR is mandatory and \fIstopIP\fR is optional (one \fIstartIP\fR address is scanned if \fIstopIP\fR is NULL); while the latter can walk several IP address ranges represented by a nutscan_ip_range_list_t structure\&. .sp Those IP arguments may be either IPv4 or IPv6 addresses or host names\&. .sp You MUST call \fBnutscan_init\fR(3) before using this function\&. .SH "BUGS" .sp Design or implementation of this function may be incomplete: until recently, this man page stated that it was not implemented yet\&. Source code is present, although some blocks are commented away or hidden with #if 0\&. .SH "RETURN VALUE" .sp The \fBnutscan_scan_ipmi()\fR function is not implemented yet\&. .SH "SEE ALSO" .sp \fBnutscan_init\fR(3), \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_snmp\fR(3), \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3), \fBnutscan_new_device\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3), \fBnutscan_init_ip_ranges\fR(3), \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_add_ip_range\fR(3), \fBnutscan_cidr_to_ip\fR(3) nut-2.8.3/docs/man/nutscan_new_device.30000644000200500020050000000442715001555062014677 00000000000000'\" t .\" Title: nutscan_new_device .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_NEW_DEVICE" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_new_device \- Create a new nutscan_device_t structure\&. .SH "SYNOPSIS" .sp .nf #include nutscan_device_t * nutscan_new_device(void); .fi .SH "DESCRIPTION" .sp The \fBnutscan_new_device()\fR function allocates a new nutscan_device_type_t structure\&. .SH "RETURN VALUE" .sp The \fBnutscan_new_device()\fR function returns the newly allocated nutscan_device_type_t structure\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-device\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_scan_usb\fR(3), \fBnutscan_scan_xml_http_range\fR(3), \fBnutscan_scan_nut\fR(3), \fBnutscan_scan_avahi\fR(3), \fBnutscan_scan_ipmi\fR(3), \fBnutscan_scan_snmp\fR(3) \fBnutscan_display_ups_conf\fR(3), \fBnutscan_display_parsable\fR(3) \fBnutscan_display_sanity_check\fR(3), \fBnutscan_display_sanity_check_serial\fR(3), \fBnutscan_display_ups_conf_with_sanity_check\fR(3), \fBnutscan_free_device\fR(3), \fBnutscan_add_option_to_device\fR(3) \fBnutscan_add_device_to_device\fR(3) nut-2.8.3/docs/man/nut-ipmipsu.80000644000200500020050000001241715001555100013322 00000000000000'\" t .\" Title: nut-ipmipsu .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUT\-IPMIPSU" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nut-ipmipsu \- Driver for IPMI Power Supply Units (PSU) .SH "SYNOPSIS" .sp \fBnut\-ipmipsu\fR \-h .sp \fBnut\-ipmipsu\fR \-a \fIPSU_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This driver is experimental, and still a work\-in\-progress\&. Feedback is encouraged\&. .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the nut\-ipmipsu driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp This driver should support a wide range of PSUs through local IPMI interface\&. .sp nut\-ipmipsu currently uses the GNU FreeIPMI project, for IPMI implementation\&. .SH "EXTRA ARGUMENTS" .sp This driver doesn\(cqt support any optional settings\&. .SH "INSTALLATION" .sp This driver may be not built by default\&. You can build it by installing the libfreeipmi\-dev dependencies and using configure \-\-with\-ipmi=yes\&. .sp You also need to give proper permissions on the local IPMI device file (/dev/ipmi0 for example) to allow the NUT user to access it\&. .sp An \fBudev\fR rules file (nut\-ipmipsu\&.rules) is provided and automatically installed on an \fBudev\fR enabled system\&. This file is generally installed in /etc/udev/rules\&.d/, or /lib/udev/rules\&.d/ on newer systems, to address the permission settings problem\&. .sp For more information, refer to scripts/udev/README\&.adoc in NUT sources\&. .SH "INSTANT COMMANDS" .sp This driver doesn\(cqt support any instant commands\&. .SH "IMPLEMENTATION" .sp The port value is used to identify the PSU\&. For instance, to target FRU \fI0x2\fR, use the following in \fBups\&.conf\fR: .sp .if n \{\ .RS 4 .\} .nf [pdu] driver = nut\-ipmipsu port = id2 .fi .if n \{\ .RE .\} .sp This driver will report various information related to a PSU, including: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} manufacturer, model, serial and part numbers, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} nominal voltage and frequency, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} actual current and voltage, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} status of the PSU: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIOL\fR means that the PSU is present and providing power, .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIOFF\fR means that the PSU is present but not providing power (power cable removed), .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fIstale\fR (no data) means that the PSU is not present (i\&.e\&. physically removed)\&. .RE .RE .sp Here is an example output for a Dell r610 server: .sp .if n \{\ .RS 4 .\} .nf device\&.mfr: DELL device\&.mfr\&.date: 01/05/11 \- 08:51:00 device\&.model: PWR SPLY,717W,RDNT device\&.part: 0RN442A01 device\&.serial: CN179721130031 device\&.type: psu driver\&.name: nut\-ipmipsu driver\&.parameter\&.pollinterval: 2 driver\&.parameter\&.port: id2 driver\&.version: 2\&.6\&.1\-3139M driver\&.version\&.data: IPMI PSU driver driver\&.version\&.internal: 0\&.01 input\&.current: 0\&.20 input\&.frequency\&.high: 63 input\&.frequency\&.low: 47 input\&.voltage: 232\&.00 input\&.voltage\&.maximum: 264 input\&.voltage\&.minimum: 90 ups\&.id: 2 ups\&.realpower\&.nominal: 717 ups\&.status: OL ups\&.voltage: 12 .fi .if n \{\ .RE .\} .SH "AUTHOR" .sp Arnaud Quette .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} GNU FreeIPMI home page: http://www\&.gnu\&.org/software/freeipmi/ .RE nut-2.8.3/docs/man/nut-driver-enumerator.txt0000644000200500020050000001234515001555412015764 00000000000000NUT-DRIVER-ENUMERATOR(8) ======================== NAME ---- nut-driver-enumerator - Tool to map NUT device entries to service instances SYNOPSIS -------- *nut-driver-enumerator.sh* -h *nut-driver-enumerator.sh* (no args) *nut-driver-enumerator.sh* [--COMMAND] DESCRIPTION ----------- *nut-driver-enumerator.sh* implements the set-up and querying of the mapping between NUT driver configuration sections for each individual monitored device, and the operating system service management framework service instances into which such drivers are wrapped for independent execution and management (on platforms where NUT currently supports this integration -- currently this covers Linux distributions with systemd and systems derived from Solaris 10 codebase, including proprietary Sun/Oracle Solaris and numerous open-source illumos distributions with SMF). It may be not installed in packaging for other operating systems. This script provides a uniform interface for further NUT tools such as linkman:upsdrvsvcctl[8] to implement their logic as platform-independently as was possible and practical. It is not currently intended for end-user consumption (and so is located in the 'libexec' directory), with *upsdrvsvcctl* exposing the most useful data and actions with its 'list' and 'resync' arguments. One part of the platform complexity that *nut-driver-enumerator.sh* hides is the difference of rules for valid service instance names in various frameworks, as well as system tools and naming patterns involved. COMMANDS -------- *nut-driver-enumerator.sh (no args)*:: Update wrapping of devices into services *nut-driver-enumerator.sh --daemon(=freq)*:: Update wrapping of devices into services in an infinite loop; Default freq is 60 sec. *nut-driver-enumerator.sh --daemon-after(=freq)*:: Update wrapping of devices into services in an infinite loop; first do one run of the loop though, then daemonize (this way service unit is deemed started only when NUT config and driver instances are in sync). Default freq is 60 sec. *nut-driver-enumerator.sh --reconfigure*:: Stop and un-register all service instances and recreate them (e.g. if new dependency template was defined in a new version of the script or package) *nut-driver-enumerator.sh --get-service-framework*:: Print the detected service management framework in this OS *nut-driver-enumerator.sh --list-devices*:: Print list of devices in NUT config *nut-driver-enumerator.sh --list-services*:: Print list of service instances which wrap registered NUT devices (full name of service unit) *nut-driver-enumerator.sh --list-instances*:: Print list of service instances which wrap registered NUT devices (just instance suffix) *nut-driver-enumerator.sh --get-service-for-device DEV*:: Print the full name of service unit which wraps a NUT device named `DEV` *nut-driver-enumerator.sh --get-device-for-service SVC*:: Print the NUT device name for full or instance-suffix name of a service unit `SVC` which wraps it *nut-driver-enumerator.sh --list-services-for-devices*:: Print a TAB-separated list of service units and corresponding NUT device names which each such unit wraps *nut-driver-enumerator.sh --show-all-configs*:: Show the complete normalized list of device configuration blocks (same as used later by the parser in the script to make decisions) *nut-driver-enumerator.sh --show-device-config DEV*:: Show configuration block of the specified NUT device *nut-driver-enumerator.sh --show-device-config-value DEV KEY*:: Show single configuration key of the specified NUT device ENVIRONMENT VARIABLES --------------------- By default *nut-driver-enumerator.sh* executed without arguments would automatically start any newly registered service instances wrapping the NUT devices, and would also restart the `nut-server` service if the configuration was changed. Environment variable `AUTO_START=no` disables this default part of the action. Also see below for environment variable `REPORT_RESTART_42=no` value. DIAGNOSTICS ----------- *nut-driver-enumerator.sh* will return a zero exit code if it had nothing to do (all currently defined drivers match all of the currently defined service instances, one-to-one) and if it had no errors in its operation. Other codes can be returned as a result of re-synchronization of mappings: *42*:: NUT device sections and system service instances differed before, but now match up -- so now the caller should likely restart some services. Note that the drivers' service instances may have been started or stopped as required (by `AUTO_START=yes`) -- but maybe the upsmon or upssched services should restart. If you pass environment variable `REPORT_RESTART_42=no` then this codepath would return 0 (as a non-error exit code). In default mode, such non-null reconfiguration should cause the nut-driver-enumerator service to restart and this would propagate to other NUT services that depend on it. *13*:: Sections and services differed, and still do not match up *1*:: Bad inputs, e.g. unrecognized service management framework *2*:: Absent or unreadable `ups.conf` file AUTHOR ------ Jim Klimov SEE ALSO -------- linkman:upsdrvsvcctl[8], linkman:ups.conf[5] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/upsset.cgi.80000644000200500020050000001131515001555050013114 00000000000000'\" t .\" Title: upsset.cgi .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSSET\&.CGI" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsset.cgi \- Web\-based UPS administration program .SH "SYNOPSIS" .sp \fBupsset\&.cgi\fR .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp As a CGI program, this should be invoked through your web server\&. If you run it from the command line, it will sit there until you give it input resembling a POST request\&. .sp .5v .RE .SH "DESCRIPTION" .sp \fBupsset\&.cgi\fR lets you access many administrative functions within the UPS software from your web browser\&. You can change settings and invoke instant commands where available\&. .SH "CHANGING SETTINGS" .sp Some UPS hardware allows you to change certain variables to other values\&. To see what\(cqs available, pick a UPS from the chooser and select "settings", then select "View" to update the page\&. .sp You should see a list of items with the descriptions on the left side and the possible options or input spaces on the right\&. After changing something, be sure to "Save changes" to update the values in your UPS\&. .sp If your UPS doesn\(cqt support any read/write variables, there will be nothing to do on this page\&. .sp Setting values in read/write variables can also be done from the command line with \fBupsrw\fR(8)\&. .SH "INSTANT COMMANDS" .sp Some UPS hardware also has provisions for performing certain actions at the user\(cqs command\&. These include battery tests, battery calibration, front panel tests (beep!) and more\&. To access this section, do as above, but pick "Commands" as the function\&. .sp If your UPS supports any instant commands, they will be listed in a chooser widget\&. Pick the one you like and "Issue command" to make it happen\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp some dangerous commands like "Turn off load" may not happen right away\&. This is a feature, not a bug\&. .sp .5v .RE .sp The apcsmart driver and some others require that you send this command twice within a short window in order to make it happen\&. This is to keep you from accidentally killing your systems by picking the wrong one\&. .sp To actually turn off the load, you have to send the command once, then send it again after 3 seconds elapse but before 15 seconds pass\&. If you do it too quickly or slowly, you have to wait at least 3 seconds but not 15 seconds again\&. .sp You can also invoke instant commands from the command line with \fBupscmd\fR(8)\&. .SH "ACCESS CONTROL" .sp It sends commands and settings via the server \fBupsd\fR(8) to your driver, which manages the hardware for you\&. You must use credentials defined in \fBupsd.users\fR(5) file on that data server with appropriate permissions\&. .sp upsset will only talk to \fBupsd\fR(8) servers that have been defined in your \fBhosts.conf\fR(8)\&. If it complains about "Access to that host is not authorized", check your hosts\&.conf first\&. .SH "SECURITY" .sp upsset will not run until you convince it that your CGI directory has been secured\&. This is due to the possibility of someone using upsset to try password combinations against your \fBupsd\fR(8) server\&. .sp See the example upsset\&.conf file for more information on how you do this\&. The short explanation is\(emif you can\(cqt lock it down, don\(cqt try to run it\&. .SH "FILES" .sp \fBhosts.conf\fR(5), \fBupsset.conf\fR(5) .SH "SEE ALSO" .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan_cidr_to_ip.txt0000644000200500020050000000226515001555412015354 00000000000000NUTSCAN_CIDR_TO_IP(3) ===================== NAME ---- nutscan_cidr_to_ip - Convert a CIDR IP to a range of IP address. SYNOPSIS -------- ------ #include int nutscan_cidr_to_ip(const char * cidr, char ** start_ip, char ** stop_ip); ------ DESCRIPTION ----------- The *nutscan_cidr_to_ip()* function converts a range of IP address in the CIDR format given as a string in 'cidr', to two IPs in strings pointed by 'start_ip' and 'stop_ip' which can be used as input parameters in the scanning functions of the libnutscan API. It is the caller's responsibility to linkmanext:free[3] the 'start_ip' and 'stop_ip' strings. RETURN VALUE ------------ The *nutscan_cidr_to_ip()* function returns '0' if an error occurred (invalid 'cidr' address) or '1' if successful. NOTES ----- Technically, the function is currently defined in 'nutscan-ip.h' file. SEE ALSO -------- linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_display_ups_conf[3] nut-2.8.3/docs/man/upscli_sendline_timeout.30000644000200500020050000000003315001555117015750 00000000000000.so man3/upscli_sendline.3 nut-2.8.3/docs/man/asem.80000644000200500020050000000753615001555101011764 00000000000000'\" t .\" Title: asem .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "ASEM" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" asem \- Driver for UPS in ASEM PB1300 .SH "SYNOPSIS" .sp \fBasem\fR \-h .sp \fBasem\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBasem\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The \fBasem\fR driver supports the UPS in ASEM PB1300 embedded PCs\&. Likely other I2C devices from the same manufacturer will work too, since this is a "custom" charger\&. .sp Seems that there are two versions of the charger\&. Older one is based on Max1667, newer one is a custom solution\&. Both are on I2C address \fB0x09\fR\&. To be compatible with both versions, the driver just reads \fBbit 15\fR of address \fB0x13\fR which yields online/on battery status\&. .sp Battery monitor is a BQ2060 at address \fB0x0B\fR\&. .SH "EXTRA ARGUMENTS" .sp The required parameter for this driver is the I2C bus name: .PP \fBport\fR=\fIdev\-node\fR .RS 4 On the Asem PB1300, this should be /dev/i2c\-7 for the i801 SMBUS adapter\&. .RE .sp This driver also supports the following optional settings: .PP \fBlb\fR=\fInum\fR .RS 4 Set the low battery threshold to \fInum\fR volts\&. .RE .PP \fBhb\fR=\fInum\fR .RS 4 Set the high battery threshold to \fInum\fR volts\&. .RE .SH "INSTALLATION" .sp This driver is specific to the Linux I2C API, and requires the libi2c\-dev library and headers from lm_sensors project, or its equivalent, to compile\&. .sp Beware that the SystemIO memory used by the I2C controller is reserved by ACPI\&. If only a native I2C driver (e\&.g\&. i2c_i801, as of 3\&.5\&.X Linux kernels) is available, then you\(cqll need to relax the ACPI resources check\&. For example, you can boot with the acpi_enforce_resources=lax option\&. .SH "KNOWN ISSUES AND BUGS" .sp The driver shutdown function is not implemented, so other arrangements must be made to turn off the UPS\&. .SH "AUTHOR" .sp Giuseppe Corbelli .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} PB1300 specifications: http://www\&.asem\&.it/en/products/industrial\-automation/box\-pcs/performance/pb1300/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} BQ2060 datasheet: http://www\&.ti\&.com/lit/ds/symlink/bq2060\&.pdf .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ .RE nut-2.8.3/docs/man/nutscan_scan_ipmi.txt0000644000200500020050000000420315001555412015175 00000000000000NUTSCAN_SCAN_IPMI(3) ==================== NAME ---- nutscan_scan_ipmi - Scan local IPMI devices. SYNOPSIS -------- ------ #include nutscan_device_t * nutscan_scan_ipmi( const char * startIP, const char * stopIP, nutscan_ipmi_t * sec); nutscan_device_t * nutscan_scan_ip_range_ipmi( nutscan_ip_range_list_t * irl, nutscan_ipmi_t * sec); ------ DESCRIPTION ----------- The *nutscan_scan_ipmi()* and *nutscan_scan_ip_range_ipmi()* functions try to detect IPMI manageable devices. If 'start_ip' for the former or 'irl' for the latter are NULL, the respective function searches for a local PSU. Otherwise, it searches for remote hosts that would serve IPMI protocols, and would try to authenticate using the data in 'sec' structure. The former issues an IPMI request on every IP ranging from 'startIP' to 'stopIP', where 'startIP' is mandatory and 'stopIP' is optional (one 'startIP' address is scanned if 'stopIP' is NULL); while the latter can walk several IP address ranges represented by a `nutscan_ip_range_list_t` structure. Those IP arguments may be either IPv4 or IPv6 addresses or host names. You MUST call linkman:nutscan_init[3] before using this function. BUGS ---- Design or implementation of this function may be incomplete: until recently, this man page stated that it was not implemented yet. Source code is present, although some blocks are commented away or hidden with `#if 0`. RETURN VALUE ------------ The *nutscan_scan_ipmi()* function is not implemented yet. SEE ALSO -------- linkman:nutscan_init[3], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_display_parsable[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_init_ip_ranges[3], linkman:nutscan_free_ip_ranges[3], linkman:nutscan_add_ip_range[3], linkman:nutscan_cidr_to_ip[3] nut-2.8.3/docs/man/upscli_set_default_connect_timeout.txt0000644000200500020050000000272415001555412020643 00000000000000UPSCLI_SET_DEFAULT_CONNECT_TIMEOUT(3) ===================================== NAME ---- upscli_set_default_connect_timeout - Configure upsclient module aspect of default timeout for initial connections. SYNOPSIS -------- ------ #include int upscli_set_default_connect_timeout(const char *secs); ------ DESCRIPTION ----------- The *upscli_set_default_connect_timeout()* function assigns upsclient module internal default connection timeout for linkman:upscli_connect[3] from a C string which represents a floating-point non-negative number (invalid parsing is ignored and does not modify the previously stored value), a `NULL` argument value sets the internal timeout to '0' meaning indefinitely blocking (NUT default for this method over at least 20 years). While this method can be called explicitly, it is recommended to call the linkman:upscli_init_default_connect_timeout[3] for consistent setting from a number of sources with different priority. RETURN VALUE ------------ The *upscli_set_default_connect_timeout()* function returns '0' on success (either if the strings was `NULL` so the built-in default '0' is applied, or if its content was valid and its value got applied), or '-1' if an error occurs (string was not `NULL`, and its content was not valid -- not a number, negative, etc.) SEE ALSO -------- linkman:upscli_connect[3], linkman:upscli_tryconnect[3], linkman:upscli_init_default_connect_timeout[3], linkman:upscli_get_default_connect_timeout[3] nut-2.8.3/docs/man/apc_modbus.80000644000200500020050000003452215001555101013146 00000000000000'\" t .\" Title: apc_modbus .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "APC_MODBUS" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" apc_modbus \- Driver for APC Smart\-UPS Modbus protocol .SH "SYNOPSIS" .sp \fBapc_modbus\fR \-h .sp \fBapc_modbus\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .SH "SUPPORTED HARDWARE" .sp Generally this driver should work for all the APC Modbus UPS devices\&. Some devices might expose more than is currently supported, like multiple phases\&. A general rule of thumb is that APC devices (or firmware versions) released after 2010 are more likely to support Modbus than the USB HID standard\&. .sp Tested with the following hardware: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} SMT1500 (Smart\-UPS 1500, Firmware 9\&.6) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} SMX750 (Smart\-UPS X 750, Firmware 10\&.1) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} SMX1500 (Smart\-UPS X 1500, Firmware 15\&.0) .RE .sp Note that you will have to enable Modbus communication\&. In the front panel of the UPS, go to Advanced Menu mode, under Configuration and enable Modbus\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This driver was tested with Serial, TCP and USB interfaces for Modbus\&. Notably, the Serial ports are not available on all devices nowadays; the TCP support may require a purchase of an additional network management card; and the USB support \fBcurrently\fR requires a non\-standard build of libmodbus (pull request against the upstream library is pending, as of at the time of this publication) as a pre\-requisite to building NUT with this part of the support\&. For more details (including how to build the custom library and NUT with it) please see NUT PR #2063 .sp .5v .RE .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp As currently published, this driver supports reading information from the UPS\&. Implementation of support to write (set modifiable variables or send commands) is expected with a later release\&. This can impact the host shutdown routines in particular (no ability to actively tell the UPS to power off or cycle in the end)\&. As a workaround, you can try integrating apctest (from the "apcupsd" project) with a "Test to kill power" into your late\-shutdown procedure, if needed\&. .sp .5v .RE .SH "EXTRA ARGUMENTS" .sp This driver also supports the following optional settings: .PP \fBport =\fR \fIstring\fR .RS 4 Some \fIvalue\fR must be set, typically \fBauto\fR\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br This could be a device filesystem path like /dev/usb/hiddev0 but current use of libusb API precludes knowing and matching by such identifiers\&. They may also be inherently unreliable (dependent on re\-plugging and enumeration order)\&. At this time the actual \fIvalue\fR is ignored, but syntactically some \fIport\fR configuration must still be there\&. .sp .5v .RE .RE .sp It is possible to control multiple UPS units simultaneously by running several instances of this driver, provided they can be uniquely distinguished by setting some combination of the \fBvendor\fR, \fBproduct\fR, \fBvendorid\fR, \fBproductid\fR, \fBserial\fR, \fBbus\fR and/or \fBdevice\fR options detailed below\&. For devices or operating systems that do not provide sufficient information, the \fBallow_duplicates\fR option can be of use (limited and risky!) .PP \fBvendorid =\fR \fIregex\fR, \fBproductid =\fR \fIregex\fR, \fBvendor =\fR \fIregex\fR, \fBproduct =\fR \fIregex\fR, \fBserial =\fR \fIregex\fR .RS 4 Select a specific UPS, in case there is more than one connected via USB\&. Each option specifies an extended regular expression (see \fBregex\fR(7) for more information on regular expressions), which must match the UPS\(cqs entire respective vendor/product/serial string values (minus any surrounding whitespace), or the whole 4\-digit hexadecimal code for vendorid and productid\&. .sp Try \fBlsusb\fR(8) or running this NUT driver with \-DD command\-line argument for finding out the strings to match\&. .sp Examples: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendor="Foo\&.Corporation\&.*" .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x vendorid="051d*" (APC) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \-x product="\&.*(Smart|Back)\-?UPS\&.*" .RE .RE .PP \fBbus =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB bus or group of buses\&. The argument is a regular expression that must match the bus name where the UPS is connected (e\&.g\&. bus="002" or bus="00[2\-3]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .RE .PP \fBdevice =\fR \fIregex\fR .RS 4 Select a UPS on a specific USB device or group of devices\&. The argument is a regular expression that must match the device name where the UPS is connected (e\&.g\&. device="001" or device="00[1\-2]") as seen on Linux in /sys/bus/usb/devices or \fBlsusb\fR(8); including leading zeroes\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br device numbers are not guaranteed by the OS to be stable across re\-boots or device re\-plugging\&. .sp .5v .RE .RE .PP \fBbusport =\fR \fIregex\fR .RS 4 If supported by the hardware, OS and libusb on the particular deployment, this option should allow to specify physical port numbers on an USB hub, rather than logical device enumeration values, and in turn \(em this should be less volatile across reboots or re\-plugging\&. The value may be seen in the USB topology output of lsusb \-tv on systems with that tool, for example\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br this option is not practically supported by some NUT builds (it should be ignored with a warning then), and not by all systems that NUT can run on\&. .sp .5v .RE .RE .PP \fBallow_duplicates\fR .RS 4 If you have several UPS devices which may not be uniquely identified by the options above (e\&.g\&. only \fIVID:PID\fR can be discovered there), this flag allows each driver instance where it is set to take the first match if available, or proceed to try another\&. .sp Normally the driver initialization would abort at this point claiming "Resource busy" or similar error, assuming that the otherwise properly matched device is unique \(em and some other process already handles it\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBWarning\fR .ps -1 .br This feature is inherently non\-deterministic! The association of driver instance name to actual device may vary between runs! .sp If you only care to know that \fBat least\fR one of your no\-name UPSes is online, this option can help\&. .sp If you must really know \fBwhich\fR one, it will not! .sp .5v .RE .RE .PP \fBusb_set_altinterface =\fR \fIbAlternateSetting\fR .RS 4 Force redundant call to usb_set_altinterface(), especially if needed for devices serving multiple USB roles where the UPS is not represented by the interface number 0 (default)\&. .RE .PP \fBusb_config_index\fR, \fBusb_hid_rep_index\fR, \fBusb_hid_desc_index\fR, \fBusb_hid_ep_in\fR, \fBusb_hid_ep_out\fR .RS 4 Force use of specific interface, endpoint, descriptor index etc\&. numbers, rather than defaulting to \fI0\fR (rarely other values in certain drivers for some devices known to use non\-zero numbers)\&. Specified as a hexadecimal number\&. .sp As a rule of thumb for usb_hid_desc_index discovery, you can see larger wDescriptorLength values (roughly 600+ bytes) in reports of lsusb or similar tools\&. .RE .PP \fBLIBUSB_DEBUG =\fR \fIINTEGER\fR .RS 4 Run\-time troubleshooting of USB\-capable NUT drivers can involve not only raising the common NUT debug verbosity (e\&.g\&. using the DEBUG_MIN setting in \fBups.conf\fR(5) or protocol commands to change the driver\&.debug value), but may also benefit from LibUSB specific debugging\&. .sp For the latter, you can set the LIBUSB_DEBUG driver option; alternatively you can classically export the environment variable LIBUSB_DEBUG before starting a NUT driver program (may be set and "exported" in driver init script or service method, perhaps via \fBnut.conf\fR(5)), to a numeric value such as 4 ("All messages are emitted")\&. .sp For more details, including the currently supported values for your version of the library, see e\&.g\&.: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/group__libusb__lib\&.html .RE .RE .PP \fBporttype\fR=\fIvalue\fR .RS 4 Set the type of the port used\&. Available values are serial for RS232/485 based connections, tcp for TCP/IP connections and usb for USB connections\&. .RE .PP \fBport\fR=\fIvalue\fR .RS 4 Depending on the port type you can select a port here\&. For usb only auto is supported, for serial you can pass a device path like /dev/ttyS0 and for tcp you can pass a hostname with optional port like example\&.com:502\&. .RE .PP \fBbaudrate\fR=\fInum\fR .RS 4 Set the speed of the serial connection\&. The default baudrate is 9600\&. .RE .PP \fBparity\fR=\fIvalue\fR .RS 4 Set the parity of the serial connection\&. Available values are N for none, E for even and O for odd\&. The default parity is N (none)\&. .RE .PP \fBdatabits\fR=\fInum\fR .RS 4 Set the data bits of the serial connection\&. The default databits is 8\&. .RE .PP \fBstopbits\fR=\fInum\fR .RS 4 Set the stop bits of the serial connection\&. The default stopbits is 1\&. .RE .PP \fBslaveid\fR=\fInum\fR .RS 4 Set the Modbus slave id\&. The default slave id is 1\&. .RE .PP \fBresponse_timeout_ms\fR=\fInum\fR .RS 4 Set the Modbus response timeout\&. The default timeout is set by libmodbus\&. It can be good to set a higher timeout on TCP connections with high latency\&. .RE .SH "BUGS" .sp This driver relies on advanced features of libmodbus to talk Modbus protocol over USB specifically (Serial and TCP are part of common library codebase)\&. At the time of this writing, the common library project is just expecting a merge of the pull request with this ability\&. .sp For the time being, if your OS distribution does not ship the required feature set, you may have to build your own libmodbus and subsequently (re\-)build NUT against this library, as detailed in the NUT GitHub Wiki at https://github\&.com/networkupstools/nut/wiki/APC\-UPS\-with\-Modbus\-protocol .sp The short sequence may be like follows: .sp .if n \{\ .RS 4 .\} .nf cd ~/ git clone \-b rtu_usb https://github\&.com/networkupstools/libmodbus cd libmodbus \&./autogen\&.sh \&./configure \-\-with\-libusb \-\-prefix=/path/to/prefix make install .fi .if n \{\ .RE .\} .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} you may need to \(oqmake && sudo make install` if you want to place this library files\(cq variant into a system path (like \-\-prefix=/usr/local/ups to match NUT defaults \(em this activity would need privilege elevation via sudo), and not into your home directory or some /tmp location\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} conversely, you may want to \&./configure \-\-with\-libusb \-\-enable\-static \-\-disable\-shared \-\-prefix=/path/to/prefix and only build and install a static libmodbus\&.a (can well be installed into /tmp or similarly short\-lived location), so that the customized Modbus+USB logic gets built directly into apc_modbus binary program and there would be no potential run\-time conflict with a dynamic library file available elsewhere in the system\&. .RE .sp .5v .RE .sp .if n \{\ .RS 4 .\} .nf cd ~/ git clone https://github\&.com/networkupstools/nut cd nut \&./autogen\&.sh \&./configure \-\-with\-drivers=apc_modbus \-\-with\-usb \-\-with\-modbus \e \-\-with\-modbus\-includes=\-I/path/to/prefix/include/modbus \e \-\-with\-modbus\-libs="\-L/path/to/prefix/lib \-lmodbus" make .fi .if n \{\ .RE .\} .sp .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Other NUT configure options may be needed for proper behavior, such as \-\-prefix, \-\-with\-sysconfdir, \-\-with\-user and \-\-with\-group to match your packaged or otherwise preceding NUT installation\&. .RE .sp .5v .RE .sp The \&./configure \-\-enable\-inplace\-runtime may be a good start to inherit build configuration from an existing NUT deployment, as further detailed at https://github\&.com/networkupstools/nut/wiki/Building\-NUT\-for\-in%E2%80%90place\-upgrades\-or\-non%E2%80%90disruptive\-tests .SH "AUTHORS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Axel Gembe .RE .SH "SEE ALSO" .SS "The core driver" .sp \fBnutupsdrv\fR(8), \fBups.conf\fR(5) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upsrw.80000644000200500020050000001451715001555047012225 00000000000000'\" t .\" Title: upsrw .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSRW" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upsrw \- Network UPS Tools device/driver variable administration tool .SH "SYNOPSIS" .sp \fBupsrw\fR [\-l] \fIups\fR .sp \fBupsrw\fR \-h .sp \fBupsrw\fR \-s \fIvariable\fR [\-u \fIusername\fR] [\-p \fIpassword\fR] [\-w] [\-t ] \fIups\fR .SH "DESCRIPTION" .sp \fBupsrw\fR allows you to view and change the read/write variables inside your UPS\&. It sends commands via the server \fBupsd\fR(8) to your driver, which configures the hardware for you\&. You must use credentials defined in \fBupsd.users\fR(5) file on that data server with appropriate permissions\&. .sp The list of variables that allow you to change their values is based on the capabilities of your UPS equipment\&. Not all models support this feature\&. Typically, cheaper hardware does not support any of them\&. Run upsrw with a UPS identifier to see what will work for you\&. .SH "OPTIONS" .PP \fB\-s\fR \fIvariable\fR .RS 4 Specify the variable to be changed inside the UPS\&. For unattended mode such as in shell scripts, use the format VAR=VALUE to specify both the variable and the value, for example: .sp .if n \{\ .RS 4 .\} .nf \-s input\&.transfer\&.high=129 .fi .if n \{\ .RE .\} .sp Without this argument, upsrw will just display the list of the variables and their possible values\&. .sp Some variables are strings, and can be set to any value within the length limit\&. Others are enumerated types and can only be set to one of those values\&. Others may be within an allowed range of values\&. Refer to the list to know what\(cqs available in your hardware\&. .RE .PP \fB\-l\fR .RS 4 Just display the list of the variables and their possible values\&. .sp Same as default activity without \fI\-s\fR argument, provided for CLI similarity with other tools\&. .RE .PP \fB\-u\fR \fIusername\fR .RS 4 Set the NUT username for the connection to the server\&. This is optional, and you will be prompted for this when using the \-s option if you don\(cqt specify \-u on the command line\&. NUT usernames are defined in \fBupsd.users\fR(5), and are not linked to system usernames\&. .RE .PP \fB\-p\fR \fIpassword\fR .RS 4 Set the password to authenticate to the server\&. This is also optional like \-u, and you will be prompted for it if necessary\&. .RE .PP \fB\-w\fR .RS 4 Wait for the completion of setting execution by the driver and return its actual result from the device\&. Note that this feature requires that both \fBupsd\fR(8) and the driver support TRACKING (NUT version 2\&.8\&.0 or higher), or it will otherwise fail\&. .sp The command will also block until an actual result is provided from the driver, or the timeout is reached (see \fB\-t\fR)\&. .RE .PP \fB\-t\fR \fIseconds\fR .RS 4 Set a timeout when using \fB\-w\fR\&. Defaults to 10 seconds\&. .RE .PP \fIups\fR .RS 4 View or change the settings on this UPS\&. The format for this option is upsname[@hostname[:port]]\&. The default hostname is "localhost"\&. .RE .SH "COMMON OPTIONS" .PP \fB\-h\fR .RS 4 Show the command\-line help message\&. .RE .PP \fB\-V\fR .RS 4 Show NUT version banner\&. More details may be available if you also export NUT_DEBUG_LEVEL=1 or greater verbosity level\&. .RE .PP \fB\-W\fR \fIsecs\fR .RS 4 Set the timeout for initial network connections (by default they are indefinitely non\-blocking, or until the system interrupts the attempt)\&. Overrides the optional NUT_DEFAULT_CONNECT_TIMEOUT environment variable\&. .RE .SH "UNATTENDED MODE" .sp If you run this program inside a shell script or similar to set variables, you will need to specify all of the information on the command line\&. This means using \-s VAR=VALUE, \-u and \-p\&. Otherwise it will put up a prompt and your program will hang\&. .sp This is not necessary when displaying the list, as the username and password are not required for read\-only mode\&. .sp Moreover, if you run this program inside a shell script or similar, you should only consider using output from stdout, not stderr\&. .SH "DIAGNOSTICS" .sp \fBupsrw\fR can\(cqt set variables on your UPS unless you provide a valid username and password\&. If you get "access denied" errors, make sure that your \fBupsd.users\fR(5) has an entry for you, and that the username you are using has permissions to SET variables\&. .sp \fBupsrw\fR without \fI\-w\fR would somewhat confusingly show "OK" meaning just that the data server connection was established, and the server did not immediately reject the request due to e\&.g\&. unknown driver variable name\&. If you care to know the actual results, do use the \-w (\-t NUM) option(s) to wait for them\&. .SH "VALUE FORMAT" .sp When using \fBupsrw\fR to modify a numeric float value, that values must be given using decimal (base 10) english\-based representation, so using a dot, in non\-scientific notation\&. So hexadecimal, exponents, and comma for thousands separator are forbidden\&. .sp For example: "1200\&.20" is valid, while "1,200\&.20" and "1200,20" are invalid\&. .SH "HISTORY" .sp This program used to be called upsct2, which was ambiguous and confusing\&. .SH "SEE ALSO" .sp \fBupsd\fR(8), \fBupscmd\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/microdowell.txt0000644000200500020050000000151215001555412014020 00000000000000MICRODOWELL(8) ============== NAME ---- microdowell - Driver for Microdowell Enterprise UPS series SYNOPSIS -------- *microdowell* -h *microdowell* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the Microdowell driver. For information about the core driver, see linkman:nutupsdrv[8]. SUPPORTED HARDWARE ------------------ This driver was developed for the Enterprise Nxx and Bxx models. Other Microdowell models may work, too. EXTRA ARGUMENTS --------------- This driver does not support any extra settings in the linkman:ups.conf[5]. AUTHOR ------ Elio Corbolante SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/ups.conf.50000644000200500020050000005027515001555046012575 00000000000000'\" t .\" Title: ups.conf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPS\&.CONF" "5" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" ups.conf \- UPS definitions for Network UPS Tools .SH "DESCRIPTION" .sp This file is read by the driver controller \fBupsdrvctl\fR(8), the UPS drivers which use the common core (see \fBnutupsdrv\fR(8)), \fBnut-driver-enumerator\fR(8), and the NUT data server \fBupsd\fR(8)\&. The file begins with global directives, and then each UPS has a section which contains a number of directives that set parameters for that UPS\&. .sp A UPS section begins with the name of the UPS in brackets, and continues until the next UPS name in brackets or until EOF\&. The name "default" is used internally in \fBupsd\fR(8), so you can\(cqt use it in this file\&. .sp You must define the \fIdriver\fR and \fIport\fR elements for each entry\&. Anything after that in a section is optional\&. A simple example might look like this: .sp .if n \{\ .RS 4 .\} .nf [myups] driver = blazer_ser port = /dev/ttyS0 desc = "Web server UPS" .fi .if n \{\ .RE .\} .sp A slightly more complicated version includes some extras for the hardware\-specific part of the driver: .sp .if n \{\ .RS 4 .\} .nf [bigups] driver = apcsmart port = /dev/cua00 cable = 940\-0095B sdtype = 2 desc = "Database server UPS" .fi .if n \{\ .RE .\} .sp In this case, the \fBapcsmart\fR(8) driver will receive variables called "cable" and "sdtype" which have special meanings\&. See the man pages of your driver(s) to learn which variables are supported and what they do\&. .sp Here is another example, when connecting a serial UPS on Windows: .sp .if n \{\ .RS 4 .\} .nf [windows\-ups] driver = mge\-shut port = "\e\e\e\e\&.\e\eCOM10" desc = "UPS on a Windows machine" .fi .if n \{\ .RE .\} .SH "IMPORTANT NOTES" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Contents of this file should be pure ASCII (character codes not in range would be ignored with a warning message)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Balance the run\-time user permissions to access the file (and perhaps the directory it is in) for only upsd and the drivers to be able to read it; write access is not needed\&. It is common to use chown root:nut and chmod 640 to set up acceptable file permissions\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Packages (and build recipes) typically prepare one set of user and group accounts for NUT\&. Custom builds with minimal configuration might even use nobody:nogroup or similar, which is inherently insecure\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} On systems with extra security concerns, NUT drivers, data server should run as separate user accounts which would be members of one same group for shared access to local Unix socket files and the directory they are in, as well for reading ups\&.conf, but different groups for other configuration file access\&. This would need some daemons to use customized user, group, RUN_AS_USER and/or RUN_AS_GROUP settings to override the single built\-in value\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Note that the monitoring, logging, etc\&. clients are networked\-only\&. They do not need access to these files and directories, and can run as an independent user and group altogether\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Keep in mind the security of also any backup copies of this file, e\&.g\&. the archive files it might end up in\&. .RE .RE .SH "GLOBAL DIRECTIVES" .PP \fBchroot\fR .RS 4 Optional\&. The driver will chroot(2) to this directory during initialization\&. This can be useful when securing systems\&. .RE .PP \fBdriverpath\fR .RS 4 Optional\&. Path name of the directory in which the UPS driver executables reside\&. If you don\(cqt specify this, the programs look in a built\-in default directory, which is often /usr/local/ups/bin\&. .RE .PP \fBstatepath\fR .RS 4 Optional\&. Path name of the directory in which the UPS drivers should place their state sockets for local communication with upsd data server, rather than the default location that was compiled into the program, which is often /var/state/ups\&. .sp Note that the drivers must use the same path as upsd, so the data server would prefer this setting from ups\&.conf global section, if present, over its own in upsd\&.conf\&. .sp Environment variable NUT_STATEPATH set by caller can override this setting\&. .RE .PP \fBmaxstartdelay\fR .RS 4 Optional\&. Same as the UPS field of the same name, but this is the default for UPSes that don\(cqt have the field\&. .RE .PP \fBmaxretry\fR .RS 4 Optional\&. Specify the number of attempts to start the driver(s), in case of failure, before giving up\&. A delay of \fIretrydelay\fR is inserted between each attempt\&. Caution should be taken when using this option, since it can impact the time taken by your system to start\&. .sp The default is 1 attempt\&. .RE .PP \fBnowait\fR .RS 4 Optional\&. Specify to upsdrvctl to not wait at all for the driver(s) to execute the request command\&. .sp The default (omission) is to wait\&. .sp It can be overridden by NUT_IGNORE_NOWAIT environment variable (e\&.g\&. used to work around certain issues with systemd otherwise)\&. .RE .PP \fBretrydelay\fR .RS 4 Optional\&. Specify the delay between each restart attempt of the driver(s), as specified by \fImaxretry\fR\&. Caution should be taken when using this option, since it can impact the time taken by your system to start\&. .sp The default is 5 seconds\&. .RE .PP \fBpollinterval\fR .RS 4 Optional\&. The status of the UPS will be refreshed after a maximum delay which is controlled by this setting\&. This is normally 2 seconds\&. This setting may be useful if the driver is creating too much of a load on your monitoring system or network\&. .sp Note that some drivers (such as \fBusbhid-ups\fR(8), \fBsnmp-ups\fR(8) and \fBnutdrv_qx\fR(8)) also have an option called \fBpollfreq\fR which controls how frequently some of the less critical parameters are polled\&. Details are provided in the respective driver man pages\&. .RE .PP \fBsynchronous\fR .RS 4 Optional\&. The drivers work by default in asynchronous mode initially but can fall back to synchronous mode if writes to server socket failed (i\&.e \fBsynchronous=auto\fR)\&. This means that all data are pushed by the driver on the communication socket to upsd (Unix socket on Unix, Named pipe on Windows) without waiting for these data to be actually consumed\&. With some HW, such as ePDUs, that can produce a lot of data, asynchronous mode may cause some congestion, resulting in the socket to be full, and the driver to appear as not connected\&. In such case, the driver will provide the following debug message: .sp .if n \{\ .RS 4 .\} .nf write XX bytes to socket Y failed .fi .if n \{\ .RE .\} .sp By enabling the \fIsynchronous\fR flag (value = \fIyes\fR), the driver will wait for data to be consumed by upsd, prior to publishing more\&. This can be enabled either globally or per driver\&. .sp The default of \fIauto\fR acts like \fIno\fR (i\&.e\&. asynchronous mode) for backward compatibility of the driver behavior, until communications fail with a "Resource temporarily unavailable" condition, which happens when the driver has many data points to send in a burst, and the server can not handle that quickly enough so the buffer fills up\&. .RE .PP \fBuser\fR .RS 4 Optional\&. Overrides the compiled\-in default unprivileged username for all NUT device drivers\&. See the discussion of the \-u option in \fBnutupsdrv\fR(8) for details\&. .RE .PP \fBgroup\fR .RS 4 Optional\&. Overrides the compiled\-in (and/or global\-section) default unprivileged group name for all NUT device drivers, used for the socket file access\&. See the discussion of the \-g option in \fBnutupsdrv\fR(8) for details\&. This may be specifically useful for ensuring access to dynamic device filesystem nodes, such as USB (or serial\-over\-USB) hot\-plug support, or with device filesystems re\-generated by an OS for every reboot\&. .RE .PP \fBdebug_min\fR \fIINTEGER\fR .RS 4 Optional\&. Specify a minimum debug level for all driver daemons, e\&.g\&. for troubleshooting a deployment, without impacting foreground or background running mode directly\&. Command\-line option \-D can only increase this verbosity level\&. .RE .PP \fBLIBUSB_DEBUG\fR \fIINTEGER\fR .RS 4 Optional\&. For run\-time troubleshooting of USB\-capable NUT drivers, you can specify verbosity of LibUSB specific debugging as a numeric value such as 4 ("All messages are emitted")\&. Should not have any practical impact on other NUT drivers\&. .sp For more details, including the currently supported values for your version of the library, see e\&.g\&.: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/group__libusb__lib\&.html .RE .RE .SH "UPS FIELDS" .PP \fBdriver\fR .RS 4 Required\&. This specifies which program will be monitoring this UPS\&. You need to specify the one that is compatible with your hardware\&. See \fBnutupsdrv\fR(8) for more information on drivers in general and pointers to the man pages of specific drivers\&. .RE .PP \fBport\fR .RS 4 Required\&. This is the serial port where the UPS is connected\&. On a Linux system, the first serial port usually is \fI/dev/ttyS0\fR\&. On FreeBSD and similar systems, it probably will be \fI/dev/cuaa0\fR\&. On Windows, the first serial port will be "\e\e\e\e\&.\e\eCOM1" (note the escaped slashes)\&. .RE .PP \fBuser\fR .RS 4 Optional\&. Overrides the compiled\-in (and/or global\-section) default unprivileged username for a particular NUT device driver\&. See the discussion of the \-u option in \fBnutupsdrv\fR(8) for details\&. This may be specifically useful for ensuring access to dynamic device filesystem nodes, such as USB (or serial\-over\-USB) hot\-plug support, or with device filesystems re\-generated by an OS for every reboot\&. .RE .PP \fBgroup\fR .RS 4 Optional\&. Overrides the compiled\-in (and/or global\-section) default unprivileged group name for a particular NUT device driver, used for the socket file access\&. See the discussion of the \-g option in \fBnutupsdrv\fR(8) for details\&. This may be specifically useful for ensuring access to dynamic device filesystem nodes, such as USB (or serial\-over\-USB) hot\-plug support, or with device filesystems re\-generated by an OS for every reboot\&. .RE .PP \fBsdorder\fR .RS 4 Optional\&. When you have multiple UPSes on your system, you usually need to turn them off in a certain order\&. upsdrvctl shuts down all the 0s, then the 1s, 2s, and so on\&. To exclude a UPS from the shutdown sequence, set this to \-1\&. .sp The default value for this parameter is 0\&. .RE .PP \fBsdcommands\fR .RS 4 Optional\&. Comma\-separated list of instant command name(s) to send to the UPS when you request its shutdown\&. .sp Default logic is built into each driver (where supported) and can be referenced here as the shutdown\&.default value\&. .sp The primary use\-case is for devices whose drivers "natively" support trying several commands, but the built\-in order of those calls a command that is mis\-handled by the specific device model (so the handling is reported as successful and the loop stops, but nothing happens as far as the load power\-down is concerned)\&. .sp Another use\-case is differentiation of automated power\-off scenarios where the UPS and its load should stay "OFF" (e\&.g\&. by building emergency power\-off) vs\&. those where the load should return to work automatically when it is safe to do so\&. NOTE: This would \fBcurrently\fR need editing of ups\&.conf for such cases before nutshutdown sees the file; but could be better automated in future NUT releases\&. .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br User\-provided commands may be something other than actual shutdown, e\&.g\&. a beeper to test that the INSTCMD happened such and when expected, and the device was contacted, without impacting the load fed by the UPS\&. .sp .5v .RE .RE .PP \fBallow_killpower\fR .RS 4 Optional\&. This allows you to request driver\&.killpower instant command, to immediately call the driver\-specific default implementation of upsdrv_shutdown() method, for same effect as when a NUT driver is started with \-k command\-line flag\&. This option can be toggled with \fBupsrw\fR(8) as driver\&.flag\&.allow_killpower during run\-time\&. .RE .PP \fBdesc\fR .RS 4 Optional\&. This allows you to set a brief description that upsd will provide to clients that ask for a list of connected equipment\&. .RE .PP \fBnolock\fR .RS 4 Optional\&. When you specify this, the driver skips the port locking routines every time it starts\&. This may allow other processes to seize the port if you start more than one accidentally\&. .sp You should only use this if your system won\(cqt work without it\&. .sp This may be needed on Mac OS X systems\&. .RE .PP \fBignorelb\fR .RS 4 Optional\&. When you specify this, the driver ignores a low battery condition flag that is reported by the UPS (some devices will switch off almost immediately after setting this flag, or will report this as soon as the mains fails)\&. Instead it will use either of the following conditions to determine when the battery is low: .sp .if n \{\ .RS 4 .\} .nf battery\&.charge < battery\&.charge\&.low battery\&.runtime < battery\&.runtime\&.low .fi .if n \{\ .RE .\} .sp The idea is to set the battery\&.charge\&.low and/or battery\&.runtime\&.low levels in \fBups\&.conf\fR to a value that gives enough time to cleanly shutdown your system: .sp .if n \{\ .RS 4 .\} .nf override\&.battery\&.charge\&.low = 30 override\&.battery\&.runtime\&.low = 180 .fi .if n \{\ .RE .\} .sp In order for this to work, your UPS should be able to (reliably) report charge and/or runtime remaining on battery\&. Use with caution! .RE .PP \fBmaxstartdelay\fR .RS 4 Optional\&. This can be set as a global variable above your first UPS definition and it can also be set in a UPS section\&. This value controls how long upsdrvctl will wait for the driver to finish starting\&. This keeps your system from getting stuck due to a broken driver or UPS\&. .sp Note that after this time upsdrvctl would just move along with its business (whether retrying the same driver if maxretry>1, or trying another driver if starting them all, or just eventually exit); however, each such most recently started "stuck" driver process may be further initializing in the background, and might even succeed eventually\&. .sp They would not be actively killed by upsdrvctl after this timeout expires\&. .sp The default is 75 seconds\&. .RE .PP \fBmaxretry\fR .RS 4 Optional\&. This can be set as a global variable above your first UPS definition and it can also be set in a UPS section\&. See explanation above, in the global section\&. .RE .PP \fBretrydelay\fR .RS 4 Optional\&. This can be set as a global variable above your first UPS definition and it can also be set in a UPS section\&. See explanation above, in the global section\&. .RE .PP \fBsynchronous\fR .RS 4 Optional\&. Same as the global directive of the same name, but this is for a specific device\&. .RE .PP \fBusb_set_altinterface\fR[=\fIaltinterface\fR] .RS 4 Optional\&. Force the USB code to call usb_set_altinterface(0), as was done in NUT 2\&.7\&.2 and earlier\&. This should not be necessary, since the default for bAlternateSetting (as shown in lsusb) is zero on all USB devices seen to date\&. However, this redundant call to usb_set_altinterface() prevents certain UPSes from working on Mac OS X\&. If your UPS requires explicitly setting the alternate interface, include this flag, and email the nut\-upsdev list with details about your UPS and operating system\&. .RE .PP \fBusb_config_index\fR, \fBusb_hid_rep_index\fR, \fBusb_hid_desc_index\fR, \fBusb_hid_ep_in\fR, \fBusb_hid_ep_out\fR .RS 4 Optional\&. Force use of specific interface, endpoint, descriptor index etc\&. numbers, rather than defaulting to 0 (rarely other values in certain drivers for some devices known to use non\-zero numbers)\&. Specified as a hexadecimal number\&. .sp As a rule of thumb for usb_hid_desc_index discovery, you can see larger wDescriptorLength values (roughly 600+ bytes) in reports of lsusb or similar tools\&. .RE .PP \fBdefault\&.\fR .RS 4 Optional\&. Set a default value for which is used in case the UPS doesn\(cqt provide a value, but will be overwritten if a value is available from the UPS: .sp .if n \{\ .RS 4 .\} .nf default\&.input\&.voltage\&.nominal = 230 .fi .if n \{\ .RE .\} .sp The above will report the nominal input voltage to be 230, unless the UPS tells us differently\&. .RE .PP \fBoverride\&.\fR .RS 4 Optional\&. Set a value for that overrides any value that may be read from the UPS\&. Used for overriding values from the UPS that are clearly wrong (some devices report wrong values for battery voltage for instance): .sp .if n \{\ .RS 4 .\} .nf override\&.battery\&.voltage\&.nominal = 12 .fi .if n \{\ .RE .\} .sp Use with caution! This will only change the appearance of the variable to the outside world, internally in the UPS the original value is used\&. .RE .sp All other fields are passed through to the hardware\-specific part of the driver\&. See those manuals for the list of what is allowed\&. .PP \fBdebug_min\fR \fIINTEGER\fR .RS 4 Optional\&. Specify a minimum debug level for this driver daemon, e\&.g\&. for troubleshooting a deployment, without impacting foreground or background running mode directly\&. If the global debug_min is also set, this driver\-level setting overrides it\&. Command\-line option \-D can only increase this verbosity level\&. .RE .PP \fBLIBUSB_DEBUG\fR \fIINTEGER\fR .RS 4 Optional\&. For run\-time troubleshooting of USB\-capable NUT drivers, you can specify verbosity of LibUSB specific debugging as a numeric value such as 4 ("All messages are emitted")\&. .sp For more details, including the currently supported values for your version of the library, see e\&.g\&.: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/ .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} https://libusb\&.sourceforge\&.io/api\-1\&.0/group__libusb__lib\&.html .RE .RE .SH "INTEGRATION" .sp \fBupsdrvctl\fR(8) uses this file to start and stop the drivers\&. .sp The drivers themselves also obtain configuration data from this file\&. Each driver looks up its section and uses that to configure itself\&. .sp \fBupsd\fR(8) learns about which UPSes are installed on this system by reading this file\&. If this system is called "doghouse" and you have defined a UPS in your \fBups\&.conf\fR called "snoopy", then you can monitor it from \fBupsc\fR(8) or similar as "snoopy@doghouse"\&. .SH "SEE ALSO" .sp \fBupsd\fR(8), \fBnutupsdrv\fR(8), \fBupsdrvctl\fR(8), \fBupsdrvsvcctl\fR(8) .SS "Internet resources" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/upscli_init.30000644000200500020050000001101315001555051013341 00000000000000'\" t .\" Title: upscli_init .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "UPSCLI_INIT" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" upscli_init \- Initialize upsclient module specifying security properties\&. .SH "SYNOPSIS" .sp .nf #include int upscli_init( int certverify, const char *certpath, const char *certname, const char *certpasswd); .fi .SH "DESCRIPTION" .sp The \fBupscli_init()\fR function initializes upsclient module and sets many TLS/SSL\-related properties: \fIcertverify\fR to 1 makes certificate verification required for all SSL connections and \fIcertpath\fR is the location of certificate database\&. .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If compiled with OpenSSL, \fIcertpath\fR refers to directory containing certificates where the certificates must be named according to their hash values ending in a "\&.0" extension\&. If two certificates result in the same hash value (thus file name), the "\&.0" can be incremented to "\&.1" and so on, as needed\&. The shell command for creating links in this manner would be: .sp .if n \{\ .RS 4 .\} .nf :; ln \-s ca\&.pem \&./$(openssl x509 \-hash \-noout \-in ca\&.pem)\&.0 .fi .if n \{\ .RE .\} .sp Alternatively, the c_rehash utility (provided by e\&.g\&. openssl\-perl package) can take a directory and iterate it to link all certificates found in that directory, in the manner described above\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} If compiled with NSS, \fIcertpath\fR refers to a directory containing its database files\&. .RE .sp If compiled with NSS and using SSL, you can specify \fIcertname\fR with the name of the certificate to send to upsd, and \fIcertpasswd\fR with the password used to decrypt certificate private key\&. .sp If compiled with NSS, it would normally log either the infamous message "Init SSL without certificate database" if no \fIcertpath\fR was provided, or "Init SSL with certificate database located at %s" otherwise\&. Since some programmatic consumers become confused by such extra text on the stderr of tools they call (such as monitoring systems doing upsc queries), you can export an environment variable NUT_QUIET_INIT_SSL with string values "true", "TRUE" or "1", to avoid logging these messages and just emit them as debug stream (at verbosity 1 or higher)\&. .sp As part of general initialization, \fBupscli_init()\fR function can call the \fBupscli_init_default_connect_timeout\fR(3) method (if it was never used before): this allows unmodified (legacy) NUT clients to consistently benefit from presence of the NUT_DEFAULT_CONNECT_TIMEOUT environment variable for \fBupscli_connect\fR(3) attempts to be not blocking (as per default)\&. .sp You can call \fBupscli_add_host_cert\fR(3) to register specific host security policy before initialize connections to them\&. .sp You must call \fBupscli_cleanup\fR(3) when exiting application\&. .SH "RETURN VALUE" .sp The \fBupscli_init()\fR function returns \fI1\fR on success, or \fI\-1\fR if an error occurs\&. .SH "SEE ALSO" .sp \fBupscli_add_host_cert\fR(3), \fBupscli_cleanup\fR(3), \fBupscli_connect\fR(3), \fBupscli_disconnect\fR(3), \fBupscli_init_default_connect_timeout\fR(3), \fBupscli_fd\fR(3), \fBupscli_splitaddr\fR(3), \fBupscli_splitname\fR(3), \fBupscli_ssl\fR(3), \fBupscli_strerror\fR(3), \fBupscli_upserror\fR(3) nut-2.8.3/docs/man/bestups.txt0000644000200500020050000001072015001555412013166 00000000000000BESTUPS(8) ========== NAME ---- bestups - Driver for Best Power / SOLA (Phoenixtec protocol) UPS equipment SYNOPSIS -------- *bestups* -h *bestups* -a 'UPS_NAME' ['OPTIONS'] NOTE: This man page only documents the hardware-specific features of the bestups driver. For information about the core driver, see linkman:nutupsdrv[8]. NOTE ---- Please note that this driver is deprecated and will not receive new development. If it works for managing your devices -- fine, but if you are running it to try setting up a new device, please consider the newer linkman:nutdrv_qx[8] instead, which should handle all 'Q*' protocol variants for NUT. If your device works with this driver, but does not work with linkman:nutdrv_qx[8], please report this via the mailing list or issue tracker. SUPPORTED HARDWARE ------------------ *bestups* was designed to monitor Best Power UPS hardware like the Fortress, Fortress Telecom, Axxium Rackmount and Patriot Pro. It also recognizes and supports SOLA units such as the 325, 520 and 620. In addition, the Best 610 is supported using the `ID' option. Other UPS hardware using the Phoenixtec protocol should also work, but they will generate a warning since their battery information is not known. This driver does not support some older Best/SOLA units. (For older Fortress units, see linkman:bestfortress[8].) EXTRA ARGUMENTS --------------- This driver supports the following optional settings in the linkman:ups.conf[5]: *nombattvolt=*'num':: Override the battery float voltage which is normally determined by asking the hardware. This is useful if your UPS constantly reports `battery.charge` values just below 100% even when it's completely charged. + If you have this problem, set this to whatever `battery.voltage` reports when the UPS is known to be completely charged with a good battery. + The author's Best Fortress 750 uses `nombattvolt=27.4`. *battvoltmult=*'num':: Multiply the reported battery voltage by this number. Some devices report only a fraction of the total battery voltage. + For example, the SOLA 610 700VA UPS (with a 24V battery) reports the single cell voltage (about 2.27V when fully charged). In this particular case you can set `battvoltmult = 12` in linkman:ups.conf[8] to fix this. *ID=*'string':: Set the Identification response string. This should only be used with hardware that supports the Phoenixtec protocol status inquiry commands, but not the "ID" command, such as the Best/SOLA 610. Format of the ID string is: AAA,BBBB,CCC,DDD,EE.E,FF.F + AAA is the three-character identification for the UPS model. + BBBB is the output power in VA (volt amperes). B is an integer number ranging from 0 to 9. + CCC is the Nominal Input Voltage. C is an integer number ranging from 0 to 9. The unit is Volts AC. + DDD is the Nominal Output Voltage. D is an integer number ranging from 0 to 9. The unit is Volts AC. + EE.E is the Battery Voltage that will cause the UPS to shut itself off. E is an integer number ranging from 0 to 9. Then unit is Volts DC and a decimal point is present. + FF.F or FFF.F is the Battery Voltage at full charge. F is an integer number ranging from 0 to 9. Then unit is Volts DC. Typically, for 700VA, 1KVA and 1.5KVA units, the format is FF.F. For 2KVA and 3KVA units, the format is FFF.F. + Example: a Best 610 1.5KVA unit would use the string "610,1500,120,120,10.0,48.0". BUGS ---- The battery charge percentage value (in `battery.charge`) is derived from the voltage data that the UPS returns, since the UPS doesn't return that value directly. On some hardware, the charge will remain at 100% for a long time and then drops quickly shortly before the battery runs out. You can confirm from the `battery.voltage` readings that this is a problem with the UPS and not this driver. Similarly, the float from the charger in some models forces the battery charge percentage back up to 100% immediately after the UPS goes back on-line, so you can't tell when it is really recharged. Finally, some models give one value for the battery's nominal voltage and yet actually have a nominal voltage slightly below that. This leads to things such as the perpetual 98.7% charge on the author's Fortress 750, even when it's been charging for weeks. You can use `nombattvolt=` in linkman:ups.conf[8] to fix this. AUTHORS ------- * Russell Kroll * Jason White SEE ALSO -------- The core driver: ~~~~~~~~~~~~~~~~ linkman:nutupsdrv[8] Internet resources: ~~~~~~~~~~~~~~~~~~~ The NUT (Network UPS Tools) home page: https://www.networkupstools.org/ nut-2.8.3/docs/man/nutscan_init_ip_ranges.30000644000200500020050000000506215001555061015554 00000000000000'\" t .\" Title: nutscan_init_ip_ranges .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "NUTSCAN_INIT_IP_RANG" "3" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" nutscan_init_ip_ranges \- Initialize contents of a `nutscan_ip_range_list_t` structure (and optionally create one in the first place)\&. .SH "SYNOPSIS" .sp .nf #include nutscan_ip_range_list_t * nutscan_init_ip_ranges(nutscan_ip_range_list_t *irl); .fi .SH "DESCRIPTION" .sp The \fBnutscan_init_ip_ranges()\fR function can prepare a nutscan_ip_range_list_t structure by zeroing out its fields\&. If the argument is NULL, the structure is dynamically allocated\&. Either way, a pointer to it is returned\&. .sp A structure passed by caller is not assumed to have any valid contents to free, as it may have garbage from stack after allocation\&. .sp The caller must free the contents of the structure after completing its use by calling nutscan_free_ip_ranges (after which the structure can be re\-used), and explicitly free() the structure object itself if it was allocated dynamically (e\&.g\&. by originally calling nutscan_init_ip_ranges(NULL))\&. .SH "NOTES" .sp Technically, the function is currently defined in \fInutscan\-ip\&.h\fR file\&. .SH "SEE ALSO" .sp \fBnutscan_free_ip_ranges\fR(3), \fBnutscan_add_ip_range\fR(3), \fBnutscan_stringify_ip_ranges\fR(3), \fBnutscan_cidr_to_ip\fR(3), \fBnutscan_ip_ranges_iter_init\fR(3), \fBnutscan_ip_ranges_iter_inc\fR(3) nut-2.8.3/docs/man/nutclient_set_device_variable_values.30000644000200500020050000000004215001555117020445 00000000000000.so man3/libnutclient_variables.3 nut-2.8.3/docs/man/al175.80000644000200500020050000000747515001555064011702 00000000000000'\" t .\" Title: al175 .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 04/22/2025 .\" Manual: NUT Manual .\" Source: Network UPS Tools 2.8.3 .\" Language: English .\" .TH "AL175" "8" "04/22/2025" "Network UPS Tools 2\&.8\&.3" "NUT Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" al175 \- Driver for Eltek UPS models with AL175 alarm module .SH "SYNOPSIS" .sp \fBal175\fR \-h .sp \fBal175\fR \-a \fIUPS_NAME\fR [\fIOPTIONS\fR] .if n \{\ .sp .\} .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 \fBNote\fR .ps -1 .br .sp This man page only documents the hardware\-specific features of the \fBal175\fR driver\&. For information about the core driver, see \fBnutupsdrv\fR(8)\&. .sp .5v .RE .SH "SUPPORTED HARDWARE" .sp The \fBal175\fR driver is known to work with the following UPSes: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Eltek MPSU4000 with AL175 alarm module .RE .sp It may also work with other UPSes equipped with AL175 alarm module, but they have not been tested\&. .sp AL175 have to be configured to operate in COMLI mode\&. See documentation supplied with your hardware on how to do it\&. .SH "EXTRA ARGUMENTS" .sp This driver does not support any extra settings in the \fBups.conf\fR(5)\&. .SH "INSTANT COMMANDS" .sp This driver supports some extra commands (see \fBupscmd\fR(8)): .PP \fBtest\&.battery\&.start\fR .RS 4 Start a battery test\&. .RE .PP \fBtest\&.battery\&.stop\fR .RS 4 Stop a battery test\&. .RE .SH "VARIABLES" .sp Besides status, this driver reads UPS state into following variables: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBups\&.test\&.result\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBoutput\&.voltage\&.nominal\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBoutput\&.current\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbattery\&.voltage\&.nominal\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbattery\&.current\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBbattery\&.temperature\fR .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} \fBinput\&.transfer\&.boost\&.low\fR .RE .SH "KNOWN ISSUES AND BUGS" .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} Shutdown is not supported\&. FIXME .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} The driver was reworked to meet the project code quality criteria, without testing on real hardware\&. Some bugs may have crept in\&. .RE .SH "AUTHOR" .sp Kirill Smelkov .SH "SEE ALSO" .SS "The core driver:" .sp \fBnutupsdrv\fR(8) .SS "Internet resources:" .sp The NUT (Network UPS Tools) home page: https://www\&.networkupstools\&.org/historic/v2\&.8\&.3/ nut-2.8.3/docs/man/nutscan.txt0000644000200500020050000000457215001555412013164 00000000000000NUTSCAN(3) ========== NAME ---- nutscan - Network UPS Tools (NUT) device discovery library DESCRIPTION ----------- The Network UPS Tools (NUT) *nutscan* library provides the same discovery related features that are also offered by linkman:nut-scanner[8]. It enables the discovery of supported NUT devices (USB, SNMP, Eaton XML/HTTP and IPMI) and NUT servers (either using Avahi, or the classic connection method). DISCOVERY FUNCTIONS ------------------- First, include the required header file: #include Then, to discover new devices, use the appropriate function: - linkman:nutscan_scan_usb[3] for supported USB devices, - linkman:nutscan_scan_snmp[3] for supported SNMP agents, - linkman:nutscan_scan_xml_http_range[3] for Eaton Network Management Card, - linkman:nutscan_scan_nut[3] for NUT servers (upsd), using the classic method (search for port), - linkman:nutscan_scan_avahi[3] for NUT servers (upsd), using the mDNS (Avahi) method, - linkman:nutscan_scan_ipmi[3] for supported IPMI PSU. All of these functions return a list of devices found, using the `nutscan_device_t` structure. This structure is described in linkman:nutscan_add_device_to_device[3]. Helper functions are also provided to output data using standard formats: - linkman:nutscan_display_parsable[3] for parsable output, - linkman:nutscan_display_ups_conf[3] for ups.conf style, - linkman:nutscan_display_ups_conf_with_sanity_check[3] for ups.conf style with comments for warnings about possible configuration problems (if any). ERROR HANDLING -------------- There is currently no specific mechanism for error handling. SEE ALSO -------- linkman:nut-scanner[8], linkman:nutscan_scan_usb[3], linkman:nutscan_scan_snmp[3], linkman:nutscan_scan_xml_http_range[3], linkman:nutscan_scan_nut[3], linkman:nutscan_scan_avahi[3], linkman:nutscan_scan_ipmi[3], linkman:nutscan_display_sanity_check[3], linkman:nutscan_display_sanity_check_serial[3], linkman:nutscan_display_ups_conf_with_sanity_check[3], linkman:nutscan_display_parsable[3], linkman:nutscan_display_ups_conf[3], linkman:nutscan_new_device[3], linkman:nutscan_free_device[3], linkman:nutscan_add_device_to_device[3], linkman:nutscan_add_option_to_device[3], linkman:nutscan_init_ip_ranges[3], linkman:nutscan_free_ip_ranges[3], linkman:nutscan_add_ip_range[3], linkman:nutscan_cidr_to_ip[3] Internet resources: ~~~~~~~~~~~~~~~~~~~ http://avahi.org/ nut-2.8.3/docs/man/nutclient_authenticate.30000644000200500020050000000003515001555117015567 00000000000000.so man3/libnutclient_misc.3 nut-2.8.3/docs/nut.dict0000644000200500020050000006257315001552635011661 00000000000000personal_ws-1.1 en 3458 utf-8 AAC AAS ABI ACFAIL ACFREQ ACK ACM ACPI ACPresent ADDR ADDRCONFIG ADDRINFO ADDRLEN ADELSYSTEM ADK ADKK AEC AEF AEG AES AFE AGM AIX ALARMCRITICAL ALTROOT AMETEK APC's API APIs APM AQ ARB ARG ARS ATEK ATR ATT ATTRS ATX ATs AVL AVR AVRLCD AWG Ablerex AcceptEnv ActivePower AdMiN Adoptium Affero Agrain Albanese Alexey AllowOverride Alm Amplon Andreas Andreassen Andrzej Angelone Ansible Antonino Apodaca AppData AppVeyor ArgumentList Arjen Arkadiusz Armin Arnaud Arnaud's Aros AsciiDoc Asium Ates AudibleAlarmControl AuthConfig Autobook Autoconfigure Avocent Axel Axxium BATGNn BATNn BATTDATE BATTTEMP BATTV BATTVOLT BBBB BCD BCHARGE BCM BD BMC BNT BOH BP BQ BRD BTEST BTS BTV BUFRD BUZ BXnnnnMI BYP BZ BZOFF BZON BackPro BackUPS Bads Baggesen Bakos Balker Bartek BatteryA BatteryB Baulé BayTech Belkin's Benedikt Berge Berzonis Bieringer BigServers BlaXwan BlackOut BladeUPS BlueOcean Bo Bocchi Bohe Borns Borri Bouissou Bourne Boutell's Brabec Breiland Brownell Bs BuildBot Buildbot Bxx ByPass CA's CABAC CAs CBI CCC CCCC CDC CDN CDS CELLPADDING CELLSPACING CERTHOST CERTIDENT CERTREQUEST CERTVERIF CEST CHECKPROCNAME CHOST CHRG CL CLANGVER CLI CLOCAL CMDDESC CMDSCRIPT CN COLSPAN COMLI COMMBAD COMMFAULT COMMOK CONFILE CONTEXTs CPAN CPE CPM CPP CPPDBG CPPFLAGS CPUs CRC CREAD CSN CSS CTB CUDA CVE CXR CXX CXXCPP CXXFLAGS Casar CentOS Centralion ChangeLog Chatziathanassiou CheckUPS CheckUPSAvailable Checksum Christoph Chu Cichowski CipherString CircleCI Claesson CodeQL CodingStyle Collver Colombier Comfo CommandLineTools ConfigVoltage ConnectUPS Corbelli Corbolante Coutadeur Ctrl Cuvellard Cyber CyberPower CyberShield CygWin Cygwin DATACABLE DATAPATH DCE DCF DCO DDD DDDDD DDDDDD DDF DDThh DEADTIME DEBUGOUT DELCMD DELENUM DELINFO DELPHYS DELRANGE DES DESTDIR DEVICEALARM DEVNAME DEVREL DEXP DF DHEA DIGYS DISCHRG DLDIR DLLs DMF DN DNS DOCTYPE DOMAINs DPC DPURIFY DRIVERLIST DS DSA DSHUTD DSL DTE DTrace DUMPALL DUMPDONE DUMPSTATUS DUMPVALUE DWAKE DWITH DX Daniele Dashjr DataRoom Ddtrace Defensor DeltaUPSv DesktopFileName DeviceID DeviceKit DeviceLogin DeviceLogout Dgtk Dharm Diehl Dietze DigitalOcean DigitalOcean's Digitus Digys Dimitris Dinstalled Disassembly Dlibelf Dly Dman Dmitry DocBook DocumentRoot Doxygen DriverInstaller Dsystemtap Dynamix Dynex EAGAIN EE EEPROM EFI EG EL ELCD EMI EMP EMPDT ENDFOR ENV EOC EOF EOL EOLed EPEL EPERM EPFCLCD EPO EPS ESC ESS ESV ESXi ETIME EUROCASE EVeRr EXtreme EcoFlow Economou EditorConfig Edlman Edmundsson Edscott Effekta Egys Ekkehard Electrys Eletronicos Elio Elizarov Eltek Emilien Energia EnergySaving Enphase's Erikson Eriksson Evgeny Exar ExecCGI ExecStart ExecStartPre FD FEMEA FFF FH FHS FILEPATH FINALDELAY FIPS FIXME FMRI FO FOREACHUPS FOSS FPT FREEADDRINFO FREHn FRELn FRU FSP FTTx FTUPS FV FWIW Faber Fabio Fabrice Fairstone Farkas Feldman Ferrups Fideltronic Fideltronik Filipozzi Fiskars FlossMetrics Fontana Forza Fosshost Frama FreeBSD FreeDesktop FreeIPMI Frolov FullLoad Fuß GC GCCVER GES GETADDRINFO GETPID GID GITREV GND GNUmakefile GObject GPIO GPL GPLv GPSER GRs GTK GUESSTIMATION GUID GUIs GXE GXT Gabeler Gabor Gammons Gandi Gaspar Gathman Geerling Gembe Gert GetRWVars GetUPSCommands GetUPSList GetUPSNames GetUPSVars Ghali Giese GitHub GitHub's Gnomovision GnuTLS Goebl Gomes Goncalves Gordeev Gough Grafenthal Gtec GuideBook Guillen HB HC HDD HEADs HEHn HELn HFILE HIDIOCINITREPORT HIDRDD HITRANS HL HMAC HNX HOMEBREW HOSTLINK HOSTSYNC HOWTO HPE HPUX HREF HUPCL HUZKVEIkHnC HV HVT HW HWMON Hajduch Hanno Harnhammar Havard Heavner Hessenflow HiBox Hirschler Hlavinka Holger Homebrew Hoogervorst Hough Hrusecky Hunnox Hurd Håvard IANA IC IDE IDEN IDEs IDentifiers IFBETWEEN IFF IFSUPP IGN IMG INADDR INFOSIZE INIGO INNO INSTCMDDESC INTERNETOFFICE INTERR INTL INV INVOLT IOPlatformPluginFamily IPAR IPC IPM IPP IPSS IPs IPv IRC IRIX ISOs ITEMP ITy IVT IZ ImageFiles Infosec Innova Integrators IntelCC IntelliJ Invensys IoT Ioannou JAWAN JBUS JBus JK JKL JRE JSON JVM JW JWT Jageson Jarosch Jasuny Javadoc Javascript Jenkinsfile JoinControllers Jong Joon Jumpered KNutClient KOLFF KRT KRTL KRTS KSTAR KTTS Kain Kajetan Kaminski Kanji Kazancev Kazutoshi Kebo Keor Kersey Kia Kierdelewicz Kirill Kjell Klimov Kolodziej Korensky's Korn Korte Kralewski Kroll Krpec Kubernetes Kx LASTXFER LCDRM LCDRT LCDRTXL LDADD LDFLAGS LDLC LDRIVER LDSHARED LDSHAREDLIBC LEDs LGTM LH LIBGD LIBGPIO LIBNEON LIBNETSNMP LIBOPENSSL LIBPOWERMAN LIBSSL LIBUPSCLI LINEFREQ LINEINT LINEV LISTINSTCMD LISTRW LISTVARS LLDB LLNC LOADKWH LOADPCT LOCALSTATE LOCKFN LOCKNAME LOTRANS LTDA LTS LUA LVM LYONN Lacerda Lallement LanSafe Langille Lansafecable Laventhol Lce Legrand Lepple Levente LibGD LibLTDL LibUSB LineA LineB Lintian ListClients Lite's LocalIP LogMax LogMin LowBatt Loyer Luca Lygre Lynge MANPATH MAXAGE MAXCONN MAXLINEV MAXPARMAKES MBATTCHG MBR MCU MDigest MEC MERCHANTABILITY MF MH MIBs MIMode MINLINEV MINSUPPLIES MINTIMEL MKDIRPROG MLH MMM MNU MODENAME MONITORed MOUNTPOINT MOXA MPSU MQ MSI MSII MSIII MSVCRT MSYS MX MacKenzie's MacOS Maccelari Magalhaes Magalhà Magalhães Maint Makefile Makefiles Malkiewicz Mandriva Marcio Marek Martinezgarza Martín Marzouk Massimo Masterpower Matthijs MaxLinear McKinnon Megaline MemClientStub Metheringham Michal Michalkiewicz MicroDowell MicroFerrups Microline Micropower Microsol Mikiewicz Milkov MinGW MiniCOL MiniGuard Minislot Moar Modbus ModemManager Modris Monett Morioka Morozov Moskovitch Moxa Mozilla Msg MultiLink Multiplug MyCompany MyPasSw MyState NAK NAS NBF NConfigs NDE NETVER NETVERSION NFS NHS NMC NMCs NMS NOAUTH NOBROADCAST NOCOMM NOCOMMWARNTIME NOGET NOMBATTV NOMINV NOMOUTV NOMPOWER NONBLOCK NONUT NOP NOPARENT NOTALARM NOTBOOST NOTBYPASS NOTCAL NOTECO NOTIFYCMD NOTIFYFLAG NOTIFYFLAGS NOTIFYMSG NOTOFF NOTOTHER NOTOVER NOTTRIM NQA NTP NUT's NUTCI NUTCONF NUTClient NVA NX Nadav Nagios Nash NaturalDocs Naur Necedah NetBSD NetBeans NetInvent NetPro NetServer NetUps NetXML Netman NetworkUPSTools Neus Niels Niklas Niro Nobreak Nobreaks Nom NotePad Novell NuGet NutException Nxx OAH OBLBDURATION OBSOLETION OC OEM OEM'ed OFFDURATION OID OIDs OLHVT OMNIVS OMNIVSINT ONF ONV OO OOM OSABI OSs OUTDIR OUTPUTV OUTVOLT OV OVERDURATION Oden OffTime Ohloh Oldworld Olli Omni OmniGuard OmniOS OmniSmart OnLine OnTime OneAC OpenBSD OpenIPMI OpenIndiana OpenPGP OpenSSL OpenSolaris OpenSource OpenUPS OpenWRT Opengear Opensource Opti OptiUPS Orsiris Orvaldi Orzechowski OutletSystem OutputOverload PBT PBTn PBTnn PC PC's PCI PDC PDUs PDX PEX PFCLCD PGFn PGP PHP PHVn PINGs PIPEFN PLD PLL PLVn POG POLLFAIL POLLFREQALERT POSIX POWERDOWNFLAG POWEREX POWERLINE POWERSTATE PPA PPD PPDn PPDnnn PPP PR PR'ed PROGRA PROGS PROTVER PRs PSA PSD PSF PSFn PSGPSER PSSENTR PSUs PSW PSX PSZ PThreads PULS PV PWR PXG PYTHONIOENCODING PYTHONPATH PaaS Pac PackageRequired Parisi PartOf Patrik Pavel Pawe PbAc Perriault Petri Petter Pezzini Phasak PhoenixContact PhoenixTec Phoenixtec Pi PiJuice PiNUT Plesser PnP Pohle PointBre Pos Potrans Poush PowerAlert PowerCOM PowerCom PowerES PowerKinetics PowerMac PowerMan PowerManagerII PowerMust PowerNet PowerOff PowerPC PowerPS PowerPal PowerPanel PowerShare PowerShell PowerShield PowerSure PowerTech PowerTrust PowerVS PowerWalker PowerWare Powerchute Powercool Powervar Powerwell Prachi Prereqs PresentStatus Priv ProductID Progra ProgramFiles Proxmox Prynych Pulizzi PyDOC PyNUT PyNUTClient PyNUTError PyPI PyQt QBDR QBT QBV QBYF QBYV QE QFLAG QFRE QGR QGS QHE QID QLDL QMD QMF QMOD QP QPAR QPD QQ QQQ QRI QVFW QWS QinHeng Quette RBWARNTIME RDLCK RDNT RDWR README REALPATH REDi REFREPO REPLACEBATT REPLBATT REQSSL RETPCT REXX RISC RK RMCARD RMCPplus RMXL RNF RNG ROF RPATH RPC RPMdrake RPT RRR RSA RSM RST RTU RTXL RUPS RWD Rackmount Radek RatedVA RealSmart RedHat Redhat Regados Reinholdtsen Remi RemoteIP Remoting Rene René Repotec's Repoteck RequireAny RestartSec Richthof Rickard Ridgway Riihikallio Rik Rocketfish Rodrigues Rodríguez Rouben Rozman Rucelf RunAs RunUPSCommand RxD Ryabov Rzepecki SAI SASU SCM SCO SCR SDA SDE SDFLAG SDR SDT SECCTRL SELFTEST SELFTESTS SELinux SENTR SER SERIALNO SERVER's SESS SETFL SETINFOs SETLK SFE SG SGI SHA SHUTDOWNCMD SHUTDOWNEXIT SHUTDOWNSCRIPT SIG SIGHUP SIGINT SIGKILL SIGPIPE SIGPWR SIGTERM SIGURG SIGUSR SIGWINCH SKP SKU SL SMALLBUF SMBUS SMF SMK SMT SMTP SMX SNMPv SNR SOCK SOCKADDR SOCKLEN SOCOMECUPS SOFF SOLA SOMECO SOURCEMODE SOV SPARC SPC SPECs SPLY SPS SRC SSD SSSS STARTTLS STB STDCALL STESTI STI STIME STO STP STRARG SUBDIRS SUNWlibusbugen SUNWugen SUNWusb SURTD SUSE SVR SX SXI SXL SYMLINKDIR SafeNet Salicru Salvia Santinoli Savia Sawatzky Schmier Schoch Schonefeld Schroder ScriptAlias Sekury Selinger SendEnv Senoidal Sep Sequentializing SerialNumber Serv Serveur SetRWVar Shambarger Shara ShareAlike Shaul ShutDown Sibbald Sicon Sidorov SigLevel Silvino Sinline Sistem Sistemas SlackPack Slackware SlaveComputer SlaveVersion SmartBoost SmartNUT SmartOnline SmartPro SmartSlot SmartTrim SmartUPS Smelkov SnR SnRm Socomec Sola Solaris Soltec Soltys SomeVendor Sotirov's SourceForge Soyntec Spanier Spiros Sporbeck SquareOne Stanislav StatePath Stefano Stimits StrangeOS SuSE Suatoni Sublicensing SunOS SuperPower Sweex Sy Sycon Symmetra Symmetras SyntaxWarning Sysgration SyslogIdentifier SystemIO Systeme Syu Szady TBD TBR TCIFLUSH TCIOFLUSH TCSANOW TEMPC TEMPF TESTPASS TEoQ TGS TIMELEFT TIOCM TIOCMBIC TIOCMBIS TLS TLSv TODO TRACKINGDELAY TREELINK TRYSSL TSR TST TT TTT TXF TXG TXV Tchakhmakhtchian TcpClient Technic Technorama Tecnoware Tefft Telecom Temurin Termux Teurlings Thanos Thecus Theodor Thierry Tigra Tnn Tomek Toolset TopGuard Toth TrackingID TrackingResult Tripp TrippLite Tru Tx TxD UB UBD UBR UCRT UDP UFS UHV UI UID UIDA UINT UNKCOMMAND UNSTASH UNV UPGUARDS UPM UPOII UPP UPS's UPSCONN UPSDESC UPSHOST UPSIC UPSIMAGEPATH UPSLC UPSNOTIFY UPSName UPSOutletSystemOutletDelayBeforeReboot UPSOutletSystemOutletDelayBeforeShutdown UPSOutletSystemOutletDelayBeforeStartup UPSOutletSystemOutletSwitchable UPSSTATSPATH UPSTEMP UPScode UPSes UPSilon UPSmart UPSonic UPSs UPStation UPower URI USBDEVFS USBDevice USERADDed USV UTC UTalk UUU UUUU UX Ubuntu Ulf Uncomment Unices Unitek Upsonic Ut V'ger VALIGN VARDESC VARTYPE VENDORNAME VER VERFW VFI VIB VLAN VM VM's VMIN VMM VMs VMware VNC VPATH VPC VPS VSCode VSN VTIME VV VVV Vaclav Valderen Vdc Velloso VendorID Viewpower Viewsonic Viktor VirCIO Visench Vout Vultech Václav WALKMODE WARNFATAL WARNOPT WCH WELI WHAD WIP WIPO WMNut WS WSDIR WSE WSL WTU Waldie WantedBy WatchdogSec Waveshare Wcovered WebFreak Werror Weverything Wextra WhizBang WiX Wikipedia Willian WinMerge WinNUT WinPower Wireshark Wl Wrede Wunreachable XAU XC XCP XCode XLA XOFF XON XOPEN XP XPG XPPC XSL XT XUPS XXXX XXXXXXXXXXXX XYZ Xfer Xlinker Xpert Xups YDN YQ YV YY YYYY YZ Ygor Yifeng Yoyodyne Yukai Yunto ZFS ZP ZProject Zadig Zaika Zampieri Zawadzki ZeroMQ Zhile ZnapZend abandonware abcd ablerex abuild accessmode acl acm acpi acx adb addcmd addenum addinfo additionalSOLibSearchPath addons addr addrange addvars adelsystem adkorte adm admin's adminbox adoc advfirewall advorder ae aec af afeb aggregator ai aix akeo al ala alertset alioth alist alldrv alloc allowfrom altinterface altpidpath altroot altroots amd anded antivirus aon ap apc apcc apcd apcevilhack apcsmart apctest apcupsd aphel api apinames apis appveyor ar architecting archlinux arduino arg argc argp args argv armac armel armhf asapm ascii asciidoc asciidocs asciidoctor asem ashift aspell ast async atcl ats aug augeas augparse augtest augtool auth authNoPriv authPassword authPriv authProtocol authType autoboot autoconf autodetect autodetected autodetection autoexpand autogen automagically automake autopoint autoreconf autoreplace autorestart autoscan autostart autotools autowidth auxdata avPHK avahi avr awd awk b'some b'string bAlternateSetting bUps backend backends backgrounding backport backported backports backupspro bart baseurl bashrc batchable batt battcap batteryPercentage battext battlow battnumb battpacks battvoltmult battvolts baudrate baytech baz bcdDevice bcm bcmxcp bd belkin belkinunv bestfcom bestferrups bestfort bestfortress bestuferrups bestups bfe bg bigbox bigone bigserver bigups bindir binfmt binutils bitmapped bitmask bitness bitnesses bmake bn bool boolean bootable bootenv bootfs bp bpool br brazil brcm brotli bsd bt bti btn btnG btt buf buflen bugfix bugfixes buildable buildbots builddir buildtype bullseye bursty busport busybox buzzmode bv byobu bypassOff bypassOn cStandard cablepower cachefile calc calloc cb cbe cbi cbl ccache cd cdc cdf cee cef centos cerr certfile certname certpasswd certpath certutil certverify cfg cfgadm cflag cflags cgdisk cgi cgipath cgroup cgroupsv chargetime charset checksum checksums chgrp chipset chkconfig chmod chown chr chroot chrooted chrooting chroots chunked chunking chunkname chv ci cidr cis clav clepple cli clicky cls clueful clusterware cmake cmd cmdline cmdname cmdparam cmds cmdvartab cnf codebase codepath coldstarts collectd command's commandlen committer comms compat compilerPath conf config configparser configs configurationProvider configureaz configureaza confpath const contrib copyrightable coreutils cout coverity cp cpp cppStandard cppcheck cppdbg cppnit cppunit cpqpower cpsups cpu cr crestfactor crit criticality crle crlf cron crontab crossbuild crt crw crypto csh cshdelay csi css cstdint ctime ctrl cts ctypes cua cuaa curr customizations cvt cwd cx cxx cyberpower d'un da daemonization daemonize daemonized daisychain daisychained databits datacenter datadir datagrams datalink dataok datarootdir dataset datasets datasheet datastale dblatex dcd dcn ddk ddl de deUNV debian debootstrap debouncing debuginfo deci decrement decrypt dedb dedup dedupditto deduplication dedupratio defaultrouter defs defun dep dephasing deps dereference desc deschis descr desde designator dev devclient devctl devd devel deviceGetClients devicename devscan dfl dhcp dialout diffutils dir disassembly discardable disp distcheck distclean distro distros dl dladm dll dlopen dmake dmesg dnf dnl dnsmasq docbook docdir docinfo docs dod domxml dotnet downloadable dpkg dq driverexec drivername driverpath drivertool drv drvctl drvpath drwxr drwxrwx ds dsi dsr dsssl dstate dt dtb dtbo dtc dtds dtksh dtoverlay dtparam dtr dts du dumbed dumbterm dummycons dummypass dummyups dumpxml dv dynamatrix ePDU ePDUs eaton ec eco ecomode edb editorconfig edl ef egrep ei el emacs emptor emptyDir endchar enddate endian endianness endif endl energizerups energysave english enphase enum env envvar envvars ep epdu eq errno esac essmode esupssmart et etapro eth etherstubs ev eval everups everyone's everything's evilhack exe execfuse executables executeCommand execve expandsize extapi extern externalConsole extradata faa fabula facto failmode fallthrough fasttrack fatalx fc fcb fcntl fcontext fd fdX fds fe featureReport fenton fentonups fffdddxxx ffff fi fightwarn filename filenames filesystem filesystems firewalling firmwares fmt fno fontconfig fopen forceshutdown forcessl formatconfig formatstring fosshost fp freebsd freeipmi freetype frob frontends fs fsd fsr fstab ftdi fuji func gamatronic gandi gcc gcpp gd gd's gdb gdbinit gdlib gdwarf ge gedit genericsups genericups genesisII gentoo gestion getClients getDescription getDevice getDevicesVariableValues getTrackingResult getValue getVariable getconf getent getenv getopt gettext gettextize getvar gh gif gitcache github gitignore gitk gitlab gitlog gmail gmake gmtime gnuplot gnutls goodspeed google goto gotos gperf gpg gpgsign gpio gpiochip graphviz groupadd groupname gtec gtk guesstimate guesstimation guez gufw gui guid gxe gz gzip hal hardcoded hasFeature hb hcd hcl hexnum hg hh hibernate's hiddev hidparser hidraw hidtypes hidups homebrew hoster hostname hostnames hostsfile hotplug hotplugging hovercharge hpe hpux href htaccess htm html htmlpath http httpd https huawei hudson hunnox hwdb hwinfo hwmon hwmonX hypervisor hypervisors iBox iDialog iDowell iManufacturer iPlug iProduct iSerial iUSB ib icd iconv icp icu idProduct idVendor ident idleload ie ietf ifdef ifndef ignoreFailures ignorelb ignoreoff ignoresab ignset illumos im imagesdir img imv ina includePath includedir inductor infos infoval inh init init's initctl initializer initializers initinfo initscripts initups inline inlined innotech innovart inode inplace installable installpkg installurl instcmd instcmds integrations intel intelliSenseMode intercharacter internet interoperability interoperate interoperating interprocess interruptonly interruptsize intltool inverter invmode io ioLogik ioLogikE ioLogikR iocage iostream ip ipE ipF ipmi ipmidetectd ipmimonitoring ipmipsu ipp ippon ipv ipxe irl irliter isDefault isbmex ish iso isolator iter ivp ivtscd jNUT jNut jNutWebAPI jbus jdk jenkins jessie jimklimov journalctl jpeg jpg jq jre json kVA kadets kaminski kde kex kext keychain keygen keyout keyring keyrings keyserver killall killpower kludgy kr krauler ksh ktrace kvm labcd lan langid lasaine lbrb ld ldd ldflags le len leveloffset lf libarchive libaugeas libavahi libc libcommon libcommonclient libcommonstr libcppunit libcrypto libcurl libdir libdummy libexec libexecdir libexpat libfreeipmi libgd libgpgme libgpiod libhid libhidups libi libiconv libintl libipmimonitoring libltdl liblzma libmodbus libname libneon libnetsnmp libnss libnut libnutclient libnutclientstub libnutclientsub libnutconf libnutconfig libnutscan libpcre libpng libpowerman libre libregex libs libserial libsnmp libssl libsystemd libtool libupsclient libusb libusb's libusbugen libusbx libvirt libwdi libwrap libxml libxslt libxxx libz licensor licensors liebert liebertgxt lifecycle linevoltage linkdoc linkmanext linksingledoc linksrcdoc linux linuxdoc lipo listDeviceClients listsnapshots littleguy livedata lk lldb llvm lm lmodbus ln lnetsnmp loadPercentage localcalculation localhost localip localport localtime lockf logfacility logfile login logins logout logrotate lookup loopback lowbatt lowbattery lr lregex lsd lst lsusb lt ltdl lu lua lv lvo lws lxc lxcbr lxccontainer lxcfs lxyz lz mA mDNS mS macaddr macosx mailo mailx mainFrame maintainer's maintainership maj makefile makevartable mandir manpage manpages masterguard matcher maxd maxlength maxreport maxretry maxstartdelay maxva maxvalue maxvo mbuffer mc mcedit mcview md mdadm mdutil mecer megatec memset metadata metasys methodOfFlowControl mge mgeups mgexml mgmt miDebuggerPath mib mibs microcontroller microdowell microlink microsol middleware mincharge mingw minicol minruntime mins minva minvalue minvo mips mirrorlist mis misconfigured mkdir mmZ mmap mn mockdrv modbus modelname modprobe monmaster monofasico monpasswd monuser morbo mortem mozilla msec msg msgfmt msi msvcrt msys multi multicommands multihost multilib multilink multimeter multimon mustek mv myHostingIP myauthenticationpassphrase mybox mydev mydevice mydomain mydriver myhostname myname mypass mypassword myprivatepassphrase mysecurityname myups myupsname nLogic nMONITOR nPOWERDOWNFLAG nSHUTDOWNCMD nabcd nameserver namespace nano nanosleep nashkaminski natively nb nbproject nbr nc nd nde nds netcat netclient netmask netserver netsh netsnmp netvision networkupstools netxml newapc newhidups newmge newvictronups nf ng nhnl nhs nielchiano nitram nl nlb nlogic nls nm nn nnn noAuthNoPriv nobody's nobreak nobt nocomms nodev nodownload noexec noflag nogroup nohang noimp noinst nolock nombattvolt noncommercially noout nooutstats norating noro noscanlangid nosnap nosuid notAfter notifyflags notifyme notifymsg notifytype notransferoids novendor nowait nowarn np nspr nss nuget num numOfBytesFromUPS numa numbatteries numlogins numq nutclient nutclientmem nutconf nutdev nutdevN nutdrv nutmon nutscan nutshutdown nutsrv nutupsdrv nutvalue nvi nvo nwfilter odette offdelay offsite oids ok okhlybov oksh ol oldmac oldmge oldnut omnios onbatt onbattery onbattwarn ondelay oneac online onlinedischarge ont onwards ooce openSUSE opencollective openipmi openjdk openlog openmp openpimi openssh openssl openwin oper optimizations optiups oq os ostream other's otheruser ouGDQn outliers ovmf pF pacman pacstrap parallelizable parallelized param parsable parseconf parsers passname passphrase passthrough passwd pathname pathnames pbzip pc pconf pcre pcs pdf pdu pe peasy peername pem perc perl pfSense pfexec pfy ph phoenixcontact phoenixtec picocom pid pidpath pigz pijuice pinout pinouts pipedebug pipename pixmaps pkg pkgconf pkgconfig pkgin pkgsrc plaintext plugin pluma pmset pmu png pollable pollfreq pollinterval pollonly popa portfile portfiles portname porttype posix powercom powerdev powerdown powerdownflag powerfactor powerfail powerman powermand powermust powernet poweroff powerpal powerpanel powershell powerup powervalue powerware ppc pprint ppro pragma pragmas pre preLaunchTask prepend prepended preprocess preprocessing preprocessor prerelease prereqs pretentiousVariableNamingSchemes prgshut printf priv privPassword privProtocol problemMatcher probu proc productid prog progname prtconf ps psu pthread pthreads pts ptv pty pulizzi pw pwd pwmib px pxW pxg pxgx py pycparser pydoc pygments pygtk pynut pyqt qDEB qa qemu qs queequeg quiesce qx qx's qxflags rD raritan rb rc rcctl readline readonly realpower realups rebase rebased rebasing rebootdelay rebranded reconnection recurses recursing recv redistributors reentrancy refactored refactoring refreservation regex regtype relatime releasekeyring relicensing remoteip renderer renderers renice repindex repo reportId reposurgeon repotec req resetter resolv restoreconf resync ret retrydelay revnumber rex rexx rf rfc rh richcomm riello rio rj rk rkm rktoy rms rn ro roadmap rootca rootcerts rootfs rootfs'es rpath rpc rpool rq rqt rsa rsd rsync rts rtu ru rubygem runlevel runnable runtime runtimecal runtimes rva rw réseau safenet salicru sbin sbindir scanopts scd sched scm screenshot screenshots scriptname sd sdcmd sdcommands sddelay sdk sdl sdorder sdtime sdtype se searchable secLevel secName secctrl secretpass securityLevel securityName sed selftest semanage semver sendback sendline sendmail sendsignal sendsignalfn sendsignalpid senoidal sequentialized ser seria serialno serialnumber servicebypass setFeature setaux setflags setgid setinfo setpci setq setuid setupCommands setvar setvar's sfr sgml sgs sha shellcheck shellenv shm shutdownArguments shutdowncmd shutdowndelay shutdowntime si siemens sig sigaction sigmask signedness simu sio sitesearch sitop sizeof ske skel sl slackpkg slaveid slavesync slibtool sm smartups smbus sms sn snailmail snmp snmpv snmpwalk snprintf snprintfcat snr socat sockdebug socketname socomec solari solaris solcmn solibs solint solis somename somepass something's sortdict sp spanish sparc sparcv spectype spellcheck spellchecked splitaddr splitname squasher sr src srcdir srcdoc srv srw ss sshd ssize ssl sstate stan startIP startdelay startup statepath stayoff stderr stdlib stdout stdupsv stopAtConnect stopAtEntry stopIP stopbits str strUps strace strarr strcasecmp strcat strchr strcpy strdup strerror strftime stringify strlen strncpy strnlen strptime struct structs sts stst stty stylesheet stylesheets su subcommand subdir subdirectories subdirectory subdriver subdriver's subdrivername subdrivers subdrv sublicense sublicenses submodule submodules subnet subnets subtree sudo suggestsrcdoc suid suppressions suseconds sv svc svcadm svcs svn sw symlink symlinked symlinking symlinks symmetrathreephase sys sysDescr sysOID sysObjectID sysV syscalls sysconfdir sysconfig sysfs syslog syslogd systemctl systemd systemdshutdowndir systemdsystempresetdir systemdsystemunitdir systemdtmpfilesdir systemtest sysutils sysvinit tagname targetArchitecture tcflush tcgetattr tcl tcp tcpdump tcsetattr tcsh td tdriver telnetlib tempmax tempmin termios testime testtime testuser textproc tgcware tgt tgtsize tgz th timeframe timehead timername timespec timestamp timeticks timeval tios tmp tmpfiles tmpfs tmpring tmux toolchain toolkits toolset topFrame topbot tport tripplite tripplitesu troff tryconnect tsa tsd tty ttyACM ttyS ttySx ttyU ttyUPS ttyUSB ttya ttyb ttyc ttymode ttyp tunables tuple tuples turnon tv tw tx txg txt txz typedef uA uD uM ua uart ubuntu uc ucb ucd ucrt udev udevadm ufw ugen ui uid uint ukUNV ul un uname uncomment unconfigure unconfigured undefine undervoltage unescaped unicast unicode uninstall uninterruptible uniq unistd unix unmapped unmounts unpowered unstash updateinfo upexia upower upsBypassCurrent upsBypassPower upsBypassVoltage upsIdent upsIdentModel upsMIB upsObjects upsadmin upsc upscli upsclient upscmd upscode upscommon upsct upsd upsdebug upsdebugx upsdev upsdrv upsdrvctl upsdrvquery upsdrvsvcctl upserror upsfetch upsgone upsh upshandler upsid upsidentmodel upsimage upsload upslog upslogx upsmon upsmon's upsname upsnotify upsonbatt upspass upspasswd upsrw upssched upssched's upsset upsstats upstype upsuser upswired uptime urb url urpmi usb usbconfig usbfs usbhid usbif usbinfo usbmisc usbsubdriver usbsubdrvname usbups usbus usd usec useconds useradd userid userland usermap username usernames userspace usleep usr utalk utf utils uu uucp vCPU vFnd vHDD va valgrind validationSequence valuelen vaout var's varargs varhigh variable's variadic varlow varname varvalue vbat vbatt vc vda vendorid ver verifySourceSig versa versioned versioning victron victronups vid vin vio virsh virt virtinst virtualization virtualized vivo vo volsize voltronic vscode vt wDescriptorLength waitbeforereconnect wakeup wc wdi webserver wf wget whitespace wiki wildcard wildcards wininit winnutclient winpthreads wix wmNUT wmnut workflow workflows workspace workspaceFolder workspaces writability writeinfo writeups ws xAAAA xCC xD xFF xXXXX xYYYY xZZZZ xa xaabbcc xcalloc xcode xd xe xenodm xff xfff xffff xh xhci xhtml xjf xmalloc xml xmllint xmlto xpg xpm xr xrealloc xsl xsl's xsltproc xstrdup xu xxxAP xxxx xxxxAP xz xzf yP yaml yml youruid yyy zaac zakx zfs zinto zlib znapzend znapzendzetup zpool zroot zsh zw zwfa zzz Åstrand Ørpetveit nut-2.8.3/docs/xhtml.xsl0000644000200500020050000000121114553676503012064 00000000000000 nut-2.8.3/docs/config-prereqs.txt0000644000200500020050000021217214777767434013713 00000000000000ifdef::website[] Prerequisites for building NUT on different OSes ================================================ endif::website[] This chapter aims to list packages with the tools needed on a freshly minimally deployed worker to build as many targets of NUT recipes as possible, mainly the diverse driver and documentation types. NUT codebase generally should not depend on particular operating system or kernel technology and version, and with the operating systems listed below one can benefit from use of containers (jails, zones) to build and test against numerous OS distributions on one physical or virtual machine, e.g. to cover non-regression with older tool kits while taking advantage of new releases. * For Linux systems, we have notes on linkdoc:qa-guide[Custom NUT CI farm build agents: LXC multi-arch containers,CI_LXC,docs/ci-farm-lxc-setup.txt] Some of the below are alternatives, e.g. compiler toolkits (gcc vs. clang) or SSL implementations (OpenSSL vs. Mozilla NSS) -- no problem installing both, at a disk space cost. [NOTE] ====== Some NUT branches may need additional or different software versions that are not yet included into `master` branch dependencies, e.g. the DMF (Dynamic Mapping Files) sub-project needs LUA 5.1 for build and run-time, and some Python modules for build, e.g. using OS packaging or custom call to `pip install pycparser`. In case your system still provides a Python 2.x environment (and for some reason you want to use it instead of Python 3.x), but does not anymore provide a `pip` nor `pycparser` packages for it, you may need to use an external bootstrap first, e.g.: ------ # Fetch get-pip.py for python 2.7 :; curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py :; python2 get-pip.py :; python2 -m pip --version :; python2 -m pip install pycparser ------ ====== More packages and/or system setup may be needed to actually run NUT with all features enabled; chapters below concern just with building it. General call to Test the ability to configure and build ------------------------------------------------------- Check out from git, generate files and configure to tailor to your build environment, and build some tests: ------ :; mkdir -p nut && cd nut && \ git clone https://github.com/networkupstools/nut/ -b master . :; ./autogen.sh && \ ./configure --with-doc=all --with-all --with-cgi && \ make all && make check && make spellcheck ------ You can toggle some `configure` options to check different dependency variants, e.g. `--with-ssl=nss` vs. `--with-ssl=openssl` For reproducible runs of various pre-sets of configuration during development, take a look at `ci_build.sh` script and different `BUILD_TYPE` (and other) environment variable settings that it supports. A minimal run with it is just to call the script, e.g.: ------ :; mkdir -p nut && cd nut && \ git clone https://github.com/networkupstools/nut/ -b fightwarn . :; ./ci_build.sh ------ [NOTE] ====== To build older releases, such as "vanilla" NUT 2.7.4 and older, you may need to address some nuances: * Ensure that `python` in `PATH` points to a python-2.x implementation (`master` branch is fixed to work with python 2 and 3) * Ensure that `bash` is your user and maybe system shell (or ensure the generated `configure` script gets interpreted by it) * Generally you may have better results with GNU Make newer than 3.81 than with other make implementations; however, builds are regularly tested by CI with Sun dmake and BSD make as well, so recipes should not expect GNU-only syntax and constructs to work * Parallel builds should be okay in current development version and since NUT 2.8.0 (is a bug to log and fix, if not), but they may be failure-prone in 2.7.4 and earlier releases ====== For intensive rebuilds, `ccache` is recommended. Note that instructions below detail how to provide its directory with symlinks as `/usr/lib/ccache` which is not the default case in all OS distributions. Recent versions of the NUT `ci_build.sh` script allow to override the location by using the `CI_CCACHE_SYMLINKDIR` environment variable, which is cumbersome and only recommended for build agents with immutable system areas, etc. Build prerequisites to make NUT from scratch on various Operating Systems ------------------------------------------------------------------------- Debian 10/11/12/13 ~~~~~~~~~~~~~~~~~~ Being a popular baseline among Linux distributions, Debian is an important build target. Related common operating systems include Ubuntu and customized distros for Raspberry Pi, Proxmox, as well as many others. For some (newer) distributions, `apt` or other front-ends may be preferable to `apt-get`, but otherwise the commands are equivalent. The package list below should largely apply to those as well, however note that some well-known package names tend to differ. A few of those are noted below. [NOTE] ====== While Debian distros I've seen (8 to 11) provide a "libusb-dev" for libusb-0.1 headers, the binary library package name is specifically versioned package by default of the current release (e.g. "libusb-0.1-4"), while names of both the library and development packages for libusb-1.0 must be determined with: ------ :; apt-cache search 'libusb.*1\.0.*' ------ yielding e.g. "libusb-1.0-0-dev" (string name was seen with different actual package source versions on both Debian 8 "Jessie" and Debian 11 "Buster"). ====== [NOTE] .FUN NOTE ====== For development on the road (or a native ARM build) you can use the link:https://termux.dev/en/[Termux] project on Android. It provides a sufficiently Debian-like operating environment for all intents and purposes, but you may have to use their `pkg` wrapper instead of `apt` tooling directly, and `ldd` may be in a package separate from `binutils`, but otherwise the Debian/Ubuntu oriented lists of packages below apply. You would need at least a couple of gigabytes available on the internal phone storage though, especially if using `ccache` or setting up cross builds. The Termux distribution as of this writing seems to lack cppunit packages but you can build it from https://www.freedesktop.org/wiki/Software/cppunit/ e.g. `--with-prefix=${HOME}/nut-deps/usr` and `make install` there. A custom `PKG_CONFIG_PATH=${HOME}/nut-deps/usr/lib/pkgconfig` would find it during NUT build. ====== Debian-like package installations commonly start with an update of metadata about recently published package revisions: ------ :; apt-get update :; apt-get install \ ccache time \ git perl curl \ make autoconf automake libltdl-dev libtool binutils \ valgrind \ cppcheck \ pkg-config \ gcc g++ clang # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; apt-get install \ gdb # NOTE: Older Debian-like distributions may lack a "libtool-bin" :; apt-get install \ libtool-bin # See comments below, python version and package naming depends on distro :; apt-get install \ python # NOTE: For python, you may eventually have to specify a variant like this # (numbers depending on default or additional packages of your distro): # :; apt-get install python2 python2.7 python-is-python2 # and/or: # :; apt-get install python3 python3.9 # You can find a list of what is (pre-)installed with: # :; dpkg -l | grep -Ei 'perl|python' # # For localization maintenance (currently in Python NUT-Monitor app), # provide an `msgfmt` implementation, e.g.: # :; apt-get install gettext # # To install the Python NUT-Monitor app, you may need some modules. # Ideally, they would be packaged, named according to major Python version: # :; apt-get install python3-pyqt5 # # If not packaged for your distro: # :; apt-get install pip # For Python3: # :; python3 -m pip install PyQt5 configparser # For spell-checking, highly recommended if you would propose pull requests: :; apt-get install \ aspell aspell-en # For other doc types (man-page, PDF, HTML) generation - massive packages # (TEX, X11): :; apt-get install \ asciidoc source-highlight python3-pygments dblatex # For CGI graph generation - massive packages (X11): :; apt-get install \ libgd-dev # Debian 13 serves metadata needed for NUT to find where to install the # service unit files in a separate development package; earlier distro # releases did not seem to require it explicitly: :; apt-get install \ systemd-dev # Optionally for sd_notify integration: :; apt-get install \ libsystemd-dev # NOTE: Some older Debian-like distributions, could ship "libcrypto-dev" # and/or "openssl-dev" instead of "libssl-dev" by its modern name # and may lack a libgpiod2 + libgpiod-dev altogether :; apt-get install \ libcppunit-dev \ libssl-dev libnss3-dev \ augeas-tools libaugeas-dev augeas-lenses \ libusb-dev libusb-1.0-0-dev \ libi2c-dev \ libmodbus-dev \ libsnmp-dev \ libpowerman0-dev \ libfreeipmi-dev libipmimonitoring-dev \ libavahi-common-dev libavahi-core-dev libavahi-client-dev # For libneon, see below # NOTE: Older Debian-like distributions may lack a "libgpiod-dev" # Others above are present as far back as Debian 7 at least :; apt-get install \ libgpiod-dev # NOTE: Some distributions lack a lua*-dev and only offer the base package :; apt-get install lua5.1 :; apt-get install lua5.1-dev || true :; apt-get install \ bash dash ksh busybox ------ Alternatives that can depend on your system's other packaging choices: ------ :; apt-get install libneon27-dev # ... or :; apt-get install libneon27-gnutls-dev ------ Over time, Debian and Ubuntu had different packages and libraries providing the actual methods for I2C; if your system lacks the `libi2c` (and so fails to `./configure --with-all`), try adding the following packages: ------ :; apt-get install build-essential git-core libi2c-dev i2c-tools lm-sensors ------ For cross-builds (note that not everything supports multilib approach, limiting standard package installations to one or another implementation; in that case local containers each with one ARCH may be a better choice, with `qemu-user-static` playing a role to "natively" run the other-ARCH complete environments): ------ :; apt-get install \ gcc-multilib g++-multilib \ crossbuild-essential \ gcc-10:armhf gcc-10-base:armhf \ qemu-user-static ------ NOTE: For Jenkins agents, also need to `apt-get install openjdk-21-jdk-headless`. You may have to ensure that `/proc` is mounted in the target chroot (or do this from the running container). CentOS 6 and 7 ~~~~~~~~~~~~~~ CentOS is another popular baseline among Linux distributions, being a free derivative of the RedHat Linux, upon which many other distros are based as well. These systems typically use the RPM package manager, using directly `rpm` command, or `yum` or `dnf` front-ends depending on their generation. For CI farm container setup, prepared root filesystem archives from http://download.proxmox.com/images/system/ worked sufficiently well. Prepare CentOS repository mirrors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For CentOS 7 it seems that not all repositories are equally good; some of the software below is only served by EPEL (Extra Packages for Enterprise Linux), as detailed at: * https://docs.fedoraproject.org/en-US/epel/ * https://www.redhat.com/en/blog/whats-epel-and-how-do-i-use-it * https://pkgs.org/download/epel-release You may have to specify a mirror as the `baseurl` in a `/etc/yum.repos.d/...` file (as the aged distributions become less served by mirrors), such as: * https://www.mirrorservice.org/sites/dl.fedoraproject.org/pub/epel/7/x86_64/ + ------ # e.g. for CentOS7 currently: :; yum install \ https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-7-14.noarch.rpm # And edit /etc/yum.repos.d/epel.repo to uncomment and set the baseurl=... # lines, and comment away the mirrorlist= lines (if yum hiccups otherwise) ------ For systemd support on CentOS 7 (no equivalent found for CentOS 6), you can use backports repository below: ------ :; curl https://copr.fedorainfracloud.org/coprs/jsynacek/systemd-backports-for-centos-7 > /etc/yum.repos.d/systemd-backports-for-centos-7.repo ------ For CentOS 6 (the oldest I could try) the situation is similar, with sites like https://www.getpagespeed.com/server-setup/how-to-fix-yum-after-centos-6-went-eol detailing how to replace `/etc/yum.repos.d/` contents (you can wholesale rename the existing directory and populate a new one with `curl` downloads from the article), and additional key trust for EPEL packages: ------ :; yum install \ https://dl.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm ------ Set up CentOS packages for NUT ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Instructions below apply to both CentOS 6 and 7 (a few nuances for 6 commented). For newer distributions, `dnf` may be preferable to `yum`, but otherwise the commands are equivalent. General developer system helpers mentioned in linkdoc:qa-guide[Custom NUT CI farm build agents: LXC multi-arch containers,CI_LXC,docs/ci-farm-lxc-setup.txt]: ------ :; yum update :; yum install \ sudo vim mc p7zip pigz pbzip2 tar ------ To have SSH access to the build VM/Container, you may have to install and enable it: ------ :; yum install \ openssh-server openssh-clients :; chkconfig sshd on :; service sshd start # If there are errors loading generated host keys, remove mentioned files # including the one with .pub extension and retry with: #:; service sshd restart ------ NOTE: Below we request to install generic `python` per system defaults. You may request specifically `python2` or `python3` (or both): current NUT should be compatible with both (2.7+ at least). NOTE: On CentOS, `libusb` means 0.1.x and `libusbx` means 1.x.x API version (latter is not available for CentOS 6). NOTE: On CentOS, it seems that development against libi2c/smbus is not supported. Neither the suitable devel packages were found, nor i2c-based drivers in distro packaging of NUT. Resolution and doc PRs are welcome. ------ :; yum install \ ccache time \ file \ git perl curl \ make autoconf automake libtool-ltdl-devel libtool \ valgrind \ cppcheck \ pkgconfig \ gcc gcc-c++ clang # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; yum install \ gdb # See comments below, python version and package naming depends on distro :; yum install \ python # NOTE: For python, you may eventually have to specify a variant like this # (numbers depending on default or additional packages of your distro): # :; yum install python-2.7.5 # and/or: # :; yum install python3 python3-3.6.8 # You can find a list of what is (pre-)installed with: # :; rpm -qa | grep -Ei 'perl|python' # Note that CentOS 6 includes python-2.6.x and does not serve newer versions # For spell-checking, highly recommended if you would propose pull requests: :; yum install \ aspell aspell-en # For other doc types (man-page, PDF, HTML) generation - massive packages # (TEX, X11): :; yum install \ asciidoc source-highlight python-pygments dblatex # For CGI graph generation - massive packages (X11): :; yum install \ gd-devel # Optionally for sd_notify integration (on CentOS 7+, not on 6): :; yum install \ systemd-devel # NOTE: "libusbx" is the CentOS way of naming "libusb-1.0" (not in CentOS 6) # vs. the older "libusb" as the package with "libusb-0.1" :; yum install \ cppunit-devel \ openssl-devel nss-devel \ augeas augeas-devel \ libusb-devel libusbx-devel \ i2c-tools \ libmodbus-devel \ net-snmp-devel \ powerman-devel \ freeipmi-devel \ avahi-devel \ neon-devel #?# is python-augeas needed? exists at least... #?# no (lib)i2c-devel ... #?# no (lib)ipmimonitoring-devel ... would "freeipmi-ipmidetectd" #?# cut it at least for run-time? #?# no (lib)gpio(d)-devel - starts with CentOS 8 (or extra repositories #?# for later minor releases of CentOS 7) # Some NUT code related to lua may be currently limited to lua-5.1 # or possibly 5.2; the former is default in CentOS 7 releases... :; yum install \ lua-devel :; yum install \ bash dash ksh ------ NOTE: `busybox` is not packaged for CentOS 7 release; a static binary can be downloaded if needed. For more details, see https://unix.stackexchange.com/questions/475584/cannot-install-busybox-on-centos CentOS packaging for 64-bit systems delivers the directory for dispatching compiler symlinks as `/usr/lib64/ccache`. You can set it up same way as for other described environments by adding a symlink `/usr/lib/ccache`: ------ :; ln -s ../lib64/ccache/ "$ALTROOT"/usr/lib/ ------ [NOTE] ====== For Jenkins agents, also need to install JDK 17 or newer, which is not available for CentOS 6 nor 7 directly (in distribution packaging). Alternative packaging, such as Temurin from the Adoptium project, is possible (checked for at least CentOS 7), see link:https://adoptium.net/installation/linux/#_centosrhelfedora_instructions[their instructions] for specific details. This may require updated library package versions as dependencies from the OS distribution, so you may also have to make sure that your `/etc/yum.repos.d/*` files (certainly `CentOS-Base.repo`, maybe also `CentOS-fasttrack.repo` and/or `CentOS-CR.repo`) to use e.g. ---- baseurl=https://vault.centos.org/centos/$releasever/os/$basearch/ ---- lines if the `mirrorlist` ones do not suffice to find living mirrors (WARNING: the `/os/` part of the URL would vary for different repository types). ====== Arch Linux ~~~~~~~~~~ Update the lower-level OS and package databases: ------ :; pacman -Syu ------ Install tools and prerequisites for NUT: ------ :; pacman -S --needed \ base-devel \ autoconf automake libtool libltdl \ clang gcc \ ccache \ git \ vim python perl \ pkgconf \ cppcheck valgrind # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; pacman -S --needed \ gdb # For spell-checking, highly recommended if you would propose pull requests: :; pacman -S --needed \ aspell en-aspell # For man-page doc types generation: :; pacman -S --needed \ asciidoc # For other doc types (PDF, HTML) generation - massive packages (TEX, X11): :; pacman -S --needed \ source-highlight dblatex # For CGI graph generation - massive packages (X11): :; pacman -S --needed \ gd # Optionally for sd_notify integration: :; pacman -S --needed \ systemd :; pacman -S --needed \ cppunit \ openssl nss \ augeas \ libusb \ neon \ net-snmp \ freeipmi \ avahi #?# no (lib)gpio(d) :; pacman -S --needed \ lua51 :; pacman -S --needed \ bash dash busybox ksh93 ------ Recommended for NUT CI farm integration (matching specific toolkit versions in a build matrix), and note the unusual location of `/usr/lib/ccache/bin/` for symlinks: ------ :; gcc --version gcc (GCC) 12.2.0 ... # Note: this distro delivers "gcc" et al as file names # so symlinks like this may erode after upgrades. # TODO: Rename and then link?.. :; (cd /usr/bin \ && for V in 12 12.2.0 ; do for T in gcc g++ cpp ; do \ ln -fsr $T $T-$V ; \ done; done) :; (cd /usr/lib/ccache/bin/ \ && for V in 12 12.2.0 ; do for T in gcc g++ ; do \ ln -fsr /usr/bin/ccache $T-$V ; \ done; done) :; clang --version clang version 14.0.6 ... :; (cd /usr/bin && ln -fs clang-14 clang++-14 && ln -fs clang-14 clang-cpp-14) :; (cd /usr/lib/ccache/bin/ \ && for V in 14 ; do for T in clang clang++ ; do \ ln -fsr /usr/bin/ccache $T-$V ; \ done; done) ------ Also for CI build agents, a Java environment (JDK17+ since autumn 2024) is required: ------ # Search for available Java versions: :; pacman -Ss | egrep 'jre|jdk' # Pick one: :; pacman -S --needed \ jre17-openjdk-headless # If needed to change default implementation, consult: :; archlinux-java help ------ Slackware Linux 15 ~~~~~~~~~~~~~~~~~~ Another long-term presence in the Linux landscape, and sometimes the baseline for appliances, the Slackware project recently hit release 15 in 2022, averaging two years per major release. It can be installed e.g. in a VM, using ISO images from the project site; see: * http://www.slackware.com/ => http://www.slackware.com/getslack/ => https://mirrors.slackware.com/slackware/slackware-iso/slackware64-15.0-iso/ * https://slackware.nl/slackware/slackware64-current-iso/ You would have to first log in as `root` and run `cgdisk` to define partitioning for your virtual HDD, such as the common `/boot`, `swap` and `/` Linux layout, and run `setup` to install "everything". Note that "out of the box" Slackware does not currently on networked package repositories and calculated dependency trees, so one has to know exactly what they want installed. Third-party projects for package managers are also available, e.g. link:https://slackpkg.org/documentation.html[`slackpkg`] => see also https://docs.slackware.com/slackware:slackpkg and https://slackpkg.org/stable/ : ---- :; wget https://slackpkg.org/stable/slackpkg-15.0.10-noarch-1.txz && \ installpkg slackpkg-15.0.10-noarch-1.txz ---- Uncomment a mirror from `/etc/slackpkg/mirrors` according to your location and other preferences (or use the top-listed default), and begin with: ---- :; slackpkg update ---- Note that packages may be only installed or re-installed/upgraded as separate explicit operations, so the procedure to bring your system into needed shape is a bit cumbersome (and each command may by default be interactive with a choice menu), e.g.: ---- :; for P in \ bash mc vim sudo \ ; do slackpkg info "$P" || slackpkg install $P || break ; done ---- For procedures below, this is automated via `root` profile to become a `slackpkg-install` command: ---- :; grep "slackpkg-install" ~/.profile || { cat >> ~/.profile << 'EOF' slackpkg-install() { for P in "$@" ; do echo "=== $P:" slackpkg info "$P" || slackpkg install "$P" || break done } EOF } :; . ~/.profile ---- If something has a hiccup, it suggests to look for the right name, e.g.: ---- :; slackpkg search python ---- For NUT dependencies and build tools: ---- :; slackpkg update # Baseline toolkits: # Note there is no cppcheck, cppunit, valgrind... # Note clang compiler tools are part of llvm package :; slackpkg-install \ ccache time \ coreutils diffutils \ git python3 perl curl \ make autoconf automake libtool binutils \ pkg-config \ gcc llvm # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; slackpkg-install gdb # For spell-checking, highly recommended if you would propose pull requests: :; slackpkg-install aspell{,-en} # Note there is no direct "asciidoc" nor "a2x", just the competing project # "rubygem-asciidoctor" that NUT currently has no recipes for, so you can # not compile man/html/pdf docs here, per the default repository. See below # for tools from alternative repositories, which seem to work well. Man page # compilation would require docbook-xml resources; older versions are in # this package https://slackbuilds.org/repository/15.0/system/docbook-xml/ # and recent ones are in not-installed part of main repository: :; slackpkg-install linuxdoc-tools # More on Python (for NUT-Monitor UI): :; slackpkg-install \ python-pip qt5 gettext-tools gettext # For CGI graph generation - massive packages (X11): :; slackpkg-install \ gd # General dependencies: :; slackpkg-install \ openssl openssl-solibs mozilla-nss \ libusb \ net-snmp \ neon # Shells: :; slackpkg-install \ bash dash ksh93 ---- Some more packages are available on the side, including Java (useful e.g. to make this environment into a fully fledged Jenkins worker). Other common NUT dependencies absent from primary Slackware repositories can be found and downloaded (seek `*.txz` package files, although a few are named `*.tgz`) from here, and passed to `installpkg`: * http://www.slackware.com/~alien/slackbuilds/openjdk17/ * http://www.slackware.com/~alien/slackbuilds/asciidoc/ * http://www.slackware.com/~alien/slackbuilds/cppunit/ * http://www.slackware.com/~alien/slackbuilds/lua/ (5.1 in "stable") and http://www.slackware.com/~alien/slackbuilds/lua53/ (5.4 in "current" as of Slackware 15.1 candidate in the works) -- note that LUA is not needed for the current NUT code base, but may become needed after import of features from forks ...and even the environment for Windows cross-builds, ancient compilers and modern toolkits to cover all bases: * http://www.slackware.com/~alien/slackbuilds/MinGW-w64/ * http://www.slackware.com/~alien/slackbuilds/docker/ * http://www.slackware.com/~alien/slackbuilds/gcc34/ * http://www.slackware.com/~alien/slackbuilds/gcc5/ FWIW, another "more official" but older Java package seems to be at: * http://www.slackware.com/~alien/slackbuilds/openjdk/ * https://slackbuilds.org/repository/15.0/development/jdk/ An example routine to install the latest instance of a package could be like this: ---- :; wget -m -l1 http://www.slackware.com/~alien/slackbuilds/asciidoc/pkg/ && \ find . -name '*.t?z' :; (cd ./www.slackware.com/~alien/slackbuilds/asciidoc/pkg/ && \ installpkgasciidoc-8.1.0-noarch-2.tgz ) ---- Note that some packages are further separated by Slackware version, e.g. with sub-directories for `15.0` and `current`: ---- :; wget -r -l1 -nd -R gif,css,jpg,html,htm --remove-listing \ http://www.slackware.com/~alien/slackbuilds/openjdk17/pkg64/15.0/ :; installpkg openjdk17-17.0.12_7-x86_64-1alien.txz ---- Upon community members' recommendations, Sotirov's SlackPack is also considered a reputable repository: https://sotirov-bg.net/slackpack/ and should cover most if not all of the dependencies required for NUT building (including PowerMan, IPMI etc.) [NOTE] ====== If setting up a CI farm agent with builds in RAM disk, keep in mind that default mount options for `/dev/shm` preclude script execution. Either set up the agent in a non-standard fashion (to use another work area), or if this is a dedicated machine -- relax the mount options in `/etc/fstab`. Here is an example with `noexec` which we *must avoid* for such use-case: ---- :; mount | grep /dev/shm tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,inode64) ---- ====== FreeBSD 12.2 ~~~~~~~~~~~~ NOTE: As of 2024, this version is way beyond EOL -- packages have been removed from mirrors. A discussion at https://forums.freebsd.org/threads/easy-upgrading-from-12-2-rel-in-2024.92695/ touches on upgrades in such situation. An alternate mirror (that worked to bump the system to `openjdk17`, as of this writing in Nov 2024) can be found at https://mirror.sg.gs/freebsd-pkg/FreeBSD:12:amd64/quarterly/ and written into `/etc/pkg/FreeBSD.conf` similarly to existing `url` entry. Note that `PATH` for builds on BSD should include `/usr/local/...`: ------ :; PATH=/usr/local/libexec/ccache:/usr/local/bin:/usr/bin:$PATH :; export PATH ------ NOTE: You may want to reference `ccache` even before all that, as detailed below. ------ :; pkg install \ git perl5 curl \ gmake autoconf automake autotools libltdl libtool \ valgrind \ cppcheck \ pkgconf \ gcc clang # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; pkg install \ gdb # See comments below, python version and package naming depends on distro :; pkg install \ python # NOTE: For python, you may eventually have to specify a variant like this # (numbers depending on default or additional packages of your distro): # :; pkg install python2 python27 # and/or: # :; pkg install python3 python37 # You can find a list of what is (pre-)installed with: # :; pkg info | grep -Ei 'perl|python' # For spell-checking, highly recommended if you would propose pull requests: :; pkg install \ aspell en-aspell # For other doc types (man-page, PDF, HTML) generation - massive packages # (TEX, X11): :; pkg install \ asciidoc source-highlight textproc/py-pygments dblatex # For CGI graph generation - massive packages (X11): :; pkg install \ libgd :; pkg install \ cppunit \ nss \ augeas \ libmodbus \ neon \ net-snmp \ powerman \ freeipmi \ avahi # NOTE: At least on FreeBSD 12, system-provided crypto exists and is used # by libnetsnmp, libneon, etc. - but is not marked as a package. Conversely, # the openssl-1.1.1k (as of this writing) can be installed as a package into # /usr/local/lib and then causes linking conflicts. The core system-provided # build of openssl does include headers and is useful for NUT build "as is". # ONLY INSTALL THIS PACKAGE IF REQUIRED (may get problems to rectify later): :; test -e /lib/libcrypto.so -a -e /usr/lib/libssl.so || \ pkg install openssl :; pkg install \ lua51 :; pkg install \ bash dash busybox ksh93 ------ Recommended: ------ :; pkg install ccache :; ccache-update-links ------ For compatibility with common setups on other operating systems, can symlink `/usr/local/libexec/ccache` as `/usr/lib/ccache` and possibly add dash-number suffixed symlinks to compiler tools (e.g. `gcc-10` beside `gcc10` installed by package). NOTE: For Jenkins agents, also need to `pkg install openjdk11` (17 or 21 required since autumn 2024) -- and do note its further OS configuration suggestions for special filesystem mounts. Due to BSD specific paths *when not using* an implementation of `pkg-config` or `pkgconf` (so guessing of flags is left to administrator -- TBD in NUT `m4` scripts), better use this routine to test the config/build: ---- :; ./configure --with-doc=all --with-all --with-cgi \ --without-avahi --without-powerman --without-modbus \ ### CPPFLAGS="-I/usr/local/include -I/usr/include" \ ### LDFLAGS="-L/usr/local/lib -L/usr/lib" ---- Note the lack of `pkg-config` also precludes `libcppunit` tests, although they also tend to mis-compile/mis-link with GCC (while CLANG seems okay). OpenBSD 6.5 ~~~~~~~~~~~ Note that `PATH` for builds on BSD should include `/usr/local/...`: ------ :; PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH :; export PATH ------ NOTE: You may want to reference `ccache` even before all that, as detailed below. OpenBSD delivers many versions of numerous packages, you should specify your pick interactively or as part of package name (e.g. `autoconf-2.69p2`). NOTE: For the purposes of builds with Jenkins CI agents, since summer 2022 it requires JDK11 which was first delivered with OpenBSD 6.5. Earlier iterations used OpenBSD 6.4 and version nuances in this document may still reflect that. FIXME: Since autumn 2024, JDK17+ is required. Maybe time to EOL OpenBSD 6.x workers, or to SSH into them from a nearby machine's Java agent?.. Alternately, consider https://github.com/adoptium/jdk17/blob/master/doc/building.md During builds, you may have to tell system dispatcher scripts which version to use (which feels inconvenient, but on the up-side for CI -- this system allows to test many versions of auto-tools in the same agent), e.g.: ------ :; export AUTOCONF_VERSION=2.69 AUTOMAKE_VERSION=1.13 ------ To use the `ci_build.sh` don't forget `bash` which is not part of OpenBSD base installation. It is not required for "legacy" builds arranged by just `autogen.sh` and `configure` scripts. NOTE: The OpenBSD 6.5 `install65.iso` installation includes a set of packages that seems to exceed whatever is available on network mirrors; for example, the CD image included `clang` program while it is not available to `pkg_add`, at least not via http://ftp.netbsd.hu/mirrors/openbsd/6.5/packages/amd64/ mirror. The `gcc` version on CD image differed notably from that in the networked repository (4.2.x vs. 4.9.x). You may have to echo a working base URL (part before "6.5/..." into the `/etc/installurl` file, since the old distribution is no longer served by default site. ------ # Optionally, make the environment comfortable, e.g.: :; pkg_add sudo bash mc wget rsync :; pkg_add \ git curl \ gmake autoconf automake libltdl libtool \ valgrind \ cppcheck \ pkgconf \ gcc clang # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; pkg_add install \ gdb # See comments below, python version and package naming depends on distro :; pkg_add \ python # NOTE: For python, you may eventually have to specify a variant like this # (numbers depending on default or additional packages of your distro): # :; pkg_add python-2.7.15p0 py-pip # and/or: # :; pkg_add python-3.6.6p1 py3-pip # although you might succeed specifying shorter names and the packager # will offer a list of matching variants (as it does for "python" above). # NOTE: "perl" is not currently a package, but seemingly part of base OS. # You can find a list of what is (pre-)installed with: # :; pkg_info | grep -Ei 'perl|python' # For spell-checking, highly recommended if you would propose pull requests: :; pkg_add \ aspell # For other doc types (man-page, PDF, HTML) generation - massive packages # (TEX, X11): :; pkg_add \ asciidoc source-highlight py-pygments dblatex \ docbook2x docbook-to-man # For CGI graph generation - massive packages (X11): :; pkg_add \ gd :; pkg_add \ cppunit \ openssl nss \ augeas \ libusb1 \ net-snmp \ avahi # For netxml-ups driver the library should suffice; however for nut-scanner # you may currently require to add a `libneon.so` symlink (the package seems # to only deliver a numbered SO library name), e.g.: :; pkg_add neon && \ if ! test -s /usr/local/lib/libneon.so ; then ln -s "`cd /usr/local/lib && ls -1 libneon.so.* | sort -n | tail -1`" \ /usr/local/lib/libneon.so fi # Select a LUA-5.1 (or possibly 5.2?) version :; pkg_add \ lua :; pkg_add \ bash dash ksh93 :; pkg_add \ argp-standalone \ freeipmi ------ Recommended: ------ :; pkg_add ccache :; ( mkdir -p /usr/lib/ccache && cd /usr/lib/ccache && \ for TOOL in cpp gcc g++ clang clang++ clang-cpp ; do \ ln -s ../../local/bin/ccache "$TOOL" ; \ done ; \ ) :; ( cd /usr/bin && for T in gcc g++ cpp ; \ do ln -s "$T" "$T-4.2.1" ; done ) :; ( cd /usr/lib/ccache && for T in gcc g++ cpp ; \ do ln -s "$T" "$T-4.2.1" ; done ) :; ( cd /usr/bin && for T in clang clang++ clang-cpp ; \ do ln -s "$T" "$T-7.0.1" ; done ) :; ( cd /usr/lib/ccache && for T in clang clang++ clang-cpp ; \ do ln -s "$T" "$T-7.0.1" ; done ) ------ For compatibility with common setups on other operating systems, can add dash-number suffixed symlinks to compiler tools (e.g. `gcc-4.2.1` beside `gcc` installed by package) into `/usr/lib/ccache`. NOTE: For Jenkins agents, also need to `pkg_add jdk` (if asked, pick version 11 or 17); can request `pkg_add jdk%11`. You would likely have to update the trusted CA store to connect to NUT CI, see e.g. (raw!) download from https://gist.github.com/galan/ec8b5f92dd325a97e2f66e524d28aaf8 but ensure that you run it with `bash` and it does `wget` the certificates (maybe with `--no-check-certificate` option if the OS does not trust current internet infrastructure either), and revise the suggested certificate files vs. https://letsencrypt.org/certificates/ and/or comments to that gist. Due to BSD specific paths *when not using* an implementation of `pkg-config` or `pkgconf` (so guessing of flags is left to administrator -- TBD in NUT `m4` scripts), better use this routine to test the config/build: ------ :; ./configure --with-doc=all --with-all --with-cgi \ --without-avahi --without-powerman --without-modbus \ ### CPPFLAGS="-I/usr/local/include -I/usr/include" ### LDFLAGS="-L/usr/local/lib -L/usr/lib" ------ Note the lack of `pkg-config` also precludes `libcppunit` tests, although they also tend to mis-compile/mis-link with GCC (while CLANG seems okay). NetBSD 9.2 ~~~~~~~~~~ Instructions below assume that `pkgin` tool (pkg-src component to "install binary packages") is present on the system. Text below was prepared with a VM where "everything" was installed from the ISO image, including compilers and X11. It is possible that some packages provided this way differ from those served by `pkgin`, or on the contrary, that the list of suggested tool installation below would not include something a bare-minimum system would require to build NUT. Note that `PATH` for builds on NetBSD should include `local` and `pkg`; the default after installation of the test system was: ------ :; PATH="/sbin:/usr/sbin:/bin:/usr/bin:/usr/pkg/sbin:/usr/pkg/bin" :; PATH="$PATH:/usr/X11R7/bin:/usr/local/sbin:/usr/local/bin" :; export PATH ------ NOTE: You may want to reference `ccache` even before all that, e.g. in the system-wide `/etc/profile` or build-user's `~/.profile`, as detailed below: ------ :; PATH="/usr/lib/ccache:$PATH" :; export PATH ------ To use the `ci_build.sh` don't forget `bash` which may be not part of NetBSD base installation. It is not required for "legacy" builds arranged by just `autogen.sh` and `configure` scripts. Also note that the `install-sh` helper added by autotools from OS-provided resources when generating the `configure` script may be old and its directory creation mode is not safe for parallel-`make` installations. If this happens, you can work around by `make MKDIRPROG="mkdir -p" install -j 8` for example. [NOTE] ====== Instructions below rely on `pkgin`, an `apt`/`yum`-like front-end tool for managing pkgsrc binary packages. It is available out of the box on the system this document describes, but if an e.g. older release lacks it, it can be added using the older tooling: ---- :; CDN="http://cdn.NetBSD.org/pub/pkgsrc/packages/NetBSD" :; PKG_PATH="${CDN}/$(uname -p)/$(uname -r|cut -f '1 2' -d.)/All/" :; export PKG_PATH :; pkg_add pkgin ---- For more details, see https://www.pkgsrc.org/#index1h1 and https://www.librebyte.net/en/cli-en/pkgin-a-netbsd-package-manager/ (the latter also provides a nice cheat-sheet about `pkgin` operations). ====== [NOTE] ====== On NetBSD 9.2 the `openpimi` and `net-snmp` packages complain that they require either OS ABI 9.0, or that `CHECK_OSABI=no` is set in a `pkg_install.conf`. Such file was not found in the test system, but can be created in `/etc/` and is honoured by `pkgin`: ---- :; grep CHECK_OSABI /etc/pkg_install.conf || \ ( echo CHECK_OSABI=no >> /etc/pkg_install.conf ) ---- ====== ------ :; pkgin install \ git perl curl \ mozilla-rootcerts mozilla-rootcerts-openssl \ bmake gmake autoconf automake libltdl libtool \ cppcheck \ pkgconf \ gcc7 gcc14 clang # See comments below, python version and package naming depends on distro :; pkgin install \ python27 python39 python312 python313 :; ( cd /usr/pkg/bin && ( ln -fs python2.7 python2 ; ln -fs python3.13 python3 ) ) # You can find a list of what is (pre-)installed with: # :; pkgin list | grep -Ei 'perl|python' # For localization maintenance (currently in Python NUT-Monitor app), # provide an `msgfmt` implementation, e.g.: # :; pkgin install gettext # # To install the Python NUT-Monitor app, you may need some modules: # For Python2: # :; pkgin install py27-gtk2 # For Python3: # :; pkgin install py312-qt5 py313-qt5 # For spell-checking, highly recommended if you would propose pull requests: :; pkgin install \ aspell aspell-en # For man-page doc types, footprint on this platform is moderate: :; pkgin install \ asciidoc # FIXME: Missing packages? # For other doc types (PDF, HTML) generation - massive packages (TEX, X11): # :; pkgin install \ # source-highlight py39-pygments dblatex # For CGI graph generation - massive packages (X11): :; pkgin install \ gd openmp :; pkgin install \ cppunit \ openssl nss \ augeas \ libusb libusb1 \ neon \ net-snmp \ avahi # Select a LUA-5.1 (or possibly 5.2?) version :; pkgin install \ lua51 # lua52 :; pkgin install \ bash dash ast-ksh oksh ------ [NOTE] ====== There seems to be no FreeIPMI for NetBSD, but there's OpenIPMI (can help someone implementing actual support for it): ------ :; pkgin install \ openipmi ------ It still seems to not work for NUT's expectations of FreeIPMI (we have basic detection support for OpenIPMI but no code yet). ====== Recommended: For compatibility with common setups on other operating systems, can add dash-number suffixed symlinks to compiler tools (e.g. `gcc-7` beside the `gcc` installed by package) near the original binaries and into `/usr/lib/ccache`: ------ :; ( cd /usr/pkg/bin && for TOOL in cpp gcc g++ ; do \ for VER in "7" "14" ; do \ ln -fs "../gcc$VER/bin/$TOOL" "${TOOL}-${VER}" ; \ done ; \ done ) # Note that the one delivered binary is `clang-13` (in originally described # installation; `clang-18` after an update in 2025 which auto-removed the # older version) and many (unnumbered) symlinks to it. For NUT CI style of # support for builds with many compilers, complete the known numbers: :; ( cd /usr/pkg/bin && for TOOL in clang-cpp clang++ ; do \ for VER in "-18" ; do \ ln -s clang-18 "$TOOL$VER" ; \ done ; \ done ) :; pkgin install ccache :; ( mkdir -p /usr/lib/ccache && cd /usr/lib/ccache && \ for TOOL in cpp gcc g++ clang ; do \ for VER in "" "-7" "-14" ; do \ ln -s ../../pkg/bin/ccache "$TOOL$VER" ; \ done ; \ done ; \ for TOOL in clang clang++ clang-cpp ; do \ for VER in "" "-18" ; do \ ln -s ../../pkg/bin/ccache "$TOOL$VER" ; \ done ; \ done ; \ ) ------ NOTE: For Jenkins agents, also need to `pkgin install openjdk21` (will be in `JAVA_HOME=/usr/pkg/java/openjdk21`). Note that the location may be not exposed in `PATH` by default, so you may want to edit your system-wide `/etc/profile` or build user's `~/.profile` with: ------ JAVA_HOME="/usr/pkg/java/openjdk21" export JAVA_HOME PATH="${JAVA_HOME}/bin:${PATH}" export PATH ------ OpenIndiana as of releases 2021.10 to 2024.04 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Note that due to IPS and `pkg(5)`, a version of python is part of baseline illumos-based OS; this may not be the case on some other illumos distributions which do not use IPS however. Currently they use python 3.7 or newer. To build older NUT releases (2.7.4 and before), you may need to explicitly `pkg install python-27`. Typical tooling would include: ------ :; pkg install \ git curl wget \ gnu-make autoconf automake libltdl libtool \ valgrind \ pkg-config \ gnu-binutils developer/linker # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; pkg install \ gdb # NOTE: For python, some suitable version should be available since `pkg(5)` # tool is written in it. Similarly, many system tools are written in perl # so some version should be installed. You may specify additional variants # like this (numbers depending on default or additional packages of your # distro; recommended to group `pkg` calls with many packages at once to # save processing time for calculating a build strategy): # :; pkg install runtime/python-27 # and/or: # :; pkg install runtime/python-37 runtime/python-35 runtime/python-39 # Similarly for perl variants, e.g.: # :; pkg install runtime/perl-522 runtime/perl-524 runtime/perl-534 # You can find a list of what is available in remote repositories with: # :; pkg info -r | grep -Ei 'perl|python' # For spell-checking, highly recommended if you would propose pull requests: :; pkg install \ aspell text/aspell/en # For other doc types (man-page, PDF, HTML) generation - massive packages # (TEX, X11): :; pkg install \ asciidoc libxslt \ docbook/dtds docbook/dsssl docbook/xsl docbook docbook/sgml-common \ pygments-39 \ image/graphviz expect graphviz-tcl # For CGI graph generation - massive packages (X11): :; pkg install \ gd :; pkg install \ openssl library/mozilla-nss \ library/augeas python/augeas \ libusb-1 libusbugen system/library/usb/libusb \ system/header/header-usb driver/usb/ugen \ libmodbus \ library/neon \ system/management/snmp/net-snmp \ system/management/powerman \ freeipmi \ avahi # With 2024.04, some packages were split for development vs. run-time # and/or based on architecture: :; pkg install \ system/library/mozilla-nss/header-nss \ library/nspr library/nspr/32 :; pkg install \ lua :; pkg install \ dash bash shell/ksh93 ### Maybe :; pkg install \ gnu-coreutils ### Maybe - after it gets fixed for GCC builds/linkage :; pkg install \ cppunit ------ For extra compiler coverage, we can install a large selection of versions, although to meet NUT CI farm expectations we also need to expose "numbered" filenames, as automated below: ------ # NOTE: not all compiler versions may be served, some are obsoleted over time. # Check current distro repository offers with: :; pkg info -r '*clang*' '*gcc*' :; pkg search -r '*bin/g++*' :; pkg search -r '*bin/clang++*' :; pkg install \ gcc-48 gcc-49 gcc-5 gcc-6 gcc-7 gcc-9 gcc-10 gcc-11 \ clang-80 clang-90 \ ccache # As of this writing, clang-13 refused to link (claiming issues with # --fuse-ld which was never specified) on OI; maybe later it will: #:; pkg install \ # developer/clang-13 runtime/clang-13 # With OI 2024.04 there's also clang-18 available in the mix, and as of # 2025 packaging, clang-19 as well: :; pkg install \ developer/clang-19 runtime/clang-19 # Get clang-cpp-X visible in standard PATH (for CI to reference the right one), # and make sure other frontends are exposed with versions (not all OI distro # releases have such symlinks packaged right), e.g.: :; (cd /usr/bin && for X in 8 9 19 ; do for T in "" "++" "-cpp"; do \ ln -fs "../clang/$X.0/bin/clang$T" "clang${T}-${X}" ; \ done; done) # If /usr/lib/ccache/ symlinks to compilers do not appear after package # installation, or if you had to add links like above, call the service: :; svcadm restart ccache-update-symlinks ------ We can even include a `gcc-4.4.4-il` version (used to build the illumos OS ecosystems, at least until recently, which is a viable example of an old GCC baseline); but note that so far it conflicts with `libgd` builds at `./configure --with-cgi` stage (its binaries require newer ecosystem): ------ :; pkg install \ illumos-gcc@4.4.4 # Make it visible in standard PATH :; (cd /usr/bin && for T in gcc g++ cpp ; do \ ln -s ../../opt/gcc/4.4.4/bin/$T $T-4.4.4 ; \ done) # If /usr/lib/ccache/ symlinks to these do not appear, call the service: :; svcadm restart ccache-update-symlinks ------ OI currently also does not build `cppunit`-based tests well, at least not with GCC (they segfault at run-time with `ostream` issues); a CLANG build works for that however. It also lacks out-of-the-box Tex suite and `dblatex` in particular, which `asciidoc` needs to build PDF documents. It may be possible to add these from third-party repositories (e.g. SFE) and/or build from sources. No pre-packaged `cppcheck` was found, either. [NOTE] ====== For Jenkins agents, also need to `pkg install runtime/java/openjdk17` for JRE/JDK 17. Java 17 or 21 is required to run Jenkins agents after autumn 2024. If updating from older releases, you may need to update default implementation, e.g.: ---- :; pkg set-mediator -V 17 java ---- ====== OmniOS CE (as of releases 151036 - 151052) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Being a minimal-footprint system, OmniOS CE provides very few packages out of the box. There are additional repositories supported by the project, as well as third-party repositories such as SFE. For some dependencies, it may happen that you would need to roll and install your own builds in accordance with that project's design goals. Note you may need not just the "Core" IPS package publisher, but also the "Extra" one. As of release 151052, it can be attached right in the installer; otherwise the `pkg (set-)publisher` commands can be used. See OmniOS CE web site for setup details. ------ # Optionally, make the environment comfortable, e.g.: :; pkg install sudo bash application/mc wget rsync pigz pbzip2 p7zip top # NOTE: not all compiler versions may be served by all releases (e.g. OmniOS # did not deliver clang in Core nor Extra repositories for quite a while), # and some are obsoleted over time. While OmniOS 151036 lacked any clang, # LTS 151046 offered a range of clang 13 to 17, and current stable (151052) # includes also 18 and 19. Unlike OpenIndiana, OmniOS does not provide # implicit default (not-numbered) packages for neither clang nor gcc. # Check your distro repository offers with: :; pkg info -r '*clang*' '*gcc*' :; pkg search -r '*bin/g++*' :; pkg search -r '*bin/clang++*' # Then install a suitable one, e.g.: :; pkg install \ developer/clang-17 :; pkg install \ developer/build/autoconf developer/build/automake \ developer/build/libtool library/libtool/libltdl \ build-essential ccache git developer/pkg-config \ runtime/perl \ asciidoc \ libgd # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; pkg install \ gdb # May be or not be provided, depending on distro age: :; pkg install \ net-snmp # For crypto-enabled builds: :; pkg install \ openssl-3 # By r151046, some packages were split for development vs. run-time; # to provide support for Mozilla NSS, you need libraries and headers: :; pkg install \ system/library/mozilla-nss \ system/library/mozilla-nss/header-nss \ library/nspr library/nspr/header-nspr # NOTE: For python, some suitable version should be available since `pkg(5)` # tool is written in it. You may specify an additional variant like this # (numbers depending on default or additional packages of your distro): # :; pkg install runtime/python-37 # You can find a list of what is available in remote repositories with: # :; pkg info -r | grep -Ei 'perl|python' ------ Your OmniOS version may lack a pre-packaged libusb, however the binary build from contemporary OpenIndiana can be used (copy the header files and the library+symlinks for all architectures you would need). [NOTE] ====== As of July 2022, a `libusb-1` package recipe was proposed for the `omnios-extra` repository (NUT itself and further dependencies may also appear there, per link:https://github.com/networkupstools/nut/issues/1498[issue #1498]), and is available as of release 151046 and later on: ------ :; pkg install \ libusb-1 ------ ====== You may need to set up `ccache` with the same `/usr/lib/ccache` dir used in other OS recipes. Assuming your Build Essentials pulled GCC 11 version, and ccache is under `/opt/ooce` namespace, that would be like: ------ :; GCCVER=11 :; mkdir -p /usr/lib/ccache :; cd /usr/lib/ccache :; ln -fs ../../../opt/ooce/bin/ccache gcc :; ln -fs ../../../opt/ooce/bin/ccache g++ :; ln -fs ../../../opt/ooce/bin/ccache gcpp :; ln -fs ../../../opt/ooce/bin/ccache gcc-${GCCVER} :; ln -fs ../../../opt/ooce/bin/ccache g++-${GCCVER} :; ln -fs ../../../opt/ooce/bin/ccache gcpp-${GCCVER} ------ Given that many of the dependencies can get installed into that namespace, you may have to specify where `pkg-config` will look for them (note that library and binary paths can be architecture bitness-dependent; the `ci_build.sh` script should take care of this for many scenarios): ------ :; ./configure PKG_CONFIG_PATH="/opt/ooce/lib/amd64/pkgconfig" --with-cgi ------ You may also have to fiddle with either `LD_LIBRARY_PATH`, `crle (-c)` or `./configure --with-something-libs` options to compensate for lack of `-R` linker options in the `pkg-config` information provided by that repository: by default the NUT programs can build with the information they get, but fail to find the needed shared objects at run-time. More about this situation is tracked at https://github.com/networkupstools/nut/issues/2782 Note also that the minimal footprint nature of OmniOS CE precludes building any large scope easily, so avoid docs and "all drivers" unless you provide whatever they need to happen. [NOTE] ====== For Jenkins agents, also need to `pkg install runtime/java/openjdk21` for JRE/JDK 17. Java 17 or 21 is required to run Jenkins agents after autumn 2024. If updating from older releases, you may need to update default implementation, e.g.: ---- :; pkg set-mediator -V 21 java ---- ====== Solaris 8 ~~~~~~~~~ Builds for a platform as old as this are not currently covered by regular NUT CI farm runs, however since the very possibility of doing this was recently verified, some notes follow. For context: Following a discussion in the mailing list starting at https://alioth-lists.debian.net/pipermail/nut-upsuser/2022-December/013051.html and followed up by GitHub issues and PR: * https://github.com/networkupstools/nut/issues/1736 * https://github.com/networkupstools/nut/issues/1737 (about a possible but not yet confirmed platform problem) * https://github.com/networkupstools/nut/pull/1738 ...recent NUT codebase was successfully built and self-tested in a Solaris 8 x86 VM (a circa 2002 release), confirming the project's adherence to the goal that if NUT ran on a platform earlier, so roughly anything POSIX-ish released this millennium and still running, it should still be possible -- at least as far as our part of equation is concerned. That said, platform shows its age vs. later standards (script interpreters and other tools involved), and base "complete install" lacked compilers, so part of the tested build platform setup involved third-party provided package repositories. One helpful project was extensive notes about preparation of the Solaris 8 VM (and our further comments there), which pointed to the still active "tgcware" repository and contains scripts to help prepare the freshly installed system: * https://github.com/mac-65/Solaris_8_x86_VM * https://github.com/mac-65/Solaris_8_x86_VM/issues/1 * http://jupiterrise.com/tgcware/sunos5.8_x86/stable/ Note that scripts attached to the notes refer to older versions of the packages than what is currently published, so I ended up downloading everything from the repository into the VM and using shell wildcards to pick the packages to install (mind the package families with similar names when preparing such patterns). After the OS, tools and feasible third-party dependencies were installed, certain environment customization was needed to prepare for NUT build in particular (originally detailed in GitHub issues linked above): * For `CONFIG_SHELL`, system `dtksh` seems to support the syntax (unlike default `/bin/sh`), but for some reason segfaults during `configure` tests. Alternatively `/usr/tgcware/bin/bash` (4.4-ish) can be used successfully. System-provided bash 2.x is too old for these scripts. * To run `ci_build.sh` CI/dev-testing helper script, either the shebang should be locally fixed to explicitly call `/usr/tgcware/bin/bash`, or the build environment's `PATH` should point to this `bash` implementation as a first hit. If we want to primarily use OS-provided tools, this latter option may need a bit of creative setup; I made a symlink into the `/usr/lib/ccache` directory which has to be first anyway (before compilers). * The system-provided default `grep` lacks the `-E` option which was preferred over generally obsoleted `egrep` since link:https://github.com/networkupstools/nut/pull/1660[PR #1660] -- however pre-pending `/usr/xpg4/bin` early in the `PATH` fixes the problem. * The builds of `gcc` in TGCWARE repository were picky about shared objects linking as needed to run them, so `LD_LIBRARY_PATH` had to refer to its library directories (generally this is frowned upon and should be a last resort). * Due to lack of Python in that OS release, NUT augeas support had to be disabled when preparing the build from Git sources (generated files may be available as part of distribution tarballs however): `WITHOUT_NUT_AUGEAS=true; export WITHOUT_NUT_AUGEAS; ./autogen.sh` Overall, the successful test build using the NUT standard CI helper script `ci_build.sh` had the following shell session settings: ---- ### Common pre-sets from .profile or .bashrc (long lines wrapped for readability): ### bash-2.03$ echo $PATH ### /usr/bin:/usr/dt/bin:/usr/openwin/bin:/bin:/usr/ucb:/usr/tgcware/bin:\ ### /usr/tgcware/gnu:/usr/tgcware/gcc42/bin:/usr/tgcware/i386-pc-solaris2.8/bin ### bash-2.03$ echo $LD_LIBRARY_PATH ### /usr/lib:/usr/tgcware/lib:/usr/tgcware/gcc42/lib:\ ### /usr/tgcware/i386-pc-solaris2.8/lib ### Further tuning for the build itself: :; git clean -fffdddxxx :; CONFIG_SHELL=/usr/tgcware/bin/bash \ WITHOUT_NUT_AUGEAS=true \ PATH="/usr/xpg4/bin:$PATH" \ /usr/tgcware/bin/bash ./ci_build.sh ---- MacOS with homebrew ~~~~~~~~~~~~~~~~~~~ Some CI tests happen on MacOS using a mix of their default xcode environment for compilers, and Homebrew community packaging for dependencies (including `bash` since the system one is too old for `ci_build.sh` script syntax). See `.travis.yml` and `.circleci/config.yml` for practical details of the setup, and https://brew.sh if you want to install it on your MacOS system (note that its default packaged locations known as `HOMEBREW_PREFIX` differ depending on architecture -- see https://docs.brew.sh/Installation for more details; find via `brew config | grep HOMEBREW_PREFIX: | awk '{print $2}'`). [NOTE] ====== The quickest pre-configuration for `ci_build.sh` integration with this non-default build system would be to add this line into your shell profile: ---- eval "$(brew shellenv)" ---- ====== NOTE: Homebrew is not the only build/packaging system available for MacOS, so NUT scripts do not make any assumptions nor try to find a build system they were not told about (via `HOMEBREW_PREFIX` in this case). Currently known dependencies for basic build include: ---- # Optional for a quick spin: :; HOMEBREW_NO_AUTO_UPDATE=1; export HOMEBREW_NO_AUTO_UPDATE # Required: :; brew install ccache bash libtool binutils autoconf automake git m4 \ pkg-config aspell asciidoc docbook-xsl cppunit gd \ libusb neon net-snmp \ nss openssl \ libmodbus freeipmi powerman # To debug eventual core dump files, or trace programs with an IDE like # NetBeans (perhaps remotely), you may want the GNU Debugger program: :; brew install gdb # Recommended: :; brew install curl wget midnight-commander ---- NOTE: for `asciidoc`/`a2x` to work, you should `export XML_CATALOG_FILES` with the location of packaged resources (`${HOMEBREW_PREFIX}/etc/xml/catalog`). On one test system, man page builds spewed warnings like `:1: SyntaxWarning: invalid escape sequence '\S'` due to incompatibility of older asciidoc with new Python syntax requirements, but seemed to produce reasonable results otherwise. Note that `ccache` is installed in a different location than expected by default in the `ci_build.sh` script, so if your system allows to add the symbolic link to `/opt/homebrew/opt/ccache/libexec` (`/usr/local/opt/ccache/libexec` on x86) as `/usr/lib/ccache` -- please do so as the easiest way out. Alternatively, to prepare building sessions with `ci_build.sh` you can: ---- :; export CI_CCACHE_SYMLINKDIR="/opt/homebrew/opt/ccache/libexec" ### ...or for x86 builders: #:; export CI_CCACHE_SYMLINKDIR="/usr/local/opt/ccache/libexec" ---- NOTE: For Jenkins agents, also need to `brew install --cask temurin@21` for JRE/JDK 21. Java 17 or 21 (an LTS) is required to run Jenkins agents after summer 2024. The compiler is part of Apple's XCode ecosystem. Just try to run `clang` in a GUI terminal, and a pop-up will appear offering to install it. Note that you would have to create symbolic links to version-numbered names of compilers, e.g. `clang-14` and `clang++-14` in both `/usr/local/bin` (pointing to `/bin/clang(++)` and in the `ccache` location prepared above (pointing to `../bin/ccache`), and repeat that in locations prepared by XCode installation such as `/Library/Developer/CommandLineTools/usr/bin/` and `/usr/local/Homebrew/Library/Homebrew/shims/mac/super/` just as `ln -s clang{,-14} ; ln -s clang++{,-14}`. Apparently `clang` is the only compiler available; various names of `gcc*` are links to the same binaries. WARNING: Take care to *NOT* symlink a `clang-cpp(-14)` which is not a name recognized by XCode dispatcher program, so requests to it freeze. On a machine dedicated to CI purposes, it may be wise to disable Spotlight search indexing with `sudo mdutil -a -i off`, disable active desktop themes, etc. (normally you would not even log in interactively). For scratch workers (VMs) also consider going to System Preferences => Software Updates => Advanced, and un-checking all the boxes (disable the overheads of pulling in the updates you won't remember in an hour anyway). If you eventually find that the `kernel_task` consumes a lot of CPU, this is usually the system's way of throttling (scheduling A LOT of high-priority no-op cycles to preempt any other workload). In this case please investigate cooling and hardware compatibility (especially in a VM), or find and follow community documentation about neutering `IOPlatformPluginFamily.kext` module (probably not on the bare-metal MacOS instance -- find the cooling problem there instead). * https://grafxflow.co.uk/blog/mac-os-x/delete-ioplatformpluginfamilykext-macos-big-sur Windows builds ~~~~~~~~~~~~~~ There have been several attempts to adjust NUT codebase to native builds for Windows, as well as there are many projects helping to produce portable programs. Further TODO for Windows would include: * MSVCRT (ubiquitous) vs. UCRT (more standards compliant, but since Windows 10) https://docs.microsoft.com/en-us/cpp/porting/upgrade-your-code-to-the-universal-crt?view=msvc-160 * libusb-0.1 vs. libusb-1.0 NOTE: Native mingw, MSYS2, etc. builds on Windows are known to suffer from interaction with antivirus software which holds executable files open and so not writable by the linker. This may cause random steps in the `configure` script or later during the build to fail. If that happens to you, disable the antivirus completely or exempt at least the NUT build area from protection. Windows with mingw ^^^^^^^^^^^^^^^^^^ See `scripts/Windows/README.adoc` for original recommendations for the effort, including possibilities of cross-builds with mingw available in Linux. Unfortunately these did not work for me at the time of testing, yielding some issues downloading mingw both in Windows and Linux environments. So I explored other downloads, as detailed below. See also: * https://winlibs.com/ * https://azrael.digipen.edu/~mmead/www/public/mingw/ * https://www.mingw-w64.org/downloads/ NOTE: Seems the mingw installer has problems with current authentication and redirect on SourceForge. You can download and unpack 7z archives from https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/ into e.g. `C:\Progra~1\mingw-w64\x86_64-8.1.0-release-posix-seh-rt_v6-rev0` location on your Windows system. Then for building further NUT dependencies see `scripts/Windows/README.adoc`. Windows with MSYS2 ^^^^^^^^^^^^^^^^^^ The MSYS2 ecosystem is available at https://www.msys2.org/ and builds upon earlier work by link:https://www.mingw-w64.org[MinGW-w64] (in turn a fork of link:https://sourceforge.net/projects/mingw/[MinGW.org (aka mingw-w32)]) and link:http://cygwin.com/[Cygwin] projects, to name a few related efforts. It also includes `pacman` similar to that in Arch Linux for easier dependency installation, and many packages are available "out of the box" this way. The project is currently sponsored by Microsoft and seems to be supported by Visual Studio Code IDE for building and debugging projects, for more details see https://code.visualstudio.com/docs/cpp/config-mingw Notable pages of the project include: * https://www.msys2.org/ with current download link and first-installation instructions * https://www.msys2.org/wiki/MSYS2-introduction/ for general overview * https://packages.msys2.org/search?t=binpkg for search in package repository After downloading and installing MSYS2 archive for the first time, they suggest to start by updating the base ecosystem (using their terminal): ---- :; pacman -Syu ---- Wait for metadata and base package downloads, agree that all MSYS2 programs including your terminal would be closed/restarted, and wait for this stage to complete. Run it again to refresh more of the ecosystem, now without restarting it: ---- :; pacman -Syu ---- Finally, install tools and prerequisites for building NUT; note that some of the recommended package names are "umbrellas" for several implementations, and the `pacman` would ask you which (or "all") to install in those cases. NOTE: Suggestions below use `x86_64` generic variants where possible, and `clang` where available to try both build toolkits on the platform. If you want to build `i686` (32-bit) or alternate backends (e.g. `ucrt` instead of default `msvcrt`), poke the repository search to see what is available. NOTE: To build NUT with `ci_build.sh` (and generally -- to help `configure` script find the dependencies listed below), start the terminal session with "MSYS2 MinGW x64" shortcut. Other options set up the environment variables for toolkits listed in their shortcut names, and so tend to prefer "wrong" flags and paths to dependencies (if you have several variants installed). The "MSYS2 MinGW UCRT x64" was also reported to work. To avoid toolkit variant mismatches, you may require to use their specific builds preferentially: ---- PATH="/mingw64/bin:$PATH" export PATH ---- ...and also add these lines to the `~/.bashrc` file. ---- # This covers most of the common FOSS development baseline, including # python, perl, autotools, gcc, clang, git, binutils, make, pkgconf... :; pacman -S --needed \ base-devel mingw-w64-x86_64-toolchain \ autoconf-wrapper automake-wrapper libtool mingw-w64-x86_64-libltdl \ clang gcc \ ccache mingw-w64-x86_64-ccache \ git aspell aspell-en \ vim python \ mingw-w64-x86_64-python-pygments # PThreads come as an extra feature; note there are many variants, # see https://packages.msys2.org/search?t=binpkg&q=pthread :; pacman -S --needed \ mingw-w64-x86_64-winpthreads-git \ mingw-w64-clang-x86_64-winpthreads-git # Note that MSYS2 includes libusb-1.0 "natively" # The NUT codebase adjustments for Windows might at this moment expect older # ecosystem via https://github.com/mcuee/libusb-win32 -- subject to fix then. :; pacman -S --needed \ mingw-w64-x86_64-libusb \ mingw-w64-clang-x86_64-libusb # Seems that the older libusb-win32 (libusb-0.1) is also available as: :; pacman -S --needed \ mingw-w64-x86_64-libusb-win32 \ mingw-w64-clang-x86_64-libusb-win32 # Alternately there is libusb-compat (libusb-1.0 codebase exposing the older # libusb-0.1 API) which SHOULD NOT be installed along with the real libusb-0.1: # :; pacman -S --needed mingw-w64-x86_64-libusb-compat-git \ # mingw-w64-clang-x86_64-libusb-compat-git # This also pulls *-devel of several other projects: :; pacman -S --needed \ mingw-w64-x86_64-neon libneon-devel # Other dependencies: :; pacman -S --needed \ mingw-w64-x86_64-libmodbus-git \ mingw-w64-clang-x86_64-libmodbus-git \ mingw-w64-x86_64-libgd \ mingw-w64-clang-x86_64-libgd # For C++ tests: :; pacman -S --needed \ mingw-w64-x86_64-cppunit \ mingw-w64-clang-x86_64-cppunit ---- `ccache` wrapper scripts are available as e.g. `/mingw64/lib/ccache/bin/gcc` and lack a set for `clang` tools; easy-peasy fix with: ---- :; cd /mingw64/lib/ccache/bin :; for T in clang clang++ clang-cpp ; do \ sed "s/gcc/$T/" < gcc > "$T" ; chmod +x "$T" ; done ---- Note that default `ccache` seems quirky on Windows MSYS2, possibly due to mixing of the path separator characters and/or embedding and choking on the `C:` in path names. Overall it seems unable to create the cache files after it has created the cache directory tree (though you might have to pre-create the `${HOME}/.ccache` anyway, as NUT `ci_build.sh` script does. As found in experimentation, setting the `PATH` consistently for toolkits involved is very important. * https://github.com/ccache/ccache/discussions/784 * https://sourceforge.net/p/msys2/tickets/253/ Notable packages *not found* in the repo: * snmp (net-snmp, ucd-snmp) -- instructions in `scripts/Windows/README.adoc` document now covers building it from source in MSYS2 MinGW x64 environment, essentially same as for Linux cross builds with proper `ARCH` and `PREFIX` * libregex (C version, direct NUT `configure` script support was added by the Windows branch); MSYS2 however includes `libpcre` pulled by some of the dependencies above... * augeas * avahi * powerman * ipmi Not installed above (yet?): * https://packages.msys2.org/search?t=binpkg&q=serial -- for these need to first check if termios is part of baseline Note that `ccache` symlinks for MSYS2 are installed into `/usr/lib/ccache/bin` directory (not plain `/usr/lib/ccache` as elsewhere). [NOTE] ====== After you successfully build NUT (perhaps using `ci_build.sh`), if you install it into a prototype area by `make DESTDIR=... install` then you should add the third-party shared libraries involved, for that file set to be usable. Something along these lines: ------ :; find "$DESTDIR" -name '*.exe' -type f | while read F ; do ldd "$F" \ | grep ' /mingw64/' ; done | awk '{print $3}' | sort | uniq \ | while read LIB ; do cp -pf "$LIB" "$DESTDIR/mingw64/bin/" ; done ------ Keep in mind that a similar trick (or links to `*.dll` -- and symlinks are problematic on that platform) may be needed in other directories, such as `sbin` and `cgi-bin`: ------ :; ( cd "$DESTDIR/mingw64/bin/" && ln *.dll ../sbin && ln *.dll ../cgi-bin ) ------ ====== nut-2.8.3/docs/design.txt0000644000200500020050000002347714777767434012250 00000000000000NUT design document =================== This software is designed around a layered scheme with drivers, a data server, and clients. These layers communicate with text-based protocols for easier maintenance and diagnostics. The layering ------------ The NUT driver(s) and the data server run on the same system, which has some communications media connected to the power device (e.g. a serial or USB link, a local IPMI interface, or a network interface in the engineering VLAN). While each driver program talks the device vendor-defined protocol over such media, it also talks the local NUT Socket protocol to the local data server. Clients connect to the data server using the common NUT Network protocol over TCP, whether on `localhost` or remotely. One most notable client is `upsmon`, which is responsible for shutdown of the system it runs on, when the power situation becomes critical. Design-wise, it normally splits into two daemons to minimize security risks: one remains with 'root' privileges and is only used to start the configured `SHUTDOWNCMD` when the time comes, and the other half drops privileges and does the bulk of work. NOTE: There were requests for enhancement to also implement connectivity using the common NUT Network protocol using local sockets, so clients running on the same machine as the data server would not have to always use the TCP/IP stack; however this is currently not implemented. image:images/nut_layering.png[NUT layering] How information gets around --------------------------- From the equipment ~~~~~~~~~~~~~~~~~~ DRIVERS talk to the EQUIPMENT and receive updates. For most hardware this is polled (DRIVER asks EQUIPMENT about a variable), but forced updates are also possible. The exact method is not important, as it is abstracted by the driver. From the driver ~~~~~~~~~~~~~~~ The core of all DRIVERS maintains internal storage for every variable that is known along with the auxiliary data for those variables. It sends updates to this data to any process which connects to the Unix domain socket. The DRIVERS will also provide a full atomic copy of their internal knowledge upon receiving the "DUMPALL" command on the socket. The dump is in the same format as updates, and is followed by "DUMPDONE". When "DUMPDONE" has been received, the view is complete. The SERVER will connect to the socket of each DRIVER and will request a dump at that time. It retains this data in local storage for later use. It continues to listen on the socket for additional updates. This protocol is documented in link:sock-protocol.txt[]. From the server ~~~~~~~~~~~~~~~ The SERVER's internal storage maintains a complete copy of the data which is in the DRIVER, so it is capable of answering any request immediately. When a request for data arrives from a CLIENT, the SERVER looks through the internal storage for that UPS and returns the requested data if it is available. The format for requests from the CLIENT is documented in link:protocol.txt[]. Instant commands ---------------- "Instant commands" is the term given to a set of actions that result in something happening to the UPS. Some of the common ones are `test.battery.start` to initiate a battery test and `test.panel.start` to test the front panel of the UPS. They are passed to the SERVER from a CLIENT using an authenticated network connection. The SERVER first checks to make sure that the instant command is valid for the DRIVER. If it's supported, a message is sent via a socket to the DRIVER containing the command and any auxiliary information. At this point, there is no confirmation to the SERVER of the command's execution. This is (still) planned for a future release. This has been delayed since returning a response involves some potentially interesting timing issues. Remember that `upsd` services clients in a round-robin fashion, so all queries must be lightweight and speedy. NOTE: FIXME: Wasn't "TRACKING" mechanism for "INSTCMD/SET VAR" introduced to address just this? See https://github.com/networkupstools/nut/pull/659 Setting variables ----------------- Some variables in the DRIVER or EQUIPMENT can be changed, and carry the FLAG_RW flag. Upon receiving a SET command from the CLIENT, the SERVER first verifies that it is valid for that DRIVER in terms of writability and data type. If those checks pass, it then sends the SET command through the socket, much like the instant command design. The DRIVER is expected to commit the value to the EQUIPMENT and update its internal representation of that variable. Like the instant commands, there is currently no acknowledgement of the command's completion from the DRIVER. This, too, is planned for a future release. NOTE: FIXME: Wasn't "TRACKING" mechanism for "INSTCMD/SET VAR" introduced to address just this? See https://github.com/networkupstools/nut/pull/659 Example data path ----------------- Here's the path a piece of data might take through this architecture. The event is a UPS going on battery, and the final result is a pager delivering the alpha message to the admin. 1. EQUIPMENT reports on battery by setting flag in status register 2. DRIVER notices this flag and stores it in the `ups.status` variable as OB. This update gets pushed out to any listeners via the sockets. 3. SERVER `upsd` sees activity on the socket, reads it, parses it, and commits the new data to its local version of the status variable. 4. CLIENT `upsmon` does a routine poll of SERVER for `ups.status` and gets `OB`. 5. CLIENT `upsmon` then invokes its `NOTIFYCMD` which is `upssched`. 6. `upssched` starts up a daemon to handle a timer which will expire about 30 seconds into the future. 7. 30 seconds later, the timer expires since the UPS is still on battery, and so `upssched` calls the `CMDSCRIPT` which is `upssched-cmd`. 8. `upssched-cmd` parses the args and calls `sendmail`. 9. Avian carriers, smoke signals, SMTP, and some magic result in the message getting from the pager company's gateway to a transmitter and then to the admin's pager. This scenario requires some configuration, obviously: 1. There's an UPS driver running. (Whatever applies for the hardware) 2. `upsd` has a valid UPS entry in 'ups.conf' for this UPS. [myups] driver = nutupsdrv port = /dev/ttySx 3. `upsd` has a valid user for `upsmon` in 'upsd.users' file. [monuser] password = somepass upsmon primary 4. `upsmon` is set to monitor this UPS with this user in 'upsmon.conf' file. MONITOR myups@localhost 1 monuser somepass primary 5. `upsmon` is set to `EXEC` the `NOTIFYCMD` for the `ONBATT` condition in 'upsmon.conf' file. NOTIFYFLAG ONBATT EXEC 6. `upsmon` calls `upssched` as the `NOTIFYCMD` in 'upsmon.conf' file. NOTIFYCMD /path/to/upssched 7. `upssched` has a 30 second timer for `ONBATT` in 'upssched.conf' file. AT ONBATT * START-TIMER upsonbatt 30 8. `upssched` calls `upssched-cmd` as the `CMDSCRIPT` in 'upssched.conf'. CMDSCRIPT /path/to/upssched-cmd 9. `upssched-cmd` knows what to do with `upsonbatt` keyword as its first argument (a quick `case..esac` construct, see the examples) History ------- The oldest versions of this software (1998) had no separation between the driver and the network server, and only supported the latest APC Smart-UPS hardware as a result. The network protocol used brittle binary structs. This had numerous bad implications for compatibility and portability. After the driver and server were separated, data was shared through the state file concept. Status was written into a static array (the "info array") by drivers, and that array was stored on disk. The `upsd` would periodically read that file into a local copy of that array. Shared memory mode was added a bit later, and that removed some of the lag from the status updates. Unfortunately, it didn't have any locking originally, and the possibility for corruption due to races existed. `mmap()` support was added at some point after that, and became the default. The drivers and `upsd` would `mmap()` the file into memory and read or write from it. Locking was done using the state file as the token, so contention problems were avoided. This method was relatively quick, but it involved at least 3 copies of the data (driver, disk/mmap, server) and a whole lot of locking and unlocking. It could occasionally delay the driver or server when waiting for a lock. In April 2003, the entire state management subsystem was removed and replaced with a single local socket. The drivers listen for connections and push updates asynchronously to any listeners. They also recognize a few commands. Drivers also dampen the flow of updates, and only push them out when something actually changes. As a result, `upsd` no longer has to poll any files on the disk, and can just `select()` all of its file descriptors (fds) and wait for activity. When one of them is active, it reads the fd and parses the results. Updates from the hardware now get to `upsd` about as fast as they possibly can. Drivers used to call `setinfo()` to change the local array, and then would call `writeinfo()` to push the array onto the disk, or into the mmap/shared memory space. This introduced a lag since many drivers poll quite a few variables during an update. By 2013 much of the work on NUT for Windows branch (based off the NUT v2.6.5 release) was completed, adding named pipes as the equivalent to local sockets as well as to cross-program signals. This work got a face-lift and was merged into the main code base about a decade later, in 2022. In April 2023 (eventually released with NUT v2.8.1 and enhanced/fixed in later releases), a new use-case was added: interactions of two instances of a driver program over the local socket, as an alternative to signals for the already-running driver to reload configuration, exit and make way for a new instance of the driver daemon, or command the UPS to kill power without the overhead of a new connection made by such new instance. nut-2.8.3/docs/developer-guide.txt0000644000200500020050000001072214777767434014044 00000000000000:titles.underlines: "__","==","--","~~","^^" Network UPS Tools Developer Guide _________________________________ :Author: Russell_Kroll,_Arnaud_Quette,_Charles_Lepple,_Peter_Selinger,_Jim_Klimov_and_NUT_project_community_contributors :Author Initials: RK, AQ, CL, PS & JK Introduction ============ NUT is both a powerful toolkit and framework that provides support for Power Devices, such as Uninterruptible Power Supplies, Power Distribution Units and Solar Controllers. This document intends to describe how NUT is designed, and the way to develop new device drivers and client applications. [[design]] include::design.txt[] [[versioning]] include::nut-versioning.adoc[] [[developers]] include::developers.txt[] [[new-drivers]] include::new-drivers.txt[] [[sock-protocol]] include::sock-protocol.txt[] [[augeas]] include::../scripts/augeas/README.adoc[] [[devscan]] include::../tools/nut-scanner/README.adoc[] [[new-clients]] include::new-clients.txt[] [[net-protocol]] include::net-protocol.txt[] [[dev-tools]] NUT developers tools ==================== NUT provides several tools for clients and core developers, and QA people. [[dev-simu]] Device simulation ----------------- The dummy-ups driver propose a simulation mode, also known as 'Dummy Mode'. This mode allows to simulate any kind of devices, even non existing ones. Using this method, you can either replay a real life sequence, <>, or directly interact through `upsrw` or by editing the device file, to modify the variables' values. Here is an example to setup a device simulation: - install NUT as usual, if not already done - get a simulation file (`.dev`) or sequence (`.seq`), or generate one using the <>. Sample files are provided in the `data` directory of the NUT source. You can also download these from the development repository, such as the link:https://github.com/networkupstools/nut/raw/master/data/evolution500.seq[evolution500.seq] or from link:https://github.com/networkupstools/nut-ddl/[NUT DDL] collection. - copy the simulation file to your sysconfig directory, like `/etc/nut` or `/etc/ups` - configure NUT for simulation (linkman:ups.conf[5]): + [dummy] driver = dummy-ups port = evolution500.dev desc = "dummy-ups in dummy mode" + - now start NUT, at least `dummy-ups` and `upsd`: + :; upsdrvctl start dummy :; upsd + - and check the data: + :; upsc dummy ... + - you can also use `upsrw` to modify the data in memory: + :; upsrw -s ups.status="OB LB" -u user -p password dummy + - or directly edit your copy of `/etc/nut/evolution500.seq`. In this case, modification will only apply according to the `TIMER` events and the current position in the sequence. For more information, refer to linkman:dummy-ups[8] manual page. [[dev-simu-disco]] Simulated devices discovery --------------------------- Any simulation file that is saved in the sysconfig directory can be automatically discovered and configured using nut-scanner: ---- :; nut-scanner -n :; nut-scanner --nut_simulation_scan ---- [[dev-recording]] Device recording ---------------- To complete `dummy-ups`, NUT provides a device recorder script called `nut-recorder.sh` and located in the 'tools/' directory of the NUT source tree. This script uses `upsc` to record device information, and stores these in a differential fashion every 5 seconds (by default). Its usage is the following: Usage: dummy-recorder.sh [output-file] [interval] For example, to record information from the device 'myups' every 10 seconds: :; nut-recorder.sh myups@localhost myups.seq 10 During the recording, you will want to generate power events, such as power failure and restoration. These will be tracked in the simulation files, and be eventually be replayed by the <> driver. NUT core development and maintenance ==================================== This section is intended to people who want to develop new core features, or to do some maintenance. include::macros.txt[] [[roadmap]] include::../TODO.adoc[] [[nut-names]] Appendix A: NUT command and variable naming scheme ================================================== include::nut-names.txt[] [[daisychain]] Appendix B: NUT daisychain support notes ======================================== include::daisychain.txt[] [[lib-info]] Appendix C: NUT libraries complementary information =================================================== include::../lib/README.adoc[] nut-2.8.3/docs/new-drivers.txt0000644000200500020050000010247414777767434013237 00000000000000Creating a new driver to support another device =============================================== This chapter will present the process of creating a new driver to support another device. Since NUT already supports many major power device protocols through several generic drivers (`genericups`, `usbhid-ups`, `snmp-ups`, `blazer_*` and `nutdrv_qx`), creation of new drivers has become rare. NOTE: We have yet to unify modbus drivers under same umbrella like `nutdrv_qx` covering the Megatec Qx protocol family. So most of the time, this process will be limited to completing one of these generic drivers. Smart vs. Contact-closure ------------------------- If your UPS only does contact closure readings over an RS-232 serial port, then go straight to the <> chapter for information on adding support. It's a lot easier to add a few lines to a header file than it is to create a whole new driver. Serial vs. USB vs. SNMP and more -------------------------------- If your UPS connects to your computer via a USB port, then it most likely appears as a USB HID device (this is the simplest way for the vendor to write a Windows control program for it). What comes next depends on whether the vendor implemented the HID PDC (Power Device Class) specification, or simply used the HID protocol to transport serial data to the UPS microcontroller. A rough heuristic is to check the length of the HID Descriptor length (`wDescriptorLength` in `lsusb -v` output). If it is less than 200 bytes long, the UPS probably has a glorified USB-to-serial converter built in. Since the query strings often start with the letter `Q`, this family of protocols is often referred to as `Q*` in the NUT documentation. See the <> chapter for more details. Otherwise, if the HID Descriptor is longer, you can go to the <> chapter. You can probably add support for your device by writing a new subdriver to the existing usbhid-ups driver, which is easier (and more maintainable) than writing an entire new driver. If your USB UPS does not appear to fall into either of these two categories, feel free to contact the `nut-upsdev` mailing list with details of your device. Similarly, if your UPS connects to your computer via an SNMP network card, you can probably add support for your device by adding a new subdriver to the existing snmp-ups driver. Instructions are provided in the <> chapter. Overall concept --------------- The basic design of drivers is simple. `main.c` handles most of the work for you. You don't have to worry about arguments, config files, or anything else like that. Your only concern is talking to the hardware and providing data to the outside world. Skeleton driver --------------- Familiarize yourself with the design of `skel.c` in the drivers directory. It shows a few examples of the functions that `main.c` will call to obtain updated information from the hardware. Essential structure ------------------- upsdrv_info_t ~~~~~~~~~~~~~ This structure tracks several description information about the driver: * *name*: the driver full name, for banner printing and "driver.name" variable. * *version*: the driver's own version. For sub driver information, refer below to sub_upsdrv_info. This value has the form "X.YZ", and is published by main as "driver.version.internal". * *authors*: the driver's author(s) name. If multiple authors are listed, separate them with a newline character so that it can be broken up by author if needed. * *status*: the driver development status. The following values are allowed: - DRV_BROKEN: setting this value will cause main to print an error and exit. This is only used during conversions of the driver core to keep users from using drivers which have not been converted. Drivers in this state will be removed from the tree after some period if they are not fixed. - DRV_EXPERIMENTAL: set this value if your driver is potentially broken. This will trigger a warning when it starts so the user doesn't take it for granted. - DRV_BETA: this value means that the driver is more stable and complete. But it is still not recommended for production systems. - DRV_STABLE: the driver is suitable for production systems, but not 100 % feature complete. - DRV_COMPLETE: this is the gold level! It implies that 100 % of the protocol is implemented, and a full QA pass. * *subdrv_info*: array of upsdrv_info_t for sub driver(s) information. For example, this is used by usbhid-ups. This information is currently used for the startup banner printing and tests. Essential functions ------------------- upsdrv_initups ~~~~~~~~~~~~~~ Open the port (`device_path`) and do any low-level things that it may need to start using that port. If you have to set DTR or RTS on a serial port, do it here. Don't do any sort of hardware detection here, since you may be going into upsdrv_shutdown next. upsdrv_initinfo ~~~~~~~~~~~~~~~ Try to detect what kind of UPS is out there, if any, assuming that's possible for your hardware. If there is a way to detect that hardware and it doesn't appear to be connected, display an error and exit. This is the last time your driver is allowed to bail out. This is usually a good place to create variables like `ups.mfr`, `ups.model`, `ups.serial`, determine and declare supported instant commands (maybe model-dependent, typically for all devices supported by the driver), and other "one time only" items. upsdrv_updateinfo ~~~~~~~~~~~~~~~~~ Poll the hardware, and update any variables that you care about monitoring. Use `dstate_setinfo()` to store the new values. Do at most one pass of the variables. You MUST return from this function or upsd will be unable to read data from your driver. main will call this function at regular intervals. Don't spent more than a couple of seconds in this function. Typically five (5) seconds is the maximum time allowed before you risk that the server declares the driver stale. If your UPS hardware requires a timeout period of several seconds before it answers, consider returning from this function after sending a command immediately and read the answer the next time it is called. You must never abort from upsdrv_updateinfo(), even when the UPS doesn't seem to be attached anymore. If the connection with the UPS is lost, the driver should retry to re-establish communication for as long as it is running. Calling `exit()` or any of the `fatal*()` functions is specifically not allowed anymore. upsdrv_shutdown ~~~~~~~~~~~~~~~ Do whatever you can to make the UPS power off the load but also return after the power comes back on. You may use a different command that keeps the UPS off if the user has requested that with a configuration setting. You should attempt the UPS shutdown command even if the UPS detection fails. If the UPS does not shut down the load, then the user is vulnerable to a race if the power comes back on during the shutdown process. This method should not directly `exit()` the driver program (neither should it call `fatalx()` nor `fatal_with_errno()` methods). It can `upslogx(LOG_ERR, ...)` or `upslog_with_errno(LOG_ERR, ...)`, and then `set_exit_flag(N)` if required, using values `EF_EXIT_FAILURE` (`-1`) for eventual `exit(EXIT_FAILURE)` and `EF_EXIT_SUCCESS` (`-2`) for `exit(EXIT_SUCCESS)`, which would be handled in the standard driver loop or in `forceshutdown()` method of `main.c`. Data types ---------- To be of any use, you must supply data in `ups.status`. That is the minimum needed to let upsmon do its job. Whenever possible, you should also provide anything else that can be monitored by the driver. Some obvious things are the manufacturer name and model name, voltage data, and so on. If you can't figure out some value automatically, use the `ups.conf` options to let the user tell you. This can be useful when a driver needs to support many similar hardware models, but can't probe to see what is actually attached. Manipulating the data --------------------- All status data lives in structures that are managed by the dstate functions. All access and modifications must happen through those functions. Any other changes are forbidden, as they will not pushed out as updates to things like upsd. Adding variables ~~~~~~~~~~~~~~~~ dstate_setinfo("ups.model", "Mega-Zapper 1500"); Many of these functions take format strings, so you can build the new values right there: dstate_setinfo("ups.model", "Mega-Zapper %d", rating); Setting flags ~~~~~~~~~~~~~ Some variables have special properties. They can be writable, and some are strings. The `ST_FLAG_*` values can be used to tell upsd more about what it can do. dstate_setflags("input.transfer.high", ST_FLAG_RW); Status data ~~~~~~~~~~~ UPS status flags like on line (OL) and on battery (OB) live in ups.status. Don't manipulate this by hand. There are functions which will do this for you. status_init() -- before doing anything else (clear internal buffers, etc.) status_get(val) -- optionally check if a status word had been set since the most-recent status_init() status_set(val) -- add a status word (OB, OL, etc) status_commit() -- push out the update Possible values for status_set: OL -- On line (mains is present) OB -- On battery (mains is not present) LB -- Low battery HB -- High battery RB -- The battery needs to be replaced CHRG -- The battery is charging DISCHRG -- The battery is discharging (inverter is providing load power) BYPASS -- UPS bypass circuit is active -- no battery protection is available CAL -- UPS is currently performing runtime calibration (on battery) OFF -- UPS is offline and is not supplying power to the load OVER -- UPS is overloaded TRIM -- UPS is trimming incoming voltage (called "buck" in some hardware) BOOST -- UPS is boosting incoming voltage FSD -- Forced Shutdown (restricted use, see the note below) Internally, an `ALARM` value would be added (typically as first in the list) if the `ups.alarm` is currently not empty. For more details, see below in `alarm_set()` description. [NOTE] ====== The NUT data server `upsd` initially sets `ups.status` to a value of `WAIT` when first connecting to a NUT driver using the socket protocol, and issues a `DUMPALL` command. This temporary `WAIT` status gets overwritten whenever any relevant information update from a driver arrives, typically either as part of its own initialization, or of the regular polling loop. This may seem roughly similar to a "Data stale" situation; however, the NUT clients like `upsmon` should not infer anything for shutdown decisions from this lack of initial connection, like they do for *loss* of connection during a known critical power situation. For some more detailed insight into the NUT driver's current state machine position (as reported by the driver after communications are established), see also `driver.state`. ====== Anything else will not be recognized by the usual clients expecting a particular NUT standard release. New tokens may appear over time, but driver developers should coordinate with the nut-upsdev list before creating something new, since there will be duplication and ugliness otherwise. It is possible that eventually, due to hardware and software design evolution, some concepts would be superseded by others. Fundamental meanings of the flags listed above should not change (but these flags may become no longer issued by the current NUT drivers; then may still be used e.g. in forks or older packaged builds). Clients however MUST accept any space-separated tokens in `ups.status` without error or crash, and MUST treat those defined above with the ascribed meanings, but MAY ignore unidentified tokens (quietly by default, or acknowledge the skip with a debug log message). [NOTE] ============================================================================== - upsd injects `FSD` by itself following that command by a primary upsmon process. Drivers must not set that value, apart from specific cases (see below). - As an exception, drivers may set `FSD` when an imminent shutdown has been detected. In this case, the "on battery + low battery" condition should not be met. Otherwise, setting status to `OB LB` should be preferred. - the `OL` and `OB` flags are an indication of the input line status only. - the `CHRG` and `DISCHRG` flags are being replaced with `battery.charger.status`. See the linkdoc:user-manual[NUT command and variable naming scheme,nut-names] for more information. ============================================================================== Similar functionality can be supported for `experimental.ups.mode.buzzwords`, where it is tracked dynamically (e.g. due to ECO/ESS/HE/Smart or similar marketing buzzword modes supported by the device), using the following methods in the processing loop: buzzmode_init() -- before doing anything else (clear internal buffers, etc.) buzzmode_get(val) -- optionally check if an UPS mode buzzword had been set since the most-recent buzzmode_init() buzzmode_set(val) -- add an UPS mode buzzword (vendor:eaton:ECO, etc.) buzzmode_commit() -- push out the update UPS alarms ---------- These work like `ups.status`, and have three special functions which you must use to manage them. alarm_init() -- before doing anything else alarm_set() -- add an alarm word alarm_commit() -- push the value into ups.alarm NOTE: the ALARM flag in ups.status is automatically set whenever you use alarm_set. To remove that flag from ups.status, call alarm_init and alarm_commit without calling alarm_set in the middle. You should never try to set or unset the ALARM flag manually. If you use UPS alarms, the call to status_commit() should be after alarm_commit(), otherwise there will be a delay in setting the ALARM flag in ups.status. There is no official list of alarm words as of this writing, so don't use these functions until you check with the upsdev list. Also refer to the <> chapter of the user manual and developer guide for information related to alarms handling in daisychain mode. Staleness control ----------------- If you're not talking to a polled UPS, then you must ensure that it is still out there and is alive before calling dstate_dataok(). Even if nothing is changing, you should still "ping" it or do something else to ensure that it is really available. If the attempts to contact the UPS fail, you must call dstate_datastale() to inform the server and clients. - dstate_dataok() + You must call this if polls are succeeding. A good place to call this is the bottom of upsdrv_updateinfo(). - dstate_datastale() + You must call this if your status is unusable. A good technique is to call this before exiting prematurely from upsdrv_updateinfo(). Don't hide calls to these functions deep inside helper functions. It is very hard to find the origin of staleness warnings, if you call these from various places in your code. Basically, don't call them from any other function than from within upsdrv_updateinfo(). There is no need to call either of these regularly as was stated in previous versions of this document (that requirement has long gone). Serial port handling -------------------- Drivers which use serial port functions should include serial.h and use these functions (and cross-platform data types) whenever possible: - TYPE_FD + Cross-platform data type to represent a serial-port connection. - ERROR_FD_SER + Macro value representing an invalid serial-port connection. - VALID_FD_SER(TYPE_FD_SER fd) + This macro evaluates to `true` if `fd` currently has a "valid" value (e.g. represents a connected device). You should invalidate the `fd` when you initialize the variable or close the connection, by assigning `fd = ERROR_FD`. - INVALID_FD_SER(TYPE_FD_SER fd) + This macro evaluates to `true` if `fd` does not currently have a "valid" value. - TYPE_FD_SER ser_open(const char *port) + This opens the port and locks it if possible, using one of fcntl, lockf, or uu_lock depending on what may be available. If something fails, it calls fatal for you. If it succeeds, it always returns the fd that was opened. - TYPE_FD_SER ser_open_nf(const char *port) + This is a non-fatal version of ser_open(), that does not call fatal if something fails. - int ser_set_speed(TYPE_FD_SER fd, const char *port, speed_t speed) + This sets the speed of the port and also does some basic configuring with tcgetattr and tcsetattr. If you have a special serial configuration (other than 8N1), then this may not be what you want. + The port name is provided again here so failures in tcgetattr() provide a useful error message. This is the only place that will generate a message if someone passes a non-serial port /dev entry to your driver, so it needs the extra detail. - int ser_set_speed_nf(TYPE_FD_SER fd, const char *port, speed_t speed) + This is a non-fatal version of ser_set_speed(), that does not call fatal if something fails. - int ser_set_dtr(TYPE_FD_SER fd, int state) - int ser_set_rts(TYPE_FD_SER fd, int state) + These functions can be used to set the modem control lines to provide cable power on the RS232 interface. Use state = 0 to set the line to 0 and any other value to set it to 1. - int ser_get_dsr(TYPE_FD_SER fd) - int ser_get_cts(TYPE_FD_SER fd) - int ser_get_dcd(TYPE_FD_SER fd) + These functions read the state of the modem control lines. They will return 0 if the line is logic 0 and a non-zero value if the line is logic 1. - int ser_close(TYPE_FD_SER fd, const char *port) + This function unlocks the port if possible and closes the fd. You should call this in your upsdrv_cleanup handler. - ssize_t ser_send_char(TYPE_FD_SER fd, unsigned char ch) + This attempts to write one character and returns the return value from write. You could call write directly, but using this function allows for future error handling in one place. - ssize_t ser_send_pace(TYPE_FD_SER fd, useconds_t d_usec, const char *fmt, ...) + If you need to send a formatted buffer with an intercharacter delay, use this function. There are a number of UPS controllers which can't take commands at the full speed that would normally be possible at a given bit rate. Adding a small delay usually turns a flaky UPS into a solid one. + The return value is the number of characters that was sent to the port, or '-1' if something failed. - ssize_t ser_send(TYPE_FD_SER fd, const char *fmt, ...) + Like ser_send_pace, but without a delay. Only use this if you're sure that your UPS can handle characters at the full line rate. - ssize_t ser_send_buf(TYPE_FD_SER fd, const void *buf, size_t buflen) + This sends a raw buffer to the fd. It is typically used for binary transmissions. It returns the results of the call to write. - ssize_t ser_send_buf_pace(TYPE_FD_SER fd, useconds_t d_usec, const void *buf, size_t buflen) + This is just ser_send_buf with an intercharacter delay. - ssize_t ser_get_char(TYPE_FD_SER fd, void *ch, time_t d_sec, useconds_t d_usec) + This will wait up to d_sec seconds + d_usec microseconds for one character to arrive, storing it at ch. It returns 1 on success, -1 if something fails and 0 on a timeout. + NOTE: The delay value must not be too large, or your driver will not get back to the usual idle loop in main in time to answer the PINGs from upsd. That will cause an oscillation between staleness and normal behavior. - ssize_t ser_get_buf(TYPE_FD_SER fd, void *buf, size_t buflen, time_t d_sec, useconds_t d_usec) + Like ser_get_char, but this one reads up to buflen bytes storing all of them in buf. The buffer is zeroed regardless of success or failure. It returns the number of bytes read, -1 on failure and 0 on a timeout. + This is essentially a single read() function with a timeout. - ssize_t ser_get_buf_len(TYPE_FD_SER fd, void *buf, size_t buflen, time_t d_sec, useconds_t d_usec) + Like ser_get_buf, but this one waits for buflen bytes to arrive, storing all of them in buf. The buffer is zeroed regardless of success or failure. It returns the number of bytes read, -1 on failure and 0 on a timeout. + This should only be used for binary reads. See ser_get_line for protocols that are terminated by characters like CR or LF. - ssize_t ser_get_line(TYPE_FD_SER fd, void *buf, size_t buflen, char endchar, const char *ignset, time_t d_sec, useconds_t d_usec) + This is the reading function you should use if your UPS tends to send responses like "OK\r" or "1234\n". It reads up to buflen bytes and stores them in buf, but it will return immediately if it encounters endchar. The endchar will not be stored in the buffer. It will also return if it manages to collect a full buffer before reaching the endchar. It returns the number of bytes stored in the buffer, -1 on failure and 0 on a timeout. + If the character matches the ignset with strchr(), it will not be added to the buffer. If you don't need to ignore any characters, just pass it an empty string -- `""`. + The buffer is always cleared and is always `null`-terminated. It does this by reading at most `(buflen - 1)` bytes. + NOTE: Any other data which is read after the endchar in the serial buffer will be lost forever. As a result, you should not use this unless your UPS uses a polled protocol. + Let's say your endchar is `\n` and your UPS sends `"OK\n1234\nabcd\n"`. This function will `read()` all of that, find the first `\n`, and stop there. Your driver will get `"OK"`, and the rest is gone forever. + This also means that you should not "pipeline" commands to the UPS. Send a query, then read the response, then send the next query. - ssize_t ser_get_line_alert(TYPE_FD_SER fd, void *buf, size_t buflen, char endchar, const char *ignset, const char *alertset, void handler(char ch), time_t d_sec, useconds_t d_usec) + This is just like ser_get_line, but it allows you to specify a set of alert characters which may be received at any time. They are not added to the buffer, and this function will call your handler function, passing the character as an argument. + Implementation note: this function actually does all of the work, and ser_get_line is just a wrapper that sets an empty alertset and a NULL handler. - ssize_t ser_flush_in(TYPE_FD_SER fd, const char *ignset, int verbose) + This function will drain the input buffer. If verbose is set to a positive number, then it will announce the characters which have been read in the syslog. You should not set verbose unless debugging is enabled, since it could be very noisy. + This function returns the number of characters which were read, so you can check for extra bytes by looking for a nonzero return value. Zero will also be returned if the read fails for some reason. - int ser_flush_io(TYPE_FD_SER fd) + This function drains both the in- and output buffers. Return zero on success. - void ser_comm_fail(const char *fmt, ...) + Call this whenever your serial communications fail for some reason. It takes a format string, so you can use variables and other things to clarify the error. This function does built-in rate-limiting so you can't spam the syslog. + By default, it will write 10 messages, then it will stop and only write 1 in 100. This allows the driver to keep calling this function while the problem persists without filling the logs too quickly. + In the old days, drivers would report a failure once, and then would be silent until things were fixed again. Users had to figure out what was happening by finding that single error message, or by looking at the repeated complaints from upsd or the clients. + If your UPS frequently fails to acknowledge polls and this is a known situation, you should make a couple of attempts before calling this function. + NOTE: This does not call dstate_datastale. You still need to do that. - void ser_comm_good(void) + This will clear the error counter and write a "re-established" message to the syslog after communications have been lost. Your driver should call this whenever it has successfully contacted the UPS. A good place for most drivers is where it calls dstate_dataok. USB port handling ----------------- Drivers which use USB functions should include usb-common.h and use these: Structure and macro ~~~~~~~~~~~~~~~~~~~ You should use the usb_device_id_t structure, and the USB_DEVICE macro to declare the supported devices. This allows the automatic extraction of USB information, to generate the Hotplug, udev and UPower support files. The structure allows to convey `uint16_t` values of VendorID and ProductID, and an optional matching-function callback to interrogate the device in more detail (constrain known supported firmware versions, OEM brands, etc.) For example: -------------------------------------------------------------------------------- /* SomeVendor name */ #define SOMEVENDOR_VENDORID 0xXXXX /* USB IDs device table */ static usb_device_id_t sv_usb_device_table [] = { /* some models 1 */ { USB_DEVICE(SOMEVENDOR_VENDORID, 0xYYYY), NULL }, /* various models */ { USB_DEVICE(SOMEVENDOR_VENDORID, 0xZZZZ), NULL }, { USB_DEVICE(SOMEVENDOR_VENDORID, 0xAAAA), NULL }, /* Terminating entry */ { 0, 0, NULL } }; -------------------------------------------------------------------------------- Function ~~~~~~~~ - is_usb_device_supported(usb_device_id_t *usb_device_id_list, USBDevice_t *device) + Call this in your device opening / matching function. Pass your usb_device_id_t list structure, and a set of VendorID, DeviceID, as well as Vendor, Product and Serial strings, possibly also Bus, bcdDevice (device release number) and Device name on the bus strings, in the USBDevice_t fields describing the specific piece of hardware you are inspecting. + This function returns one of the following value: + -- * NOT_SUPPORTED (0), * POSSIBLY_SUPPORTED (1, returned when the VendorID is matched, but the DeviceID is unknown), * or SUPPORTED (2). -- + For implementation examples, refer to the various USB drivers, and search for the above patterns. NOTE: This set of USB helpers is due to expand is the near future... Variable names -------------- PLEASE don't make up new variables and commands just because you can. The new dstate functions give us the power to create just about anything, but that is a privilege and not a right. Imagine the mess that would happen if every developer decided on their own way to represent a common status element. Check the <> section first to find the closest fit. If nothing matches, contact the upsdev list, and we'll figure it out. Patches which introduce unlisted names may be modified or dropped. [[commands]] Message passing support ----------------------- upsd can call drivers to store values in read/write variables and to kick off instant commands. This is how you register handlers for those events. The driver core (drivers/main.c) has a structure called upsh. You should populate it with function pointers in your upsdrv_initinfo() function. Right now, there are only two possibilities: - setvar = setting UPS variables (SET VAR protocol command) - instcmd = instant UPS commands (INSTCMD protocol command) SET ~~~ If your driver's function for handling variable set events is called my_ups_set(), then you'd do this to add the pointer: upsh.setvar = my_ups_set; my_ups_set() will receive two parameters: const char * -- the variable being changed const char * -- the new value You should return either STAT_SET_HANDLED if your driver recognizes the command, or STAT_SET_UNKNOWN if it doesn't. Other possibilities will be added at some point in the future. INSTCMD ~~~~~~~ This works just like the set process, with slightly different values arriving from the server. upsh.instcmd = my_ups_cmd; Your function will receive two args: const char * -- the command name const char * -- (reserved) You should return either STAT_INSTCMD_HANDLED or STAT_INSTCMD_UNKNOWN depending on whether your driver can handle the requested command. Notes ~~~~~ Use strcasecmp. The command names arriving from upsd should be treated without regards to case. Responses ~~~~~~~~~ Drivers will eventually be expected to send responses to commands. Right now, there is no channel to get these back through upsd to the client, so this is not implemented. This will probably be implemented with a polling scheme in the clients. Enumerated types ---------------- If you have a variable that can have several specific values, it is enumerated. You should add each one to make it available to the client: dstate_addenum("input.transfer.low", "92"); dstate_addenum("input.transfer.low", "95"); dstate_addenum("input.transfer.low", "99"); dstate_addenum("input.transfer.low", "105"); Range values ------------ If you have a variable that support values comprised in one or more ranges, you should add each one to make it available to the client: dstate_addrange("input.transfer.low", 90, 95); dstate_addrange("input.transfer.low", 100, 105); Writable strings ---------------- Strings that may be changed by the client should have the ST_FLAG_STRING flag set, and a maximum length (in bytes) set in the auxdata. dstate_setinfo("ups.id", "Big UPS"); dstate_setflags("ups.id", ST_FLAG_STRING | ST_FLAG_RW); dstate_setaux("ups.id", 8); If the variable is not writable, don't bother with the flags or the auxiliary data. It won't be used. Instant commands ---------------- If your hardware and driver can support a command, register it. dstate_addcmd("load.on"); Don't forget to define the implementation for such commands in a common method, and register that your driver has an instant command handler at all -- with a line in `upsdrv_initinfo()` like: upsh.instcmd = blazer_instcmd; Delays and ser_* functions -------------------------- The new ser_* functions may perform reads faster than the UPS is able to respond in some cases. This means that your driver will call select() and read() numerous times if your UPS responds in bursts. This also depends on how fast your system is. You should check your driver with `strace` or its equivalent on your system. If the driver is calling read() multiple times, consider adding a call to usleep before going into the ser_read_* call. That will give it a chance to accumulate so you get the whole thing with one call to read without looping back for more. This is not a request to save CPU time, even though it may do that. The important part here is making the strace/ktrace output easier to read. write(4, "Q1\r", 3) = 3 nanosleep({0, 300000000}, NULL) = 0 select(5, [4], NULL, NULL, {3, 0}) = 1 (in [4], left {3, 0}) read(4, "(120.0 084.0 120.0 0 60.0 22.6"..., 64) = 47 Without that delay, that turns into a mess of selects and reads. The select returns almost instantly, and read gets a tiny chunk of the data. Add the delay and you get a nice four-line status poll. Canonical input mode processing ------------------------------- If your UPS uses "\n" and/or "\r" as endchar, consider the use of Canonical Input Mode Processing instead of the ser_get_line* functions. Using a serial port in this mode means that select() will wait until a full line is received (or times out). This relieves you from waiting between sending a command and reading the reply. Another benefit is, that you no longer have to worry about the case that your UPS sends "OK\n1234\nabcd\n". This will be broken up cleanly in "OK\n", "1234\n" and "abcd\n" on consecutive reads, without risk of losing data (which is an often forgotten side effect of the ser_get_line* functions). Currently, an example how this works can be found in the safenet and upscode2 drivers. The first uses a single "\r" as endchar, while the latter accepts either "\n", "\n\r" or "\r\n" as line termination. You can define other termination characters as well, but can't undefine "\r" and "\n" (so if you need these as data, this is not for you). Adding the driver into the tree ------------------------------- In order to build your new driver, it needs to be added to `drivers/Makefile.am`. At the moment, there are several driver list variables corresponding to the general protocol of the driver (`SERIAL_DRIVERLIST`, `SNMP_DRIVERLIST`, etc.). If your driver does not fit into one of these categories, please discuss it on the nut-upsdev mailing list. There are also `*_SOURCES` and optional `*_LDADD` variables to list the source files, and any additional linker flags. If your driver uses the C math library, be sure to add `-lm`, since this flag is not always included by default on embedded systems. When you add a driver to one of these lists, pay attention to the backslash continuation characters (`\\`) at the end of the lines. The `automake` program converts the `Makefile.am` files into `Makefile.in` files to be processed by `./configure`. See the discussion in <> about automating the rebuild process for these files. [[contact-closure]] include::contact-closure.txt[] [[hid-subdrivers]] include::hid-subdrivers.txt[] [[snmp-subdrivers]] include::snmp-subdrivers.txt[] [[nutdrv_qx-subdrivers]] include::nutdrv_qx-subdrivers.txt[] nut-2.8.3/docs/security.txt0000644000200500020050000007143714777767434012645 00000000000000Notes on securing NUT ===================== The NUT Team is very interested in providing the highest security level to its users. Many internal and external mechanisms exist to secure NUT. And several steps are needed to ensure that your NUT setup meets your security requirements. This chapter will present you these mechanisms, by increasing order of security level. This means that the more security you need, the more mechanisms you will have to apply. NOTE: You may want to have a look at NUT Quality Assurance, since some topics are related to NUT security and reliability. [[verifySourceSig]] How to verify the NUT source code signature ------------------------------------------- In order to verify the NUT source code signature for releases, perform the following steps: - Retrieve the link:https://www.networkupstools.org/download.html[NUT source code] (nut-X.Y.Z.tar.gz) and the matching signature (nut-X.Y.Z.tar.gz.sig) - Retrieve the link:https://www.networkupstools.org/source/nut-key.gpg[NUT maintainer's signature keyring]: $ gpg --fetch-keys https://www.networkupstools.org/source/nut-key.gpg [NOTE] ====== As of NUT 2.8.0, a new release key is used, but the `nut-key.gpg` should be cumulative with older chain key files (includes them). You can view the key list in a downloaded copy of the URL above with: $ gpg --with-colons --import-options import-show --dry-run --import < nut-key.gpg ...and as of this writing, it should contain two key sets for various identities of "Arnaud Quette" and one set of "Jim Klimov". ====== Just in case, the previous key file used since NUT 2.7.3 release is stored as link:https://www.networkupstools.org/source/nut-key-2.7.3.gpg[NUT old maintainer's signature for 2.7.3-2.7.4 releases] In order to verify an even older release, please use link:https://www.networkupstools.org/source/nut-old-key.gpg[NUT old maintainer's signature since 2002 until 2.7.3 release] - Launch the GPG checking using the following command: $ gpg --verify nut-X.Y.Z.tar.gz.sig - You should see a message mentioning a "Good signature", with formatting which depends on your gpg version, like: gpg: Signature made Thu Jun 1 00:10:16 2023 CEST ... gpg: Good signature from "Jim Klimov ..." ... Primary key fingerprint: B834 59F7 76B9 0224 988F 36C0 DE01 84DA 7043 DCF7 ... [NOTE] ====== The previously used maintainer's signatures would output (with markup of older gpg tools here): gpg: Signature made Wed Apr 15 15:55:30 2015 CEST using RSA key ID 55CA5976 gpg: Good signature from "Arnaud Quette ..." ... or: gpg: Signature made Thu Jul 5 16:15:05 2007 CEST using DSA key ID 204DDF1B gpg: Good signature from "Arnaud Quette ..." ... ====== //////// Maintainer notes for posterity: * See https://github.com/networkupstools/nut/issues/1963 and https://github.com/networkupstools/nut/issues/1410 for recent forays into this area. * Repo is https://github.com/networkupstools/nut-source-archive.git * Keys in the file can be viewed with: ---- :; gpg --with-colons --import-options import-show --dry-run --import < nut-key.gpg ---- * Old keys as well as a new maintainer key can be imported first into a temporary keyring (existing target file and a slash in its path name argument are allegedly important): ---- :; rm -f tmpring.gpg ; touch tmpring.gpg :; gpg --no-default-keyring --keyring ./tmpring.gpg --import nut-key.gpg :; gpg --no-default-keyring --keyring ./tmpring.gpg --import nut-old-key.gpg :; gpg --no-default-keyring --keyring ./tmpring.gpg --import nut-key-2.7.3.gpg :; gpg --no-default-keyring --keyring ./tmpring.gpg --import ~/.gnupg/HEXCODEMYNEWKEYDATA.pub ---- ** Note that whenever the key owner edits the primary key data, e.g. to add or remove "uid" entries with e-mail aliases, or sub-keys dedicated for specific purposes, the `~/.gnupg/HEXCODEMYNEWKEYDATA.pub` is changed and should be re-published to OpenPGP servers, to nut-website, to GitHub account, etc. * This (binary) keychain can be exported into ASCII-armor format, and also update the keychain file used by default: ---- :; gpg --no-default-keyring --keyring ./tmpring.gpg --export -a > nut-key.gpg ---- //////// How to verify the NUT source code checksum ------------------------------------------ As a weaker but simpler alternative to verifying a *signature*, you can verify just the accompanying checksums of the source archive file. This is useful primarily to check against bit-rot in original storage or in transit. As far as disclaimers go: ideally, you should cover all provided algorithms -- e.g. MD5 and SHA256 -- to minimize the chance that intentional malicious tampering on the wire goes undetected. A myriad tools can check that on various platforms; some examples follow: # Example original checksum to compare with, from NUT website: $ cat nut-2.8.0.tar.gz.sha256 c3e5a708da797b7c70b653d37b1206a000fcb503b85519fe4cdf6353f792bfe5 nut-2.8.0.tar.gz # Generate checksum of downloaded archive with perl (a NUT build dependency # generally, though you may have to install Digest::SHA module from CPAN): $ perl -MDigest::SHA=sha256_hex -le "print sha256_hex <>" nut-2.8.0.tar.gz c3e5a708da797b7c70b653d37b1206a000fcb503b85519fe4cdf6353f792bfe5 # Generate checksum of downloaded archive with openssl (another optional # NUT build dependency): $ openssl sha256 nut-2.8.0.tar.gz SHA256(nut-2.8.0.tar.gz)= c3e5a708da797b7c70b653d37b1206a000fcb503b85519fe4cdf6353f792bfe5 # Generate checksum of downloaded archive with coreutils: $ sha256sum nut-2.8.0.tar.gz c3e5a708da797b7c70b653d37b1206a000fcb503b85519fe4cdf6353f792bfe5 nut-2.8.0.tar.gz # Auto-check downloaded checksum against downloaded archive with coreutils: $ sha256sum -c nut-2.8.0.tar.gz.sha256 nut-2.8.0.tar.gz: OK # Generate checksum of downloaded archive with GPG: $ gpg --print-md SHA256 nut-2.8.0.tar.gz nut-2.8.0.tar.gz: C3E5A708 DA797B7C 70B653D3 7B1206A0 00FCB503 B85519FE 4CDF6353 F792BFE5 System level privileges and ownership ------------------------------------- All configuration files should be protected so that the world can't read them. Use the following commands to accomplish this: chown root:nut /etc/nut/* chmod 640 /etc/nut/* Finally, the <> directory, which holds the communication between the driver(s) and `upsd`, should also be secured. chown root:nut /var/state/ups chmod 0770 /var/state/ups NUT level user privileges ------------------------- Administrative commands such as setting variables and the instant commands are powerful, and access to them needs to be restricted. NUT provides an internal mechanism to do so, through linkman:upsd.users[5]. This file defines who may access instant commands and settings, and what is available. During the initial <>, we have created a monitoring user for `upsmon`. You can also create an `administrator` user in NUT with full power using: [administrator] password = mypass actions = set instcmds = all For more information on how to restrict actions and instant commands, refer to linkman:upsd.users[5] manual page. NOTE: NUT administrative user definitions should be used in conjunction with <>. Network access control ---------------------- If you are not using NUT on a standalone setup, you will need to enforce network access to `upsd`. There are various ways to do so. NUT LISTEN directive ~~~~~~~~~~~~~~~~~~~~ linkman:upsd.conf[5]. LISTEN interface port Bind a listening port to the interface specified by its Internet address. This may be useful on hosts with multiple interfaces. You should not rely exclusively on this for security, as it can be subverted on many systems. Listen on TCP port `port` instead of the default value which was compiled into the code. This overrides any value you may have set with `configure --with-port`. If you don't change it with configure or this value, `upsd` will listen on port 3493 for this interface. Multiple LISTEN addresses may be specified. The default is to bind to `127.0.0.1` if no LISTEN addresses are specified (and `::1` if IPv6 support is compiled in). LISTEN 127.0.0.1 LISTEN 192.168.50.1 LISTEN ::1 LISTEN 2001:0db8:1234:08d3:1319:8a2e:0370:7344 As a special case, `LISTEN * ` (with an asterisk) will try to listen on "ANY" IP address for both IPv6 (`::0`) and IPv4 (`0.0.0.0`), subject to `upsd` command-line arguments, or system configuration or support. Note that if the system supports IPv4-mapped IPv6 addressing per RFC-3493, and does not allow to disable this mode, then there may be one listening socket to handle both address families. This parameter will only be read at startup. You'll need to restart (rather than reload) `upsd` to apply any changes made here. Firewall ~~~~~~~~ NUT has its own official IANA port: 3493/tcp. The `upsmon` process on secondary systems, as well as any other NUT client (such as `upsc`, `upscmd`, `upsrw`, NUT-Monitor, ...) connects to the `upsd` process on the system which manages the UPS, via this TCP port. Usually an `upsmon` process runs on the latter system in "primary" mode for the devices connected to it. The `upsd` process does not initiate outgoing connections. Certain NUT drivers (for network-managed devices) can initiate their own connections to various ports according to corresponding vendor protocol. You should use this to restrict network access. [[UFW]] include::../scripts/ufw/README.adoc[] [[TCP_Wrappers]] TCP Wrappers ~~~~~~~~~~~~ If the server is build with tcp-wrappers support enabled, it will check if the NUT username is allowed to connect from the client address through the `/etc/hosts.allow` and `/etc/hosts.deny` files. NOTE: This will only be done for commands that require the user to be logged into the server. `hosts.allow`: upsd : admin@127.0.0.1/32 upsd : observer@127.0.0.1/32 observer@192.168.1.0/24 `hosts.deny`: upsd : ALL Further details are described in hosts_access(5). Configuring SSL --------------- SSL is available as a build option (`--with-ssl`). It encrypts sessions between `upsd` and clients, and can also be used to authenticate servers. This means that stealing port 3493 from `upsd` will no longer net you interesting passwords. Several things must happen before this will work, however. This chapter will present these steps. SSL is available via two back-end libraries : NSS and OpenSSL (historically). You can choose to use one of them by specifying it with a build option (`--with-nss` or `--with-openssl`). If neither is specified, the configure script will try to detect one of them, with a precedence for OpenSSL. OpenSSL backend usage ~~~~~~~~~~~~~~~~~~~~~ This section describes how to enable NUT SSL support using link:http://www.openssl.org[OpenSSL]. Install OpenSSL ^^^^^^^^^^^^^^^ Install link:http://www.openssl.org[OpenSSL] as usual, either from source or binary packages. If using binary packages, be sure to include the developer libraries. Recompile and install NUT ^^^^^^^^^^^^^^^^^^^^^^^^^ Recompile NUT from source, starting with `configure --with-openssl`. Then install everything as usual. Create a certificate and key for upsd ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ openssl (the program) should be in your PATH, unless you installed it from source yourself, in which case it may be in `/usr/local/ssl/bin`. Use the following command to create the certificate: openssl req -new -x509 -nodes -out upsd.crt -keyout upsd.key You can also put a `-days nnn` in there to set the expiration. If you skip this, it may default to 30 days. This is probably not what you want. It will ask several questions. What you put in there doesn't matter a whole lot, since nobody is going to see it for now. Future versions of the clients may present data from it, so you might use this opportunity to identify each server somehow. Figure out the hash for the key ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the following command to determine the hash of the certificate: openssl x509 -hash -noout -in upsd.crt You'll get back a single line with 8 hex characters. This is the hash of the certificate, which is used for naming the client-side certificate. For the purposes of this example the hash is *0123abcd*. Install the client-side certificate ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the following commands to install the client-side certificate: mkdir chmod 0755 cp upsd.crt /.0 Example: mkdir /usr/local/ups/etc/certs chmod 0755 /usr/local/ups/etc/certs cp upsd.crt /usr/local/ups/etc/certs/0123abcd.0 If you already have a file with that name in there, increment the `0` part until you get a unique filename that works. If you have multiple client systems (like `upsmon` instances in secondary mode), be sure to install this file on them as well. We recommend making a directory under your existing confpath to keep everything in the same place. Remember the path you created, since you will need to put it in `upsmon.conf` later. It must not be writable by unprivileged users, since someone could insert a new client certificate and fool `upsmon` into trusting a fake `upsd`. Create the combined file for upsd ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To do so, use the below commands: cat upsd.crt upsd.key > upsd.pem chown root:nut upsd.pem chmod 0640 upsd.pem This file must be kept secure, since anyone possessing it could pretend to be `upsd` and harvest authentication data if they get a hold of port 3493. Having it owned by `root` and readable by group `nut` allows `upsd` to read the file without being able to change the contents. This is done to minimize the impact if someone should break into `upsd`. NUT reads the key and certificate files after dropping privileges and forking. Note on certification authorities (CAs) and signed keys ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There are probably other ways to handle this, involving keys which have been signed by a CA you recognize. Contact your local SSL guru. Install the server-side certificate ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Install the certificate with the following command: mv upsd.pem Example: mv upsd.pem /usr/local/ups/etc/upsd.pem After that, edit your `upsd.conf` and tell it where to find it: CERTFILE /usr/local/ups/etc/upsd.pem Clean up the temporary files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rm -f upsd.crt upsd.key Restart upsd ^^^^^^^^^^^^ It should come back up without any complaints. If it says something about keys or certificates, then you probably missed a step. If you run `upsd` as a separate user id (like `nutsrv`), make sure that user can read the `upsd.pem` file. Point upsmon at the certificates ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Edit your `upsmon.conf`, and tell it where the `CERTPATH` is: CERTPATH Example: CERTPATH /usr/local/ups/etc/certs Recommended: make upsmon verify all connections with certificates ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Put this in `upsmon.conf`: CERTVERIFY 1 Without this, there is no guarantee that the `upsd` is the right host. Enabling this greatly reduces the risk of man in the middle attacks. This effectively forces the use of SSL, so don't use this unless all of your `upsd` hosts are ready for SSL and have their certificates in order. Recommended: force upsmon to use SSL ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Again in `upsmon.conf`: FORCESSL 1 If you don't use `CERTVERIFY 1`, then this will at least make sure that nobody can sniff your sessions without a large effort. Setting this will make `upsmon` drop connections if the remote `upsd` doesn't support SSL, so don't use it unless all of them have it running. NSS backend usage ~~~~~~~~~~~~~~~~~ This section describes how to enable NUT SSL support using link:http://www.mozilla.org/projects/security/pki/nss/[Mozilla NSS]. Install NSS ^^^^^^^^^^^ Install link:http://www.mozilla.org/projects/security/pki/nss/[Mozilla NSS] as usual, either from source or binary packages. If using binary packages, be sure to include the developer libraries, and nss-tools (for `certutil`). Recompile and install NUT ^^^^^^^^^^^^^^^^^^^^^^^^^ Recompile NUT from source, starting with `configure --with-nss`. Then install everything as usual. Create certificate and key for the host ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NSS (package generally called libnss3-tools) will install a tool called `certutil`. It will be used to generate certificates and manage certificate database. Certificates should be signed by a certification authorities (CAs). Following commands are typical samples, contact your SSL guru or security officer to follow your company procedures. .Generate a server certificate for `upsd`: - Create a directory where store the certificate database: `mkdir cert_db` - Create the certificate database : `certutil -N -d cert_db` - Import the CA certificate: `certutil -A -d cert_db -n "My Root CA" -t "TC,," -a -i rootca.crt` - Create a server certificate request (here called "My nut server"): `certutil -R -d cert_db -s "CN=My nut server,O=MyCompany,ST=MyState,C=US" -a -o server.req` - Make your CA sign the certificate (produces server.crt) - Import the signed certificate into server database: `certutil -A -d cert_db -n "My nut server" -a -i server.crt -t ",,"` - Display the content of certificate server: `certutil -L -d cert_db` Clients and servers in the same host could share the same certificate to authenticate them or use different ones in same or different databases. The same operation can be done in same or different databases to generate other certificates. Create a self-signed CA certificate ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NSS provides a way to create self-signed certificate which can acting as CA certificate, and to sign other certificates with this CA certificate. This method can be used to provide a CA certification chain without using an "official" certificate authority. .Generate a self-signed CA certificate: - Create a directory where store the CA certificate database: `mkdir CA_db` - Create the certificate database: `certutil -N -d CA_db` - Generate a certificate for CA: `certutil -S -d CA_db -n "My Root CA" -s "CN=My CA,O=MyCompany,ST=MyState,C=US" -t "CT,," -x -2` (Do not forget to answer `Yes` to the question "Is this a CA certificate [y/N]?") - Extract the CA certificate to be able to import it in `upsd` (or `upsmon`) certificate database: `certutil -L -d CA_db -n "My Root CA" -a -o rootca.crt` - Sign a certificate request with the CA certificate (simulate a real CA signature): `certutil -C -d CA_db -c "My Root CA" -a -i server.req -o server.crt -2 -6` Install the server-side certificate ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Just copy the database directory (just the directory and included 3 database .db files) to the right place, such as `/usr/local/ups/etc/`: mv cert_db /usr/local/ups/etc/ upsd (required): certificate database and self certificate ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Edit the `upsd.conf` to tell where find the certificate database: CERTPATH /usr/local/ups/etc/cert_db Also tell which is the certificate to send to clients to authenticate itself and the password to decrypt private key associated to certificate: CERTIDENT "certificate name" "database password" NOTE: Generally, the certificate name is the server domain name, but is not a hard rule. The certificate can be named as useful. upsd (optional): client authentication ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NOTE: This functionality is disabled by default. To activate it, recompile NUT with `WITH_CLIENT_CERTIFICATE_VALIDATION` defined: make CFLAGS="-DWITH_CLIENT_CERTIFICATE_VALIDATION" UPSD can accept three levels of client authentication. Just specify it with the directive `CERTREQUEST` with the corresponding value in the `upsd.conf` file: - NO: no client authentication. - REQUEST: a certificate is request to the client but it is not strictly validated. If the client does not send any certificate, the connection is closed. - REQUIRE: a certificate is requested to the client and if it is not valid (no validation chain) the connection is closed. Like CA certificates, you can add many "trusted" client and CA certificates in server's certificate databases. upsmon (required): upsd authentication ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In order for `upsmon` to securely connect to `upsd`, it must authenticate it. You must associate an `upsd` host name to security rules in `upsmon.conf` with the directive `CERTHOST`. `CERTHOST` associates a hostname to a certificate name. It also determines whether a SSL connection is mandatory, and if the server certificate must be validated. CERTHOST "hostname" "certificate name" "certverify" "forcessl" If the flag `forcessl` is set to `1`, and `upsd` answers that it can not connect with SSL, the connection closes. If the flag `certverify` is set to `1` and the connection is done in SSL, `upsd`'s certificate is verified and its name must be the specified `"certificate name"`. To prevent security leaks, you should set all `certverify` and `forcessl` flags to `1` (force SSL connection and validate all certificates for all peers). You can specify `CERTVERIFY` and `FORCESSL` directive (to `1` or `0`) to define a default security rule to apply to all host not specified with a dedicated `CERTHOST` directive. If a host is not specified in a `CERTHOST` directive, its expected certificate name is its hostname. upsmon (optional): certificate database and self certificate ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Like `upsd`, `upsmon` may need to authenticate itself (`upsd`'s `CERTREQUEST` directive set to `REQUEST` or `REQUIRE`). It must access to a certificate (and its private key) in a certificate database configuring `CERTPATH` and `CERTIDENT` in `upsmon.conf` in the same way as `upsd`. CERTPATH /usr/local/ups/etc/cert_db CERTIDENT "certificate name" "database password" Restart upsd ~~~~~~~~~~~~ It should come back up without any complaints. If it says something about keys or certificates, then you probably missed a step. If you run `upsd` as a separate user ID (like `nutsrv`), make sure that user can read files in the certificate directory. NUT reads the keys and certificates after forking and dropping privileges. Restart upsmon ~~~~~~~~~~~~~~ You should see something like this in the syslog from `upsd`: foo upsd[1234]: Client mon@localhost logged in to UPS [myups] (SSL) If `upsd` or `upsmon` give any error messages, or the `(SSL)` is missing, then something isn't right. If in doubt about `upsmon`, start it with `-D` so it will stay in the foreground and print debug messages. It should print something like this every couple of seconds: polling ups: myups@localhost [SSL] Obviously, if the `[SSL]` isn't there, something's broken. Recommended: sniff the connection to see it for yourself ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Using tcpdump, Wireshark (Ethereal), or another network sniffer tool, tell it to monitor port 3493/tcp and see what happens. You should only see `STARTTLS` go out, `OK STARTTLS` come back, and the rest will be certificate data and then seemingly random characters. If you see any plaintext besides that (USERNAME, PASSWORD, etc.) then something is not working. Potential problems ~~~~~~~~~~~~~~~~~~ If you specify a certificate expiration date, you will eventually see things like this in your syslog: Oct 29 07:27:25 rktoy upsmon[3789]: Poll UPS [for750@rktoy] failed - SSL error: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE: certificate verify failed You can verify that it is expired by using openssl to display the date: openssl x509 -enddate -noout -in It'll display a date like this: notAfter=Oct 28 20:05:32 2002 GMT If that's after the current date, you need to generate another cert/key pair using the procedure above. Conclusion ~~~~~~~~~~ SSL support should be considered stable but purposely under-documented since various bits of the implementation or configuration may change in the future. In other words, if you use this and it stops working after an upgrade, come back to this file to find out what changed. This is why the other documentation doesn't mention any of these directives yet. SSL support is a treat for those of you that RTFM. There are also potential licensing issues for people who ship binary packages since NUT is GPL and OpenSSL is not compatible with it. You can still build and use it yourself, but you can't distribute the results of it. Or maybe you can. It depends on what you consider "essential system software", and some other legal junk that we're not going to touch. Other packages have solved this by explicitly stating that an exception has been granted. That is (purposely) impossible here, since NUT is the combined effort of many people, and all of them would have to agree to a license change. This is actually a feature, since it means nobody can unilaterally run off with the source -- not even the NUT team. Note that the replacement of OpenSSL by Mozilla Network Security Services (NSS) should avoid the above licensing issues. chrooting and other forms of paranoia ------------------------------------- It has been possible to run the drivers and `upsd` in a chrooted jail for some time, but it involved a number of evil hacks. From the 1.3 series, a much saner chroot behavior exists, using BIND 9 as an inspiration. The old way involved creating an entire tree, complete with libraries, a shell (!), and many auxiliary files. This was hard to maintain and could have become an interesting playground for an intruder. The new way is minimal, and leaves little in the way of usable materials within the jail. This document assumes that you already have created at least one user account for the software to use. If you're still letting it fall back on "nobody", stop right here and go figure that out first. It also assumes that you have everything else configured and running happily all by itself. Generalities ~~~~~~~~~~~~ Essentially, you need to create your configuration directory and state path in their own little world, plus a special device or two. For the purposes of this example, the chroot jail is `/chroot/nut`. The programs have been built with the default prefix, so they are using `/usr/local/ups`. First, create the confpath and bring over a few files. mkdir -p /chroot/nut/usr/local/ups/etc cd /chroot/nut/usr/local/ups/etc cp -a /usr/local/ups/etc/upsd.users . cp -a /usr/local/ups/etc/upsd.conf . cp -a /usr/local/ups/etc/ups.conf . We're using `cp -a` to maintain the permissions on those files. Now bring over your state path, maintaining the same permissions as before. mkdir -p /chroot/nut/var/state cp -a /var/state/ups /chroot/nut/var/state Next we must put `/etc/localtime` inside the jail, or you may get very strange readings in your syslog. You'll know you have this problem if `upsd` shows up as UTC in the syslog while the rest of the system doesn't. mkdir -p /chroot/nut/etc cp /etc/localtime /chroot/nut/etc Note that this is not `cp -a`, since we want to copy the *content*, not the symlink that it may be on some systems. Finally, create a tiny bit of `/dev` so the programs can enter the background properly -- they redirect file descriptors into the bit bucket to make sure nothing else grabs fds 0-2. mkdir -p /chroot/nut/dev cp -a /dev/null /chroot/nut/dev Try to start your driver(s) and make sure everything fires up as before. upsdrvctl -r /chroot/nut -u nutdev start Once your drivers are running properly, try starting `upsd`. upsd -r /chroot/nut -u nutsrv Check your syslog. If nothing is complaining, try running clients like `upsc` and `upsmon`. If they seem happy, then you're done. symlinks ~~~~~~~~ After you do this, you will have two copies of many things, like the confpath and the state path. I recommend deleting the "real" `/var/state/ups`, replacing it with a symlink to `/chroot/nut/var/state/ups`. That will let other programs reference the `.pid` files without a lot of hassle. You can also do this with your confpath and point `/usr/local/ups/etc` (or equivalent on your system) at `/chroot/nut/usr/local/ups/etc` unless you're worried about something hurting the files inside that directory. In that case, you should maintain a "golden" copy and push it into the chroot path after making changes. The `upsdrvctl` itself does not chroot, so the `ups.conf` still needs to be in the usual confpath. upsmon ~~~~~~ This has not yet been applied to `upsmon`, since it can be quite complicated when there are notifiers that need to be run. One possibility would be for `upsmon` to have three instances: - privileged root parent that listens for a shutdown command - unprivileged child that listens for notify events - unprivileged chrooted child that does network I/O This one is messy, and may not happen for some time, if ever. Config files ~~~~~~~~~~~~ You may now set `chroot=` and `user=` in the global section of `ups.conf`. The `upsd` chroots before opening any config files, so there is no way to add support for that in `upsd.conf` at the present time. nut-2.8.3/docs/hid-subdrivers.txt0000644000200500020050000004663014777767434013725 00000000000000How to make a new subdriver to support another USB/HID UPS ---------------------------------------------------------- Overall concept ~~~~~~~~~~~~~~~ USB (Universal Serial Port) devices can be divided into several different classes (audio, imaging, mass storage etc). Almost all UPS devices belong to the "HID" class, which means "Human Interface Device", and also includes things like keyboards and mice. What HID devices have in common is a particular (and very flexible) interface for reading and writing information (such as X/Y coordinates and button states, in the case of a mouse, or voltages and status information, in the case of a UPS). The NUT "usbhid-ups" driver is a meta-driver that handles all HID UPS devices. It consists of a core driver that handles most of the work of talking to the USB hardware, and several sub-drivers to handle specific UPS manufacturers (MGE, APC, and Belkin are currently supported). Adding support for a new HID UPS device is easy, because it requires only the creation of a new sub-driver. There are a few USB UPS devices that are not true HID devices. These devices typically implement some version of the manufacturer's serial protocol over USB (which is a really dumb idea, by the way). An example is the original Tripplite USB interface (USB idProduct = 0001). Its HID descriptor is only 52 bytes long (compared to several hundred bytes for a true PDC HID UPS). Such devices are *not* supported by the usbhid-ups driver, and are not covered in this document. If you need to add support for such a device, read new-drivers.txt and see the "tripplite_usb" driver for inspiration. HID Usage Tree ~~~~~~~~~~~~~~ From the point of view of writing a HID subdriver, a HID device consists of a bunch of variables. Some variables (such as the current input voltage) are read-only, whereas other variables (such as the beeper enabled/disabled/muted status) can be read and written. These variables are usually grouped together and arranged in a hierarchical tree shape, similar to directories in a file system. This tree is called the "usage" tree. For example, here is part of the usage tree for a typical APC device. Variable components are separated by `.`. Typical values for each variable are also shown for illustrative purposes. [width="35%"] |================================================ |UPS.Battery.Voltage | 11.4 V |UPS.Battery.ConfigVoltage | 12 V |UPS.Input.Voltage | 117 V |UPS.Input.ConfigVoltage | 120 V |UPS.AudibleAlarmControl | 2 (=enabled) |UPS.PresentStatus.Charging | 1 (=yes) |UPS.PresentStatus.Discharging | 0 (=no) |UPS.PresentStatus.ACPresent | 1 (=yes) |================================================ As you can see, variables that describe the battery status might be grouped together under "Battery", variables that describe the input power might be grouped together under "Input", and variables that describe the current UPS status might be grouped together under "PresentStatus". All of these variables are grouped together under "UPS". This hierarchical organization of data has the advantage of being very flexible; for example, if some device has more than one battery, then similar information about each battery could be grouped under "Battery1", "Battery2" and so forth. If your UPS can also be used as a toaster, then information about the toaster function might be grouped under "Toaster", rather than "UPS". However, the disadvantage is that each manufacturer will have their own idea about how the usage tree should be organized, and usbhid-ups needs to know about all of them. This is why manufacturer specific subdrivers are needed. To make matters more complicated, usage tree components (such as "UPS", "Battery", or "Voltage") are internally represented not as strings, but as numbers (called "usages" in HID terminology). These numbers are defined in the "HID Usage Tables", available from http://www.usb.org/developers/hidpage/. The standard usages for UPS devices are defined in a document called "Usage Tables for HID Power Devices" (the Power Device Class [PDC] specification). For example: -------------------------------------------------------------------------------- 0x00840010 = UPS 0x00840012 = Battery 0x00840030 = Voltage 0x00840040 = ConfigVoltage 0x0084001a = Input 0x0084005a = AudibleAlarmControl 0x00840002 = PresentStatus 0x00850044 = Charging 0x00850045 = Discharging 0x008500d0 = ACPresent -------------------------------------------------------------------------------- Thus, the above usage tree is internally represented as: -------------------------------------------------------------------------------- 00840010.00840012.00840030 00840010.00840012.00840040 00840010.0084001a.00840030 00840010.0084001a.00840040 00840010.0084005a 00840010.00840002.00850044 00840010.00840002.00850045 00840010.00840002.008500d0 -------------------------------------------------------------------------------- To make matters worse, most manufacturers define their own additional usages, even in cases where standard usages could have been used. for example Belkin defines `00860040` = ConfigVoltage (which is incidentally a violation of the USB PDC specification, as `00860040` is reserved for future use). Thus, subdrivers generally need to provide: - manufacturer-specific usage definitions, - a mapping of HID variables to NUT variables. Moreover, subdrivers might have to provide additional functionality, such as custom implementations of specific instant commands (load.off, shutdown.restart), and conversions of manufacturer specific data formats. Usage macros in drivers/hidtypes.h ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The `drivers/hidtypes.h` header provides a number of macro names for entries in the standard usage tables for Power Device `USAGE_POW_` and Battery System `USAGE_BAT_` data pages. If NUT codebase would ever need to refresh those macros, here is some background information (based on NUT issue #1189 and PR #1290): These data were parsed from (a very slightly updated version of) https://github.com/abend0c1/hidrdd/blob/master/rd.conf file, which incorporates the complete USB-IF usage definitions for Power Device and Battery System pages (among many others), so we didn't have to extract the names and values from the USB-IF standards documents (did check it all by eye though). The file was processed with the following chain of commands: ------ :; grep -e '^0084' -e '^0085' rd.conf \ | sed 's/,.*$//;s/ *$//' \ | sed 's/ /_/g;s/_/ /' \ | tr '[:lower:]' '[:upper:]' \ | sed 's/\(0085.... \)/\1USAGE_BAT_/;s/\(0084.... \)/\1USAGE_POW_/;s/\([A-Z_]*\)_PAGE/PAGE_\1/' \ | awk '{print "#define "$2" 0x"$1}' ------ Writing a subdriver ~~~~~~~~~~~~~~~~~~~ In preparation for writing a subdriver for a device that is currently unsupported, run usbhid-ups with the following command line: drivers/usbhid-ups -DD -u root -x explore -x vendorid=XXXX \ -x port=auto -s ups (substitute your device's 4-digit VendorID instead of "XXXX"). This will produce a bunch of debugging information, including a number of lines starting with "Path:" that describe the device's usage tree. This information forms the initial basis for a new subdriver. You should save this information to a file, e.g.: drivers/usbhid-ups -DD -u root -x explore -x vendorid=XXXX \ -x port=auto -s ups -d1 2>&1 | tee /tmp/info You can now create an initial "stub" subdriver for your device by using helper script `scripts/subdriver/gen-usbhid-subdriver.sh`. NOTE: This only creates a driver code "stub" which needs to be further customized to be actually useful (see "Customization" below). Use the script as follows: scripts/subdriver/gen-usbhid-subdriver.sh < /tmp/info where `/tmp/info` is the file where you previously saved the debugging information. This script prompts you for a name for the subdriver; use only letters and digits, and use natural capitalization such as "Belkin" (not "belkin" or "BELKIN"). The script may prompt you for additional information. You should put the generated files into the drivers/ subdirectory, and update `usbhid-ups.c` by adding the appropriate `#include` line and by updating the definition of `subdriver_list` in `usbhid-ups.c`. You must also add the subdriver to USBHID_UPS_SUBDRIVERS in `drivers/Makefile.am` and call `autoreconf` and/or `./configure` from the top-level NUT directory. You can then recompile `usbhid-ups`, and start experimenting with the new subdriver. Updating a subdriver ~~~~~~~~~~~~~~~~~~~~ You may have a device from vendor (and maybe model) whose support `usbhid-ups` already claims. However, you may feel that the driver does not represent all data points that your device serves. This may be possible, as vendors tend to use the same identifiers for unrelated products, as well as produce revisions of devices with same marketed name but different internals (due to chip and other components availability, cost optimization, etc.) Even without sinister implications, UPS firmwares evolve and so bugs and features can get added, fixed and removed over time with truly the same hardware being involved. In this case you should follow the same instructions as above for "Writing a subdriver", but specify the same subdriver name as the one which supports your device family already. Then compare the generated source file with the one already committed to NUT codebase, paying close attention to `..._hid2nut[]` table which maps "usage" names to NUT data points. There may be several "usage" values served by different device models or firmware versions, that provide same information for a NUT data point, such as `input.voltage`. For the `hid2nut` mapping tables, first hit wins (so you may e.g. prefer to check values with better precision first). Using a GUI tool with partial-line difference matching and highlighting, such as Meld or WinMerge, is recommended for this endeavour. For new data points in `hid2nut` tables be sure to not invent new names, but use standard ones from `docs/nut-names.txt` file. Temporarily, the `experimental.*` namespace may be used. If you need to standardize a name for some concept not addressed yet, please do so via nut-upsdev mailing list discussion. Customization ~~~~~~~~~~~~~ The initially generated subdriver code is only a stub, and will not implement any useful functionality (in particular, it will be unable to shut down the UPS). In the beginning, it simply attempts to monitor some UPS variables. To make this driver useful, you must examine the NUT variables of the form "unmapped.*" in the hid_info_t data structure, and map them to actual NUT variables and instant commands. There are currently no step-by-step instructions for how to do this. Please look at the files to see how the currently implemented subdrivers are written: - apc-hid.c/h - belkin-hid.c/h - cps-hid.c/h - explore-hid.c/h - libhid.c/h - liebert-hid.c/h - mge-hid.c/h - powercom-hid.c/h - tripplite-hid.c/h NOTE: To test existing data points (including those not yet translated to standard NUT mappings conforming to <>), you can use custom drivers built after you `./configure --with-unmapped-data-points`. Production driver builds must not include any non-standard names. Fixing report descriptors ~~~~~~~~~~~~~~~~~~~~~~~~~ It is a fact of life that fellow developers make mistakes, and firmware authors do too. In some cases there are inconsistencies about bytes seen on the wire vs. their logical values, such value range and signedness if interpreting them according to standard. NUT drivers now include a way to detect and fix up known issues in such flawed USB report descriptors, side-stepping the standard similarly where deemed needed. A pointer to such hook method is part of the `subdriver_t` structure detailing each `usbhid-ups` subdriver nuances, defaulting to a `fix_report_desc()` trivial implementation. For some practical examples, see e.g. `apc_fix_report_desc()` method in the `drivers/apc-hid.c` file, and `cps_fix_report_desc()` in `drivers/cps-hid.c` file. Finally note that such fix-ups may be not applicable to all devices or firmware versions for what they assume their target audience is. If you suspect that the fix-up method is actually causing problems, you can quickly disable it with `disable_fix_report_desc` driver option for `usbhid-ups`. If the problem does dissipate, please find a way to identify your "fixed" hardware/firmware vs. those models where existing fix-up method should be applied, and post a pull request so the NUT driver would handle both cases. Investigating report descriptors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Beside looking for problems with report descriptor processing in NUT code, it is important to make sure what data the device actually serves on the wire, and if it is logically consistent with the protocol requirements. While here, keep in mind that USB protocol on the wire has a specified order of bytes involved, while processing on your computer may lay them out differently due to bitness and endianness of the current binary build. General NUT codebase (`libhid.c`, `hidparser.c`) aims to abstract this, so application code like drivers can deal with their native numeric data types, but when troubleshooting, do not rule out possibility of flaws there as well. And certainly do not code any assumptions about ordered multiple-byte ranges in a protocol buffer. For a deep dive into the byte stream, you will need additional tools: * get/build/install link:https://regina-rexx.sourceforge.io[regina-rexx] * get/install link:https://github.com/abend0c1/hidrdd[HIDRDD] (uses REXX as the interpreter) Typical troubleshooting of suspected firmware/protocol issues goes like this: * Turn the NUT `usbhid-ups` driver debug verbosity level up to 5 (or more) and restart the driver, so it would record the HEX dump of report descriptor * Look for reports from the driver of any problems it has already detected and possibly amended (LogMin/LogMax, report descriptor fix-ups) * Extract the HEX dump of the report descriptor from USB driver output from the first step above, and run it through HIDRDD (and/or REXX directly, per example below). * Look at the HIDRDD output, with reference to any documents related to your device and the USB/HID power devices class available in NUT documentation, e.g. at https://www.networkupstools.org/ups-protocols.html * Especially look for inconsistencies in the USB HID report descriptors (RD): * between the min/max (logical and physical) values, * the sizes of the report fields they apply to, * the expected physical values (e.g., supply and output voltages, over-voltage/under-voltage transfer points, ...) * If you're seeing unexpected values for particular variables, look at the raw data that is being sent, decide whether it makes sense in the context of the logical and physical min/max values from the report descriptor. * Read the NUT code, tracing through how each value gets processed looking for where the result deviates from expectations... * Think, code, test, rinse, repeat, post a PR :) .Example direct use of REXX =========================== Example adapted from https://github.com/networkupstools/nut/issues/2039 Run a NUT `usb-hid` driver with at least debug verbosity level 3 (`-DDD`) to get a report descriptor dump starting with a line like this: ---- 3.670755 [D3] Report Descriptor: (909 bytes) => 05 84 09 04 a1 01 ... ---- ...and copy-paste those reported lines as input into `rexx` tool, which would generate a C source file including human-worded description and a relevant data structure: ---- :; rexx rd.rex -d --hex 05 84 09 04 a1 01 85 01 09 18 ... 55 b1 02 c0 c0 c0 //-------------------------------------------------------------------------------- // Decoded Application Collection //-------------------------------------------------------------------------------- /* 05 84 (GLOBAL) USAGE_PAGE 0x0084 Power Device Page 09 04 (LOCAL) USAGE 0x00840004 UPS (Application Collection) A1 01 (MAIN) COLLECTION 0x01 Application (Usage=0x00840004: Page=Power Device Page, Usage=UPS, Type=Application Collection) 85 01 (GLOBAL) REPORT_ID 0x01 (1) 09 18 (LOCAL) USAGE 0x00840018 Outlet System (Physical Collection) ... */ // All structure fields should be byte-aligned... #pragma pack(push,1) //-------------------------------------------------------------------------------- // Power Device Page featureReport 01 (Device <-> Host) //-------------------------------------------------------------------------------- typedef struct { uint8_t reportId; // Report ID = 0x01 (1) // Collection: CA:UPS CP:OutletSystem CP:Outlet int8_t POW_UPSOutletSystemOutletSwitchable; // Usage 0x0084006C: Switchable, Value = to int8_t POW_UPSOutletSystemOutletDelayBeforeStartup; // Usage 0x00840056: Delay Before Startup, Value = -1 to 60 int8_t POW_UPSOutletSystemOutletDelayBeforeShutdown; // Usage 0x00840057: Delay Before Shutdown, Value = -1 to 60 int8_t POW_UPSOutletSystemOutletDelayBeforeReboot; // Usage 0x00840055: Delay Before Reboot, Value = -1 to 60 int8_t POW_UPSOutletSystemOutletSwitchable_1; // Usage 0x0084006C: Switchable, Value = -1 to 60 int8_t POW_UPSOutletSystemOutletDelayBeforeStartup_1; // Usage 0x00840056: Delay Before Startup, Value = -1 to 60 int8_t POW_UPSOutletSystemOutletDelayBeforeShutdown_1; // Usage 0x00840057: Delay Before Shutdown, Value = -1 to 60 int8_t POW_UPSOutletSystemOutletDelayBeforeReboot_1; // Usage 0x00840055: Delay Before Reboot, Value = -1 to 60 } featureReport01_t; #pragma pack(pop) ---- =========================== Shutting down the UPS ~~~~~~~~~~~~~~~~~~~~~ It is desirable to support shutting down the UPS. Usually (for devices that follow the HID Power Device Class specification), this requires sending the UPS two commands. One for shutting down the UPS (with an 'offdelay') and one for restarting it (with an 'ondelay'), where offdelay < ondelay. The two NUT commands for which this is relevant, are 'shutdown.return' and 'shutdown.stayoff'. Since the one-to-one mapping above doesn't allow sending two HID commands to the UPS in response to sending one NUT command to the driver, this is handled by the driver. In order to make this work, you need to define the following four NUT values: ups.delay.start (variable, R/W) ups.delay.shutdown (variable, R/W) load.off.delay (command) load.on.delay (command) If the UPS supports it, the following variables can be used to show the countdown to start/shutdown: ups.timer.start (variable, R/O) ups.timer.shutdown (variable, R/O) The `load.on` and `load.off` commands will be defined implicitly by the driver (using a delay value of '0'). Define these commands yourself, if your UPS requires a different value to switch on/off the load without delay. Note that the driver expects the `load.off.delay` and `load.on.delay` to follow the HID Power Device Class specification, which means that the `load.on.delay` command should NOT switch on the load in the absence of mains power. If your UPS switches on the load regardless of the mains status, DO NOT define this command. You probably want to define the `shutdown.return` and/or `shutdown.stayoff` commands in that case. Commands defined in the subdriver will take precedence over the ones that are composed in the driver. When running the driver with the '-k' flag, it will first attempt to send a `shutdown.return` command and if that fails, will fallback to `shutdown.reboot`. nut-2.8.3/docs/cables/0000755000200500020050000000000015001555413011477 500000000000000nut-2.8.3/docs/cables/apc-rs500-serial.txt0000644000200500020050000000164614553676503015075 00000000000000Desc: APC UPS cable - for Back-UPS RS 500 File: apc-rs500-serial.txt Date: 14 July 2004 Auth: Russell Kroll , Martin Edlman This document was constructed from a mail from Martin. He figured out the pinouts to make the Back-UPS RS 500 work with a normal serial port. Here are the details: --- UPS side PC side RJ45 (8 pins) DB9F 1 orange/white 2,8,9 2 orange 1 3 green/white chassis/ground 4 blue - 5 blue/white - 6 green 5 7 brown/white 4,6 8 brown - +---+ +-----+ +-----+ | | +---------------+ 8 7 6 5 4 3 2 1 view from back (cable entry) --- Note this results in OL=-CTS, LB=DCD, SD=ST, CP=RTS, so it should work with the existing genericups type 20. nut-2.8.3/docs/cables/Makefile.am0000644000200500020050000000015214777534445013476 00000000000000# Network UPS Tools: cable docs CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp nut-2.8.3/docs/cables/mgeups.txt0000644000200500020050000000264114777534445013510 00000000000000Desc: MGE UPS SYSTEMS serial cable File: mgeups.txt Date: 10 April 2002 Auth: Arnaud Quette or This document describes the cable for MGE smart protocols : UTalk (ASCII), and SHUT (Serial HID UPS Transfer, binary) . First notice that MGE UPS SYSTEMS supply a standard cable, bundled with the UPS unit and compatible with MS Windows and Unices (Ref 66049). For more information, see below note about serial cable, PnP and Unix. Cable description ----------------- UPS COMPUTER MALE DB9 FEMALE DB9 2 ---------------- 2 TX 3 ---------------- 3 RX 5 ---------------- 5 GND -- 4 | -- 6 -- 7 | -- 8 UPS connector description ------------------------- 5 4 3 2 1 _______________ \o o o o o/ \ o o o o/ --------- 9 8 7 6 9 pin Male DB-9 connector on UPS Notes ----- - this is a universal serial cable, so it should work with any MGE serial model. - max. length of cable is 1,80 m. - Computer pin 6 (RTS) is reserved for PnP use, which could trouble communication on some Unices if cabled. However, new models (such as Ellipse, Evolution, Pulsar and Comet EXtreme, EXtreme C, ...) handle this, so you can safely cable pin 6 or use a standard (bundled) "windows" cable (Ref 66049). nut-2.8.3/docs/cables/sms.txt0000644000200500020050000000064714553676503013010 00000000000000Desc: SMS UPS cables, for Upsilon compatible SMS UPS File: sms.txt Date: 9 October 2001 Auth: Marcio Gomes COMPUTER UPS FEMEA DB9 MACHO DB9 2 ---------- 6 3 ---------- 9 4/8 ---------- 5 5 ---------- 8 - This cable is working with Manager III 1300 VA and 650 VA, SMS UPS's - Jump in computer side pins 4/8 and connect to pin 1 in UPS side - Use NUT blazer_ser driver nut-2.8.3/docs/cables/apc.txt0000644000200500020050000003735514777534445012765 00000000000000Desc: APC UPS cables File: apc.txt Date: 12 February 2010 Auth: Arjen de Korte &2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = docs/cables ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ CLEANFILES = *-spellchecked MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu docs/cables/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu docs/cables/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/docs/cables/ge-imv-victron.txt0000644000200500020050000000237414777534445015061 00000000000000Desc: IMV Victron UPS cables File: victron.txt Date: 13 April 2002 Auth: Daniel Prynych Data cable 1 for UPS: GE/IMV/Victron Match - 500 700 700L 1000 1000L 1500 2200 3000 GE/IMV/Victron NetPro (NetPro 19 ") - 600 1000 1200 2000 3000 4000 Driver: victronups (newvictronups) UPS PC 9 pin connector 1 --------- 3 2 --------- 2 5 --------- 5 GND 4 DTR | 1 DCD ------------------------------------ Data cable 2 for UPS: GE/IMV Victron Match Lite (all types) Driver: victronups (newvictronups) UPS PC 9 pin connector 2 --------- 3 3 --------- 2 4 --------- 5 GND 4 DTR | 1 DCD ----------------------------------- Crack cable: for UPS Victron Lite (no IMV Victron Match Lite) Driver: genericsups UPS PC 9 pin connector 1 ---------- 4 DTR 7 ---------- 1 DCD ----------+ 9 ---------- 8 CTS -----+ | 5 ---------- 5 GND | | | | R R 6,8k - 10k ohm | | 7 RTS------+----+ ---------------------------------------------- GE is General Electric Company. On July 31, 2001, the General Electric Company, acquired IMV (Victron) company. nut-2.8.3/docs/cables/repotec.txt0000644000200500020050000000070114777534445013644 00000000000000Desc: Repotec 800A (800VA) & 162A (1600VA) cable File: repotec.txt Date: 11 April 2001 Auth: Theodor Milkov PC UPS 1 (DCD) <----+---------- 2 | R 5.6k | 7 (RTS) >----+ 3 (Tx) >--------------- 6 4 (DTR) <----+---------- 5 | R 5.6k | 8 (CTS) >----+ 5 (GND) -------------+-- 4 | +-- 7 nut-2.8.3/docs/cables/imv.txt0000644000200500020050000000036214553676503012773 00000000000000Desc: IMV Match19 700 - 1500 File: imv.txt Date: 06 April 2002 Auth: Niels S. Richthof "UPS-VIC23-2" PC 9 pin connector 1 ---------------- 3 2 ---------------- 2 4 ---------------- 7 5 ---------------- 5 nut-2.8.3/docs/cables/powerware.txt0000644000200500020050000000101114777534445014211 00000000000000Desc: Powerware 3115 factory cable File: powerware.txt Date: 22 July 2005 Auth: various 1) Powerware 3115 factory cable From Peter Åstrand UPS PC 9 pin connector 5 --------- 1 2 --------- 2 1 --------- 3 4 --------- 5 6 --------- 8 2) Powerware 5119 RM Cable Layout From Daniel Thompson UPS <-----------> PC DB9-M <--------> DB9-F Pin 1 <-----------> Pin 3 Pin 2 <-----------> Pin 8 Pin 4 <-----------> Pin 4 Pin 5 <-----------> Pin 1 Shells Grounded Both Ends nut-2.8.3/docs/configure.txt0000644000200500020050000012173514777767434012754 00000000000000ifdef::website[] Configure options ================= endif::website[] As many other projects relying on GNU autotools for build recipe automation, NUT sources deliver a `configure` script which is used to set up numerous nuances relevant for your build of the project. Most of the configuration requirements are passed by `--with-something` or `--enable-something` options (allegedly, not always used consistently with autotools naming recommendations), and with environment variables like `CFLAGS` typically also passed as command line options. Default syntax of `--with-something` or `--enable-something` assumes a boolean approach, so the option as such conveys a `yes` string value, and aliases `--without-something` or `--disable-something` are handled automatically as a `no` string value, for the option named `something`. In many cases, these options are used to pass non-boolean configuration of the option in question, commonly a path, program name, compiler flags to use along with a particular dependency, user name or type of documentation to build, etc. A special case here concerns options that accept an `auto` value, where the `configure` script would opine to request a final `yes` or `no`, depending on other circumstances of the build environment and requested configuration. [NOTE] ====== When building NUT from Git sources rather than the distribution tarballs, you would have to generate the `configure` script and some further needed files by running `./autogen.sh`. This in turn may require additional tools and other dependencies on your build environment (referenced just a bit below). For common developer iterations, porting to new platforms, or in-place testing, running the `./ci_build.sh` script can be a helpful one-stop solution. The NUT linkdoc:packager-guide[Packager Guide], which presents the best practices for installing and integrating NUT, is also a good reading. The linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] document suggests prerequisite packages with tools and dependencies available and needed to build and test as much as possible of NUT on numerous platforms, written from perspective of CI testing (if you are interested in getting updated drivers for a particular device, you might select a sub-set of those suggestions). ====== There are a few options reviewed below that can be given to `configure` script to tweak your compilations. See also `./configure --help` for a current and complete listing for the current version of the codebase. NUT tracks `configure` options used during build, so you can view them to produce a replacement by asking NUT programs for `--help` or for `--version` with debugging enabled (first), e.g.: ---- :; upsd -DV Network UPS Tools upsd 2.8.1 Network UPS Tools version 2.8.1 configured with flags: --with-all=auto --with-doc=skip ... ---- A more industrial approach is to use `lib/libupsclient-config --config-flags`, where supported. Note that the `pkg-config` manifest `libupsclient.pc` does not easily convey this information. Keeping a report of NUT configuration ------------------------------------- --enable-keep_nut_report_feature If this option is enabled (not currently default), the report displayed by `configure` script will be kept in a file when the script ends, and installed into the data directory. In-place replacement defaults ----------------------------- A common situation for NUT builds is to verify whether current version of the codebase (e.g. recent and not-yet-packaged release, or a Git branch) solves some issues of an existing deployment. Such tests are simplified if the new build of NUT plays by the same systems integration rules as the already deployed (e.g. package-delivered) version, specifically about filesystem access permissions and configuration file locations. --enable-inplace-runtime Tries to detect and pre-set `configure` defaults for run-time settings (which you can still override if needed, but no longer *must* specify explicitly to be on same page as the existing setup), most notably: * `--sysconfdir` * `--with-user` * `--with-group` If the installed NUT version supports reporting of `CONFIG_FLAGS` used during its build, the `configure` script will try to take those values into account when running in this mode (and so use the same program and data installation paths, for example). NOTE: This does not currently rely on the configuration report optionally installed by `--enable-keep_nut_report_feature` above, but might do so eventually. Driver selection ---------------- Serial drivers ~~~~~~~~~~~~~~ --with-serial USB drivers ~~~~~~~~~~~ Build and install the serial drivers (default: yes) --with-usb Build and install the USB drivers (default: auto-detect) Note that you need to install the libusb development package or files, and that both libusb 0.1 and 1.0 are supported. In case both are available, libusb 1.0 takes precedence, and will be used by default. It is however possible to override this default choice by explicitly calling `--with-usb=libusb-0.1` or `--with-usb=libusb-1.0`. If you do specify the version to use (or `yes` for auto-detection), this option would fail if requested (or any) libusb version was not found. The default `auto` value would not fail in such case. WARNING: If you intend to use the `libmodbus` variant with `libusb` support, you would require `libusb-1.0` specifically; the implementation or "compat API" of `0.1` is not supported by that library version. SNMP drivers ~~~~~~~~~~~~ --with-snmp Build and install the SNMP drivers (default: auto-detect) Note that you need to install libsnmp development package or files. --with-net-snmp-config In addition to the `--with-snmp` option above, this one allows to provide a custom program name (in `PATH`) or complete pathname to `net-snmp-config` (may have copies named per architecture, e.g. `net-snmp-config-32` and `net-snmp-config-64`). This may be needed on build systems which support multiple architectures, or in cases where your distribution names this program differently. With a default value of `yes` it would mean preference of this program, compared to information from `pkg-config`, if both are available. XML drivers and features ~~~~~~~~~~~~~~~~~~~~~~~~ --with-neon Build and install the XML drivers (default: auto-detect) Note that you need to install neon development package or files. LLNC CHAOS Powerman driver ~~~~~~~~~~~~~~~~~~~~~~~~~~ --with-powerman Build and install Powerman PDU client driver (default: auto-detect) This allows to interact with the Powerman daemon, and the numerous Power Distribution Units (PDU) supported by the https://github.com/chaos/powerman[powerman] project. Note that you need to install powerman development package or files. IPMI drivers ~~~~~~~~~~~~ --with-ipmi --with-freeipmi Build and install IPMI PSU driver (default: auto-detect) This allows to monitor numerous Power Supply Units (PSU) found on servers. Note that you need to install freeipmi (0.8.5 or higher, for nut-scanner; and 1.0.1 or higher, for nut-ipmipsu) development package or files. I2C bus drivers ~~~~~~~~~~~~~~~ --with-linux_i2c Build and install i2c drivers (default: auto-detect) Note that you need to install libi2c development package or files. GPIO bus drivers ~~~~~~~~~~~~~~~~ --with-gpio Build and install GPIO drivers (default: auto-detect) Note that on Linux you need to install libgpiod library and development package or files. This seems to be present in distributions released after roughly 2018. Other platforms are not currently supported, but may be in the future. Modbus drivers ~~~~~~~~~~~~~~ --with-modbus Build and install modbus (Serial, TCP) drivers (default: auto-detect) Note that you need to install libmodbus development package or files. --with-modbus+usb Require a variant of libmodbus with RTU USB support. This feature is currently not available in upstream project or OS distribution packages, so your NUT build environment should provide a prerequisite build of https://github.com/networkupstools/libmodbus/tree/rtu_usb (may be a static library build, used from a temporary installation prefix location, to avoid potential conflicts with the OS packaged shared library). You would also need specifically `libusb-1.0` (not the older API). At the time of this writing, such constraint can be desirable for the linkman:apc_modbus[8] driver which supports different communication media. For more details please see https://github.com/networkupstools/nut/wiki/APC-UPS-with-Modbus-protocol Manual selection of drivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ --with-drivers=,,... Specify exactly which driver or drivers to build and install (this works for serial, usb, and snmp drivers, and overrides the preceding three options). As of the time of original writing (2010), there are 46 UPS drivers available. Most users will only need one, a few will need two or three, and very few people will need all of them. To save time during the compile and disk space later on, you can use this option to just build and install a subset of the drivers. For example, to select `mge-shut` and `usbhid-ups`, you'd do this: --with-drivers=apcsmart,usbhid-ups If you need to build more drivers later on, you will need to rerun `configure` with a different list. To make it build all of the drivers from scratch again, run `make clean` before starting. Optional features ----------------- CGI client interface ~~~~~~~~~~~~~~~~~~~~ --with-cgi (default: no) Build and install the optional CGI programs, HTML files, and sample CGI configuration files. This is not enabled by default, as they are only useful on web servers. See link:data/html/README[] for additional information on how to set up CGI programs. NUT Scanner tool ~~~~~~~~~~~~~~~~ --with-nut-scanner (default: auto) Build and install the optional linkman:nut-scanner[8] tool to discover some types of UPS or ePDU devices on locally or remotely connected media (such as Serial, USB, SNMP, IPMI, NetXML), as well as NUT data servers (by Avahi/mDNS broadcasts or "old" NUT port polling) and simulation device configurations that can be relayed by a local linkman:dummy-ups[8] driver instance. Many of the features depend on third-party libraries that are loosely linked at run-time using libltdl, and due to that, the build, delivery and use of the tool does not depend on *all* of them being available in the final deployment. NUT Configuration tool ~~~~~~~~~~~~~~~~~~~~~~ --with-nutconf (default: auto) Build and install the optional linkman:nutconf[8] tool to create and manipulate NUT configuration files. It also optionally supports device scanning, using the linkman:nutscan[3] library (if built), to suggest configuration of devices. Pretty documentation and man pages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --with-docs= (default: no) --with-doc= (default: no) Build and install NUT documentation file(s). Note: `--with-doc` is a legacy NUT option, and `--with-docs` is an alias that matches the more wide-spread equivalent in different packaging frameworks and projects. This feature requires AsciiDoc 8.6.3 or newer (see https://asciidoc.org). The possible documentation type values are: * `html-single` for single page HTML, * `html-chunked` for multi-paged HTML, * `pdf` for a PDF file, and * `man` for the usual man pages. Other values understood for this option are listed below: * If the `--with-doc` argument is passed without a list, or specifies just `=yes` or `=all`, it enables all supported formats with a `=yes` to require them. * An (explicit!) `--with-doc=auto` argument tries to enable all supported formats with an `=auto` but should not fail the build if something can not be generated. * A `--with-doc=no` quietly skips generation of all types of documentation, including man pages. * A `--with-doc=skip` is used to configure some of the `make distcheck*` scenarios to re-use man page files built and distributed by the main build and not waste time on re-generation of those. * A `--with-doc=dist-auto` allows to use pre-distributed MAN pages if present (should be in "tarball" release archives; should not be among Git-tracked sources; may be left over from earlier builds in same workspace), or build those if we can (the `auto` part). Practically this is implemented in detail only for `--with-doc=man=dist-auto`, as we do not dist HTML and PDF products; it is a placeholder for those to simplify the generic configuration calls. Multiple documentation format values can be specified, separated with comma. Each such value can be suffixed with `=yes` to require building of this one documentation format (abort configuration if tools are missing), `=auto` to detect and enable if we can build it on this system (and not abort if we can not), and `=no` (or `=skip`) to explicitly skip generation of this document format even if we do have the tools to build it. If a document format is mentioned in the list without a suffix, then it is treated as a `=yes` requirement. Verbose output can be enabled using: `ASCIIDOC_VERBOSE=-v make` Example valid formats of this flag: * `--with-doc` without an argument, effectively same as `--with-doc=yes` * `--with-doc=` is a valid empty list, effectively same as `--with-doc=no` * `--with-doc=auto` * `--with-doc=pdf,html-chunked` * `--with-doc=man=no,pdf=auto,html-single` Additional flags with regard to documentation generation include: --with-docs-man-section-api= (default: 3) --with-docs-man-section-cfg= (default: 5) --with-docs-man-section-cmd-sys= (default: 8) --with-docs-man-section-cmd-usr= (default: 1) Customize man page section identifiers for operating systems whose standards do not match defaults listed above for Library and API, Configuration Files, System Management Commands and User Commands sections (e.g. Solaris-derived systems might use `--with-docs-man-section-cmd-sys=1m`). This impacts not only file names of the manual pages, but also cross-links in generated documents. Note that use of these flags does not implicitly enable any `--with-docs=...` mode, which should still be specified explicitly. Python support ~~~~~~~~~~~~~~ NUT includes a client binding `PyNUT` module, as well as an optional GUI application `NUT-Monitor` (not to be confused with `nut-monitor` service name for `upsmon` as delivered by some OS distribution packages). Both python 2.7 and several versions of python 3.x are supported and regularly tested by NUT CI farm builds; other versions may work or not. Also some of the source configuration (including activity in `autogen.sh` script and later in certain `Makefile`s during build) relies on presence of `python` (and `perl`) interpreters. If they are not available, e.g. on older operating systems, certain features are skipped -- but you may have to `export` special environment variables to signal to `autogen.sh` that this is an expected situation (it would suggest which, for your current NUT version). NOTE: For CI builds (or similar reproducible developer activity) performed with `ci_build.sh` -- since this is an area which impacts both `configure` script generation by the helper `autogen.sh` script and subsequently the choices made by the `configure` script itself, settings can be made by exporting the `PYTHON` environment variable which should evaluate to some way to call the correct interpreter (e.g. `python2.7`, `/usr/bin/env python` or `/usr/bin/python3`). The `configure` script does support equivalent options, whose defaults come from detection of certain program names by current `PATH` setting. Further use of these interpreter names and other paths during NUT build and installation is managed by Makefile variable expansion, as prepared by the `configure` script. Also note that it is not required to use the same `PYTHON` implementation for `autogen.sh` to do its job, and for the `configure` script option. As noted above, both python-2.x and python-3.x variants are supported. You can consult the `m4/nut_check_python.m4` file for detection methods used. If both interpreter generations are present, and a particular un-versioned `PYTHON` is not specified or detected, then selected/detected `PYTHON3` is chosen as the ultimate `PYTHON` value. For majority of uses in the build procedure and products, the generation of Python does not matter and the un-versioned `PYTHON` value is substituted into files as the script shebang, used to find the `site-packages` location, etc. One exception is generation of NUT-Monitor GUI application which has been separated for `NUT-Monitor-py2gtk2` and `NUT-Monitor-py3qt5` due to further backend platform technical differences -- these build products specifically use `PYTHON2` and `PYTHON3` substitutions. They may be co-installed on the same system. A dispatcher shell script `NUT-Monitor` is used to launch the preferred (newest) or the only existing implementation. Please note that by default NUT tries to make use of everything in your build environment, so if both Python generation are detected -- the binding module will be delivered into both, and two versions of NUT-Monitor GUI application will be installed. If you want to avoid that behaviour on a build system with both interpreters present, you can explicitly specify to build e.g. `--without-python2 --with-python=/usr/bin/python-3.9`. The settings below may be of particular interest to non-distribution packaging efforts with their own dedicated directory trees: --with-python=SHEBANG_PATH Specify a definitive version you want used for majority of the Python code (except version-dependent scripts, see above). The `SHEBANG_PATH` should be a full program pathname, optionally with one argument, e.g. `/usr/bin/python-3.9` or `/usr/bin/env python2`. Defaults (in order): * `python`, `python3` or `python2` program if present in `PATH` by such name, * or the newest of `PYTHON3` or `PYTHON2` values (specified or detected below). --with-python2=SHEBANG_PATH --with-python3=SHEBANG_PATH For version-dependent scripts (see above) or to default the newest Python version if not specified by `--with-python` option or detected otherwise, you can provide the preferred version and implementation of Python 2 or 3 respectively. Conversely, if neither of these configure options were specified, but some `--with-python` program was specified or detected, and its report says it has Python major version 2 or 3, then the versioned interpreter string would point to that. --with-nut_monitor Install the NUT-Monitor GUI application (depending on Python 2 or 3 version availability), and optional `desktop-file-install` integration). --with-pynut Install the PyNUT module files for general consumption into "site-packages" location of the currently chosen Python interpreter(s): yes, no, auto. or dedicated as the required dependency of NUT-Monitor application (app). [WARNING] ========= The module files are installed into a particular Python version's location such as `/usr/lib/python2.7/dist-packages` even if you specify a relaxed or un-versioned interpreter like `python2` (which would be used in scripts for the NUT-Monitor application and possible other consumers of the module). If the preferred Python version in the deployed system changes later (so the `python2` symlink for this example would point elsewhere) the module import would become not resolvable for such consumers, until it is installed into that other Python's "site-packages" location. ========= Development files ~~~~~~~~~~~~~~~~~ --with-dev (default: no) Build and install the upsclient and nutclient library and header files, to build further projects against NUT (such as wmNUT client and many others). Also delivers `libnutscan` library and header files, if `--with-nut-scanner` is enabled. Disabled development file delivery, in particular, disables installation of static libraries. --with-dev-libnutconf (yes/no/auto, default: no) Build and install the nutconf library and header files, to build further projects against NUT (especially those that need to set it up). This is currently not automatically tied into either `--with-dev` nor `--with-nutconf` (note below on `--with-all`), because the tool and library are experimental and the API may yet undergo significant changes in the coming years. It is more recommended to use the CLI tool as a presumably more stable API for third-party integrations, than the library directly. This feature may however be enabled or disabled implicitly, using `--with-all(=yes/no/auto)` request, based on a combination of `--with-nutconf` and `--with-dev` options: * if `--without-all`, default to set `--with-dev-libnutconf=no`; otherwise... * if either `--without-dev` or `--without-nutconf`, default to set `--with-dev-libnutconf=no`; otherwise... * if either `--without-dev=auto` and/or `--without-nutconf=auto`, default to set `--with-dev-libnutconf=auto`; otherwise... * if both `--with-dev` and `--with-nutconf`, default to set `--with-dev-libnutconf=yes`. Requires C++11 support to be enabled (available in compiler, not neutered by explicit selection of an older standard). --enable-ldflags-nut-rpath (yes/no/auto/flags, default: auto) --enable-ldflags-nut-rpath-cxx (yes/no/auto/flags, default: auto) NUT development files include the `*.pc` metadata for `pkg-config` ecosystem and a legacy `libupsclient-config` script, both used to deliver compiler and linker options for third-party programs to build against NUT libraries. There can be a problem during run-time, when NUT is installed into a location that the system linker does not know to look into, e.g. the default `--prefix` value of `/usr/local/ups`, that the built programs fail to dynamically link with the shared objects of NUT libraries, unless deprecated tricks like the `LD_LIBRARY_PATH` setting are applied. These options allow NUT to add linker options, which set "RPATH" in consumer binaries, to the announced metadata. As a result, third-party programs or libraries are hard-coded to look for NUT libraries in a certain location, in addition to system locations and similar paths added by other dependencies. By default (in `auto` mode), the `configure` script queries the compiler for known system library paths (currently supported with GCC and CLANG builds), and checks the NUT `libdir` against that list. If there is a hit, no extra flags are announced; otherwise, the format detected for currently used linker by autoconf libtool macros is added to the announced metadata for builds against NUT. If this causes problems, you can either `--disable-...` these flags or provide the desired string explicitly. Options for developers ~~~~~~~~~~~~~~~~~~~~~~ --enable-spellcheck (default: auto) Activate recipes for documentation source file spelling checks with `aspell` tool. Default behavior depends on availability of the tool, so if present -- it would run for `make check` by default, to facilitate quicker acceptance of contributions. --enable-check-NIT (default: no) Add `make check-NIT` to default activity of `make check` to run the NUT Integration Testing suite. This is potentially dangerous (e.g. due to port conflicts when running many such tests in same environment), so not active by default. --enable-maintainer-mode (default: no) Use maintainer mode to keep `Makefile.in` and `Makefile` in sync with ever-changing `Makefile.am` content after Git updates or editing. --enable-cppcheck (default: no) Activate recipes for static analysis with `cppcheck` tools (if available). --with-unmapped-data-points (default: no) Build SNMP and USB-HID subdrivers with entries discovered by the scripts which generated them from data walks, but developers did not rename yet to NUT mappings conforming to `docs/nut-names.txt` standards. Production driver builds must not include any non-standard names. --enable-NUT_STRARG-always (default: auto) Enable the `NUT_STRARG` macro (to handle `NULL` string printing) even if the system libraries seem to safely support this behavior natively? This flag should primarily help against overly zealous static analysis tools in recent compiler generations. The `auto` value enables the flag for certain compiler versions known to complain about some of our use cases -- even though those seem to be false positives. --enable-configure-debug Cause the `configure` script run to report some internal values of variables as it goes through making of choices, to help recipe developers troubleshoot it. I want it all! ~~~~~~~~~~~~~~ --with-all (no default) Build and install all of the above (the serial, USB, SNMP, XML/HTTP and PowerMan drivers, the CGI programs and HTML files, and the upsclient library). You can also use `--with-all=auto` to detect available prerequisites and only build everything that we can build on this system (but not fail due to inability to request a build of something from the full scope). Networking transport security ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --with-ssl (default: auto-detect) --with-nss (default: auto-detect) --with-openssl (default: auto-detect) Enable SSL support, using either Mozilla NSS or OpenSSL. If both are present, and nothing was specified, OpenSSL support will be preferred. Read link:docs/security.txt[] for instructions on SSL support. NOTE: Currently the two implementations differ in supported features. Networking access security ~~~~~~~~~~~~~~~~~~~~~~~~~~ --with-wrap (default: auto-detect) Enable libwrap (tcp-wrappers) support. Refer to linkman:upsd[8] man page for more information. Networking IPv6 ~~~~~~~~~~~~~~~ --with-ipv6 (default: auto-detect) Enable IPv6 support. AVAHI/mDNS ~~~~~~~~~~ --with-avahi (default: auto-detect) Build and install Avahi support, to publish NUT server availability using mDNS protocol. This requires Avahi development files for the Core and Client parts. LibLTDL ~~~~~~~ --with-libltdl (default: auto-detect) Enable libltdl (Libtool dlopen abstraction) support. This is required to build `nut-scanner` which loads third-party libraries dynamically, based on requested scanning options. This allows to build and package the tool without requiring all possible dependencies to be installed in each run-time environment. Other configuration options --------------------------- NUT data server port ~~~~~~~~~~~~~~~~~~~~ --with-port=PORT Change the TCP port used by the network code. Default is 3493 as registered with IANA. Ancient versions of `upsd` used port 3305. NUT 2.0 and up use a substantially different network protocol and are not able to communicate with anything older than the 1.4 series. If you have to monitor a mixed environment, use the last 1.4 version, as it contains compatibility code for both the old "REQ" and the new "GET" versions of the protocol. Daemon user accounts ~~~~~~~~~~~~~~~~~~~~ --with-user= --with-group= See also `--enable-inplace-runtime`. Programs started as `root` will `setuid()` to `` for somewhat safer operation. You can override this with `-u ` in several programs, including `upsdrvctl` (and all drivers by extension), `upsd`, and `upsmon`. The "user" directive in `ups.conf` overrides this at run time for the drivers. NOTE: `upsmon` does not totally drop `root` because it may need to initiate a shutdown. There is always at least a stub process remaining with `root` powers. The network code runs in another (separate) process as the new user. The `` is used for the permissions of some files, particularly the hotplugging rules for USB. The idea is that the device files for any UPS devices should be readable and writable by members of that group. The default value for both the username and groupname is `nobody` (or `nogroup` on systems that have it when `configure` script runs). This was done since it's slightly better than staying around as `root`. Running things as `nobody` is not a good idea, since it's a hack for NFS access. You should create at least one separate user for this software. If you use one of the `--with-user` and `--with-group` options, then you have to use the other one too. See the link:INSTALL.nut[] document and the FAQ for more on this topic. Syslog facility ~~~~~~~~~~~~~~~ --with-logfacility=FACILITY Change the facility used when writing to the log file. Read the man page for `openlog` to get some idea of what's available on your system. Default is `LOG_DAEMON`. External API integration scripts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sometimes as a developer or user you need to interact with a device for which a "proper" NUT driver does not yet exist (or is not in your version), but some proof-of-concept script can be good enough to collect some data. In some cases, an UPS does not support local monitoring at all, but has a network port for cloud-based monitoring through its vendor's portal. Such data can be converted and fed into the NUT `dummy-ups` driver, and so represented in the NUT ecosystem, by rewriting the "sequence" file whose contents it processes in a loop (see linkman:dummy-ups[8] for more details). NUT provides sample scripts for such integration, which can be used if you have a suitable use-case, or provide inspiration for you to begin experiments with a new device and (as often happens) a shell or Python script polling it for information. For more details, see `scripts/external_apis` in NUT sources (and pull requests with more integrations would be welcome there). --enable-extapi-enphase=(yes|auto|no) Enable installation of integration script for External API: Enphase Monitor (default: no) Installation directories ------------------------ --prefix=PATH This is a fairly standard option with GNU autoconf, and it sets the base path for most of the other install directories. The default is `/usr/local/ups`, which puts everything but the state sockets in one easy place, and does not conflict with usual distribution packaging. If you like having things to be at more of a "system" level, setting the prefix to `/usr/local` or even `/usr` might be better. --exec_prefix=PATH This sets the base path for architecture dependent files. By default, it is the same as ``. --sysconfdir=PATH Changes the location where NUT's configuration files are stored. By default this path is `/etc`. Setting this to `/etc/nut` or `/etc/ups` might be useful. See also `--enable-inplace-runtime`. The `NUT_CONFPATH` environment variable overrides this at run time. --sbindir=PATH --bindir=PATH Where executable files will be installed. Files that are normally executed by root (`upsd`, `upsmon`, `upssched`) go to ``, all others to ``. The defaults are `/sbin` and `/bin` respectively. See also `--with-drvpath` below. --with-drvpath=PATH The UPS drivers will be installed to this path. By default they install to `/bin`, i.e. `/usr/local/ups/bin`. You would want a location that remains mounted when most of the system is prepared to turn off, so some distributions package NUT drivers into `/lib/nut` or similar. See link:config-notes.txt[] detailing how to set up system shutdown. The `driverpath` global directive in the `ups.conf` file overrides this at run time. --datadir=PATH Change the data directory, i.e., where architecture independent read-only data for the currently built project is installed. By GNU Autotools default, this is `/share` (same as the system-wide "data root" which we also consult for third-party data such as Augeas lens delivery locations), i.e. `/usr/local/ups/share`. + Typically this is reconfigured to a `'${datarootdir}/nut'` value. + At the moment, this directory only holds two files by default -- the optional `cmdvartab` and `driver.list`, but may hold additional data on certain systems (e.g. FreeBSD quirks, Solaris SMF or init methods, sometimes documentation). --mandir=PATH Sets the base directories for the man pages. The default is `/man`, i.e. `/usr/local/ups/man`. --includedir=PATH Sets the path for include files to be installed when `--with-dev` is selected. For example, `upsclient.h` is installed here. The default is `/include`. --libdir=PATH Sets the installation path for libraries. Depending on the build configuration, this can include the `libupsclient`, `libnutclient`, `libnutclientsub`, `libnutscan` and their pkg-config metadata (see `--with-pkgconfig-dir` option). The default is `/lib`. --libexecdir=PATH Sets the installation path for "executable libraries" -- helper scripts or programs that are not intended for direct and regular use by people, and rather are implementation details of services. Depending on the build configuration, this can include the `nut-driver-enumerator.sh`, `sockdebug`, and others. The default is `/libexec`. Package distributions may want to use this option to customize this path to include the package name, e.g. set it to `/libexec/nut`. --with-pkgconfig-dir=PATH Where to install pkg-config `*.pc` files. This option only has an effect if `--with-dev` is selected, and causes a pkg-config file to be installed in the named location. The default is `/pkgconfig`. Use `--without-pkgconfig-dir` to disable this feature altogether. --with-cgipath=PATH The CGI programs will be installed to this path. By default, they install to `/cgi-bin`, which is usually `/usr/local/ups/cgi-bin`. NOTE: If you set the prefix to something like `/usr`, you should set the `cgipath` to something else, because `/usr/cgi-bin` is pretty ugly and non-standard. The CGI programs are not built or installed by default. Use `./configure --with-cgi` to request that they are built and installed. --with-htmlpath=PATH HTML files will be installed to this path. By default, this is `/html`. Note that HTML files are only installed if `--with-cgi` is selected. --with-hotplug-dir=PATH Where to install Linux 2.4 hotplugging rules. The default is to use `/etc/hotplug`, if that directory exists, and to not install it otherwise. Note that this installation directory is not a subdirectory of `` by default. When installing NUT as a non-root user, you may have to override this option. Use `--without-hotplug-dir` to disable this feature altogether. --with-udev-dir=PATH Where to install Linux 2.6 hotplugging rules, for kernels that have the "udev" mechanism. The default is to use `/etc/udev`, if that directory exists, and to not install it otherwise. Note that this installation directory is not a subdirectory of `` by default. When installing NUT as a non-root user, you may have to override this option. Use `--without-udev-dir` to disable this feature altogether. --with-systemdsystemunitdir=PATH Where to install Linux systemd unit definitions. Useless and harmless on other OSes, including Linux distributions without systemd, just adding a little noise to configure script output. Use `--with-systemdsystemunitdir=auto` (default) to detect the settings using pkg-config if possible. Use `--with-systemdsystemunitdir(=yes)` to require detection of these settings with pkg-config, or fail configuration if not possible. Use `--with-systemdsystemunitdir=no` to disable this feature altogether. --with-systemdsystempresetdir=PATH Where to install Linux systemd unit presets (lists of services enabled or disabled by default). Useless and harmless on other OSes, including Linux distributions without systemd, just adding a little noise to the configure script output. Use `--with-systemdsystempresetdir=auto` (default) to detect the settings using pkg-config if possible. Use `--with-systemdsystempresetdir(=yes)` to require detection of these settings with pkg-config, or fail configuration if not possible. Use `--with-systemdsystempresetdir=no` to disable this feature altogether. --with-systemdshutdowndir=PATH Where to install Linux systemd unit definitions for shutdown handling. Useless and harmless on other OSes, including Linux distributions without systemd, just adding a little noise to configure script output. Use `--with-systemdshutdowndir` to detect the settings using pkg-config. Use `--with-systemdshutdowndir=no` to disable this feature altogether. --with-systemdtmpfilesdir=PATH Where to install Linux systemd configuration for tmpfiles handling (the automatically created locations for PID, state and similar run-time files). Useless and harmless on other OSes, including Linux distributions without systemd, just adding a little noise to configure script output. Use `--with-systemdtmpfilesdir` to detect the settings using pkg-config. Use `--with-systemdtmpfilesdir=no` to disable this feature altogether. --with-libsystemd=(auto|yes|no) --with-libsystemd-includes=CFLAGS --with-libsystemd-libs=LDFLAGS If the build system provides `libsystemd` headers, NUT binaries can be built with tighter integration to this service management framework. In this case NUT daemons (`upsd`, `upsmon`, `upslog` and drivers) would report their life-cycle milestones (`READY`, `RELOADING`, `STOPPING`) and support the watchdog reports (if enabled in their respective units by end-user -- not done by default since the numbers depends on monitoring system performance). Default: "auto" (integration enabled if detected). --with-augeas-lenses-dir=PATH Where to install Augeas configuration-management lenses. Only useful and valid if you use Augeas to parse and modify configuration files. The default is to use `/usr/share/augeas/lenses`, if that directory exists, and to not install it otherwise. Directories used by NUT at run-time ----------------------------------- --with-pidpath=PATH Changes the directory where NUT pid files are stored for processes running as `root`. By default this is `/var/run`. Certain programs like `upsmon` will leave files here. --with-altpidpath=PATH Programs that normally don't have `root` powers, like the drivers and `upsd`, write their PID files here. By default this is whatever the statepath (below) is, as those programs should be able to write there. The `NUT_ALTPIDPATH` environment variable overrides this at run time. --with-statepath=PATH Change the default location of the local Unix sockets created by the drivers to interact with the data server `upsd` to report their state and receive commands. Default is `/var/state/ups`. This is also the default location for non-`root` daemons to write a PID file, if a separate location is not specified by `--with-altpidpath` option. The `NUT_STATEPATH` environment variable overrides this at run time. NOTE: Fun fact: in early iterations of the NUT project, the drivers and the data server did exchange information by writing and reading complete state files in a commonly accessible location, hence the name. --with-powerdownflag=FILEPATH Change the default location (full filename path) of the POWERDOWNFLAG created by `upsmon` (as `root`) to tell the late-shutdown integration that this machine should tell all UPSes for which it is a "primary" NUT server to cut power to the load. Default is `/etc/killpower` on POSIX systems and `"C:\\killpower"` (note the double backslashes) on Windows. Things the compiler might need to find -------------------------------------- pkg-config tooling ~~~~~~~~~~~~~~~~~~ --with-pkg-config This option allows to provide a custom program name (in `PATH`) or a complete pathname to `pkg-config` which describes `CFLAGS`, `LIBS` and possibly other build-time options in `*.pc` files, to use third-party libraries. On build systems which support multiple architectures you may also want to set `PKG_CONFIG_PATH` to match your current build. LibGD ~~~~~ --with-gd-includes="-I/foo/bar" If you installed `libgd` in some place where your C preprocessor can't find the header files, use this switch to add additional `-I` flags. --with-gd-libs="-L/foo/bar -labcd -lxyz" If your copy of `libgd` isn't linking properly, use this to give the proper `-L` and `-l` flags to make it work. See `LIBS=` in gd's `Makefile`. NOTE: the `--with-gd` switches are not necessary if you have gd 2.0.8 or higher installed properly. The `gdlib-config` script or pkg-config manifest will be detected and used by default in that situation. --with-gdlib-config This option allows to provide a custom program name (in `PATH`) or a complete pathname to `gdlib-config`. This may be needed on build systems which support multiple architectures, or in cases where your distribution names this program differently. LibUSB ~~~~~~ --with-libusb-config This option allows to provide a custom program name (in `PATH`) or a complete pathname to `libusb-config` (usually delivered only for libusb-0.1 version, but not for libusb-1.0). This may be needed on build systems which support multiple architectures or provide several versions of libusb, or in cases where your distribution names this program differently. Various ~~~~~~~ --with-ssl-includes, --with-usb-includes, --with-snmp-includes, --with-neon-includes, --with-libltdl-includes, --with-powerman-includes="-I/foo/bar" If your system doesn't have `pkg-config` and support for any of the above libraries isn't found (but you know it is installed), you must specify the compiler flags that are needed. --with-ssl-libs, --with-usb-libs, --with-snmp-libs, --with-neon-libs, --with-libltdl-libs --with-powerman-libs="-L/foo/bar -R/foo/bar -labcd -lxyz" If system doesn't have `pkg-config` or it fails to provides hints for some of the settings that are needed to set it up properly and the build in defaults are not right, you can specify the correct values for your system here. nut-2.8.3/docs/config-notes.txt0000644000200500020050000012023414777767434013357 00000000000000Configuration notes =================== This chapter describes most of the configuration and use aspects of NUT, including establishing communication with the device and configuring safe shutdowns when the UPS battery runs out of power. There are many programs and <> in this package. You should check out the <> and other accompanying documentation to see how it all works. [NOTE] ====== NUT does not currently provide proper graphical configuration tools. However, there is now support for linkdoc:developer-guide[Augeas,augeas_user], which will enable the easier creation of configuration tools. The linkman:nutconf[8] tool should also help with programmatic manipulation of various NUT configuration files. Moreover, linkman:nut-scanner[8] is available to discover supported devices (USB, SNMP, Eaton XML/HTTP and IPMI) and NUT servers (using Avahi or the classic connection method). ====== Details about the configuration files ------------------------------------- Generalities ~~~~~~~~~~~~ All configuration files within this package are parsed with a common state machine, which means they all can use a number of extras described here. First, most of the programs use an upper-case word to declare a configuration directive. This may be something like MONITOR, NOTIFYCMD, or ACCESS. The case does matter here. "monitor" won't be recognized. Next, the parser does not care about whitespace between words. If you like to indent things with tabs or spaces, feel free to do it here. If you need to set a value to something containing spaces, it has to be contained within "quotes" to keep the parser from splitting up the line. That is, you want to use something like this: SHUTDOWNCMD "/sbin/shutdown -h +0" Without the quotes, it would only see the first word on the line. OK, so let's say you really need to embed that kind of quote within your configuration directive for some reason. You can do that too. NOTIFYCMD "/bin/notifyme -foo -bar \"hi there\" -baz" In other words, `\` can be used to escape the `"`. Finally, for the situation where you need to put the `\` character into your string, you just escape it. NOTIFYCMD "/bin/notifyme c:\\dos\\style\\path" The `\` can actually be used to escape any character, but you only really need it for `\`, `"`, and `#` as they have special meanings to the parser. When using file names with space characters, you may end up having tricky things since you need to write them inside `""` which must be escaped: NOTIFYCMD "\"c:\\path with space\\notifyme\" \"c:\\path with space\\name\"" `#` is the comment character. Anything after an unescaped `#` is ignored. Something like this... identity = my#1ups will actually turn into `identity = my`, since the `#` stops the parsing. If you really need to have a `#` in your configuration, then escape it. identity = my\#1ups Much better. The `=` character should be used with care too. There should be only one "simple" `=` character in a line: between the parameter name and its value. All other `=` characters should be either escaped or within "quotes". password = 123=123 is incorrect. You should use: password = 123\=123 or: password = "123=123" Line spanning ~~~~~~~~~~~~~ You can put a backslash at the end of the line to join it to the next one. This creates one virtual line that is composed of more than one physical line. Also, if you leave the `""` quote container open before a newline, it will keep scanning until it reaches another one. If you see bizarre behavior in your configuration files, check for an unintentional instance of quotes spanning multiple lines. Basic configuration ------------------- This chapter describes the base configuration to establish communication with the device. This will be sufficient for PDU. But for UPS and SCD, you will also need to configure <>. image:images/simple.png[] On operating systems with service management frameworks (such as Linux systemd and Solaris/illumos SMF), the life-cycle of driver, data server and monitoring client daemons is managed respectively by `nut-driver` (multi-instance service), `nut-server` and `nut-monitor` services. These are in turn wrapped by an "umbrella" service (or systemd "target") conveniently called `nut` which allows to easily start or stop all those of the bundled services, which are enabled on a particular deployment. [[Driver_configuration]] Driver configuration ~~~~~~~~~~~~~~~~~~~~ Create one section per UPS in linkman:ups.conf[5] file. NOTE: The default path for a source installation is `/usr/local/ups/etc`, while packaged installation will vary. For example, `/etc/nut` is used on Debian and derivatives, while `/etc/ups` or `/etc/upsd` is used on RedHat and derivatives. To find out which driver to use, check the <>, or `data/driver.list(.in)` source file. Once you have picked a driver, create a section for your UPS in 'ups.conf'. You must supply values at least for "driver" and "port". Some drivers may require other flags or settings. The "desc" value is optional, but is recommended to provide a better description of what useful load your UPS is feeding. A typical device without any extra settings looks like this: [mydevice] driver = mydriver port = /dev/ttyS1 desc = "Workstation" [NOTE] ====== USB drivers (such as `usbhid-ups` for non-SHUT mode, `nutdrv_qx` for non-serial mode, `bcmxcp_usb`, `tripplite_usb`, `blazer_usb`, `riello_usb` and `richcomm_usb`) are special cases and ignore the 'port' value. You must still set this value, but it does not matter what you set it to; a common and good practice is to set 'port' to *auto*, but you can put whatever you like. If you only own one USB UPS, the driver will find it automatically if it matches the identifiers are built into that driver. If you own more than one, refer to the driver's manual page for more information on matching a specific device, or trying specific subdriver or protocol options with a currently unknown device. ====== NOTE: On Windows systems, the second serial port (`COM2`), equivalent to `/dev/ttyS1` on Linux, would be `\\\\.\\COM2`. References: linkman:ups.conf[5], linkman:nutupsdrv[8], linkman:bcmxcp_usb[8], linkman:blazer_usb[8], linkman:nutdrv_qx[8], linkman:richcomm_usb[8], linkman:riello_usb[8], linkman:tripplite_usb[8], linkman:usbhid-ups[8] [[Starting_drivers]] Starting the driver(s) in legacy operating systems ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Generally, you can just start the driver(s) for your hardware (all sections defined in 'ups.conf') using the following command: :; upsdrvctl start Make sure the driver doesn't report any errors. It should show a few details about the hardware and then enter the background. You should get back to the command prompt a few seconds later. For reference, a successful start of the `usbhid-ups` driver looks like this: # upsdrvctl start Network UPS Tools - Generic HID driver 0.34 (2.4.1) USB communication driver 0.31 Using subdriver: MGE HID 1.12 Detected EATON - Ellipse MAX 1100 [ADKK22008] If the driver doesn't start cleanly, make sure you have picked the right one for your hardware. You might need to try other drivers by changing the "driver=" value in 'ups.conf'. Be sure to check the driver's man page to see if it needs any extra settings in 'ups.conf' to detect your hardware. If it says `can't bind /var/state/ups/...` or similar, then your state path probably isn't writable by the driver. Check the <> vs. the user account your driver starts as. After making changes, try the <> step again. [[Starting_drivers_NDE]] Driver(s) as a service ~~~~~~~~~~~~~~~~~~~~~~ On operating systems with init-scripts managing life-cycle of the operating environment, the `upsdrvctl` program is also commonly used in those scripts. It has a few downsides, such as that if the device was not accessible during OS startup and the driver connection timed out, it would remain not-started until an administrator (or some other script) "kicks" the driver to retry startup. Also, startup of the `upsd` data server daemon and its clients like `upsmon` is delayed until all the NUT drivers complete their startup (or time out trying). This can be a big issue on systems which monitor multiple devices, such as big servers with multiple power sources, or administrative workstations which monitor a datacenter full of UPSes. For this reason, NUT starting with version 2.8.0 supports startup of its drivers as independent instances of a `nut-driver` service under the Linux systemd and Solaris/illumos SMF service-management frameworks (corresponding files and scripts may be not pre-installed in packaging for other systems). Such service instances have their own and independent life-cycle, including parallel driver start and stop processing, and retries of startup in case of failure as implemented by the service framework in the OS. The Linux systemd solution also includes a `nut-driver.target` as a checkpoint that all defined drivers have indeed started up (as well as being a singular way to enable or disable startup of drivers). In both cases, a service named `nut-driver-enumerator` is registered, and when it is (re-)started it scans the currently defined device sections in 'ups.conf' and the currently defined instances of `nut-driver` service, and brings them in sync (adding or removing service instances), and if there were changes -- it restarts the corresponding drivers (via service instances) as well as the data server which only reads the list of sections at its startup. This helper service should be triggered whenever your system (re-)starts the `nut-server` service, so that it runs against an up-to-date list of NUT driver processes. Two service bundles are provided for this feature: a set of `nut-driver-enumerator-daemon*` units starts the script as a daemon to regularly inspect and apply the NUT configuration to OS service unit wrappings (mainly intended for monitoring systems with a dynamic set of monitored power devices, or for systems where filesystem events monitoring is not a clockwork-reliable mechanism to 100% rely on); while the other `nut-driver-enumerator.*` units run the script once per triggering of the service (usually during boot-up; configuration file changes can be detected and propagated by systemd most of the time, but not by SMF out of the box). A service-oriented solution also allows to consider that different drivers have different dependencies -- such as that networked drivers should begin startup after IP addresses have been assigned, while directly-connected devices might need nothing beside a mounted filesystem (or an activated USB stack service or device rule, in case of Linux). Likewise, systems administrators can define further local dependencies between services and their instances as needed on particular deployments. This solution also adds the `upsdrvsvcctl` script to manage NUT drivers as system service instances, whose CLI mimics that of `upsdrvctl` program. One addition is the `resync` argument to trigger `nut-driver-enumerator`, another is a `list` argument to display current mappings of service instances to NUT driver sections. Also, original tool's arguments such as the `-u` (user to run the driver as) or `-D` (debug of the driver) do not make sense in the service context -- the accounts to use and other arguments to the driver process are part of service setup (and an administrator can manage it there). Note that while this solution tries to register service instances with same names as NUT configuration sections for the devices, this can not always be possible due to constraints such as syntax supported by a particular service management framework. In this case, the enumerator falls back to MD5 hashes of such section names, and the `upsdrvsvcctl` script supports this to map the user-friendly NUT configuration section names to actual service names that it would manage. References: man pages: linkman:nutupsdrv[8], linkman:upsdrvctl[8], linkman:upsdrvsvcctl[8] Data server configuration (upsd) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Configure `upsd`, which serves data from the drivers to the clients. First, edit 'upsd.conf' to allow access to your client systems. By default, `upsd` will only listen to `localhost` port 3493/tcp. If you want to connect to it from other machines, you must specify each interface you want `upsd` to listen on for connections, optionally with a port number. LISTEN 127.0.0.1 3493 LISTEN ::1 3493 As a special case, `LISTEN * ` (with an asterisk) will try to listen on "ANY" IP address for both and IPv6 (`::0`) and IPv4 (`0.0.0.0`), subject to `upsd` command-line arguments, or system configuration or support. Note that if the system supports IPv4-mapped IPv6 addressing per RFC-3493, and does not allow to disable this mode, then there may be one listening socket to handle both address families. NOTE: Refer to the NUT user manual <> for information on how to access and secure upsd clients connections. Next, create 'upsd.users'. For now, this can be an empty file. You can come back and add more to it later when it's time to configure `upsmon` or run one of the management tools. Do not make either file world-readable, since they both hold access control data and passwords. They just need to be readable by the user you created in the preparation process. The suggested configuration is to `chown` it to `root`, `chgrp` it to the group you created, then make it readable by the group. NOTE: If you installed NUT from source and used `make install-as-root`, or if your distribution packaging did, the sample configuration files would have the suggested ownership and permissions assigned, so if you use e.g. `cp -pf upsd.users.sample upsd.users` (as `root`) to start out with some annotated comments and adapt that to your deployment, the copied files should also get the expected safe permissions. :; chown root:nut upsd.conf upsd.users :; chmod 0640 upsd.conf upsd.users References: man pages: linkman:upsd.conf[5], linkman:upsd.users[5], linkman:upsd[8] [[Starting_upsd]] Starting the data server ~~~~~~~~~~~~~~~~~~~~~~~~ Start the network data server: :; upsd Make sure it is able to connect to the driver(s) on your system. A successful run looks like this: # upsd Network UPS Tools upsd 2.4.1 listening on 127.0.0.1 port 3493 listening on ::1 port 3493 Connected to UPS [eaton]: usbhid-ups-eaton `upsd` prints dots while it waits for the driver to respond. Your system may print more or less depending on how many drivers you have and how fast they are. NOTE: If `upsd` says that it can't connect to a UPS or that the data is stale, then your 'ups.conf' is not configured correctly, or you have a driver that isn't working properly. You must fix this before going on to the next step. NOTE: Normally `upsd` requires that at least one driver section is defined in the 'ups.conf' file, and refuses to start otherwise. If you intentionally do not have any driver sections defined (yet) but still want the data server to run, respond and report zero devices (e.g. on an automatically managed monitoring deployment), you can enable the `ALLOW_NO_DEVICE true` option in the 'upsd.conf' file. NOTE: Normally `upsd` requires that at all `LISTEN` directives defined in the 'upsd.conf' file are honoured (except for mishaps possible with many names of `localhost`), and refuses to start otherwise. If you want to allow start-up in cases where at least one but possibly not all of the `LISTEN` directives were honoured, you can enable the `ALLOW_NOT_ALL_LISTENERS true` option in the 'upsd.conf' file. Note you would have to restart `upsd` to pick up the `LISTEN`ed IP address if it appears later, so probably configuring `LISTEN *` is a better choice in such cases. On operating systems with service management frameworks, the data server life-cycle is managed by `nut-server` service. Reference: man page: linkman:upsd[8] Check the UPS data ~~~~~~~~~~~~~~~~~~ Status data ^^^^^^^^^^^ Make sure that the UPS is providing good status data. You can use the `upsc` command-line client for this: :; upsc myupsname@localhost ups.status You should see just one line in response: OL `OL` means your system is running on line power. If it says something else (like `OB` -- on battery, or `LB` -- low battery), your driver was probably misconfigured during the <> step. If you reconfigure the driver, use `upsdrvctl stop` to stop it, then start it again as shown in the <> step. Reference: man page: linkman:upsc[8] All data ^^^^^^^^ Look at all of the status data which is being monitored. :; upsc myupsname@localhost What happens now depends on the kind of device and driver you have. In the list, you should see `ups.status` with the same value you got above. A sample run on an UPS (Eaton Ellipse MAX 1100) looks like this: battery.charge: 100 battery.charge.low: 20 battery.runtime: 2525 battery.type: PbAc device.mfr: EATON device.model: Ellipse MAX 1100 device.serial: ADKK22008 device.type: ups driver.name: usbhid-ups driver.parameter.pollfreq: 30 driver.parameter.pollinterval: 2 driver.parameter.port: auto driver.version: 2.4.1-1988:1990M driver.version.data: MGE HID 1.12 driver.version.internal: 0.34 input.sensitivity: normal input.transfer.boost.low: 185 input.transfer.high: 285 input.transfer.low: 165 input.transfer.trim.high: 265 input.voltage.extended: no outlet.1.desc: PowerShare Outlet 1 outlet.1.id: 2 outlet.1.status: on outlet.1.switchable: no outlet.desc: Main Outlet outlet.id: 1 outlet.switchable: no output.frequency.nominal: 50 output.voltage: 230.0 output.voltage.nominal: 230 ups.beeper.status: enabled ups.delay.shutdown: 20 ups.delay.start: 30 ups.firmware: 5102AH ups.load: 0 ups.mfr: EATON ups.model: Ellipse MAX 1100 ups.power.nominal: 1100 ups.productid: ffff ups.serial: ADKK22008 ups.status: OL CHRG ups.timer.shutdown: -1 ups.timer.start: -1 ups.vendorid: 0463 Reference: man page: linkman:upsc[8], <> Startup scripts ~~~~~~~~~~~~~~~ NOTE: This step is not necessary if you installed from packages. Edit your startup scripts, and make sure `upsdrvctl` and `upsd` are run every time your system starts. In newer versions of NUT, you may have a 'nut.conf' file which sets the `MODE` variable for bundled init-scripts, to facilitate enabling of certain features in the specific end-user deployments. If you installed from source, check the `scripts` directory for reference init-scripts, as well as systemd or SMF service methods and manifests. [[UPS_shutdown]] Configuring automatic shutdowns for low battery events ------------------------------------------------------ The whole point of UPS software is to bring down the OS cleanly when you run out of battery power. Everything else is roughly eye candy. To make sure your system shuts down properly, you will need to perform some additional configuration and run upsmon. Here are the basics. [[Shutdown_design]] Shutdown design ~~~~~~~~~~~~~~~ When your UPS batteries get low, the operating system needs to be brought down cleanly. Also, the UPS load should be turned off so that all devices that are attached to it are forcibly rebooted, and subsequently start in the predictable order and state suitable for your data center. Here are the steps that occur when a critical power event happens, for the simpler case of one UPS device feeding one or several systems: 1. The UPS goes on battery 2. The UPS reaches low battery (a "critical" UPS), that is to say, `upsc` displays: + ups.status: OB LB + The exact behavior depends on the specific device, and is related to such settings and readings as: - `battery.charge` and `battery.charge.low` - `battery.runtime` and `battery.runtime.low` 3. The `upsmon` primary notices the "critical UPS" situation and sets "FSD" -- the "forced shutdown" flag to tell all secondary systems that it will soon power down the load. + [WARNING] ========= By design, since we require power-cycling the load and don't want some systems to be powered off while others remain running if the "wall power" returns at the wrong moment as usual, the "FSD" flag can not be removed from the data server unless its daemon is restarted. If we do take the first step in critical mode, then we intend to go all the way -- shut down all the servers gracefully, and power down the UPS. Keep in mind that some UPS devices and corresponding drivers would latch the "FSD" again even if "wall power" is available, but the remaining battery charge is below a threshold configured as "safe" in the device (usually if you manually power on the UPS after a long power outage). This is by design of respective UPS vendors, since in such situation they can not guarantee that if a new power outage happens, their UPS would safely shut down your systems again. So it is deemed better and safer to stay dark until batteries become sufficiently charged. ========= + (If you have no secondary systems, skip to step 6) 4. `upsmon` secondary systems see "FSD" and: - generate a `NOTIFY_SHUTDOWN` event - wait `FINALDELAY` seconds -- typically `5` - call their `SHUTDOWNCMD` - disconnect from `upsd` 5. The `upsmon` primary system waits up to `HOSTSYNC` seconds (typically `15`) for the secondary systems to disconnect from `upsd`. If any are still connected after this time, `upsmon` primary stops waiting and proceeds with the shutdown process. 6. The `upsmon` primary: - generates a `NOTIFY_SHUTDOWN` event - waits `FINALDELAY` seconds -- typically `5` - creates the `POWERDOWNFLAG` file in its local filesystem -- usually `/etc/killpower`, or `/run/nut/killpower` in a temporary file system - calls the `SHUTDOWNCMD` 7. On most systems, `init` takes over, kills your processes, syncs and unmounts some filesystems, and remounts some read-only. 8. `init` then runs your shutdown script. This checks for the `POWERDOWNFLAG`, finds it, and tells the UPS driver(s) to power off the load by sending commands to the connected UPS device(s) they manage. 9. All the systems lose power. 10. Time passes. The power returns, and the UPS switches back on. 11. All systems reboot and go back to work. /////////////////////////////////// https://github.com/networkupstools/nut/issues/1370 TODO: Check other docs and code to spell out expected behavior with multiple UPS devices (when not all of them go critical or even on battery) and servers with multiple inputs. Does the `upsmon` primary system power-cycle a "critical" UPS if that is not the only one feeding it, so it is not shutting down now? /////////////////////////////////// How you set it up ~~~~~~~~~~~~~~~~~ [[NUT_user_creation]] NUT user creation ^^^^^^^^^^^^^^^^^ Create a `upsd` user for `upsmon` to use while monitoring this UPS. Edit 'upsd.users' and create a new section. The `upsmon` will connect to `upsd` and use these user name (in brackets) and password to authenticate (as specified in its configuration via `MONITOR` line). This example is for defining a user called "monuser": [monuser] password = mypass upsmon primary # or upsmon secondary References: linkman:upsd[8], linkman:upsd.users[5] Reloading the data server ^^^^^^^^^^^^^^^^^^^^^^^^^ Reload `upsd`. Depending on your configuration, you may be able to do this without stopping the `upsd` daemon process (if it had saved a PID file earlier): :; upsd -c reload If that doesn't work (check the syslog), just restart it: :; upsd -c stop :; upsd For systems with integrated service management (Linux systemd, illumos/Solaris SMF) their corresponding `reload` or `refresh` service actions should handle this as well. Note that such integration generally forgoes saving of PID files, so `upsd -c ` would not work. If your workflow requires to manage these daemons beside the OS provided framework, you can customize it to start `upsd -FF` and save the PID file. NUT releases after 2.8.0 define aliases for these units, so if your Linux distribution uses NUT-provided unit definitions, `systemctl reload upsd` may also work. NOTE: If you want to make reloading work later, see the entry in the link:FAQ.html[FAQ] about starting `upsd` as a different user. Power Off flag file ^^^^^^^^^^^^^^^^^^^ Set the `POWERDOWNFLAG` location for `upsmon`. In 'upsmon.conf', add a `POWERDOWNFLAG` directive with a filename. The `upsmon` will create this file when the UPS needs to be powered off during a power failure when low battery is reached. We will test for the presence of this file in a later step. POWERDOWNFLAG /etc/killpower References: man pages: linkman:upsmon[8], linkman:upsmon.conf[5] Securing upsmon.conf ^^^^^^^^^^^^^^^^^^^^ The recommended setting is to have it owned by `root:nut`, then make it readable by the group and not by the world. This file contains passwords that could be used by an attacker to start a shutdown, so keep it secure. NOTE: If you installed NUT from source and used `make install-as-root`, or if your distribution packaging did, the sample configuration files would have the suggested ownership and permissions assigned, so if you use e.g. `cp -pf upsmon.conf.sample upsmon.conf` (as `root`) to start out with some annotated comments and adapt that to your deployment, the copied files should also get the expected safe permissions. :; chown root:nut upsmon.conf :; chmod 0640 upsmon.conf This step has been placed early in the process so you secure this file before adding sensitive data in the next step. Create a MONITOR directive for upsmon ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Edit 'upsmon.conf' and create a `MONITOR` line with the UPS definition (@), username and password from the <> step, and the "primary" or "secondary" setting. If this system is the UPS manager (i.e. it's connected to this UPS directly and can manage it using a suitable NUT driver), its `upsmon` is the primary: MONITOR myupsname@mybox 1 monuser mypass primary If it's just monitoring this UPS over the network, and some other system is the primary, then this one is a secondary: MONITOR myupsname@mybox 1 monuser mypass secondary The number `1` here is the "power value". This should always be set to 1, unless you have a very special (read: expensive) system with redundant power supplies. In such cases, refer to the User Manual: - <>, - <>. Note that the "power value" may also be 0 for a monitoring (administrative) system which only observes the remote UPS status but is not impacted by its power events, and so does not shut down when the UPS does. References: linkman:upsmon[8], linkman:upsmon.conf[5] Define a SHUTDOWNCMD for upsmon ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Still in 'upsmon.conf', add a directive that tells `upsmon` how to shut down your system. This example seems to work on most systems: SHUTDOWNCMD "/sbin/shutdown -h +0" Notice the presence of "quotes" here to keep it together. If your system has special needs (e.g. system-provided shutdown handler is ungracefully time constrained), you may want to set this to a script which does customized local shutdown tasks before calling `init` or `shutdown` programs to handle the system side of this operation. Start upsmon ^^^^^^^^^^^^ :; upsmon If it complains about something, then check your configuration. On operating systems with service management frameworks, the monitoring client life-cycle is managed by `nut-monitor` service. Checking upsmon ^^^^^^^^^^^^^^^ Look for messages in the `syslog` to indicate success. It should look something like this: May 29 01:11:27 mybox upsmon[102]: Startup successful May 29 01:11:28 mybox upsd[100]: Client monuser@192.168.50.1 logged into UPS [myupsname] Any errors seen here are probably due to an error in the config files of either `upsmon` or `upsd`. You should fix them before continuing. Startup scripts ^^^^^^^^^^^^^^^ NOTE: This step is not need if you installed from packages. Edit your startup scripts, and add a call to `upsmon`. Make sure `upsmon` starts when your system comes up. On systems with `upsmon` primary (also running the data server), do it after `upsdrvctl` and `upsd`, or it will complain about not being able to contact the server. You may delete the `POWERDOWNFLAG` in the startup scripts, but it is not necessary. `upsmon` will clear that file for you when it starts. NOTE: Init script examples are provide in the 'scripts' directory of the NUT source tree, and in the various <<_binary_packages,packages>> that exist. Shutdown scripts ^^^^^^^^^^^^^^^^ NOTE: This step is not need if you installed from packages. Edit your shutdown scripts, and add `upsdrvctl shutdown`. You should configure your system to power down the UPS after the filesystems are remounted read-only. Have it look for the presence of the `POWERDOWNFLAG` (from linkman:upsmon.conf[5]), using this as an example: ------------------------------------------------------------------------------ if (/sbin/upsmon -K) then echo "Killing the power, bye!" /sbin/upsdrvctl shutdown sleep 120 # uh oh... the UPS power-off failed # you probably want to reboot here so you don't get stuck! # *** see also the section on power races in the FAQ! *** fi ------------------------------------------------------------------------------ A more elaborate example can be found in NUT sources, e.g.: https://github.com/networkupstools/nut/blob/master/scripts/systemd/nutshutdown.in [WARNING] ============================================================================== - Be careful that `upsdrvctl shutdown` command will probably power off your machine and others fed by the UPS(es) which it manages. Don't use it unless your system is ready to be halted by force. If you run RAID, read the <<_raid_warning,RAID warning>> below! - Make sure the filesystem(s) containing `upsdrvctl`, `upsmon`, the `POWERDOWNFLAG` file, 'ups.conf' and your UPS driver(s) are mounted (possibly in read-only mode) when the system gets to this point. Otherwise it won't be able to figure out what to do. - If for some reason you can not ensure `upsmon` program is executable at this point, your script can `(test -f /etc/killpower)` in a somewhat non-portable manner, instead of asking `upsmon -K` for the verdict according to its current configuration. ============================================================================== [[Testing_shutdowns]] Testing shutdowns ^^^^^^^^^^^^^^^^^ UPS equipment varies from manufacturer to manufacturer and even within model lines. You should test the <> on your systems before leaving them unattended. A successful sequence is one where the OS halts before the battery runs out, and the system restarts when power returns. The first step is to see how `upsdrvctl` will behave without actually turning off the power. To do so, use the `-t` argument: :; upsdrvctl -t shutdown It will display the sequence without actually calling the drivers. You can finally test a forced shutdown sequence (FSD) using: :; upsmon -c fsd This will execute a full shutdown sequence, as presented in <>, starting from the 3rd step. If everything works correctly, the computer will be forcibly powered off, may remain off for a few seconds to a few minutes (depending on the driver and UPS type), then will power on again. If your UPS just sits there and never resets the load, you are vulnerable to a power race and should add the "reboot after timeout" hack at the very least. Also refer to the section on power races in the link:FAQ.html[FAQ]. Using suspend to disk ~~~~~~~~~~~~~~~~~~~~~ Support for suspend to RAM and suspend to disk has been available in the Linux kernel for a while now. For obvious reasons, suspending to RAM isn't particularly useful when the UPS battery is getting low, but suspend to disk may be an interesting concept. This approach minimizes the amount of disruption which would be caused by an extended outage. The UPS goes on battery, then reaches low battery, and the system takes a snapshot of itself and halts. Then it is turned off and waits for the power to return. Once the power is back, the system reboots, pulls the snapshot back in, and keeps going from there. If the user happened to be away when it happened, they may return and have no idea that their system actually shut down completely in the middle (although network connections will drop). In order for this to work, you need to shutdown NUT (UPS driver, `upsd` server and `upsmon` client) in the `suspend` script and start them again in the `resume` script. Don't try to keep them running. The `upsd` server will latch the FSD state (so it won't be usable after resuming) and so will the `upsmon` client. Some drivers may work after resuming, but many don't and some UPS devices will require re-initialization, so it's best not to keep them running either. NOTE: Starting with NUT v2.8.3, there is some growing support for system-wide sleep on some platforms (e.g. to catch the "going to sleep" event and make a note of it in the daemons, to take the least-surprise corrective actions after a significant change in system clock readings), but the warnings in previous paragraph may still apply. After stopping NUT driver, server and client you'll have to send the UPS the command to shutdown only if the `POWERDOWNFLAG` is present. Note that most likely you'll have to allow for a grace period after calling `upsdrvctl shutdown` since the system will still have to take a snapshot of itself after that. Not all drivers and devices support this, so before going down this road, make sure that the one you're using does. - see if you can query or configure settings named like `load.off.delay`, `ups.delay.shutdown`, `offdelay` and/or `shutdown_delay` RAID warning ~~~~~~~~~~~~ If you run any sort of RAID equipment, make sure your arrays are either halted (if possible) or switched to "read-only" mode. Otherwise you may suffer a long resync once the system comes back up. The kernel may not ever run its final shutdown procedure, so you must take care of all array shutdowns in userspace before `upsdrvctl shutdown` runs. If you use software RAID (md) on Linux, get `mdadm` and try using `mdadm --readonly` to put your arrays in a safe state. This has to happen after your shutdown scripts have remounted the filesystems. On hardware RAID or other kernels, you have to do some detective work. It may be necessary to contact the vendor or the author of your driver to find out how to put the array in a state where a power loss won't leave it "dirty". Our understanding is that most if not all RAID devices on Linux will be fine unless there are pending writes. Make sure your filesystems are remounted read-only and you should be covered. [[DataRoom]] Typical setups for enterprise networks and data rooms ----------------------------------------------------- The split nature of this UPS monitoring software allows a wide variety of power connections. This chapter will help you identify how things should be configured using some general descriptions. There are two main elements: 1. There's a UPS attached to a communication (serial, USB or network) port on this system. 2. This system depends on a UPS for power. You can play "mix and match" with those two to arrive at these descriptions for individual hosts: - A: 1 but not 2 - B: 2 but not 1 - C: 1 and 2 A small to medium sized data room usually has one 'C' and a bunch of 'Bs'. This means that there's a system (type 'C') hooked to the UPS which depends on it for power. There are also some other systems in there (type 'B') which depend on that same UPS for power, but aren't directly connected to it communications-wise. Larger data rooms or those with multiple UPSes may have several "clusters" of the "single 'C', many 'Bs'" depending on how it's all wired. Finally, there's a special case. Type 'A' systems are connected to an UPS's communication port, but don't depend on it for power. This usually happens when an UPS is physically close to a box and can reach the serial port, but the power wiring is such that it doesn't actually feed that box. Once you identify a system's type, use this list to decide which of the programs need to be run for monitoring: - A: driver and `upsd` - B: `upsmon` (in secondary mode) - C: driver, `upsd`, and `upsmon` (in primary mode, as the UPS manager) image:images/advanced.png[] To further complicate things, you can have a system that is hooked to multiple UPSes, but only depends on one for power. This particular situation makes it an `A` relative to one UPS, and a `C` relative to the other. The software can handle this -- you just have to tell it what to do. NOTE: NUT can also serve as a data proxy to increase the number of clients, or share the communication load between several `upsd` instances. If you are running large server-class systems that have more than one power feed, see the next section for information on how to handle it properly. [[BigServers]] Typical setups for big servers with UPS redundancy -------------------------------------------------- By using multiple `MONITOR` statements in 'upsmon.conf', you can configure an environment where a large machine with redundant power monitors multiple separate UPSes. image:images/bigbox.png[] Example configuration ~~~~~~~~~~~~~~~~~~~~~ For the examples in this section, we will use a server with four power supplies installed and locally running the full NUT stack, including `upsmon` in primary mode -- as the UPS manager. Two UPSes, 'Alpha' and 'Beta', are each driving two of the power supplies (by adding up, we know about the four power supplies of the current system). This means that either 'Alpha' *or* 'Beta' can totally shut down and the server will be able to keep running. The 'upsmon.conf' configuration which reflects this is the following: MONITOR ups-alpha@myhost 2 monuser mypass primary MONITOR ups-beta@myhost 2 monuser mypass primary MINSUPPLIES 2 With such configuration, `upsmon` on this system will only shut down when both UPS devices reach a critical (on battery + low battery) condition, since 'Alpha' and 'Beta' each provide the same power value. As an added bonus, this means you can move a running server from one UPS to another (for maintenance purpose for example) without bringing it down since the minimum sufficient power will be provided at all times. The `MINSUPPLIES` line tells `upsmon` that we need at least 2 power supplies to be receiving power from a good UPS (on line or on battery, just not on battery *and* low battery). NOTE: We could have used a 'Power Value' of `1` for both UPS, and have `MINSUPPLIES` set to `1` too. These values are purely arbitrary, so you are free to use your own rules. Here, we have linked these values to the number of power supplies that each UPS is feeding (2) since this maps better to physical topology and allows to throw a third or fourth UPS into the mix without much configuration headache. Multiple UPS shutdowns ordering ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you have multiple UPSes connected to your system, chances are that you need to shut them down in a specific order. The goal is to shut down everything but the one keeping `upsmon` alive at first, then you do that one last. To set the order in which your UPSes receive the shutdown commands, define the `sdorder` value in your 'ups.conf' device sections. [bigone] driver = usbhid-ups port = auto sdorder = 2 [littleguy] driver = mge-shut port = /dev/ttyS0 sdorder = 1 [misc] driver = blazer_ser port = /dev/ttyS1 sdorder = 0 The order runs from 0 to the highest number available. So, for this configuration, the order of shutdowns would be 'misc', 'littleguy', and then 'bigone'. NOTE: If you have a UPS that shouldn't be powered off when running `upsdrvctl shutdown`, set its `sdorder` to `-1`. Other redundancy configurations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are a lot of ways to handle redundancy and they all come down to how many power supplies, power cords and independent UPS connections you have. A system with a 1:1 cord:supply ratio has more wires stuffed behind it, but it's much easier to move things around since any given UPS drives a smaller percentage of the overall power. More information can be found in the linkdoc:user-manual[NUT user manual], and the various link:man/index.html[user manual pages]. nut-2.8.3/docs/asciidoc.txt0000644000200500020050000000073214777534445012534 00000000000000Using AsciiDoc in NUT ===================== Charles Lepple :Author Initials: CFL Intro ----- See the https://asciidoc-py.github.io/userguide.html[AsciiDoc User Guide] for more information. Works in Progress ----------------- - link:website/index.html[The NUT Website] - link:user-manual.html[The NUT User Manual] - link:developer-guide.html[The NUT Developer Guide] - link:packager-guide.html[The NUT Packager Guide] - link:man/index.html[Man pages] nut-2.8.3/docs/sms-brazil-protocol.txt0000644000200500020050000003617114777767434014714 00000000000000SMS Brazil Protocols ==================== Using the PowerView (accompanying UPS application for Windows) as source, there is a folder, called `protocols` inside the installed directory, e.g. `"C:\Alerta24h\SMS_Power_View\resource"`. There are 4 protocol files (`monofasico.xml`, `trifasico.xml`, `upsilon.xml` and `voltronic.xml`), and one file called `verificaProtocolo.xml`. The file `verificaProtocolo.xml` has serial/USB commands to be sent, to detect the UPS device. The file contents are: .verificaProtocolo.xml [source,xml] ---- QSG isNobreakVoltronic Resgata medidores e status do UPS G1 isNobreakTrifasico Detecta se o no-break é trifásico I isNobreakMonofasico Detecta se o no-break é monofásico Q1 isNobreakSinusTriad Resgata medidores e status do UPS ---- In the `sms_ser.c` and `sms_ser.h` there is only the `monofasico.xml` implementation, because is describes my UPS and I can implement and validate it. But it is totally valid if someone has another SMS_Brazil UPS and wanted to include another protocol, you can send me an email (looking in the `sms_ser.h` source to get it). Here is the `monofasico.xml` protocol: .monofasico.xml [source,xml] ---- Q MedidoresEstado Resgata medidores e status do UPS Q MedidoresEstadoDefault Resgata um bean com os valores pré-definidos para os medidores e status do UPS I Informacoes Resgata informações do UPS I InformacoesDefault Resgata informações do UPS The F Caracteristicas Resgata características do UPS F CaracteristicasDefault Resgata características default do UPS M MudaBeep Muda o beep L TesteBateriaBaixa Teste até bateria baixa T TestePorSegundos Teste por 'n' segundos S ShutdownPorSegundos Shutdown em n segundos R ShutdownRestore Shutdown e restore D CancelarTeste Cancelamento de Teste C CancelarShutdownRestore Cancelamento de Shutdown ou restore ---- nut-2.8.3/docs/FAQ.txt0000644000200500020050000014535114777767434011402 00000000000000ifndef::external_title[] NUT Frequently Asked Questions ============================== endif::external_title[] == I just upgraded, and ... You have read link:UPGRADING.adoc[UPGRADING] in the base directory of the distribution, right? If not, go read it now, then come back to this file if your question wasn't answered in there. == My UPS driver now says it's 'broken', and won't start. What now? Or a variation like... == My favorite UPS driver disappeared after an upgrade. What now? Drivers are occasionally removed from the tree if they are no longer receiving maintenance, or sometimes renamed to better reflect their hardware support scope or replaced by a more generic driver. There have been several architectural changes to the driver code in recent times, and drivers which were not converted by someone are eventually dropped. This is called progress. We do this in order to avoid a situation where someone believes that a driver is being maintained when it is actually rotting slowly in the tree. It also keeps the tree free of old compatibility hacks for code that nobody actually uses anyway. To get a driver back into current releases, you need to convert it yourself or get someone to do it for you. This is not difficult. The hardest part of any driver is decoding the protocol, and that's already been done in the old version. == My UPS driver program won't work. I'm starting it as root, and root owns the device, so what's the problem? *Answer 1* The drivers drop root privileges long before the serial or USB port is opened. You'll need to change the permissions on that port so that their new user id can access it. Normally this is 'nobody', but it may be changed at compile-time by using `configure --with-user` or in the `ups.conf` file for driver settings with `user=...`. Read the error message. If you have a permissions mismatch, then you'll see something like this: Network UPS Tools - APC Smart protocol driver 0.60 (1.1.7) This program is currently running as youruid (UID 1234) /dev/ttyS2 is owned by user root (UID 0), mode 0600 Change the port name, or fix the permissions or ownership of /dev/ttyS2 and try again. Unable to open /dev/ttyS2: Permission denied Now is a good time to point out that using 'nobody' is a bad idea, since it's a hack for NFS access. You should create a new role account (perhaps called 'ups' or 'nut'), and use that instead. Also, scroll down to the "security domains" question to see an even better way of restricting privileged operations. Neither the drivers nor `upsd` ever need 'root' powers, and that answer tells you how to make it work. *Answer 2* You can also specify a user with `user=` in the global part of linkman:ups.conf[5]. Just define it before any of your `[sections]`: ---- user = nut [myups] driver = mge-shut port = /dev/ttyS0 ---- == upsc, upsstats, and the other clients say 'access denied'. The device communication port (serial, USB or network) permissions are fine, so what gives? In this case, "access denied" means the access to linkman:upsd[8], not the device communication port. You're being denied since the system has no permission to speak to `upsd` according to its access controls. There can be due to various reasons. To fix it, check: - the LISTEN directive in linkman:upsd.conf[5]. It should allow your local or remote access method, - your firewall rules. Port '3493/tcp' must be opened to incoming connections, - your *tcp-wrappers* configuration (`hosts.allow` and `hosts.deny`) if used. Refer to the linkman:upsd[8] and linkman:upsd.conf[5] man pages for more information. == I get a 'not listening on...' error from upsd. Verify your LISTEN directive. It should be one of the valid IP addresses for the computer running `upsd` (or `0.0.0.0`, which is `INADDR_ANY`), not an address for a client. The LISTEN directive lets you pick which interface `upsd` listens on. If you are trying to limit the clients which can connect to `upsd`, you either need to use tcp-wrappers or kernel firewall rules. This isn't a NUT-specific limitation -- it applies equally to your web server or mailer daemon. == Which UPS should I buy? One with a no-questions-asked money-back guarantee. Seriously. The NUT developers cannot take responsibility for recommending an UPS (see the LICENSE file for more details on the explicit lack of warranty), only to find out that the manufacturer has changed the internals of the UPS without changing the model name. That said, from time to time, certain vendors have helped out by providing hardware for testing, results of their testing efforts, or protocol specifications. We try to publish this information on the NUT website, so you can take this into consideration when selecting an UPS brand. == I have an APC Smart-UPS connected with a grey APC serial cable and it won't work. The Back-UPS type in the genericups driver works but then I don't get to use all the nifty features in there. Why doesn't the right driver work? The problem lies in your choice of cable. APC's grey cables generally only do "dumb" signalling -- very basic yes/no info about the battery and line status. While that is sufficient to detect a low battery condition while on battery, you miss out on all the goodies that you paid for. Note that the 940-0095B happens to be a grey cable, but it is actually a dual mode cable and can be used in smart mode. If you have this cable, you need to edit your ups.conf to look like this: [myups] driver = apcsmart port = /dev/whatever cable = 940-0095B All other grey cables from APC are assumed to be "dumb". If your grey cable isn't the 940-0095B, the solution is to dump that cable and find one that supports APC's "smart" signalling. Typically these come with the UPS and are black. If your smart cable has wandered off, one can be built rather easily with some connectors and cable -- there's no fancy wiring or resistors. See this URL for a handy diagram: https://www.networkupstools.org/cables/940-0024C.jpg There is also a text version of that diagram in the docs/cables directory of the NUT source distribution. Either one should allow you to build a good clone of APC's 940-0024C cable. There are simpler solutions involving 3 wires that work just fine too, but Powerchute won't find the loopback DTR-DCD and RTS-CTS and will be annoyed. If you don't ever plan to use Powerchute, 3 wires (RxD, TxD, GND) are sufficient. It should also be noted that the genericups driver has no way to detect the UPS, so it will fire up quite happily if it can open the serial port. Merely having it start up is not necessarily an indication of success. You should start it and then check the status with upsc or similar to be sure that it's reading the hardware properly. == Why doesn't upsd implement the functionality of upsmon? I have to run THREE programs to monitor my UPS! *Answer 1* We try to follow the "tool for the job" philosophy of Unix. It may mean more programs running, but the flexibility you get is usually worth it. Yes, the machine with the UPS attached will generally have 3 processes (driver, `upsd`, `upsmon`) running, but this design allows a much bigger setup. Imagine a data room with a bunch of machines all drawing power from the same UPS. Only one can be connected by a serial or USB cable, and the rest of them just run an `upsmon` client. Besides, if `upsmon` were rolled into `upsd`, `upsd` would get even bigger than it is now. You'd have one less process, but the RAM consumption would be pretty close to what you have now -- but consumed on each system involved. See the "Data Room" section in link:docs/config-notes.txt[] for more configuration ideas and explanations. *Answer 2* If this really bothers you, roll up your sleeves and use the linkman:sockdebug[8]] code to write a "upsmon" type program that sits on top of the state sockets. It won't work over the network, but it means you don't need `upsd`. It also means only one host can monitor the UPS. This is also a good option to consider if you can't use networked monitoring code for security or safety reasons. *Answer 3* There are plans in the queue... for a long time... to extend `upsd` data server and the NUT clients with ability to use a local Unix socket for the NUT Networked protocol. This would also allow to forgo the dependency on TCP/IP stack for communications within one machine. See the TODO file for more on this and other related topics. == Why isn't upssched part of upsmon? Most users will never have any reason to use `upssched`. It's complicated, and getting it right for your situation can be tricky. Having it live in a separate program saves resources and lets most people avoid it completely. It is also coherent with the answer to the previous question. == Why doesn't upsmon send a SIGPWR signal to init so it can deal with power events? *Answer 1* New versions of the `init` man page taken from the *sysvinit* package are saying that usage of `SIGPWR` is discouraged, since `/dev/initctl` control channel is the preferred way of communication. *Answer 2* The name of the game is portability. Not everyone's `init` handles that kind of signalling gracefully. What's more, some admins might want to do things differently even if they have that kind of `init` running. So, to be compatible, upsmon just invokes a shell command. If you want to use init's `SIGPWR` stuff, just put the right "kill" line in a shell script and make your `upsmon` call it. Everyone wins. == Why won't bestups talk to my Best Fortress UPS? There are at least two different protocols being used for hardware with very similar names. The bestups driver tends to support the units built around the newer "PhoenixTec" protocol, and the bestfortress driver supports the older Best hardware. There is a similar problem with the tripplite_usb driver: it only supports the older, proprietary protocol. Newer standards-compliant Tripp Lite UPS models are supported by usbhid-ups. We name drivers based on the information available at the time the driver was first written, which often is incomplete. == What's this about 'data stale'? It means your UPS driver hasn't updated things in a little while. upsd refuses to serve up data that isn't fresh, so you get the errors about staleness. If this happens to you, make sure your driver is still running. Also look at the syslog. Sometimes the driver loses the connection to the UPS, and that will also make the data go stale. This might also happen on certain virtualization platforms. If you cannot reproduce the problem on a physical machine, please report the bug to the virtualization software vendor. If this happens a lot, you might consider cranking up DEADTIME in the upsmon.conf to suppress some of the warnings for shorter intervals. Use caution when adjusting this number, since it directly affects how long you run on battery without knowing what's going on with the UPS. Note: some drivers occasionally need more time to update than the default value of MAXAGE (in `upsd.conf`) allows. As a result, they are temporarily marked stale even though everything is fine. This can happen with MGE Ellipse equipment -- see the linkman:mge-shut[8] or linkman:usbhid-ups[8] man pages. In such cases, you can raise the value of MAXAGE to avoid these warnings; try a value like 25 or 30. == Why do the client programs say 'Driver not connected' when I try to run them? *Answer 1* This means that `upsd` can't connect to the driver for some reason. Your `ups.conf` entry might be wrong, or the driver might not be running. Maybe your state path is not configured properly. Check your syslog. upsd will complain regularly if it can't connect to a driver, and it should say why it can't connect. Note: if you jumped in with both feet and didn't follow the link:INSTALL.nut[] document, you probably started `upsd` by itself. You have to run `upsdrvctl start` (explicitly -- on legacy systems only) to start the drivers after configuring `ups.conf`. On operating systems with a supported service management framework, you might wrap your NUT drivers into individual services instances with `upsdrvsvcctl resync` and then manage those with commands like `upsdrvsvcctl stop` and `upsdrvsvcctl start` (note that on other systems this tool may be not pre-installed via packaging). In fact, service instances prepared by the `nut-driver-enumerator` script and service based on contents of your `ups.conf` file and automatically maintained by the respective framework can conflict with manual execution of drivers, so `upsdrvctl` would emit a warning in NUT builds with that capability (can be silenced by exporting a `NUT_QUIET_INIT_NDE_WARNING` environment variable with any value). *Answer 2* Some USB UPS devices have unreliable USB to serial interfaces. In that case, it's advised to unplug / plug the device and try again. If that resolves the issue, you should consider resetting the USB hub the device is attached to before starting the nut driver, using `usb_resetter` script (for Linux) from https://github.com/netinvent/usb_resetter See files under `scripts/usb_resetter/` in NUT sources for more information. == Why don't the pathnames in your documentation match the package I installed? Each distribution has conventions for where specific file types should be stored. The NUT project cannot possibly track all of these conventions, so the documentation assumes the default installation directory prefix of `/usr/local/ups` when describing file locations. It also allows custom builds of NUT to minimally conflict with files of a packaged installation. The distributions tend not to change the base name of the files, so you can search for drivers and configuration files in the package database of installed files. For instance, on Debian or Ubuntu derivatives, you can use `dpkg --search usbhid-ups` to see where the drivers are stored. == Everything works perfectly during the shutdown, and the UPS comes back on, but my system stays off. What's happening? Assuming you don't have the problem in the next question, then you probably have an ATX motherboard, have APM or ACPI enabled in your kernel (assuming Linux here), and are reaching the 'halt' at the bottom of your shutdown scripts. Your machine obeys and shuts down, and stays down, since it remembers the 'last state' when the UPS restarts. One solution is to change your shutdown scripts so you never reach that point. You *want* the system to die without reaching the part where the kernel tells it to shut down. A possible script might look like this (see `scripts/systemd/nutshutdown` in NUT sources for a more streamlined and modern variant): ------ # other shutdown stuff here (mount -o remount,ro ...) # `upsmon -K` if available on still mounted filesystems # at this point is more portable than the `test` below if (test -f /etc/killpower || /sbin/upsmon -K) then /sbin/upsdrvctl shutdown sleep 600 # this should never return # uh oh, we never got shut down! (power race?) reboot fi halt -p ------ The other solution is to change your BIOS setting to "always power on" instead of "last state", assuming that's possible. == My system has an ATX power supply. It will power off just fine, but it doesn't turn back on. What can I do to fix this? This depends on how clueful your motherboard manufacturer is, and isn't a matter of the OS. You have to do one of the following things depending on what's supported: - Set a jumper on the motherboard that means "return after outage" - Set something in the BIOS that says "power up after power failure" - Try using something (like a capacitor) across the power button to "push" it for you -- this might not work if it needs a delay - Hack the cable between the power supply and the motherboard to fool it into powering up whenever line power is present - Teach a monkey to watch the machine and press the power button when the outage is over. This might work, but it creates high produce bills. If you can't use one of the first two options, give the board to an enemy. Let them worry about it. == My Mac won't power back up by itself into Linux after the UPS shuts down. What can I do about this? This is about the same situation as the ATX question above, only worse. Earlier Macs apparently supported a hack where you could cat some magic characters at `/dev/adb` to enable "server mode". This would instruct the system to reboot while unattended. From Usenet post <6boftzxz51.fsf@ecc-office.sp.cs.cmu.edu>: ------ # Send packet over the ADB bus to the PowerMac CUDA chip # telling it to reboot automatically when power is restored # after a power failure. cat /etc/local/autoboot.adb > /dev/adb # autoboot.adb contains these three bytes (in hex): 01 13 01 ------ Later PowerPC Macs with a PMU and the appropriate kernel driver can achieve the same effect with the following command: echo server_mode=1 > /proc/pmu/options The following pages have some slightly more kludgy answers which involve the use of `setpci`, and are highly model-specific: - https://www.mythic-beasts.com/support/servers/colo/macminicolo_howto - http://superuser.com/questions/212434/reboot-after-power-failure-for-mac-running-ubuntu - http://ubuntuforums.org/showthread.php?t=1209576 Note: this question has been in the FAQ for several years now, and there's still no clean answer. Let me guess: everyone who runs a server on Mac hardware has a team of trained monkeys, and feeds them by growing bananas in the tropical environment formed by waste heat from the equipment. The rest of us are still waiting for the answer. Booting into the Mac OS to frob the "file server" panel is not an acceptable solution. == My Mac won't power back up by itself into Mac OS X after the UPS shuts down. What can I do about this? This is relatively simple to fix. If you have console or VNC access, log in as an administrator, go to System Preferences, click on Energy Saver, click on the options tab, check "Restart automatically after a power failure". Alternatively, you can connect via SSH and run `sudo pmset autorestart 1` to achieve the same effect. == I want to keep the drivers and upsd in their own security domains. How can this be accomplished? Using a few role accounts and a common group, you can limit access to resources such as the serial port(s) leading to the UPS hardware. This is just an example. Change the values to suit your systems. - Create a user called 'nutdev' and another called 'nutsrv'. Put them both in a group called 'nut'. - Change the owner of any serial ports that will be used to nutdev, and set the mode to 0600. Then change the ownership of your state directory (usually /var/state/ups) to nutdev.nut. For my development system this yields the following /dev entries: 0 crw------- 1 nutdev tty 4, 64 Sep 3 17:11 /dev/ttyS0 0 crw------- 1 nutdev tty 4, 65 Sep 3 17:11 /dev/ttyS1 - Switch to root, then start the drivers: # upsdrvctl -u nutdev start - The listing for /var/state/ups then looks like this: 4 drwxrwx--- 2 nutdev nut 4096 Aug 20 18:37 . 4 drwxr-xr-x 4 root root 4096 May 14 21:20 .. 4 srw-rw---- 1 nutdev nut 0 Sep 3 17:10 apcsmart-ups1 4 srw-rw---- 1 nutdev nut 0 Sep 3 17:10 blazer_ser-ups2 You may have to remove old socket or state files first if you are changing to this security scheme from an older version. The drivers will create new files with the right owners and modes. Note that `/var/state/ups` is group writable since `upsd` will place the `upsd.pid` file here by default. You may have to change the groups of `upsd.conf` and `upsd.users` to make them readable to the NUT `upsd` program. These files should not be owned nor writable by `nutsrv`, since someone could compromise the daemon and change the config files. Instead, put `nutsrv` in a group (`nut` in this example), then make the files owned by `root.nut`, with POSIX bits mode `0640`. Once the config files are ready, start upsd: :; upsd -u nutsrv Check your syslog to be sure everything's happy, then be sure to update your startup scripts so it uses this procedure on your next boot. If you like this, you'll probably also find the linkmanext:chroot[2] process to be useful and interesting. See link:security.txt[] for more details. == What's the point of that 'security domains' concept above? The point is limiting your losses. If someone should happen to break into `upsd` in that environment, they should only gain access to that one user account. Direct access to the serial device is not possible, since that is owned by another user. There is also the possibility of running the drivers and `upsd` in a chroot jail. See the `chroot` option in link:security.txt[], `upsd` and driver documentation. Why give would-be vandals any sort of help? Put it this way -- I *wrote* good chunks of this stuff, and I still run the programs this way locally. You should definitely consider using this technique. == How can I make upsmon shut down my system after some fixed interval? You probably don't want to do this, since it doesn't maximize your runtime on battery. Assuming you have a good reason for it (see the next entry), then look at link:scheduling.txt[] or the linkman:upssched[8] man page for some ideas. ///////////////////////////////////////////////////////////////// TODO: figure out how to link to the upssched man page above. ///////////////////////////////////////////////////////////////// == Why doesn't upsmon shut down my system? I pulled the plug and nothing happened. Wait. The `upsmon` client doesn't consider a UPS to be critical until it's *both* 'on battery' and 'low battery' at the same time. This is by design. Nearly every UPS supports the notion of detecting the low battery all by itself. When the voltage drops below a certain point, it _will_ let you know about it. If your system has a really complicated or time-consuming shutdown procedure, you might need to shut down before the UPS raises the low battery flag. For most users, however, the default behavior is adequate. Ask yourself this: why buy a nice big UPS with the matching battery and corresponding runtime and then shutdown early? If anything, I'd rather have a few more minutes running on battery during which the power might return. Once the power's back, it's business as usual with no visible interruption in service. If you purposely shut down early, you guarantee an interruption in service by bringing down the box. See link:upssched.txt[] for information on how you can shutdown early if this is what you really want to do. == The CGI programs report 'access to that host is not authorized' -- what's going on? Those programs need to see a host in your hosts.conf before they will attempt communications. This keeps people from feeding it random `host=` settings, which would annoy others with outgoing connection attempts from your system. If your linkman:hosts.conf[5] turns out to be configured correctly with proper `MONITOR` entries and all that, check the permissions. Your web server may be running the CGI programs as a user that can't read the file. If you run your web server in a chroot jail, make sure the programs can still read `hosts.conf`. You may have to copy it into the jail for this to work. If you do that, make sure it's not writable by any of the user accounts which run inside the jail. == upsd is running, so why can't I connect to it? Assuming you haven't changed the TCP port number on the command line or at compile-time, then you may have some sort of firewall blocking the connection. `upsd` listens on TCP port '3493' by default. If you do not specify a `LISTEN` directive in `upsd.conf`, `upsd` only listens on the loopback interface. See the linkman:upsd.conf[5] man page for details. == How do you make upsmon reload the config file? Or a variation like... == How do you make upsd reload the config file? Either find the pid of the background process and send it a SIGHUP, or just start it again with '-c reload' (requires that the previously started daemon saves a PID file). If you send the signals yourself instead of using -c, be sure you hit the right process. There are usually two `upsmon` processes, and you should only send signals to one of them. To be safe, read the PID file. If your daemons are managed as systemd units, it is more idiomatic to use the framework commands, e.g. `systemctl reload nut-server` (upsd) or `systemctl reload nut-monitor` (upsmon). Note that the implementation of `nut-server.service` by default starts `upsd -F` and does not save a PID file; if your workflow requires to use plain `upsd -c reload`, you should customize the unit (with a drop-in file) to start `upsd -FF`. NUT releases after 2.8.0 define aliases for these units, so if your Linux distribution uses NUT-provided unit definitions, `systemctl reload upsd` may also work. == I just bought a new WhizBang UPS that has a USB connector. How do I monitor it? There are several driver to support USB models. - linkman:usbhid-ups[8] supports various manufacturers complying to the HID Power Device Class (PDC) standard, - linkman:tripplite_usb[8] supports various older Tripp-Lite units (with USB ProductID 0001) - linkman:bcmxcp_usb[8] supports various Powerware units, - linkman:blazer_usb[8] supports various manufacturers that use the Megatec / Q1 protocol. - linkman:nutdrv_qx[8] supports various manufacturers that use the wider Megatec / Q* protocol family. This is the driver slated to receive all further development in this area, it was specially designed to support many more sub-drivers and has added a lot over time, so please do try it first nowadays. - linkman:apc_modbus[8] supports some APC branded devices built after 2010 (requires to be built against a libmodbus version with RTU USB support) Refer to the respective 'driver-name' (8) man page for more information. You can also consult the Hardware Compatibility List (HCL) and filter on USB: https://www.networkupstools.org/stable-hcl.html?connection=USB == My USB UPS has a bogus Vendor ID 0x0001 and Product ID 0x0000, what driver supports it? Unfortunately, many devices are made without registering as a Vendor with the corresponding standards body, and use generic USB chips for interfacing with a computer (roughly similar to using a network interface card with a random MAC address and PCI ID, and thus poorly identifiable device specifics needed to automatically load some certain driver). Often they also lack a unique serial number field, so monitoring several devices is problematic. One frequent case is with devices identifying as "Fry's Electronics" and/or "MEC0003", if those metadata are served at all, or plain "0001/0000" in ID field. In some cases they are accompanied by "UPSmart" software with a "MEGA(USB)" connection option that works for Windows users. Your best bet is to search for community discussions of issues on NUT GitHub at https://github.com/networkupstools/nut/issues?q=is%3Aissue and try options there. Devices with these chips were known to connect with drivers for such unrelated protocols as Megatec Q* (different sub-drivers, often `fabula` or `hunnox`), ATCL, or USB-HID. == My USB UPS is supported but doesn't work! On Linux, udev rules are provided to set the correct permissions on device file. This allows the NUT driver to communicate with the UPS, through this device file. However, the driver may still fail to start and support the device, with a message like: failed to claim USB device: could not claim interface 0: Operation not permitted *Operation not permitted* is a message pointing to a privilege issue. The most frequent issue is that udev has not actually applied the rule: - if NUT has been freshly installed, - and if the device USB cord was already plugged when installing NUT. In this case, just unplug and plug back the USB cord, then restart NUT. Instead of unplugging, you might also be able to run `udevadm trigger --subsystem-match=usb --action=change` to fix permissions. There was a mistake in the naming of the NUT udev rules file which resulted in the rules being overridden by another udev configuration file. While this has been fixed in the Git master branch, your distribution may still be affected. Details are available in the following GitHub issue: https://github.com/networkupstools/nut/issues/140 There may also be a conflict with an already running instance of the driver, e.g. when a systemd unit instance `nut-driver@yourdevicename.service` was automatically created and started by the `nut-driver-enumerator`, and then you try to follow older revisions of the NUT documentation or blogs, and start another copy with `upsdrvctl` (which should only be used on legacy systems nowadays). == Why do you not use the Linux kernel HID driver when communicating with USB UPSes? When the `usbhid-ups` was first written, it replaced an older driver `hidups` which used the Linux kernel USB HID API. At the time, the kernel HID API could not distinguish between identical Usage IDs that were nested in different parent IDs, so many common measurements were not available from `hidups`. For this reason, the libusb approach was chosen, which has the added side effect of being more portable than the Linux HID API. The Linux hiddev device nodes have very similar permissions problems as the `/dev/bus/usb` nodes that the libusb approach uses. Due to difficulties in running libusb on OS X and Windows, those platforms might actually benefit more from a native HID approach. == I get a message from the kernel that the driver "did not claim interface 0 before use" On Linux, if two copies of a driver are competing for the UPS, these messages will appear in dmesg: usbfs: process 29641 (usbhid-ups) did not claim interface 0 before use This can be a symptom of a source install conflicting with a package install. There is a rudimentary locking mechanism in NUT, but there is a chance that the packages might not use the same directory as the NUT default, and the conflict will be reported by the kernel. Also see above about conflicts between driver instances started by a service management framework like systemd and started manually (e.g. with `upsdrvctl`). == Why does my (Eaton 5E) USB UPS on Linux connect but quickly disconnects soon? This issue was extensively investigated by NUT community members in https://github.com/networkupstools/nut/issues/630 and resulted in a chain of distribution bugs logged such as https://bugzilla.redhat.com/show_bug.cgi?id=1715504 The gist of it is that some versions of Linux kernel used an "USB HID quirk" for certain devices, see Linux kernel source `drivers/hid/hid-quirks.c` file, including MGE/Eaton vendor ID (0x0463) based on an older device a contributor had issues with. Firmware in newer devices no longer had the bug which needed the "quirk" and misbehaved when it was enabled. While newer (and much older) Linux kernels should not have the problem, with the quirk removed according to https://lkml.org/lkml/2018/11/26/580 having the issue in the field really depends on the combination of Linux kernel and device firmware that meet. Either way, it seems that problematic combinations preclude Linux from seeing the device as a `hid-generic` first, to hand it over to a NUT driver. This quirk can be tuned with a kernel boot parameter (via GRUB etc.): usbhid.quirks=0x0463:0xffff:0x08 to re-enable the NOGET quirk. For context, according to https://bugzilla.redhat.com/show_bug.cgi?id=1875532 the symptoms for the problem look like this: # Plug in the UPS and observe the dmesg logs, # the following continuously appears: [ 93.568082] usb 1-6: new full-speed USB device number 9 using xhci_hcd [ 94.311469] usb 1-6: New USB device found, idVendor=0463, idProduct=ffff, bcdDevice= 0.01 [ 94.311475] usb 1-6: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 94.311483] usb 1-6: Product: 5E [ 94.311486] usb 1-6: Manufacturer: EATON [ 96.269989] hid-generic 0003:0463:FFFF.000A: hiddev96,hidraw2: USB HID v1.10 Device [EATON 5E] on usb-0000:00:14.0-6/input0 [ 107.369425] hid-generic 0003:0463:FFFF.000A: usb_submit_urb(ctrl) failed: -1 [ 107.369469] hid-generic 0003:0463:FFFF.000A: timeout initializing reports [ 112.828826] usb 1-6: USB disconnect, device number 9 [ 113.284452] usb 1-6: new full-speed USB device number 10 using xhci_hcd [ 114.027693] usb 1-6: New USB device found, idVendor=0463, idProduct=ffff, bcdDevice= 0.01 [ 114.027698] usb 1-6: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 114.027701] usb 1-6: Product: 5E [ 114.027704] usb 1-6: Manufacturer: EATON [ 115.984222] hid-generic 0003:0463:FFFF.000B: hiddev96,hidraw2: USB HID v1.10 Device [EATON 5E] on usb-0000:00:14.0-6/input0 [ 126.825756] hid-generic 0003:0463:FFFF.000B: usb_submit_urb(ctrl) failed: -1 [ 126.825775] hid-generic 0003:0463:FFFF.000B: timeout initializing reports [ 132.527809] usb 1-6: USB disconnect, device number 10 A similar report on the driver side may look like: usbhid-ups[4554]: libusb_get_report: Input/output error upsd[4591]: Data for UPS [eaton] is stale - check driver usbhid-ups[4554]: Can't claim USB device [0463:ffff]: No such file or directory upsd[4591]: Can't connect to UPS [eaton] (usbhid-ups-eaton): No such file or directory upsmon[5148]: Poll UPS [eaton@localhost] failed - Driver not connected upsmon[5148]: Communications with UPS eaton@localhost lost Other similar looking issues may include improper setup of udev, upower and similar frameworks to hand over the device from the OS to a driver daemon; competition with other software probing USB devices (ModemManager was mentioned in this context), including running several copies of the NUT drivers trying to use same port (e.g. one started by services and another manually as you tried to debug the problems). Software quirks aside, please do test with a different USB cable and/or port on the computer. These were known to cause grief beyond what can be fixed with a few key words ;) Finally, sometimes the issue is on the OS side (and/or USB chipset), to the point that the USB driver can not be unloaded and re-attached until you power cycle the system. == Why doesn't my package work? Or a variation like... == I can't run this because there's no package for it. Why isn't this in a package yet? Sorry, can't help you there. All official releases are source code and are posted on https://www.networkupstools.org/ along with PGP signatures for verification. This means all packages have been built by a third party. If you have an issue that's related to packaging, you will need to seek help with whoever built it for you. == My UPS is directly connected to an appliance with a limited version of NUT, how can I monitor the UPS from arbitrary clients? You can set up a separate general-purpose system as the NUT server for your "arbitrary clients", using `dummy-ups` in "relay mode" as the driver. This instance of `dummy-ups` would in turn be the NUT client allowed to interact with the appliance and that way with the UPS connected there. NOTE: The original question related to a NAS with NUT provided in its firmware OS, that only allowed one or few clients and not a whole rack's worth of client IP addresses. == My networked UPS can't handle being monitored by dozens of NUT clients Network management cards on many UPSes are rather puny appliances, often known to either limit the amount of clients who may connect, for security or performance reasons, or otherwise to crash or respond very slowly when overwhelmed. You may be better off reducing the amount of servers connected to the UPS with the `snmp-ups`, `netxml-ups` or similar type of driver, and set up other systems as clients of these NUT servers. Developers who are working on NUT, its drivers, or further projects and appliances based on NUT, and who need to monitor their UPS from multiple systems using the complete NUT stack on each system (e.g. during testing), can benefit from dedicating a separate general-purpose system as the NUT server using the real (networked) driver for the UPS, while using the `dummy-ups` in "relay mode" as the driver connected to this dedicated server on each tested system. == How can I setup NUT as a proxy (setup a server to forward/relay client data)? This can easily be achieved by using the `dummy-ups` driver. The `port` field acts as the reference to the "other" UPS served by another NUT server. Example with `dummy-ups` driver: ---- [proxy] driver = dummy-ups port = upsname@ip-or-hostname[:port] desc = "UPS proxy for UPS upsname on server ip-or-hostname" ---- Also note that there is a `clone` driver with similar purpose, which allows users to group clients to a particular outlet of a device with a "real" driver running locally, and deal with this output as if it was a normal UPS. Here the `port` field references the driver socket name that the "real" UPS driver is using. See its manual page for more details and caveats. Example with `clone` driver: ---- [realups] driver = usbhid-ups port = auto [clone-outlet-1] driver = clone port = usbhid-ups-realups load.on = outlet.1.load.on load.off = outlet.1.load.off load.status = outlet.1.status [...] ---- This allows to group load attached to a separately manageable outlet (or group of outlets) on larger UPS and ePDUs, in order to power those devices on/off together. This may be also useful to delegate management of feeds to devices for purposes like hosting or supporting hardware for smaller teams sharing a rack in a larger company. == Why are there two copies of upsmon running? It's not really two complete copies if your OS forks efficiently. By default, `upsmon` runs most of the grunt work as an unprivileged user and keeps a stub process around with 'root' powers that can only shut down the system when necessary. This should make it much harder to gain 'root' in the event a hole is ever discovered in `upsmon`. If this really bothers you and you like running lots of code as `root`, start `upsmon` with `-p` option, and it will go back to being one big process. This is not recommended, so don't blame us if something bad happens in this mode. == I get the following error while building: `make[4]: don't know how to make HP-UX/nut-drvctl.sh. Stop` *Answer 1* Current NUT codebase (since v2.8.0) is regularly tested with GNU, BSD and Sun implementations of `make`, so seeing failures in release snapshots (or iterations that made it to the master branch) is very surprising. Please raise an issue on GitHub. *Answer 2* Older NUT codebase (release tarballs) has some hidden dependencies on GNU Make which show up while running `make distcheck`. If you are running `make distcheck` or its variants, you will need to install GNU Make (`devel/gmake` in the ports tree), which is incidentally what the official FreeBSD port of NUT does for all builds. == I have 'some problem' with 'some old version' ... Get the latest stable release, and see if it still happens. If it goes away, it means someone else reported it and got it fixed a long time ago. You may want to search the mailing lists to see if someone else has experienced the same problem. If so, there is a good chance that someone else has worked through the process necessary to shoehorn the latest NUT version into your distribution (potentially with unofficial packages). Some OS distributions contain old versions of NUT. If your hardware is newer than the NUT release, there is a good chance that support has not been added yet. Please do not tell us you have the "latest version for Distro XYZ" -- even if the developers are familiar with that distribution, it helps others if you quote the exact package version. NOTE: Check the release date on the version you have. If it's more than about 6-12 months old, there's probably a newer stable tree version out there. As development happens actively, be sure to also check if a custom build from Git (usually using the `master` branch of NUT https://github.com/networkupstools/nut/ repository) has your issue fixed by some kind soul already. == I can't connect with SSL using old NUT on an appliance Unfortunately, some vendors do not issue new firmwares often, and even more rarely do they significantly update any programs inside. It is not uncommon to see NUT versions over a decade old delivered with small NAS boxes, for example. This may impact not only NUT protocol compatibility, but also transport protocols such as SSL -- as cipher algorithms get outdated over time, and ones deemed insecure are no longer handled at all (by default). This is not a problem limited to NUT: old SSH Key Exchange (kex) protocols or old HTTPS mechanisms also become hard or impossible to use eventually. On one hand, you can look into NUT configuration of `DISABLE_WEAK_SSL`. On another, you can modify configuration of the newer system to allow older algorithms as required by the older other system. For NUT built against OpenSSL, the change would be in `/etc/ssl/openssl.cnf` and similar to the diff block below: ---- --- a/etc/ssl/openssl.cnf +++ b/etc/ssl/openssl.cnf @@ -52,13 +52,6 @@ tsa_policy3 = 1.2.3.4.5.7 [openssl_init] providers = provider_sect +ssl_conf = ssl_sect + +[ssl_sect] +system_default = system_default_sect + +[system_default_sect] +CipherString = DEFAULT@SECLEVEL=0 # List of providers to load [provider_sect] ---- Of course, keep in mind that by doing this you degrade your security level. If better solutions are possible in your situation, prefer to follow them! Thanks to Kajetan Rzepecki for doing the research and posting the findings in https://github.com/networkupstools/nut/issues/1899 == I built NUT from Git, and it complains about lots of missing files. What happened? If you are not actively developing a driver, can you use a snapshot instead? The NUT instance of Buildbot generates tar files of the latest NUT source after each successful build, and these snapshots include a pre-built version of the `./configure` script. WARNING: There is an outstanding bug that after the shutdown of BuildBot, no regular distribution tarballs are in fact published. To build from Git, you will need recent versions of autoconf, automake, libtool, asciidoc, a2x and its dependencies for DocBook/dblatex. Rather than publish a list of the exact versions needed (which will quickly become out of date), we recommend you consult your distribution's dependency list for building a NUT package, and use that as a starting point. That said, for the numerous systems running build agents of the NUT CI farm, their lists of dependency packages are available in `docs/config-prereqs.txt` in NUT sources. == Do I have to use a serial connection to monitor the UPS? What about direct network connections (SNMP or otherwise)? NUT currently supports USB communication through several drivers, and also SNMP and XML/HTTP (Eaton and MGE) communications. Since NUT is very extensible, support for a new communication bus can be added easily. Any time there is a gap in features, it's usually because the group of people who own that hardware and the group of people who write code don't overlap. The fix is to make them overlap -- turn an owner into a developer or vice-versa. == What happened to the patch I sent? We try to prioritize emails with patches, but you should understand that a simple fix for your bug might be complicated to integrate with the rest of NUT. Changing the way a fundamental component works, such as USB support, means a lot of testing to ensure that your fix does not break other drivers. Sometimes patches are put on hold due to a feature freeze. If it doesn't show up once the new version opens up, please send it again. It may also be much more productive to submit changes as pull requests via https://github.com/networkupstools/nut/pulls so they are automatically processed by the NUT CI farm across numerous target platforms, and various inconsistencies can be diagnosed and fixed early. == I'm not much of a programmer. How can I help? There's always work to be done outside of the realm of code bashing. Documentation can always be improved. A new user's perspective is sometimes needed to appreciate this, since developers and long-time users consider everything obvious. Bug reports and pull requests on any project's documentation are just as valuable as those for the actual programs' sources. Fielding questions on the mailing lists is also helpful. This lets other people to focus on coding issues while allowing the original poster to get some information at the same time. It's quite a relief to open that mailbox and find that someone else has already handled it successfully. == I replaced the battery in my APC Smart-UPS and now it thinks the battery is low all the time. How do you fix this? Or a variation like... == My APC UPS keeps reporting 'OL LB', even after it's been charging for many hours. What can I do about this? This happened to me, and some other people too. The combination of our experiences should prove useful to you. First, you need to realize that the UPS apparently stores data about the battery, load, and runtime. After replacing the battery, it needs to be clued in to the new situation. If the traditional runtime calibration doesn't work, you have to try something a little more drastic. You need to *completely* drain the UPS while it has a good ground. This means you can't just pull the plug. You also have to disconnect it from the computer so this software won't shut it down. The easiest way to do this is to first unplug your computer(s) from it, and plug in a token load like a lamp. Also, move the UPS to a power strip that doesn't switch the ground line or an outlet that you can switch off at your panel. Once the UPS is up at 100% charge (this is important), disconnect the power. It _must_ remain connected to the ground, or the results may not be accurate. Ignore the sounds it makes, and go away until it's done. Don't do anything to the front panel while this is happening. After all of this, put things back the way they should be and let it charge up. You should find that it again gives reasonable values and behavior, as it was when it was new. Thanks to Matthew Dharm for helping us nail down this procedure. == upsstats returns temperatures in Celsius. I like Fahrenheit. Where's the config file to switch it back? Temperature scales are handled by the template files, so edit your upsstats.html and change it from TEMPC to TEMPF. == Why is the mailing list ignoring me? You probably asked a question that's answered in this FAQ, or somewhere else in the documentation, and nobody wants to quote it for you. There is a small chance that the mailing list spam filter ate your message. Check the list archives to see if your message appears there. Also double-check that you have subscribed to the lists and completed all the confirmation rituals of its engine. Convincing the other subscribers that you've actually read down this far might be useful. You might mention "queequeg" for better results. This URL may also be helpful: http://www.catb.org/~esr/faqs/smart-questions.html == Why are you so insistent about sending emails to public mailing lists instead of to individuals? By and large, NUT is a volunteer effort. By emailing one person, you are asking them to take care of your question. If you email the list instead, you give others the opportunity to answer. In addition, the mailing lists are publicly archived, and therefore easily searchable. Chances are, you aren't the only person who will ever have that question. There are similar benefits to using the discussions on issue tracker at https://github.com/networkupstools/nut/issues and if suitable, in the currently open pull requests. == If you want mailing list replies to go to the list, why don't you add a Reply-To: header? We are not going to rehash all of the arguments for and against this in a simple FAQ entry. If you intend for your reply to go to more than just the last person who posted, it is not too much trouble to hit "Reply All". == I found some information about another kind of UPS protocol you don't support yet, but I don't know what to do with it. Can you help? If you're not a programmer, you can still help others by making that protocol available. You might host the document somewhere and send the URL to one of the mailing lists. Posting an issue with attachments on https://github.com/networkupstools/nut/issues can also be helpful. == How can you answer questions to situations that nobody's encountered yet? Isn't this a frequently asked questions file? *Answer 1* It's a kind of Magic. *Answer 2* It's both that and a frequently *anticipated* questions file, too. The idea is to write it up in here so that nobody asks the mailing list when it finally does get released. == My UPS powers up immediately after a power failure instead of waiting for the batteries to recharge! Or a variation like... == My UPS (an APC as it happens) lacks the field "battery.charge.restart" -- so how will it know when to restart? You can rig up a little hack to handle this issue in software. Essentially, you need to test for the POWERDOWNFLAG in your *startup* scripts while the filesystems are still read-only (before `upsmon` daemon has started and removed it). You can also query `upsmon -K` for presence of the file, to avoid hard-coding the path or parsing it from your `upsmon.conf` file. If the flag is there, you know your last shutdown was caused by a power failure and the UPS battery is probably still quite weak. In this situation, your best bet is to sleep it off. Pausing in your startup script to let the batteries recharge with the filesystems in a safe state is recommended. This way, if the power goes out again, you won't face a situation where there's not enough battery capacity left for upsmon to do its thing. Exactly how long to wait is a function of your UPS hardware, and will require careful testing. If this is too evil for you, buy another kind of UPS that will either wait for a minimum amount of charge, a minimum amount of time, or both. == I'm facing a power race Or a variation like... == The power came back during the shutdown, but before the UPS power off. Now the UPS does not reboot, and my computer stays off. How can I fix that? There is a situation where the power may return during the shutdown process. This is known as a race. Here's how we handle it. "Smart" UPSes typically handle this by using a command that forces the UPS to power the load off and back on. This way, you are assured that the systems will restart even if the power returns at the worst possible moment. Contact closure units (ala genericups), on the other hand, have the potential for a race when feeding multiple systems. This is due to the design of most contact closure UPSes. Typically, the "kill power" line only functions when running on battery. As a result, if the line power returns during the shutdown process, there is no way to power down the load. The workaround is to force your systems to reboot after some interval. This way, they won't be stuck in the halted state with the UPS running on line power. Implement this by modifying your shutdown script like this: ------ # `upsmon -K` if available on still mounted filesystems # at this point is more portable than the `test` below if (test -f /etc/killpower || /sbin/upsmon -K) then /sbin/upsdrvctl shutdown sleep 120 # uh oh, we never got shut down! (power race?) reboot fi ------ nut-2.8.3/docs/Makefile.am0000644000200500020050000017467515001552635012251 00000000000000# Network UPS Tools: main docs # FIXME: There is a lot of shell-scripting below which gets processed by # whatever system shell there is. While bash handles expressions like # VAL="`cmd "some params"`" # in a way that "some params" are a single token passed to "cmd" as an # argument, and the stdout of such command execution is collected into a # single-token string as "VAL" (even if with white-spaces). Some other # shells, e.g. "ksh" seems to actively dislike unbalanced double-quotes # inside the backticks (e.g. matched in some grep/sed regexes below), # although generally the approach works for such "VAL" assignments too. # Note that the newer "$(...)" syntax is not portable, older shells # have no idea about it, and it is cumbersome with `make` substitution. # Keep a lookout with multi-platform NUT CI jobs, and try to use single # quotes where possible (e.g. where pre-expanded `make` variables are # involved - so shell should not process them again anyway). MAINTAINERCLEANFILES = Makefile.in .dirstamp EXTRA_DIST = # Note: "doc" ensures the `configure`-specified list of documents we actually # want, while the default generated "all: all-am" target historically causes # some but not all of these targets to get built (e.g. ChangeLog html/pdf is # usually not made there). Post-processing "doc" as part of "all" helps # ensure that we do not rebuild stuff in vain during parallel builds (where # "all-am" and "doc" would be unordered parallel goals of the "all" target) # while getting those further goals achieved eventually in the default build. # Crucially, this allows to make sure "ChangeLog(.adoc*)" files have been # generated once (can take a looong while), settled into place, and only then # we revisit them for html/pdf rendering (another long while) without randomly # confusing the system with new timestamps and needless regenerations later on. all: @echo " DOC-FOLLOW-UP Basic 'make $@' in `pwd` is done, following up with 'make doc' to ensure complex document types" +@$(MAKE) $(AM_MAKEFLAGS) doc # Is "egrep == grep -E" always valid? (maybe all a job for configure.ac) #EGREP = egrep EGREP = grep -E # Possible man page section remapping in some distros: MAN_SECTION_API_BASE=@MAN_SECTION_API_BASE@ MAN_SECTION_CFG_BASE=@MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS_BASE=@MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR_BASE=@MAN_SECTION_CMD_USR_BASE@ # Other rewritable properties: NUT_WEBSITE_BASE=@NUT_WEBSITE_BASE@ PACKAGE_VERSION=@PACKAGE_VERSION@ TREE_VERSION=@TREE_VERSION@ IMAGE_FILES = \ images/asciidoc.png \ images/hostedby.png \ images/nut_layering.png \ images/nut-logo.png \ images/note.png \ images/warning.png \ images/blue-arrow.png \ images/simple.png \ images/advanced.png \ images/bigbox.png \ images/bizarre.png \ images/old-cgi.png # Logos which pop up in README.adoc acknowledgements and maybe other places: IMAGE_LOGO_FILES = \ images/ci/AppVeyor_logo-2x.png \ images/ci/AppVeyor_logo-ar21.png \ images/ci/CircleCI_vertical_black_logo.png \ images/ci/DO_Powered_by_Badge_blue.png \ images/ci/DO_Powered_by_Badge_blue_140pxW.png \ images/ci/fosshost_org_Host_Dark_56px.png \ images/ci/fosshost_org_Host_Light_309px.png \ images/ci/fosshost_org_Host_Light_38px.png \ images/ci/gandi-ar21.png \ images/ci/gandi-ar21.svg \ images/ci/GitHub-Mark-140pxW.png \ images/ci/GitHub-Mark-ea2971cee799.png \ images/ci/OC_logotype.png \ images/ci/OC_logo-watercolor-256.png \ images/ci/OC_logo_merged_171x32.png \ images/ci/OC_logo_merged_140x26.png IMAGE_LOGO_FILES_JENKINS_NUT = \ images/ci/ci-root.css \ images/ci/jenkins-nut-large-256px.png \ images/ci/jenkins-nut-large-squared.png \ images/ci/jenkins-nut-large.pdn \ images/ci/jenkins-nut-large.png \ images/ci/jenkins-nut-small-256px.png \ images/ci/jenkins-nut-small.pdn \ images/ci/jenkins-nut-small.png \ images/ci/jenkins-nut-squared.png \ images/ci/jenkins-nut-transparent-bg-140pxW.png \ images/ci/jenkins-nut-transparent-bg-40px.png \ images/ci/jenkins-nut-transparent-bg.png \ images/ci/jenkins-nut.css \ images/ci/jenkins-nut.png \ images/ci/jenkins-nut.txt # Only track here the local deps SHARED_DEPS = nut-names.txt daisychain.txt asciidoc.conf asciidoc.txt # See also conversions included via FULL_USER_MANUAL_DEPS USER_MANUAL_DEPS = acknowledgements.txt cables.txt config-notes.txt \ configure.txt download.txt documentation.txt features.txt history.txt \ outlets.txt scheduling.txt security.txt support.txt user-manual.txt # See also conversions included via FULL_DEVELOPER_GUIDE_DEPS DEVELOPER_GUIDE_DEPS = contact-closure.txt design.txt developers.txt \ developer-guide.txt hid-subdrivers.txt macros.txt new-clients.txt \ new-drivers.txt net-protocol.txt nutdrv_qx-subdrivers.txt \ nut-versioning.adoc snmp-subdrivers.txt sock-protocol.txt # See also conversions included via FULL_QA_GUIDE_DEPS QA_GUIDE_DEPS = nut-qa.txt config-prereqs.txt ci-farm-do-setup.adoc \ ci-farm-lxc-setup.txt qa-guide.adoc CABLES_DEPS = cables/apc-rs500-serial.txt \ cables/apc.txt cables/ge-imv-victron.txt cables/imv.txt \ cables/mgeups.txt cables/powerware.txt cables/repotec.txt \ cables/sms.txt CABLES_IMAGES = images/cables/73-0724.png images/cables/940-0024C.jpg \ images/cables/belkin-f6cx-rkm-xu-cable.jpg images/cables/Lansafecable.jpg \ images/cables/mac-940-0024C.png images/cables/mge-66049.png \ images/cables/mge-db9-rj12.jpg images/cables/mge-db9-rj45.jpg \ images/cables/mge-usb-rj45.jpg \ images/cables/SOLA-330.png ALL_TXT_SRC = nut-names.txt daisychain.txt \ $(USER_MANUAL_DEPS) $(DEVELOPER_GUIDE_DEPS) \ $(CABLES_DEPS) $(QA_GUIDE_DEPS) FAQ.txt packager-guide.txt snmp.txt \ release-notes.txt ChangeLog.txt solaris-usb.txt ASPELL_FILTER_PATH = @ASPELL_FILTER_PATH@ # NOTE: This can be set by caller such as nut-website builder: NUT_SPELL_DICT = nut.dict EXTRA_DIST += $(ALL_TXT_SRC) $(SHARED_DEPS) $(IMAGE_FILES) \ $(IMAGE_LOGO_FILES) $(IMAGE_LOGO_FILES_JENKINS_NUT) $(CABLES_IMAGES) $(NUT_SPELL_DICT) \ docinfo.xml common.xsl xhtml.xsl chunked.xsl asciidoc.txt asciidoc-vars.conf # NOTE: ALL_TXT_SRC does not include sms-brazil-protocol.txt because it # primarily includes samples of configuration files with a lot of Spanish # (Brazilian) words which confuse the spell-checker. Adding them to common # NUT_SPELL_DICT would compromise its usefulness for purely English documents. # FIXME: Add support for custom additional dictionaries for specific document # files, e.g. "something.txt.dict" if present? There is precedent and code in # nut-website recipes by now... EXTRA_DIST += sms-brazil-protocol.txt ASCIIDOC_HTML_SINGLE = \ $(top_builddir)/docs/ChangeLog.html \ user-manual.html \ developer-guide.html \ packager-guide.html \ qa-guide.html \ release-notes.html \ solaris-usb.html \ cables.html \ FAQ.html ASCIIDOC_HTML_CHUNKED = \ $(top_builddir)/docs/ChangeLog.chunked \ user-manual.chunked \ developer-guide.chunked \ packager-guide.chunked \ qa-guide.chunked \ release-notes.chunked \ solaris-usb.chunked \ cables.chunked \ FAQ.chunked ASCIIDOC_PDF = \ $(top_builddir)/docs/ChangeLog.pdf \ user-manual.pdf \ developer-guide.pdf \ packager-guide.pdf \ qa-guide.pdf \ release-notes.pdf \ solaris-usb.pdf \ cables.pdf \ FAQ.pdf # Note: "man" subdir is handled separately via all-local and check-local # for a few goals, and among SUBDIRs directly from the top-level Makefile # due to some potential dependency collisions with parallel builds. SUBDIRS = cables SUFFIXES = .txt .html .pdf SUFFIXES += .txt-spellchecked-auto .txt-spellchecked .txt-prepped SUFFIXES += .adoc-spellchecked-auto .adoc-spellchecked .adoc-prepped SUFFIXES += .in-spellchecked-auto .in-spellchecked .in-prepped SUFFIXES += .sample-spellchecked-auto .sample-spellchecked .sample-prepped SUFFIXES += .conf-spellchecked-auto .conf-spellchecked .conf-prepped # This list is defined by configure script choices and options: CHECK_LOCAL_TARGETS = @DOC_CHECK_LIST@ if WITH_SPELLCHECK CHECK_LOCAL_TARGETS += spellcheck endif WITH_SPELLCHECK check-local: $(CHECK_LOCAL_TARGETS) +@cd $(builddir)/man && $(MAKE) $(AM_MAKEFLAGS) check # Make sure sources are there for out-of-tree builds: all-local all-am-local \ @DOC_BUILD_LIST@ $(ASCIIDOC_PDF) $(ASCIIDOC_HTML_SINGLE) $(ASCIIDOC_HTML_CHUNKED): $(abs_top_builddir)/docs/.prep-src-docs all-local: +@cd $(builddir)/man && $(MAKE) $(AM_MAKEFLAGS) all-optional # This list is defined by configure script choices and options: doc: $(abs_top_builddir)/docs/.prep-src-docs @DOC_BUILD_LIST@ # This target can be called by developers to go around the configure # script choices at their risk (e.g. missing tools are possible): docs: pdf html-single html-chunked man-man html-man all-docs: docs check-docs: check-pdf check-html-single check-html-chunked check-man # Not called by default, but handy for maintainers to check which words # in the custom dictionary are used or not by the current NUT codebase. # Note that historically many words were added to facilitate rendition # of the nut-website (long ago splintered from main nut repository), # but since recently it has a way to track its own additions to the # dictionary file. This code should help populate it as well, and keep # only relevant entries in the appropriate corner of the sources. # Note this can take 5-10 minutes! spellcheck-report-dict-usage: $(NUT_SPELL_DICT).usage-report pdf: $(ASCIIDOC_PDF) # also build the HTML manpages with these targets html-single: $(ASCIIDOC_HTML_SINGLE) html-chunked: $(ASCIIDOC_HTML_CHUNKED) # htmldocdir and pdfdir are set by autoconf/automake htmldoc_DATA = if WITH_HTML_SINGLE htmldoc_DATA += $(ASCIIDOC_HTML_SINGLE) endif WITH_HTML_SINGLE # FIXME: Install tools refuse to work with directories in this context # and html-chunked documentation has a separate tree per document. # Maybe an "(un)install-data-local" or "install-data-hook" for this? #if WITH_HTML_CHUNKED #htmldoc_DATA += $(ASCIIDOC_HTML_CHUNKED) #endif WITH_HTML_CHUNKED if WITH_PDFS pdf_DATA = $(ASCIIDOC_PDFS) endif WITH_PDFS # the "for" loops might better use $^ but it might be not portable check-pdf: .check-pdf .check-pdf: $(ASCIIDOC_PDF) Makefile @FAILED=""; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(ASCIIDOC_PDF) ; do \ test -s "$$F" && { file "$$F" | $(EGREP) -i 'PDF document' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED PDF sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED PDF sanity check"; exit 0 @touch $@ # Regarding ChangeLog check: sometimes asciidoc gives up early # (we have megabytes of text and thousands of sections here). # In some cases, the intermediate XML is broken and a2x=>xmllint # notices it. In others, it is truncated at just the right place # structurally and leads to a short HTML with only part of the # expected contents. We should no longer have several processes # trying to create the files involved (or rather do so atomically # and rename into final path, in case we still have competition # here); earlier when several generators appended to the same # file we could have several copies overlaid, with one of the # document's copies starting mid-sentence of another. # The two expected mentions are in the table of contents and # in the eventual section. Checking for first/second entries, # and not exactly two mentions, should allow to catch the case # of overlapping documents. Checking for the last entry allows # to catch incomplete parses, where asciidoc gave up early. # NOTE: Technically it may be more than two, if the author and # date were used several times in the original ChangeLog file # (either with different e-mails, or if different author's work # is interleaved during the day, e.g. many PRs merged, and no # CHANGELOG_REQUIRE_GROUP_BY_DATE_AUTHOR=true setting was in place. # NOTE: No dependencies, avoids (re-)generation and log messages # but causes re-run of the check every time. ChangeLog.html-contentchecked: @FAILED=""; \ if [ -s '$(top_builddir)/ChangeLog' ] && [ -s ChangeLog.html ] ; then \ SECOND_ENTRY="`grep -E '^[0-9]' '$(top_builddir)/ChangeLog' | head -2 | tail -1 | sed 's/ *[\"<].*//'`" || SECOND_ENTRY="" ; \ FIRST_ENTRY="`grep -E '^[0-9]' '$(top_builddir)/ChangeLog' | head -1 | sed 's/ *[\"<].*//'`" || FIRST_ENTRY="" ; \ LAST_ENTRY="`grep -E '^[0-9]' '$(top_builddir)/ChangeLog' | tail -1 | sed 's/ *[\"<].*//'`" || LAST_ENTRY="" ; \ if [ -n "$${FIRST_ENTRY}" ] ; then \ O="`grep -cE "^$${FIRST_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${FIRST_ENTRY}" 'ChangeLog.html'`" ; \ MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ echo "FAILED ChangeLog.html check: does not contain expected first entry the right amount of times (huge doc, must have got aborted mid-way): $${FIRST_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ FAILED="ChangeLog.html" ; \ fi ; \ fi ; \ fi; \ if [ -n "$${SECOND_ENTRY}" ] ; then \ O="`grep -cE "^$${SECOND_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${SECOND_ENTRY}" 'ChangeLog.html'`" ; \ MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ echo "FAILED ChangeLog.html check: does not contain expected second entry the right amount of times (huge doc, must have got aborted mid-way): $${SECOND_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ FAILED="ChangeLog.html" ; \ fi ; \ fi ; \ fi; \ if [ -n "$${LAST_ENTRY}" ] ; then \ O="`grep -cE "^$${LAST_ENTRY}" '$(top_builddir)/ChangeLog'`" ; \ N="`grep -cE "title.*$${LAST_ENTRY}" 'ChangeLog.html'`" ; \ MIN="`expr $${O} + 1`" && [ "$${MIN}" -gt 0 ] 2>/dev/null || MIN=1 ; \ MAX="`expr $${O} + $${O}`" && [ "$${MAX}" -gt 2 ] 2>/dev/null || MAX=2 ; \ if [ "$${N}" -lt "$${MIN}" ] || [ "$${N}" -gt "$${MAX}" ]; then \ echo "FAILED ChangeLog.html check: does not contain expected last entry the right amount of times (huge doc, must have got aborted mid-way): $${LAST_ENTRY} (seen $${N} times, expected between $${MIN} and $${MAX})" >&2 ; \ if [ -z "$$FAILED" ] ; then \ echo "Expected size over 3MB (for common builds):" >&2 ; \ ls -la "ChangeLog.html" '$(top_builddir)/ChangeLog'* >&2 ; \ FAILED="ChangeLog.html" ; \ fi ; \ fi ; \ fi; \ if [ x"$$FAILED" = x ] ; then \ echo "PASSED $@" >&2 ; \ exit 0 ; \ fi ; \ if [ x"$$FAILED" != x ] && [ -s '$(top_builddir)/ChangeLog.adoc' ] \ && [ "`head -1 $(top_builddir)/ChangeLog.adoc`" = "=== Failed to generate the ChangeLog" ] \ ; then \ FAILED="" ; \ fi; \ fi; \ if [ x"$$FAILED" = x ] ; then \ echo " SKIP $@ : because input files were not available" >&2 ; \ exit 0 ; \ fi ; \ exit 1 check-html-single: .check-html-single .check-html-single: $(ASCIIDOC_HTML_SINGLE) Makefile +@FAILED=""; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for F in $(ASCIIDOC_HTML_SINGLE) ; do \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(XML|HTML.*document)' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ case "$$F" in \ *ChangeLog*) if [ -s '$(top_builddir)/ChangeLog' ] ; then \ $(MAKE) $(AM_MAKEFLAGS) "`basename "$$F"`"-contentchecked || FAILED="$$FAILED $$F" ; \ fi ;; \ esac ; \ done; if test -n "$$FAILED" ; then \ echo "FAILED HTML-single sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED HTML-single sanity check"; exit 0 @touch $@ check-html-chunked: .check-html-chunked .check-html-chunked: $(ASCIIDOC_HTML_CHUNKED) Makefile @FAILED=""; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ for D in $(ASCIIDOC_HTML_CHUNKED); do \ for F in "$$D"/*.html ; do \ test -s "$$F" && { file "$$F" | $(EGREP) -i '(XML|HTML.*document)' > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; \ for F in "$$D"/*.css ; do \ test -s "$$F" && { $(EGREP) -i 'CSS stylesheet' "$$F" > /dev/null ; } || FAILED="$$FAILED $$F" ; \ done; \ done; if test -n "$$FAILED" ; then \ echo "FAILED HTML-chunked sanity check for:$$FAILED" >&2 ; file $$FAILED >&2 ; exit 1; \ fi; echo "PASSED HTML-chunked sanity check"; exit 0 @touch $@ # Note: usually the results from man-page check will be reported twice: # once as a SUBDIRS child makefile, and once via DOC_CHECK_LIST expansion # Note: default `make all` in the man directory caters to drivers etc. # chosen during configure script execution. The "all-man" and "all-html" # rules build everything documented. # NOTE; we rig it up with a DOCS_NO_MAN option to simplify parallel work # from top-level Makefile, while allowing legacy "cd docs && make" to # still do the right thing by default :) check-man check-man-man all-man man-man all-html html-man: +@if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then echo " DOC-NOT-MAN SKIP: $@ called in docs/Makefile" ; exit 0 ; fi ; \ cd $(abs_top_builddir)/docs/man/ && $(MAKE) $(AM_MAKEFLAGS) -f Makefile $@ man: +@if [ x"$(DOCS_NO_MAN)" = xtrue ] ; then echo " DOC-NOT-MAN SKIP: $@ called in docs/Makefile" ; exit 0 ; fi ; \ cd $(abs_top_builddir)/docs/man/ && $(MAKE) $(AM_MAKEFLAGS) -f Makefile all CLEANFILES = *.xml *.html *.pdf *-spellchecked* *-contentchecked* .check-* docbook-xsl.css docinfo.xml.in.tmp docinfo-since-v*.xml* *-docinfo.xml* CLEANFILES += $(top_builddir)/INSTALL.nut $(top_builddir)/UPGRADING $(top_builddir)/ChangeLog.adoc CLEANFILES += $(top_builddir)/*.adoc-parsed *.adoc-parsed # These two "must be" there per autotools standards, so a "make clean" # should not compromise a rebuild: DISTCLEANFILES = $(top_builddir)/NEWS $(top_builddir)/README ### TODO: general automatic dependency generation MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG = no # Prepare text files (currently a manually tracked list) # with known presence of GitHub links to convert them from # short notation into asciidoc link markup # before rendering into HTML/PDF. # Work around some documents that have originally included # the asciidoc markup (use double-hash to avoid conversion). # The $< is okay here, it is used in a suffix rule below .adoc.adoc-parsed: @if [ -s '$@' ] && [ x"`find '$@' -newer '$<'`" != x ] ; then \ echo " DOC-ASCIIDOC-GITHUB-LINKS SKIP: $@ already exists and is newer than $<" ; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ ls -lad $@ $< || true ; \ stat $@ $< || true ; \ fi ; \ exit 0 ; \ fi ; \ echo " DOC-ASCIIDOC-GITHUB-LINKS Parsing GitHub link patterns $< => $@"; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ ls -lad $@ $< || true ; \ stat $@ $< || true ; \ fi ; \ cat '$<' | { $(SED) \ -e 's%\(link:https*://github.com/networkupstools/[a-zA-Z0-9./-]*/[1-9][0-9]*/*\[[^]]*\)\#\([1-9][0-9]*\)%\1\#\#\2%g' \ -e 's%\(issue\) *\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/nut/issues/\2[\1 \#\#\2]\3%g' \ -e 's%\(PR\|pull request\) *\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/nut/pull/\2[\1 \#\#\2]\3%g' \ -e 's%\([[ ,]\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%\1link:https://github.com/networkupstools/nut/issues/\2[\#\#\2]\3%g' \ -e 's%\(issue\) networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/\2/issues/\3[\1 \2\#\#\3]\4%g' \ -e 's%\(PR\|pull request\) *networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%link:https://github.com/networkupstools/\2/pull/\3[\1 \2\#\#\3]\4%g' \ -e 's%\([[ ,]\)networkupstools/\([^ ][^ ]*\)\#\([1-9][0-9]*\)\([^0-9]\|$$\)%\1link:https://github.com/networkupstools/\2/issues/\3[\2\#\#\3]\4%g' \ -e 's%\#\(\#[1-9][0-9]*\)%\1%g' \ ; } > "$@.tmp.$$$$" \ && mv -f "$@.tmp.$$$$" "$@" @if [ x'$@' = x'$(top_builddir)/ChangeLog.adoc-parsed' ] ; then \ touch -r '$@' '$(top_builddir)/docs/.ChangeLog.adoc-parsed.latest' || touch '$(top_builddir)/docs/.ChangeLog.adoc-parsed.latest' ; \ fi $(top_builddir)/ChangeLog.adoc-parsed: $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest: $(top_builddir)/ChangeLog.adoc-parsed @[ x"$?" != x ] && touch -r '$?' '$@' || touch '$@' CLEANFILES += .ChangeLog.adoc-parsed.latest dummy: $(top_builddir)/ChangeLog: dummy @+echo " DOC-CHANGELOG-GENERATE-WRAPPER $@ : call parent Makefile to decide if (re-)generation is needed" \ && cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) $(@F) # BSD Make dislikes the path resolution here and does not always populate '$<' # (and claims why: "Using $< in a non-suffix rule context is a GNUmake idiom"), # but it has a "$?" for "list of dependencies that are newer than the target". # For more details see https://man.freebsd.org/cgi/man.cgi if WITH_PDF_NONASCII_TITLES A2X_ASCII_IDS = else !WITH_PDF_NONASCII_TITLES A2X_ASCII_IDS = ":ascii-ids:\n" endif !WITH_PDF_NONASCII_TITLES # Timeout for ChangeLog.adoc rule to wait for competing threads to maybe create # (or start creating) the file first - then this "make" thread just waits for # it to be done, and exits, as the goal is fulfilled. MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY = 10 # Probably due to the web of makefiles and an overwhelmed job server in some # implementations, during parallel builds we can end up scheduling several # threads creating this asciidoc (and adoc-parsed later). This step only # costs a few seconds, however the updated timestamp may cause new HTML/PDF # builds which cost a lot more. Below we try a few ways to detect a build # already running and bail out early if the file exists. Otherwise we bite # the bullet and spend a few seconds, and then re-check if another thread # did exist and finished first. $(top_builddir)/ChangeLog.adoc: $(top_builddir)/ChangeLog @INPUT="$?"; \ test -n "$${INPUT}" || INPUT="$$(top_builddir)/ChangeLog" ; \ test -n "$${INPUT}" && test -n "$@" && test -s "$${INPUT}" \ || { \ MSG="FAILED to resolve input or output filename with this make implementation, or input was not generated!"; \ echo " DOC-CHANGELOG-ASCIIDOC SKIP: $${MSG}" >&2; \ test -n "$@" && { printf '=== Failed to generate the ChangeLog\n\n%s\n\nNOTE: See https://github.com/networkupstools/nut/commits/master for change history.\n\n' "$${MSG}" > "$@" ; } ; \ exit ; \ } ; \ if [ -s '$@' ] && [ x"`find '$@' -newer "$${INPUT}" 2>/dev/null`" != x ] ; then echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : SKIP (keep existing)"; rm -f "$@.tmp.$$$$"; exit 0 ; fi ; \ W=0 ; \ if [ "$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" -gt 0 ] 2>/dev/null ; then \ echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : Block for up to $(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY) sec, maybe another thread will make the file first" ; \ while [ "$${W}" -lt "$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" ] && [ x"`find '$@.tmp.'* '$@' -newer "$${INPUT}" 2>/dev/null`" = x ] ; do sleep 1 ; W="`expr $$W + 1`"; done ; touch "$@.tmp.$$$$"; \ if [ x"`find '$@' -newer "$${INPUT}" 2>/dev/null`" != x ] ; then echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : SKIP (keep existing)"; rm -f "$@.tmp.$$$$"; exit 0 ; fi ; \ fi ; \ if [ -s "$@" ] ; then echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : RE-GENERATE" ; else echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : GENERATE" ; fi ; \ { if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then ls -la "$${INPUT}" "$@" || true ; stat "$${INPUT}" "$@" || true ; fi ; } ; \ if [ "$(MAINTAINER_ASCIIDOCS_CHANGELOG_DELAY)" -gt 0 ] 2>/dev/null ; then \ echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : PROCEED, waited for $${W} sec" ; \ fi ; \ printf "ifdef::txt[]\n== Very detailed Change Log\n"$(A2X_ASCII_IDS)"endif::txt[]\n\n" > "$@.tmp.$$$$" \ && TABCHAR="`printf '\t'`" \ && $(SED) \ -e 's,^\([0-9a-zA-Z]\),=== \1,' \ -e 's,^=== \(NOTE: \),\1,' \ -e 's,/[+],/\\\\\+,g' \ -e 's,[+][+],\\\+\\\+,g' \ -e 's,^\([ '"$${TABCHAR}"'][^+]*\)\([^+/\]\)[+],\1\2\\\+,g' \ -e 's,^\([ '"$${TABCHAR}"'].*\)\([~|^]\),\1\\\2,g' \ -e 's,\[\[\([^]]*\)\]\],[\1],g' \ -e 's,^\(\s\s*\)\([0-9]\),\1{empty}\2,g' \ < "$${INPUT}" >> "$@.tmp.$$$$" \ && if [ x"`find '$@' -newer "$${INPUT}" 2>/dev/null`" != x ] ; then echo " DOC-CHANGELOG-ASCIIDOC $${INPUT} => $@ : SKIP (keep recently born competitor)"; rm -f "$@.tmp.$$$$"; \ else mv -f "$@.tmp.$$$$" "$@" ; fi # Add other directory deps (not for local EXTRA_DIST) and generated contents FULL_USER_MANUAL_DEPS = $(USER_MANUAL_DEPS) $(SHARED_DEPS) \ $(top_builddir)/README.adoc-parsed \ $(top_builddir)/INSTALL.nut.adoc-parsed \ $(top_builddir)/UPGRADING.adoc-parsed \ ../TODO.adoc ../scripts/ufw/README.adoc FULL_DEVELOPER_GUIDE_DEPS = $(DEVELOPER_GUIDE_DEPS) $(SHARED_DEPS) \ ../scripts/augeas/README.adoc ../TODO.adoc \ ../lib/README.adoc \ ../tools/nut-scanner/README.adoc FULL_QA_GUIDE_DEPS = $(QA_GUIDE_DEPS) $(SHARED_DEPS) \ $(top_builddir)/ci_build.adoc-parsed user-manual.html user-manual.chunked user-manual.pdf: $(FULL_USER_MANUAL_DEPS) developer-guide.html developer-guide.chunked developer-guide.pdf: $(FULL_DEVELOPER_GUIDE_DEPS) packager-guide.html packager-guide.chunked packager-guide.pdf: packager-guide.txt asciidoc.conf qa-guide.html qa-guide.chunked qa-guide.pdf: $(FULL_QA_GUIDE_DEPS) release-notes.html release-notes.chunked release-notes.pdf: release-notes.txt $(top_builddir)/NEWS.adoc-parsed $(top_builddir)/UPGRADING.adoc-parsed asciidoc.conf solaris-usb.html solaris-usb.chunked solaris-usb.pdf: solaris-usb.txt asciidoc.conf # We intentionally evaluate that the original generated ChangeLog file is # up to date (from dist or against git) every time we look at it. However # we do want to skip re-generation of heavy file formats afterwards if it # is still valid (for make, a need for re-evaluation without timestamps # to look at is cause to run a recipe always). We define recipes outside # the suffix-based handling and require *them* for default target builds. ChangeLog.html ChangeLog.chunked ChangeLog.pdf: ChangeLog.txt .ChangeLog.adoc-parsed.latest asciidoc.conf $(top_builddir)/docs/ChangeLog.html $(top_builddir)/docs/ChangeLog.chunked $(top_builddir)/docs/ChangeLog.pdf: ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf @+if [ -s '$(@F)' ] && [ x"`find '$(@F)' -newer '$(top_builddir)/ChangeLog.adoc-parsed'`" != x ] ; then \ echo " DOC-CHANGELOG-RENDER-WRAPPER SKIP: `pwd`/$(@F) already exists and is newer than ChangeLog.adoc-parsed" ; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ ls -lad `pwd` $@ ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf $(top_builddir)/ChangeLog $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest || true ; \ stat `pwd` $@ ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf $(top_builddir)/ChangeLog $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest || true ; \ fi ; \ exit 0 ; \ else \ echo " DOC-CHANGELOG-RENDER-WRAPPER `pwd`/$(@F) does not already exist or is older than ChangeLog.adoc-parsed" ; \ if [ x"$(MAINTAINER_ASCIIDOCS_CHANGELOG_DEBUG)" != xno ] ; then \ ls -lad `pwd` $@ ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf $(top_builddir)/ChangeLog $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest || true ; \ stat `pwd` $@ ChangeLog.txt $(top_builddir)/ChangeLog.adoc-parsed asciidoc.conf $(top_builddir)/ChangeLog $(top_builddir)/ChangeLog.adoc .ChangeLog.adoc-parsed.latest || true ; \ time $(MAKE) $(AM_MAKEFLAGS) $(@F) || exit ; \ else \ $(MAKE) $(AM_MAKEFLAGS) $(@F) || exit ; \ fi ; \ echo " DOC-CHANGELOG-RENDER-WRAPPER `pwd`/$(@F): SUCCESS" ; \ fi # Assume revisions are sorted in the file, from newest to oldest # FIXME: If we ever get more than one file to chomp this way, make it a snippet docinfo-since-v2.8.3.xml: docinfo.xml @OLDEST_REL="2.8.3"; \ IN_REVISION=false ; OLDEST_SEEN=false ; \ while read LINE ; do \ case "$${LINE}" in \ *''*) if ! $$OLDEST_SEEN ; then IN_REVISION=true ; fi ;; \ *''"$${OLDEST_REL}"''*) if $$IN_REVISION ; then echo ''; OLDEST_SEEN=true ; fi ; echo "$$LINE" ;; \ *''*''*) if ! $$OLDEST_SEEN ; then if $$IN_REVISION ; then echo ''; fi ; echo "$$LINE" ; fi ;; \ *''*) if $$IN_REVISION ; then echo "$$LINE" ; fi ; IN_REVISION=false ;; \ *''*) echo "$$LINE" ;; \ *) if ! $$OLDEST_SEEN || $$IN_REVISION ; then echo "$$LINE" ; fi ;; \ esac ; \ done < "$?" > "$@".tmp \ && mv -f "$@".tmp "$@" # Some versions of asciidoc ignore the argument of :docinfo: tag # and require (TXT_BASE_NAME)-docinfo.xml to exist: qa-guide-docinfo.xml: docinfo-since-v2.8.3.xml @rm -f '$@' || true @$(LN_S) '$?' '$@' # Note: without the "-v", asciidoc (circa 8.6.2) sometimes hangs when # generating the chunked HTML. In this case, export the environment # variable ASCIIDOC_VERBOSE to "-v", ie: # $ ASCIIDOC_VERBOSE=-v make # Note: `(top_)srcdir` and `(top_)builddir` must end with a path # separator, or be empty -- so in all cases letting the resulting # string resolve meaningfully in the filesystem during docs build. A2X_DOCINFO_DIR=$(builddir) A2X_COMMON_OPTS = $(ASCIIDOC_VERBOSE) \ --attribute=icons \ --xsltproc-opts="--nonet" \ --xsltproc-opts="--stringparam nut.localdate \"`TZ=UTC date +%Y-%m-%d`\"" \ --xsltproc-opts="--stringparam nut.localtime \"`TZ=UTC date +%H:%M:%S`\"" \ --xsltproc-opts="--stringparam nut.nutversion \"$(PACKAGE_VERSION)\"" \ --attribute=docinfodir="$${A2X_DOCINFO_DIR}" \ --attribute=iconsdir="$(srcdir)/images" \ --attribute=badges \ --attribute=external_title \ --attribute=tree_version="$(TREE_VERSION)" \ --attribute=srcdir="$(abs_srcdir)/" \ --attribute=builddir="$(abs_builddir)/" \ --attribute=top_srcdir="$(abs_top_srcdir)/" \ --attribute=top_builddir="$(abs_top_builddir)/" \ --attribute=MAN_SECTION_API_BASE='$(MAN_SECTION_API_BASE)' \ --attribute=MAN_SECTION_CFG_BASE='$(MAN_SECTION_CFG_BASE)' \ --attribute=MAN_SECTION_CMD_SYS_BASE='$(MAN_SECTION_CMD_SYS_BASE)' \ --attribute=MAN_SECTION_CMD_USR_BASE='$(MAN_SECTION_CMD_USR_BASE)' \ --attribute=NUT_WEBSITE_BASE='$(NUT_WEBSITE_BASE)' \ -a toc -a numbered --destination-dir=$${A2X_OUTDIR} # NOTE: a2x newer than 8.6.8 says "--destination-dir" is only valid for HTML. # As of version 8.6.9 it lies, and the argument is required for our distcheck # (and does affect PDF builds, as found during work on collision-avoidance - # true with at least asciidoc/a2x versions 9.0.0rc2). # For more details see issues https://web.archive.org/web/20201207082352/https://github.com/asciidoc/asciidoc/issues/44 # and https://github.com/networkupstools/nut/pull/281 (in short, attempts # to "fix" this warning broke NUT build). If this is to be retried later, see # https://github.com/networkupstools/nut/pull/281/commits/fe17861c4ea12679b3ebfefa8a6d692d79d99f2d # and do not forget to fix up docs/man/Makefile.am too ;) # NOTE: a2x tends to copy some files into its working area, preserving original # permissions. If those files are read-only in origin (e.g. packaged stylesheet # or our resources coming from EXTRA_DIST) the next a2x can not overwrite it. # Also note that such hoarding of files has potential to break parallel builds # (or cause them to produce undefined results if some bad timing happens). # As a brutal workaround for the former problem, we chmod. For second one we # might try magic with .SEQUENTIAL recipe hints, but that is gmake-dependent. # Note that empirically it treats "destination-dir" as the source root for # PDF generation (even though it claims the argument is ignored for non-HTML # targets) so we have to provide the "images/" in this case. ONLY for PDF! # Note we only remove the original target (if present), if it is a directory - # e.g. created by "html-chunked" targets. # NOTE: MKDIR_P may be defined via expanded $(top_builddir)/install-sh # so should be run from $(abs_builddir) to be safe, as we jump around # the build workspace DOCBUILD_BEGIN = { \ if test -n "$${A2X_OUTDIR}" && test "$${A2X_OUTDIR}" != '.' ; then \ rm -rf "./$${A2X_OUTDIR}" || true ; \ test -d "$@" && rm -rf "$@" || true ; \ _CWD="`pwd`" && (cd '$(abs_builddir)' && $(MKDIR_P) "$${_CWD}/$${A2X_OUTDIR}") || exit ; \ case "$${A2X_OUTDIR}" in \ tmp/pdf.*) ln -s ../../images "./$${A2X_OUTDIR}" ; \ case "$(@F)" in \ qa-guide.pdf) \ ln -s ../../docinfo-since-v2.8.3.xml "./$${A2X_OUTDIR}/docinfo.xml" ; \ ln -s ../../docinfo-since-v2.8.3.xml "./$${A2X_OUTDIR}/qa-guide-docinfo.xml" ;; \ esac \ ;; \ esac; \ else A2X_OUTDIR='.' ; fi; \ if test -s "${builddir}/docbook-xsl.css" \ && test -r "${builddir}/docbook-xsl.css" \ && ! test -w "${builddir}/docbook-xsl.css" \ ; then chmod u+w "${builddir}/docbook-xsl.css" ; fi ; \ chmod -R u+w "./$${A2X_OUTDIR}" || true; \ } # When moving "*" hope a2x did not make any "hidden" files # like ".*" that would be required for resulting documents. # Leave the "images/" dir there, though. # Otherwise, we would have to `find` them all. DOCBUILD_END = { \ if test -n "$${A2X_OUTDIR}" && test "$${A2X_OUTDIR}" != '.' ; then \ chmod -R u+w "./$${A2X_OUTDIR}" || true; \ test -d "$@" && rm -rf "$@" || true ; \ rm -f "./$${A2X_OUTDIR}/"*docinfo*.xml* || exit ; \ mv -f "./$${A2X_OUTDIR}/$(@F)" ./ || exit ; \ mv -f "./$${A2X_OUTDIR}/"*.* ./ 2>/dev/null || true ; \ rm -rf "./$${A2X_OUTDIR}" ; \ fi ; \ } ### Call the prep step consistently to create symlinks (out-of-tree) ### or just touch-files for peace of mind (in-tree builds). Then we ### use these path names (truncated "-prepped") now surely located ### in the builddir as the sources for rendered docs. *.txt-prepped *.adoc-prepped: $(abs_top_builddir)/docs/.prep-src-docs # PORTABILITY NOTE: POSIX Make forbids the suffix rule definitions with # prerequisites like done below, and GNU Make of some versions complains; # https://www.gnu.org/software/make/manual/html_node/Error-Messages.html # says the prerequisites were ignored while a suffix rule was created; # eventually the POSIX stance would be taken to define a rule for a weird # verbatim target file name with prerequisites: # ../docs/Makefile:936: warning: ignoring prerequisites on suffix rule definition # Changes from ".txt.pdf: docinfo.xml" to "*.pdf: docinfo.xml" = ".txt.pdf:" # as done below may be pointless in the end (with regard to a portable way # to trigger builds by a changed dependency), but at least predictable and # not toxic. ###.txt.txt-prepped: $(abs_top_builddir)/docs/.prep-src-docs ###.adoc.adoc-prepped: $(abs_top_builddir)/docs/.prep-src-docs # NOTE: inference rules can have only one target before the colon (POSIX), # so we use helper snippets to share code for *.adoc and *.txt sources GENERATE_HTML_SINGLE = ( \ A2X_OUTDIR="tmp/html-single.$(@F).$$$$" ; \ echo " DOC-HTML Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(A2X) $(A2X_COMMON_OPTS) --attribute=xhtml11_format --format=xhtml --xsl-file=$(srcdir)/xhtml.xsl '$<' || RES=$$? ; \ $(DOCBUILD_END) ; \ case "$(@F)" in \ *ChangeLog*) \ if [ -s '$(top_builddir)/ChangeLog' ] ; then \ $(MAKE) $(AM_MAKEFLAGS) "`basename '$(@F)'`"-contentchecked || RES=$$? ; \ if [ "$$RES" != 0 ] ; then \ echo " DOC-HTML Generating $@ (retry once)" >&2; \ rm -f "$@"; \ A2X_OUTDIR="tmp/html-single.$(@F).$$$$-retry" ; \ $(DOCBUILD_BEGIN) ; RES=0; rm -f "`basename '$(@F)'`"-contentchecked || true ; \ $(A2X) $(A2X_COMMON_OPTS) --attribute=xhtml11_format --format=xhtml --xsl-file=$(srcdir)/xhtml.xsl '$<' || RES=$$? ; \ $(DOCBUILD_END) ; \ $(MAKE) $(AM_MAKEFLAGS) "`basename '$(@F)'`"-contentchecked || RES=$$? ; \ fi ; \ fi ;; \ esac ; \ exit $$RES ; \ ) *.html: common.xsl xhtml.xsl .txt-prepped.html: +@$(GENERATE_HTML_SINGLE) .adoc-prepped.html: +@$(GENERATE_HTML_SINGLE) # Note: extra age check here because *.chunked is a directory and not all # "make" implementations check its age vs. source files, just always build: GENERATE_HTML_CHUNKED = ( \ if [ -d "$@" ] && [ x"`find '$@' -newer "$<" 2>/dev/null`" != x ] ; then \ echo " DOC-HTML-CHUNKED SKIP: keep existing $@"; \ exit 0 ; \ fi ; \ A2X_OUTDIR="tmp/html-chunked.$(@F).$$$$" ; \ echo " DOC-HTML-CHUNKED Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ $(A2X) $(A2X_COMMON_OPTS) --attribute=chunked_format --format=chunked --xsl-file=$(srcdir)/chunked.xsl '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES ; \ ) *.chunked: common.xsl chunked.xsl .txt-prepped.chunked: @$(GENERATE_HTML_CHUNKED) .adoc-prepped.chunked: @$(GENERATE_HTML_CHUNKED) # Note: non-HTML a2x modes may ignore the destination directory GENERATE_PDF = ( \ A2X_OUTDIR="tmp/pdf.$(@F).$$$$" ; \ echo " DOC-PDF Generating $@"; \ $(DOCBUILD_BEGIN) ; RES=0; \ if [ -s "$${A2X_OUTDIR}/docinfo.xml" ] ; then A2X_DOCINFO_DIR="$${A2X_OUTDIR}"; fi ; \ $(A2X) $(A2X_COMMON_OPTS) --attribute=pdf_format --format=pdf -a docinfo1 '$<' || RES=$$? ; \ $(DOCBUILD_END) ; exit $$RES ; \ ) *.pdf: docinfo.xml # Technically only needed for PDF generation, but some other recipes still complained qa-guide.adoc-prepped \ qa-guide.pdf: docinfo-since-v2.8.3.xml qa-guide-docinfo.xml .txt-prepped.pdf: @$(GENERATE_PDF) .adoc-prepped.pdf: @$(GENERATE_PDF) # Used below for spellcheck and for .prep-src-docs SPELLCHECK_SRC_DEFAULT = $(ALL_TXT_SRC) \ asciidoc-vars.conf \ ../ci_build.adoc ../README.adoc ../NEWS.adoc \ ../INSTALL.nut.adoc ../UPGRADING.adoc \ ../TODO.adoc ../scripts/ufw/README.adoc \ ../scripts/augeas/README.adoc ../lib/README.adoc \ ../tools/nut-scanner/README.adoc \ ../AUTHORS ../COPYING ../LICENSE-GPL2 ../LICENSE-GPL3 ../LICENSE-DCO if HAVE_ASPELL # Non-interactively spell check all documentation source files. # This is useful for Buildbot and automated QA processing # FIXME: how to present output (std{out,err}, single file or per target)? # NOTE: ../ChangeLog is nowadays generated from commit messages, so # its spelling (or errors in that) are not fixable and thus irrelevant. # Similarly for the ../INSTALL file that is prepared by autoconf and not # tracked as a source file by NUT Git repository. # Note that `docs/asciidoc-vars.conf` is included into docs and so impacts # their resulting spellcheck verdicts. SPELLCHECK_SRC = $(SPELLCHECK_SRC_DEFAULT) # Directory SPELLCHECK_SRC files are relative to. Overridden by other Makefiles. SPELLCHECK_SRCDIR = $(srcdir) SPELLCHECK_BUILDDIR = $(builddir) # Note: de-facto our documentation is beyond ASCII (at least in names of # international committers). The grep tests below look if the aspell output # contained something other than the OK lines (tagged with asterisk) and # aspell's version (tagged with @) and if it did - those lines must be the # spellcheck complaints. Empty OUT is ok. # We also must indent the input, because certain piped-in characters are # interpreted as commands, and seems this feature can not be turned off. # See also http://aspell.net/man-html/Through-A-Pipe.html # TODO: Is "grep -a" or "grep -b" (treat input as ascii/bin) portable enough? # Set SPELLCHECK_ERROR_FATAL=no if there are some unavoidable issues # due to spellchecking, to temporarily not fail builds due to this. # For Travis CI in particular, see ci_build.sh in NUT codebase root. SPELLCHECK_ERROR_FATAL = yes SPELLCHECK_ENV_DEBUG = no ASPELL_NUT_COMMON_ARGS = -p $(abs_srcdir)/$(NUT_SPELL_DICT) ASPELL_NUT_COMMON_ARGS += -d en --lang=en --ignore-accents ASPELL_NUT_COMMON_ARGS += --encoding=utf-8 # Note: If there is a need to use filter path (e.g. in mingw/msys2 builds), # it must be before --mode=tex (-t) option! ASPELL_NUT_TEXMODE_ARGS = if HAVE_ASPELL_FILTER_TEX_PATH ASPELL_NUT_TEXMODE_ARGS += --filter-path="$(ASPELL_FILTER_TEX_PATH)" endif HAVE_ASPELL_FILTER_TEX_PATH ASPELL_NUT_TEXMODE_ARGS += -t ASPELL_ENV_LANG = en.UTF-8 ASPELL_OUT_NOTERRORS = (^[ \t]*[\*\@]|^$$) # WARNING: The percent wildcard is a GNU extension; otherwise we need # a ".txt.txt-spellchecked" type of rule and files like "README" all # renamed to *.txt, or lots of rules for files without the extensions. # Maybe this will get simplified with renaming to *.adoc though ;) # # Other Makefiles have a relatively simple life, dealing with just a # few texts and name/extension patterns in their directories. #?#.txt.txt-spellchecked: Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) #%-spellchecked: % Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) #*-spellchecked */*-spellchecked: $(@:-spellchecked=) $(top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) # # NOTE: For some reason, at least GNU make insists on bogus calls: # update target 'asciidoc-vars.conf' due to: asciidoc-vars.conf-spellchecked # when we e.g. `make dist` after a `make spellcheck` and ended up # with removed and touched (emptied) file, only this one so far. # # NOTE: This portable rule RELIES on just one SPELLCHECK_SRC defined # at a time, with an outer Makefile caller ensuring the looping: SPELLCHECK_RECIPE_DEBUG_STREAM = /dev/null #SPELLCHECK_RECIPE_DEBUG_STREAM = &2 # Note: if we do an interactive spell-check, it updates "nut.dict" # timestamp even if contents remain. If the caller left a copy of # the file as "$(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting", # and/or "$(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive", # and the dictionary was NOT in fact modified, restore the timestamp. $(SPELLCHECK_BUILDDIR)/$(SPELLCHECK_SRC_ONE)-spellchecked: $(SPELLCHECK_SRCDIR)/$(SPELLCHECK_SRC_ONE) $(abs_top_srcdir)/docs/Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ if test x"$(SPELLCHECK_SRC_ONE)" = x ; then echo " SKIP Bogus spellcheck call for empty target filename (with make target $@ from `pwd`)" >&2 ; exit 0; fi; \ case "$@" in *-spellchecked) ;; *) echo " SKIP Bogus spellcheck call for non '*-spellchecked' target filename (with make target $@ from `pwd`)" >&2 ; exit 0;; esac; \ rm -f "$@" || true ; \ $(MKDIR_P) "$(@D)" || exit ; \ REPORT_SRCDIR="$(SPELLCHECK_SRCDIR)"; \ REPORT_SRC_ONE="$(SPELLCHECK_SRC_ONE)"; \ REPORT_PREFIX="" ; \ case "$(SPELLCHECK_SRC_ONE)" in \ /*) ;; \ */*) if [ x"$${REPORT_SRCDIR}" = x ] ; then \ echo EMPTY >$(SPELLCHECK_RECIPE_DEBUG_STREAM) ; \ REPORT_SRCDIR="`dirname '$(SPELLCHECK_SRC_ONE)'`"; \ else \ echo "APPEND: SPELLCHECK_SRCDIR='$(SPELLCHECK_SRCDIR)' SPELLCHECK_SRC_ONE='$(SPELLCHECK_SRC_ONE)' dirname='`dirname '$(SPELLCHECK_SRC_ONE)'`'" >$(SPELLCHECK_RECIPE_DEBUG_STREAM) ; \ REPORT_SRCDIR="$${REPORT_SRCDIR}/`dirname '$(SPELLCHECK_SRC_ONE)'`"; \ fi ; \ REPORT_SRC_ONE="`basename '$(SPELLCHECK_SRC_ONE)'`"; \ ;; \ *) ;; \ esac; \ if [ x"$${REPORT_SRCDIR}" != x ] ; then \ tmpREPORT_PREFIX="NUT source root :: $${REPORT_SRCDIR} :: " ; \ REPORT_SRCDIR="`cd "$${REPORT_SRCDIR}" && { pwd >$(SPELLCHECK_RECIPE_DEBUG_STREAM) ; pwd | sed 's|^'"$(abs_top_srcdir)"'/*||' ; }`" \ || { REPORT_SRCDIR="$(SPELLCHECK_SRCDIR)" ; REPORT_SRC_ONE="$(SPELLCHECK_SRC_ONE)" ; REPORT_PREFIX="" ; } ; \ fi ; \ echo "=== Got REPORT_SRCDIR='$${REPORT_SRCDIR}'" >$(SPELLCHECK_RECIPE_DEBUG_STREAM) ; \ case "$${REPORT_SRCDIR}" in \ "") ;; \ */) ;; \ *) REPORT_SRCDIR="$${REPORT_SRCDIR}/" ;; \ esac ; \ if [ x"$(SPELLCHECK_INTERACTIVE)" = xtrue ] ; then \ echo " ASPELL Spell checking (interactively) on $${REPORT_PREFIX}$${REPORT_SRCDIR}$${REPORT_SRC_ONE}"; \ LANG=$(ASPELL_ENV_LANG) LC_ALL=$(ASPELL_ENV_LANG) $(ASPELL) check $(ASPELL_NUT_COMMON_ARGS) '$(SPELLCHECK_SRCDIR)/$(SPELLCHECK_SRC_ONE)' || exit ; \ if [ -s $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive ] && [ -s $(abs_srcdir)/$(NUT_SPELL_DICT) ] && diff $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive >/dev/null ; then \ touch -r $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive $(abs_srcdir)/$(NUT_SPELL_DICT) ; \ else \ if [ -s $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting ] && [ -s $(abs_srcdir)/$(NUT_SPELL_DICT) ] && diff $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting >/dev/null ; then \ touch -r $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting $(abs_srcdir)/$(NUT_SPELL_DICT) ; \ fi ; fi ; \ else \ echo " ASPELL Spell checking on $${REPORT_PREFIX}$${REPORT_SRCDIR}$${REPORT_SRC_ONE}"; \ fi ; \ OUT="`(sed 's,^\(.*\)$$, \1,' | $(ASPELL) -a $(ASPELL_NUT_TEXMODE_ARGS) $(ASPELL_NUT_COMMON_ARGS) 2>&1) < '$(SPELLCHECK_SRCDIR)/$(SPELLCHECK_SRC_ONE)'`" \ && { if test -n "$$OUT" ; then OUT="`echo "$$OUT" | $(EGREP) -b -v '$(ASPELL_OUT_NOTERRORS)' `" ; fi; \ test -z "$$OUT" ; } \ || { RES=$$? ; \ echo "FAILED : Aspell reported errors here:" >&2 \ && echo "----- vvv" >&2 \ && echo "$$OUT" >&2 \ && echo "----- ^^^" >&2 ; \ exit $$RES; } ; \ touch "$@" # If NUT_MAKE_SKIP_FANOUT!=true we have a hack to spellcheck certain files more # quickly (in parallel). This approach is constrained to files with a known # extension and located in same directory as the Makefile that called them # (extension-less docs and relative links are built sequentially). SPELLCHECK_AUTO_ONE = ( \ SPELLCHECK_SRC_ONE="`basename '$?'`" ; \ rm -f "$@".failed ; \ $(MAKE) $(AM_MAKEFLAGS) -k -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_SRC="" SPELLCHECK_SRC_ONE="$${SPELLCHECK_SRC_ONE}" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" "$(SPELLCHECK_BUILDDIR)/$${SPELLCHECK_SRC_ONE}-spellchecked" \ || { RES=$$? ; touch "$@".failed; exit $$RES; } \ ) .txt.txt-spellchecked-auto: +@$(SPELLCHECK_AUTO_ONE) .adoc.adoc-spellchecked-auto: +@$(SPELLCHECK_AUTO_ONE) .in.in-spellchecked-auto: +@$(SPELLCHECK_AUTO_ONE) .sample.sample-spellchecked-auto: +@$(SPELLCHECK_AUTO_ONE) .conf.conf-spellchecked-auto: +@$(SPELLCHECK_AUTO_ONE) spellcheck: @if test "$(SPELLCHECK_ENV_DEBUG)" = detailed ; then \ echo "ASPELL DEBUG : information about the setup follows:"; \ LANG=$(ASPELL_ENV_LANG); LC_ALL=$(ASPELL_ENV_LANG); export LANG; export LC_ALL; \ $(ASPELL) --help || true; \ (command -v dpkg) && ( dpkg -l | grep -i aspell ) || true ; \ echo "ASPELL automatic execution line is : ( sed 's,^\(.*\)$$, \1,' < docfile.txt | $(ASPELL) -a $(ASPELL_NUT_TEXMODE_ARGS) $(ASPELL_NUT_COMMON_ARGS) | $(EGREP) -b -v '$(ASPELL_OUT_NOTERRORS)' )" ; \ echo "ASPELL proceeding to spellchecking job..."; \ else true; fi +@FAILED="" ; LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ if [ x"$(NUT_MAKE_SKIP_FANOUT)" = xtrue ] ; then \ for docsrc in $(SPELLCHECK_SRC); do \ if test "$(SPELLCHECK_ENV_DEBUG)" != no ; then \ echo "ASPELL MAKEFILE DEBUG: Will see from `pwd` if '$(SPELLCHECK_SRCDIR)/$${docsrc}-spellchecked' is up to date" >&2; \ else true ; fi ; \ $(MAKE) $(AM_MAKEFLAGS) -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_SRC="" SPELLCHECK_SRC_ONE="$${docsrc}" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" \ || FAILED="$$FAILED $(SPELLCHECK_SRCDIR)/$$docsrc"; \ done ; \ else \ SPELLCHECK_AUTO_TGT="`for docsrc in $(SPELLCHECK_SRC); do case "$${docsrc}" in */*) ;; *.adoc|*.txt|*.in|*.conf|*.sample) printf '%s ' "$${docsrc}-spellchecked-auto" ;; esac ; done`" ; \ SPELLCHECK_NOEXT_DOCS="`for docsrc in $(SPELLCHECK_SRC); do case "$${docsrc}" in */*) printf '%s ' "$${docsrc}" ;; *.adoc|*.txt|*.in|*.conf|*.sample) ;; *) printf '%s ' "$${docsrc}" ;; esac ; done`" ; \ if test "$(SPELLCHECK_ENV_DEBUG)" != no ; then \ echo "ASPELL MAKEFILE DEBUG: from `pwd`: SPELLCHECK_NOEXT_DOCS='$${SPELLCHECK_NOEXT_DOCS}' SPELLCHECK_AUTO_TGT='$${SPELLCHECK_AUTO_TGT}'" ; \ else true ; fi ; \ if [ x"$${SPELLCHECK_AUTO_TGT}" != x ] ; then \ $(MAKE) $(AM_MAKEFLAGS) -k -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_SRC="" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" $${SPELLCHECK_AUTO_TGT} ; \ FAILED="`for docsrc in $(SPELLCHECK_SRC); do if [ -e "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked-auto.failed" ] ; then printf '%s ' "$(SPELLCHECK_SRCDIR)/$${docsrc}" ; rm -f "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked-auto.failed" ; fi ; done`" ; \ fi ; \ if [ x"$${SPELLCHECK_NOEXT_DOCS}" != x ] ; then \ for docsrc in $${SPELLCHECK_NOEXT_DOCS} ; do \ $(MAKE) $(AM_MAKEFLAGS) -k -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_SRC="" SPELLCHECK_SRC_ONE="$${docsrc}" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" \ || FAILED="$$FAILED $(SPELLCHECK_SRCDIR)/$$docsrc"; \ done ; \ fi ; \ fi ; \ if test -n "$$FAILED" ; then \ echo "=====================================================================" ; \ echo "FAILED automatic spellcheck for the following sources (relative to `pwd`) using custom dictionary file '$(NUT_SPELL_DICT)': $$FAILED" ; \ echo "=====================================================================" ; \ echo "Please 'cd $(abs_top_builddir) && make spellcheck-interactive'"; \ echo "to either fix document sources or update the dictionary of accepted"; \ echo "words and spellings listed in the '$(NUT_SPELL_DICT)' file there."; \ echo "Either way, please follow up by posting a pull request or a patch"; \ echo "to integrate your fixes into the common NUT codebase."; \ echo "=====================================================================" ; \ test x"$(SPELLCHECK_ERROR_FATAL)" = xno || exit 1; \ echo "NOTE: SPELLCHECK_ERROR_FATAL == no so this make does not break the build!"; \ echo "=====================================================================" ; \ fi >&2 ; exit 0 # Interactively spell check all documentation source files below (so a human # can edit the documentation errors and/or add words to custom dictionary). # Note that here we do not restrain reported issues, so this might catch more # than the automated test above. spellcheck-sortdict: $(abs_builddir)/$(NUT_SPELL_DICT).sorted # Note that the source file may be not overwritable (distcheck, cdrom, ...), # so we'd ignore that failure. But the practical use-case is a developer's # in-tree workspace, so we want the working copy of the dictionary fixed up # for easy `git diff`ing if possible. # Note also that "$( "$@" @cp -f "$@" "$(abs_builddir)/$(NUT_SPELL_DICT)" @if [ "$(abs_builddir)" != "$(abs_srcdir)" ] ; then \ cp -f "$@" "$?" || true ; \ cp -f "$(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-sorting" "$(abs_srcdir)/" || true ; \ fi DISTCLEANFILES += $(NUT_SPELL_DICT).bak-pre-sorting $(NUT_SPELL_DICT).bak-pre-interactive .$(NUT_SPELL_DICT).sorted $(NUT_SPELL_DICT).sorted # NOTE: In "make SPELLCHECK_INTERACTIVE=true ${docsrc}-spellchecked", # after an interactive "aspell check" we follow-up by a run of usual # non-interactive spell-checker to verify that the developer actually # has fixed all of the files that the tool had concerns about, and # that the touch-file is updated if the file is okay (to speed up # any future re-runs). We also must update all relevant *-spellchecked # touch-files after "make spellcheck-sortdict" which updates "nut.dict" # file which is a prerequisite for docs checks. # After the (possibly SUBDIR-based) run we may report to the developer # that their dictionary was updated and may need a Git recommit - either # if it did change, or if caller's SPELLCHECK_REPORT_MAYBE_UPDATED_DICT=yes. SPELLCHECK_REPORT_MAYBE_UPDATED_DICT = no spellcheck-interactive: @cp -pf $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive +@FAILED="" ; for docsrc in $(SPELLCHECK_SRC); do \ if test "$(SPELLCHECK_ENV_DEBUG)" != no ; then \ echo "ASPELL (INTERACTIVE) MAKEFILE DEBUG: Will see from `pwd` if '$(SPELLCHECK_SRCDIR)/$${docsrc}-spellchecked' is up to date" >&2; \ else true ; fi ; \ $(MAKE) $(AM_MAKEFLAGS) -s -f "$(abs_top_builddir)/docs/Makefile" SPELLCHECK_INTERACTIVE="true" SPELLCHECK_SRC="" SPELLCHECK_SRC_ONE="$${docsrc}" SPELLCHECK_BUILDDIR="$(SPELLCHECK_BUILDDIR)" SPELLCHECK_SRCDIR="$(SPELLCHECK_SRCDIR)" "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" \ || FAILED="$$FAILED $(SPELLCHECK_SRCDIR)/$$docsrc"; \ done ; \ if test -n "$$FAILED" ; then \ echo "FAILED interactive spellcheck for the following sources (relative to `pwd`) using custom dictionary file '$(NUT_SPELL_DICT)': $$FAILED" >&2 ; \ exit 1; \ fi ; \ $(MAKE) $(AM_MAKEFLAGS) spellcheck-sortdict || exit ; \ for docsrc in $(SPELLCHECK_SRC); do \ if test -e "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" ; then \ touch "$(SPELLCHECK_BUILDDIR)/$${docsrc}-spellchecked" ; \ fi ; \ done @if [ "$(SPELLCHECK_REPORT_MAYBE_UPDATED_DICT)" != no ] \ || ( [ -s $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive ] && [ -s $(abs_srcdir)/$(NUT_SPELL_DICT) ] \ && ! diff $(abs_srcdir)/$(NUT_SPELL_DICT) $(abs_builddir)/$(NUT_SPELL_DICT).bak-pre-interactive >/dev/null ) \ ; then \ echo "------------------------------------------------------------------------"; \ echo "Custom dictionary file $(NUT_SPELL_DICT) may have been updated now."; \ echo "Use e.g. 'git add -p docs/$(NUT_SPELL_DICT) && git checkout -- docs/$(NUT_SPELL_DICT) && make spellcheck-sortdict && git add -p docs/$(NUT_SPELL_DICT)'"; \ echo "to review changes (please DO NOT REMOVE LINES that aspell chose to drop,"; \ echo "because other systems might not know these words in their system dictionaries)"; \ echo "------------------------------------------------------------------------" ; \ fi else !HAVE_ASPELL # This rule would probably just fail; normally with no ASPELL there are no callers for it */*-spellchecked *-spellchecked: Makefile.am $(abs_srcdir)/$(NUT_SPELL_DICT) @echo " SKIP-ASPELL $@ : Documentation spell check not available since 'aspell' was not found (or missing its English dictionary)." >&2 spellcheck: @echo "Documentation spell check not available since 'aspell' was not found (or missing its English dictionary)." spellcheck-interactive: @echo "Documentation spell check not available since 'aspell' was not found (or missing its English dictionary)." endif !HAVE_ASPELL # Note that NUT_SPELL_DICT may be an include snippet without the header line. # To exclude files like `docs/nut.dict` or `nut-website.dict(.addons)` from # the usage lookups, we assume that a `*.dict*` pattern fits any used names. # Entries prefixed with '+++' mean something used in NUT sources in context # that aspell is likely to treat as a word (standalone or surrounded by certain # chars); otherwise in entries prefixed with '---' we print hit counts and # contents (if any, ending with '^^^') for the character pattern across the # whole Git-tracked codebase (case-insensitively for good measure). # Note this can take 5-10 minutes! # TOTHINK: Constrain to (caller-specified or default) SPELLCHECK_SRC? $(NUT_SPELL_DICT).usage-report: $(NUT_SPELL_DICT) @echo "Preparing $@"; \ LANG=C; LC_ALL=C; export LANG; export LC_ALL; \ grep -v -E '^personal_ws' < $? \ | while read W ; do ( \ cd "$(abs_top_srcdir)" || exit ; \ git grep -q "$$W" -- ':!*.dict*' || git grep -qE "[0-9_,./\ -]$$W[0-9_,./\ -]" -- ':!*.dict*' ) \ && echo "+++ $$W" \ || ( \ HITS_CS="`git grep "$$W" -- ':!*.dict*'`" || true; \ HITS_CI="`git grep -i "$$W" -- ':!*.dict*'`" || true; \ if [ -n "$$HITS_CS" ] ; then HITC_CS="`echo "$$HITS_CS" | wc -l`" ; else HITC_CS=0; fi; \ if [ -n "$$HITS_CI" ] ; then HITC_CI="`echo "$$HITS_CI" | wc -l`" ; else HITC_CI=0; fi; \ printf '%s (%d case-sensitive/%d case-insensitive)\n' "--- $$W" "$$HITC_CS" "$$HITC_CI"; \ if [ "$$HITC_CS" != 0 ] ; then echo "$$HITS_CS" ; echo "^^^"; else \ if [ "$$HITC_CI" != 0 ] ; then echo "$$HITS_CI" ; echo "^^^"; fi; \ fi; \ ); \ done > "$@.tmp.$$$$" \ && test -f "$@.tmp.$$$$" \ && mv -f "$@.tmp.$$$$" "$@" @echo "Reporting words from $? possibly not used in current inspected code base revision under $(abs_top_srcdir)" >&2 ; \ grep -E '^--- ' < "$@" | grep '(0 ' || echo "SUCCESS: None found" CLEANFILES += $(NUT_SPELL_DICT).usage-report.tmp MAINTAINERCLEANFILES += $(NUT_SPELL_DICT).usage-report # When building out-of-tree, be sure to have all asciidoc resources # under the same dir structure (tool limitation) PREP_SRC = $(EXTRA_DIST) $(SPELLCHECK_SRC_DEFAULT) # NOTE: Some "make" implementations prefix a relative or absent path to # the filenames in PREP_SRC, others (e.g. Sun make) prepend the absolute # path to locate the sources, so we end up with bogus trees under docs/. # Code below tries to detect and truncate this mess, including possible # source texts located in/under parent dirs. # We also handle man page links (section-aware) for platforms where they # differ from common defaults. # NOTE: MKDIR_P may be defined via expanded $(top_builddir)/install-sh # so should be run from $(abs_builddir) to be safe, as we jump around # the build workspace prep-src-docs: $(abs_top_builddir)/docs/.prep-src-docs $(abs_top_builddir)/docs/.prep-src-docs: $(PREP_SRC) Makefile @cd "$(@D)" || exit ; \ linkroot="$(abs_builddir)" ; \ MAN_SECTIONS_DEFAULT=false ; \ if [ x"$(MAN_SECTION_API)$(MAN_SECTION_CFG)$(MAN_SECTION_CMD_SYS)$(MAN_SECTION_CMD_USR)" = x3581 ] ; then \ MAN_SECTIONS_DEFAULT=true ; \ fi ; \ if test x"$(abs_srcdir)" = x"$(abs_builddir)" ; then \ COUNT=0; \ for F in $(PREP_SRC) ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed 's#^$(abs_top_srcdir)/*#./#'`"; \ if test x"$${linkroot}" = x"$(abs_builddir)" ; then \ linkroot="$(abs_top_builddir)" ; \ cd "$(abs_top_builddir)" ; \ fi ;; \ esac ; \ if $$MAN_SECTIONS_DEFAULT ; then \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' ; \ else \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' \ -e 's,\(linkman:[^ []*\[\)3\],\1$(MAN_SECTION_API)],g' \ -e 's,\(linkman:[^ []*\[\)5\],\1$(MAN_SECTION_CFG)],g' \ -e 's,\(linkman:[^ []*\[\)8\],\1$(MAN_SECTION_CMD_SYS)],g' \ -e 's,\(linkman:[^ []*\[\)1\],\1$(MAN_SECTION_CMD_USR)],g' ; \ fi < "$${F}" > "$${F}-prepped" || exit ; \ COUNT="`expr $$COUNT + 1`" ; \ done ; \ if ! test -e "$@" ; then touch "$@" ; fi ; \ else \ COUNT=30 ; \ touch "$@.$$$$" ; \ while test -e "$@.working" -a "$$COUNT" -gt 0 ; do sleep 1; COUNT="`expr $$COUNT - 1`"; done ; \ touch "$@.working" ; \ if test -n "`find "$@" -newer "$@.$$$$" 2>/dev/null`" ; then \ rm -f "$@.$$$$" "$@.working" ; \ exit 0; \ fi ; \ rm -f "$@.$$$$" ; \ COUNT=0; \ linksrcroot="$(abs_srcdir)" ; \ for F in `echo $(PREP_SRC) | tr ' ' '\n' | sort -n | uniq` ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed 's#^$(abs_top_srcdir)/*#./#'`"; \ if test x"$${linkroot}" = x"$(abs_builddir)" ; then \ linkroot="$(abs_top_builddir)" ; \ linksrcroot="$(abs_top_srcdir)" ; \ cd "$(abs_top_builddir)" ; \ fi ;; \ "$(srcdir)"/*) F="`echo "$$F" | sed 's#^$(srcdir)/*#./#'`" ;; \ */*) ;; \ *) \ linkroot="$(abs_builddir)" ; \ linksrcroot="$(abs_srcdir)" ; \ cd "$(abs_top_builddir)" ;; \ esac ; \ D="`dirname "$$F"`" ; \ (cd '$(abs_builddir)' && $(MKDIR_P) "$${linkroot}/$$D") || { rm -f "$@.working" ; exit 1 ; } ; \ if ! test -s "$${linkroot}/$$F" && test -s "$${linksrcroot}/$$F" ; then \ echo " LN '$${linksrcroot}/$$F' => '$${linkroot}/$$F' (PWD = '`pwd`')" ; \ ln -fs "$${linksrcroot}/$$F" "$${linkroot}/$$F" || { rm -f "$@.working" ; exit 1 ; } ; \ COUNT="`expr $$COUNT + 1`" ; \ fi ; \ case "$$F" in \ *.txt|*.adoc) IS_TEXT=true ;; \ *.*) IS_TEXT=false ;; \ *) IS_TEXT=true ;; \ esac; \ if $$IS_TEXT ; then \ grep -w linkman "$${linkroot}/$${F}" > /dev/null || IS_TEXT=false ; \ fi ; \ if $$MAN_SECTIONS_DEFAULT || ! $$IS_TEXT ; then \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' ; \ else \ sed \ -e 's,\(home page:\) https://www.networkupstools.org/*$$,\1 $(NUT_WEBSITE_BASE)/,' \ -e 's,\(linkman:[^ []*\[\)3\],\1$(MAN_SECTION_API)],g' \ -e 's,\(linkman:[^ []*\[\)5\],\1$(MAN_SECTION_CFG)],g' \ -e 's,\(linkman:[^ []*\[\)8\],\1$(MAN_SECTION_CMD_SYS)],g' \ -e 's,\(linkman:[^ []*\[\)1\],\1$(MAN_SECTION_CMD_USR)],g' ; \ fi < "$${linkroot}/$${F}" > "$${linkroot}/$${F}-prepped" \ || { rm -f "$@.working" ; exit 1 ; } ; \ COUNT="`expr $$COUNT + 1`" ; \ done ; \ fi ; \ if test "$$COUNT" -gt 0 -o ! -e "$@" ; then touch "$@" ; fi @rm -f "$@.working" # Dirs to clean, etc. clean-local: $(AM_V_at)rm -rf *.chunked *.bak tmp $(AM_V_at)for F in $(PREP_SRC) ; do \ case "$$F" in \ /*) F="`echo "$$F" | sed 's#^$(abs_top_srcdir)/*#./#'`"; cd "$(abs_top_builddir)" ;; \ esac ; \ if test x"$(abs_srcdir)" != x"$(abs_builddir)" ; then \ if test -L "$$F" || test -h "$$F" ; then \ rm -f "$$F" ; \ fi ; \ fi ; \ rm -f "$${F}-prepped" ; \ done ; \ rm -f "$(abs_top_builddir)/docs/.prep-src-docs"* .PHONY: html html-chunked html-single pdf man nut-2.8.3/docs/sock-protocol.txt0000644000200500020050000002501214777767434013560 00000000000000Driver/server socket protocol ============================= Here's a brief explanation of the text-based protocol which is used between the drivers and server. The drivers may send things on the socket at any time. They will send out changes to their local storage immediately, without any sort of prompting from the server. As a result, the server must always check on any driver sockets for activity. In terms of communications, each driver is a server on the Unix socket (or Windows named pipe) which it creates, and the data server `upsd` is a client which knows where to find such sockets, how they are named, and connects to all of them to send commands and receive data updates. During development, it is possible to use tools like `socat` to connect to the socket (you may want to enable `NOBROADCAST` mode soon), e.g. socat - UNIX-CONNECT:/var/state/ups/dummy-ups-UPS1 For more insight, NUT provides an optional tool of its own (not built by default): the `sockdebug` which is built when `configure --with-dev` is in effect, or can be requested from the root directory of the build workspace: make sockdebug && \ ./server/sockdebug dummy-ups-UPS1 Formatting ---------- All parsing on either side of the socket is done by parseconf, so the same rules about escaping characters and "quoting multi-word elements" apply here. Values which may contain odd characters are typically sent through pconf_encode to apply \ characters where necessary. The "" construct is used throughout to force a multi-word value to stay together on its way to the other end. Commands used by the drivers ---------------------------- These commands (or semantically responses to server commands in some cases) can be sent by drivers to the data server over the socket protocol. SETINFO ~~~~~~~ SETINFO "" SETINFO ups.status "OB LB" There is no "ADDINFO" -- if a given variable does not exist, it is created upon receiving the first SETINFO command. DELINFO ~~~~~~~ DELINFO DELINFO ups.temperature ADDENUM ~~~~~~~ ADDENUM "" ADDENUM input.transfer.low "95" DELENUM ~~~~~~~ DELENUM "" DELENUM input.transfer.low "98" ADDRANGE ~~~~~~~~ ADDRANGE ADDRANGE input.transfer.low 95 100 DELRANGE ~~~~~~~~ DELRANGE DELRANGE input.transfer.low 95 100 SETAUX ~~~~~~ SETAUX SETAUX ups.id 8 This overrides any previous value. The auxiliary value is presently used as a length byte for read-write variables that are strings. SETFLAGS ~~~~~~~~ SETFLAGS ... SETFLAGS ups.id RW STRING Note that this command takes a variable number of arguments, as multiple flags are supported. Also note that they are not crammed together in "" quotes, since "RW STRING" would mean something completely different. This also replaces any previous flags for a given variable. Currently supported flags include `RW`, `STRING` and `NUMBER` (detailed in the NUT Network Protocol documentation); unrecognized values are quietly ignored. ADDCMD ~~~~~~ ADDCMD ADDCMD load.off DELCMD ~~~~~~ DELCMD DELCMD load.on PID ~~~ PID PID 12345 PID "StrangeOS process identifier" Response to `GETPID` query, where we serve platform-specific process identifier. On POSIX and many other platforms this would be a numeric value, but most generally it should be treated as an opaque string. DUMPDONE ~~~~~~~~ DUMPDONE This is only used to tell the server that every possible item has been transmitted in response to its DUMPALL request. Once this has been received by the server, it can be sure that it knows everything that the driver does. PONG ~~~~ PONG This is sent in response to a PING from the server. It is only used as a sanity check to make sure that the driver has not gotten stuck somewhere. OK ~~ OK Goodbye This is sent in response to a LOGOUT from the server (or more likely from a sibling driver or `upsdrvctl` program). DATAOK ~~~~~~ DATAOK This means that the driver is able to communicate with the UPS, and the data should be treated as usable. It is always sent at the end of the dump if the data is not stale. It may also be sent at other times. DATASTALE ~~~~~~~~~ DATASTALE This is sent by the driver to inform any listeners that the data is no longer usable. This usually means that the driver is unable to get any sort of meaningful response from the UPS. You must not rely on any status information once this has been sent. This will be sent in the beginning of a dump if the data is stale, and may be repeated. It is cleared by DATAOK. TRACKING ~~~~~~~~ TRACKING This is sent in response to an INSTCMD or SET VAR that includes a TRACKING, upon completion of request execution by the driver. is the integer return value from the driver handlers instcmd and setvar (see drivers/upshandler.h). The server is in charge of translating these codes into strings, as per docs/net-protocol.txt GET TRACKING. Commands sent by the server --------------------------- The data server `upsd` (or technically any client that connects to a Unix socket or Windows named pipe provided by each NUT driver) can send the following commands to the driver: PING ~~~~ PING This is sent to check on the health of a driver. The server should only send this when it hasn't heard anything valid from a driver recently. Some drivers have very little to say in terms of updates, and this may be the only communications they have with the server on a normal basis. If a driver does not respond with the PONG within a few seconds at the most, it should be treated as dead/unavailable. Data stored in the server must not be passed on to the clients when this happens. NOTE: For the `upsd` data server, the MAXAGE setting in upsd.conf controls how long since the last message from the driver it is considered stale. At 1/3 of this time the server sends a `PING` command to the driver, so there is some time for a `PONG` to arrive and reset the timer (any other message would serve that goal as well). INSTCMD ~~~~~~~ INSTCMD [] [TRACKING ] INSTCMD panel.test.start INSTCMD load.off 10 INSTCMD load.on 10 TRACKING 1bd31808-cb49-4aec-9d75-d056e6f018d2 NOTE: * is an additional and optional parameter for the command, * "TRACKING " can be provided to track commands execution status, if TRACKING was set to ON on upsd. In this case, driver will later return the execution status, using TRACKING. SET ~~~ SET "" [TRACKING ] SET ups.id "Data room" SET ups.id "Data room" TRACKING 2dedb58a-3b91-4fab-831f-c8af4b90760a NOTE: * "TRACKING " can be provided to track commands execution status, if TRACKING was set to ON on upsd. In this case, driver will later return the execution status, using TRACKING. GETPID ~~~~~~ The server (or sibling driver instances, or `upsdrvctl` tool) can use this to request the platform-specific process identifier of the driver process. On POSIX and many other platforms this would be a numeric value, but most generally it should be treated as an opaque string. DUMPALL ~~~~~~~ DUMPALL The server uses this to request a complete copy of everything the driver knows. This is returned in the form of the same commands (SETINFO, etc.) that would be used if they were being updated normally. As a result, the same parsing happens either way. The server can tell when it has a full copy of the data by waiting for DUMPDONE. That special response from the driver is sent once the entire set has been transmitted. DUMPVALUE ~~~~~~~~~ DUMPVALUE DUMPVALUE driver.version Only request the value of specified variable name (and its additional metadata in other lines), same as when `DUMPALL` iterates all such names. The NUT data server or other socket-protocol client should parse the response line by line, looking for the SETINFO line to get the value; if a DUMPDONE is seen first, the value was not available in the driver. DUMPSTATUS ~~~~~~~~~~ DUMPSTATUS Effectively an alias to `DUMPVALUE ups.status`. NOBROADCAST ~~~~~~~~~~~ This connection does not want to receive broadcast messages (implemented by `send_to_all()` method in `dstate.c`). Default is to receive everything. BROADCAST (NUM) ~~~~~~~~~~~~~~~ This connection specified whether it wants to receive broadcast messages (implemented by `send_to_all()` method in `dstate.c`), and by default enables that -- unless disabled by providing an optional zero or negative numeric argument. Note that initial default is to receive everything, so this command may be useful for connections that disabled broadcasts at some point. LOGOUT ~~~~~~ Primarily used by communications between driver processes and/or `upsdrvctl`, this command allows clients to gracefully close connection to the NUT driver which acts as the server on the socket/pipe, avoiding noisy logs about sudden disconnection. LOGOUT OK Goodbye Design notes ------------ Requests ~~~~~~~~ There is no way to request just one variable. This was done on purpose to limit the complexity of the drivers. Their job is to send out updates and handle a few simple requests. DUMPALL is provided to give the server a known foundation. To track a limited set of variables, a server just needs to do DUMPALL, then only have handlers that remember values for the variables that matter. Anything else should be ignored. Access/Security ~~~~~~~~~~~~~~~ There are no access controls in the drivers. Anything that can connect to their sockets can make requests, including SET and INSTCMD if supported by the driver and hardware. These sockets must be kept secure. If your operating system does not honor permissions or modes on sockets, then you must store them in a directory with suitable permissions to limit access. Command limitations ~~~~~~~~~~~~~~~~~~~ As parseconf is used to handle decoding and chunking of the data, there are some limits on what may be used. These default to 32 arguments of 512 characters each, which should be more than enough for everything which is currently needed by the software. These limits are strictly for sanity purposes, and may be raised if necessary. parseconf itself can handle vast numbers of arguments and characters, with some speed penalty as things get really big. Re-establishing communications ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If the server loses its connection to the driver and later reconnects, it must flush any local storage and start again with DUMPALL. The driver may have changed the internal state considerably during that time, and any other approach could leave old elements behind. nut-2.8.3/docs/cables.txt0000644000200500020050000000700214777767434012212 00000000000000ifdef::website[] Cables ====== endif::website[] APC --- 940-0024C clone ~~~~~~~~~~~~~~~ *From D. Stimits* image::images/cables/940-0024C.jpg[APCC 940-0024C clone diagram] NOTE: The original 940-0024C diagram was contributed by Steve Draper. 940-0024E clone ~~~~~~~~~~~~~~~ *Reported by Jonathan Laventhol* This cable is said to use the same wiring as 940-0024C clone. 940-0024C clone for Macs ~~~~~~~~~~~~~~~~~~~~~~~~ *From Miguel Howard* image::images/cables/mac-940-0024C.png[APCC 940-0024C clone cable for Macs] Belkin ------ OmniGuard F6C***-RKM ~~~~~~~~~~~~~~~~~~~~ *From "Daniel"* A straight-through RS-232 cable (with pins 2-7 connected through) should work with the following models: - F6C110-RKM-2U - F6C150-RKM-2U - F6C230-RKM-2U - F6C320-RKM-3U image::images/cables/belkin-f6cx-rkm-xu-cable.jpg[Belkin OmniGuard F6C***-RKM cable] Eaton ----- Documents in this section are provided courtesy of Eaton. MGE Office Protection Systems ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The three first cables also applies to MGE UPS SYSTEMS and Eaton. DB9-DB9 cable (ref 66049) ^^^^^^^^^^^^^^^^^^^^^^^^^ This is the standard serial cable, used on most units. image::images/cables/mge-66049.png[DB9-DB9 cable] DB9-RJ45 cable ^^^^^^^^^^^^^^ This cable is used on the more recent models, including Ellipse MAX, Protection Station, ... image::images/cables/mge-db9-rj45.jpg[DB9-RJ45 cable] NMC DB9-RJ45 cable ^^^^^^^^^^^^^^^^^^ The following applies to the MGE 66102 NMC (Network Management Card), and possibly other models. The NMC connection is an 8P8C RJ45-style jack. |==== |Signal | PC | NMC | | 1,4,6 | |TxD | 2 | 3 |RxD | 3 | 6 |GND | 5 | 4 | | 7,8 | | | shield | shield |==== USB-RJ45 cable ^^^^^^^^^^^^^^ This cable is used also on the more recent models, including Ellipse MAX, Protection Station, ... image::images/cables/mge-usb-rj45.jpg[USB-RJ45 cable] DB9-RJ12 cable ^^^^^^^^^^^^^^ This cable is used on some older Ellipse models. image::images/cables/mge-db9-rj12.jpg[DB9-RJ12 cable] Powerware LanSafe ~~~~~~~~~~~~~~~~~ image::images/cables/Lansafecable.jpg[Powerware LanSafe cable] SOLA-330 ~~~~~~~~ Just uses a normal serial cable, with pin 1-1 through to 9-9. image::images/cables/SOLA-330.png[SOLA-330 cable] HP - Compaq ----------- Older Compaq UPS Family ~~~~~~~~~~~~~~~~~~~~~~~ This cable can be used with the following models: T700, T1000, T1500, T1500j, T700h, T1000h, T1500h, R1500, R1500j, R1500h, T2000, T2000j, T2400h, T2400h-NA, R3000 / R3000j, R3000h, R3000h-International, R3000h-NA, R6000h-NA, R6000i, R6000j. ---- UPS PC 9 pin connector 1 --------- 3 2 --------- 2 4 -\ 4 --------- 5 | 6 -/ 6 --------- 7 ---- Contributed by Kjell Claesson and Arnaud Quette. Phoenixtec (Best Power) ----------------------- Many Best Power units (including the Patriot Pro II) have a female DB-9 socket with a non-standard pinout. |==== |Signal | PC | UPS | | 1,4,6 | NC |TxD | 2 | 2 |RxD | 3 | 1 |GND | 5 | 4 | | 7,8 | NC |==== Sources: * http://pinoutsguide.com/UPS/best_power_pinout.shtml * http://lit.powerware.com/ll_download.asp?file=m_patriotproii_jan99.pdf * Stan Gammons Tripp-Lite ---------- *From Tripp-Lite, via Bryan Kolodziej* This cable (black 73-0844 cable) is used on various models, using the "Lan 2.2 interface" and the genericups driver (upstype=5). image::images/cables/73-0724.png[73-0724 cable] nut-2.8.3/docs/packager-guide.txt0000644000200500020050000002553614777767434013645 00000000000000NUT Packager and Integrators Guide ================================== Arnaud Quette WARNING: this is a Work In Progress document. Abstract -------- The aim of this document is to describe the best way to package the Network UPS Tools, and the best practices across the various packaging implementation of NUT. So as to these can be spread on all supported platforms as a standard, and as a foundation block to build upon. /////////////////////////////////////////////////////////////////////// *sandbox* that have been done to help those improving, and give advice on what's the best way to package NUT for the remaining "not yet packaged" platform (Sun, AIX, Mac, ...). The ultimate aim is to have NUT well packaged (all NUT features available) on all supported platforms. /////////////////////////////////////////////////////////////////////// Introduction ------------ Packaging is a final aim for software. It eases and completes the software integration into an OS, and allows users to have an easy software installation and support out of the box. NOTE: Making NUT packaging more uniform should help its documentation, support and maintenance across the supported OSes. ------------------------------------------------------------------------ *sandbox* This document assumes that you have read the other NUT documents such as INSTALL.nut, FAQ, config-notes.txt, config-prereqs.txt ... Facts about NUT packaging ========================= NUT has so much evolved those two last years (with USB and SNMP support, the premises of libraries, ...) that the simple "1, 2 or 3 package(s)" approach is no more suitable. This fact has reached a high level since NUT 1.4. Actually, doing this would result in either being forced to install hosts of unneeded dependencies (net-snmp, gd, ... as seen on SUSE), to have a partially broken package [1] or not being able to use all NUT features [2]. Let's now have an overview on how NUT is currently packaged: 1) Debian: http://packages.qa.debian.org/n/nut.html nut, nut-dev, nut-usb, nut-snmp, nut-xml, nut-cgi, nut-doc 2) Mandriva http://cvs.mandriva.com/cgi-bin/cvsweb.cgi/SPECS/nut/ nut-server nut nut-cgi 3) SUSE / Novell nut 4) RedHat 5) PLD http://cvs.pld-linux.org/cgi-bin/cvsweb/SPECS/nut.spec ... (FreeBSD, Gentoo Linux, IRIX, NetBSD, OpenBSD) This shows how much the packages name split is now scattered. The result is: - that a user of several systems will be lost, and will waste time - there is a big waste of energy - this makes things hard to create standard configuration wizards [1] NUT build on Debian GNU/Linux m68k and Hurd was once broken due to hiddev dependencies, and usb support still included in the core package. [2] - snmp-ups driver is not available under Mandrake GNU/Linux, but its man is present. See http://rpms.mandrakeclub.com/rpms/mandrake/9.1/i586/Mandrake/RPMS/nut-server-1.2.1-4mdk.i586.html - secured ssh network mode not available (due to deps and/or non free) - some systems don't provide libupsclient lib/header/.pc so as to client application (such as wmnut) can't be built - the logger function is not (well) used, same goes for the syslog (triple redundancy in Mandriva) - the solution is partial in every system: lost of tests case / feedback could be shared ... ------------------------------------------------------------------------ Packagers involved ------------------ The following packagers are working on this subject: - Debian (and derivatives): Arnaud Quette - SUSE/Novell: Stanislav Brabec - Solaris, OpenSolaris, OpenIndiana and related illumos distributions: Jim Klimov - MacOS: Charles Lepple NOTE: the people below should be contacted to (re)launch discussions! The following packagers should be interested in working on this subject: - FreeBSD: Thierry Thomas? <> - Mandriva: Oden Erikson? <> - RedHat / Fedora Core: <> - Gentoo: <> - NetBSD: <> - OpenBSD: <> - PLD: Andrzej Zawadzki - E-Smith: Charlie Brady - Windows: check with WinNUT author?! - HP-UX: <> - IBM AIX: <> Possible use cases ------------------ - standalone (1 system + 1-n UPS) - network server (same as standalone, but serving data to network clients) - network monitoring client - network supervision client TO BE COMPLETED... Optimized packaging proposal ---------------------------- NOTE: The below proposed packages split is subject to discussion. The aim of this is to: - rationalize split according to the above use cases, - share resources (descriptions, i18n, ...) - find the best compromise between available features and dependencies, - standardize nut packages name, - create the foundation for the upcoming and underway improvements, - improve nut integration, - ease and improve user experience. This standard was created by: - capitalizing on the experience of existing packages, - using and improving the use of all nut features, - considering upcoming nut changes and improvements, - working closely with packagers. Overview of the package tree ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FIXME: make a dependency graph - <> - <> - <> - <> - <> - <> - <> - <> - <> - <> - <> (currently platform-dependent) - <> (platform-dependent) - <> (platform-dependent) - <> - <> - <> (or nut-control-center or Ultimate NUT Tool...) - <> Detailed view of the package tree ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [NOTE] ======================================================================== - The *Desc* field represent the package's description, as exposed by the packaging system. Each package's description is composed of a paragraph common to all NUT packages, and a part that is specific to the package. The common part (further referenced by *COMMON DESC*) is: ________________________________________________________________________ Network UPS Tools (NUT) is a client/server monitoring system that allows computers to share uninterruptible power supply (UPS) and power distribution unit (PDU) hardware. Clients access the hardware through the server, and are notified whenever the power status changes. ________________________________________________________________________ - The *Files* field lists the content of the package. - The mentioned *Size* is a rough estimation of packaged and installed size. This may varies across the systems and architecture, and is based upon the Debian x86 packages. - The *Deps* field lists the dependencies of the packages. The exact name may vary across the various systems. - The *Comment* field is used to place comment for points subject to discussion. ======================================================================== [[pkg-nut]] nut ^^^ - Desc: - Files: dummy/serial/USB drivers + upsd + upslog - Size: - Deps: [[pkg-libupsclient1]] libupsclient1 ^^^^^^^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-libupsclient1-dev]] libupsclient1-dev ^^^^^^^^^^^^^^^^^ - Desc: - Files: - Size: - Deps: NOTE: the "-dev" suffix is to be replaced by "-devel" on RPM based platforms. [[pkg-nut-cgi]] nut-cgi ^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-nut-scanner]] nut-scanner ^^^^^^^^^^^ - Desc: - Files: - Size: - Deps: NOTE: hard third-party dependency on `libltdl`; recommends `libsnmp`, `libneon`, and the `libusb` variant (0.1 or 1.0) it was built against. [[pkg-nut-powerman-pdu]] nut-powerman-pdu ^^^^^^^^^^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-nut-snmp]] nut-snmp ^^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-nut-xml]] nut-xml ^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-nut-ipmi]] nut-ipmi ^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-nut-modbus]] nut-modbus ^^^^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-nut-gpio]] nut-gpio ^^^^^^^^ - Desc: (currently platform-dependent) - Files: - Size: - Deps: [[pkg-nut-linux-i2c]] nut-linux-i2c ^^^^^^^^^^^^^ - Desc: (platform-dependent) - Files: - Size: - Deps: [[pkg-nut-macosx-ups]] nut-macosx-ups ^^^^^^^^^^^^^^ - Desc: (platform-dependent) - Files: - Size: - Deps: [[pkg-nut-clients]] nut-clients ^^^^^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-python-pynut]] python-pynut ^^^^^^^^^^^^ - Desc: - Files: - Size: - Deps: [[pkg-python-nut-gui]] python-nut-gui ^^^^^^^^^^^^^^ (or nut-control-center or Ultimate NUT Tool...) - Desc: - Files: - Size: - Deps: [[pkg-nut-doc]] nut-doc ^^^^^^^ - Desc: - Files: - Size: - Deps: ------------------------------------------------------------------------ *sandbox* nut-server ^^^^^^^^^^ Desc: Files: dummy/serial/USB drivers + upsd + upslog Size: Deps: nut-client, libusb, libc/ld B) nut-snmp Desc: Files: SNMP driver [/ manager ] Deps: nut-server, net-snmp, libc/ld C) nut-client Desc: don't force to have the server part/deps if not needed Files: upsmon, upsc, upscmd, upsrw + driver.list [+nut-dev (lib, .h, .pc, man] Deps: libc/ld E) nut-cgi Deps: Files: snmp-ups and powernet + man pages F) nut-doc: Deps: Files: dummycons + man page G) nut-dev: Deps: Files: upsmon, upsc, upscmd, upsrw H) nut-scanner: Deps: hard dependency on `libltdl`; recommends `libsnmp`, `libneon`, and the `libusb` variant (0.1 or 1.0) it was built against. Files: nut-scanner tool and libnutscan + man pages Note: "nut" can be a meta package This kind of tree obviously needs modification on the conf/make files of NUT to allow build/install in a separate way. ... TO BE CONTINUED ... Configuration option ^^^^^^^^^^^^^^^^^^^^ Example: name= "ups" or "nut" ./configure \ --prefix=/ \ --sysconfdir=/etc/$name \ --mandir=/usr/share/man \ --libdir=/usr/lib \ --includedir=/usr/include \ --datadir=/usr/share/$name \ --with-statepath=/var/run/nut \ --with-altpidpath=/var/run/nut \ --with-drvpath=/lib/nut \ --with-cgipath=/usr/lib/cgi-bin/$name \ html-path --with-pidpath=/var/run/$name \ --with-user=$name \ --with-cgi \ --without-ssl ... NOTE: For packaging (OS distribution or in-house) it is recommended to primarily `./configure --with-all` and then excise `--without-something` explicitly for items not supported on your platform, so you do not miss out on new NUT features as they come with new releases. Some may require that you update your build environment with new third-party dependencies, so a broken build of a new NUT release would let you know how to act. ------------------------------------------------------------------------ nut-2.8.3/docs/download.txt0000644000200500020050000002416014777767434012574 00000000000000Download information ==================== This section presents the different methods to download NUT. Source code ----------- [NOTE] ================================================================================ You should always use PGP/GPG to verify the signatures before using any source code. /////////// // FIXME: linkdoc:user-manual[following procedure,verifySourceSig,docs/security.txt] /////////// You can use the ifdef::website[] link:docs/user-manual.chunked/NUT_Security.html#verifySourceSig[following procedure] endif::website[] ifndef::website[] <>. endif::website[] to do so. ================================================================================ Stable tree: {tree_version} ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - link:https://www.networkupstools.org/source/{tree_version}/nut-{revision}.tar.gz[nut-{revision}.tar.gz] - link:https://www.networkupstools.org/source/{tree_version}/nut-{revision}.tar.gz.sig[PGP/GPG signature] - link:https://www.networkupstools.org/source/{tree_version}/nut-{revision}.tar.gz.sha256[SHA-256 sum] - link:https://www.networkupstools.org/source/{tree_version}/nut-{revision}.tar.gz.md5[MD5 sum] - link:https://www.networkupstools.org/source/{tree_version}/new-{revision}.txt[Release notes] - link:https://www.networkupstools.org/source/{tree_version}/ChangeLog[ChangeLog] You can also browse the link:https://www.networkupstools.org/source/{tree_version}/[stable source directory]. Development tree: ~~~~~~~~~~~~~~~~~ Code repository ^^^^^^^^^^^^^^^ The development tree is available through a Git repository hosted at link:https://github.com/[GitHub]. To retrieve the current development tree, use the following command: :; git clone git://github.com/networkupstools/nut.git OPTIONALLY you can then fetch known git tags, so semantic versions look better (based off a recent release): :; cd nut :; git fetch --tags --all The `configure` script and its dependencies are not stored in Git. To generate them, ensure that autoconf, automake and libtool are installed, then run the following script in the directory you just checked out: :; ./autogen.sh NOTE: it is optionally recommended to have Python 2.x or 3.x, and Perl, to generate some files included into the `configure` script, presence is checked by autotools when it is generated. Neutered files can be just "touched" to pass the `autogen.sh` if these interpreters are not available, and effectively skip those parts of the build later on -- `autogen.sh` will then advise which special environment variables to `export` in your situation and re-run it. Then refer to the ifdef::website[] link:docs/user-manual.chunked/index.html[NUT user manual] endif::website[] ifndef::website[] linkdoc:user-manual[NUT user manual] endif::website[] for more information. ////////////////////////// NOTE: Users that need the latest developments to support new devices *must* use Git or <>. ////////////////////////// Browse code ^^^^^^^^^^^ You can browse the "vanilla NUT" code at the link:https://github.com/networkupstools/nut/[Main GitHub repository for NUT sources], and some possibly modified copies as part of packaging recipe sources of operating system distributions, as listed below. [[Snapshots]] Snapshots ^^^^^^^^^ GitHub has several download links for repository snapshots (for particular tags or branches), but you will need a number of tools such as autoconf, automake and libtool to use these snapshots to generate the `configure` script and some other files. After you `configure` the source workspace, a `make dist-hash` recipe would create the snapshot tarballs which do not require the auto* tools, and their checksum files, such as those available on the NUT website and attached to link:https://github.com/networkupstools/nut/releases[GitHub Releases page]. ///////// TODO: #1400 to replace this with a NUT CI farm service to publish the tarballs If our Buildbot instance is behaving, you can download a snapshot which does not require auto* tools from this link:http://buildbot.networkupstools.org/snapshots[builder]. Look for the latest *[tarball]* link towards the top of the page, and be sure to check the 'Build ##' link to verify the branch name. ///////// Older versions ~~~~~~~~~~~~~~ link:https://www.networkupstools.org/source/[Browse source directory] Binary packages --------------- NOTE: The only official releases from this project are source code. NUT is already available in the following operating systems (and link:https://github.com/networkupstools/nut/wiki/Links-to-distribution-packaging-recipes-and-repository-sections[likely more]): - link:https://repology.org/project/nut/versions[Repology report on NUT] lists 745 entries about NUT, as of this writing - Linux: * link:https://github.com/42ity/nut/tree/FTY/obs[42ITy.org packaging recipes for Debian-based releases] * link:https://salsa.debian.org/debian/nut/[Debian Salsa recipes] and link:http://packages.debian.org/nut[Debian packages] * link:http://packages.ubuntu.com/nut[Ubuntu packages] * link:https://src.fedoraproject.org/rpms/nut/tree/rawhide[Fedora Rawhide recipes] and link:https://src.fedoraproject.org/rpms/nut[Red Hat / Fedora packages] * link:https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=network-ups-tools-git[Arch Linux recipe] and link:https://aur.archlinux.org/packages/network-ups-tools-git[Arch Linux package info] * link:https://gitweb.gentoo.org/repo/gentoo.git/tree/sys-power/nut[Gentoo Linux recipe] and link:http://packages.gentoo.org/package/sys-power/nut[Gentoo Linux package info] * link:https://build.opensuse.org/package/show/openSUSE%3AFactory/nut[Novell SUSE / openSUSE official package base recipe] and link:https://build.opensuse.org/package/show/hardware/nut[Novell SUSE / openSUSE official package development recipe], and link:http://software.opensuse.org/package/nut[Novell SUSE / openSUSE official package overview] * link:https://build.opensuse.org/search?search_text=nut[Numerous other recipes on Open Build System (not only by SUSE)] * link:https://github.com/openwrt/packages/tree/master/net/nut[OpenWRT recipes] * link:http://sotirov-bg.net/slackpack/search.cgi?q=nut[Slackware package overview] * link:https://github.com/void-linux/void-packages/tree/master/srcpkgs/network-ups-tools[Void Linux recipes] - BSD systems: * link:https://cgit.freebsd.org/ports/tree/sysutils/nut-devel[FreeBSD package recipe (devel)], link:https://cgit.freebsd.org/ports/tree/sysutils/nut[FreeBSD package recipe] and link:http://www.FreeBSD.org/cgi/ports.cgi?query=^nut-&stype=name[FreeBSD package overview] * link:http://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/sysutils/ups-nut/[NetBSD recipe] and link:https://pkgsrc.se/sysutils/ups-nut[NetBSD package overview] * link:http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/sysutils/nut/[OpenBSD recipe] * link:https://github.com/freenas/iocage-ports/tree/master/sysutils/nut[FreeNAS iocage-ports recipe], link:http://doc.freenas.org/9.3/freenas_services.html#ups[FreeNAS 9.3 docs on UPS integration] and link:https://www.ixsystems.com/documentation/freenas/11.3-U5/services.html#ups[FreeNAS 11.3-U5 docs on UPS integration] - Mac OS X: * link:https://github.com/fink/fink-distributions/blob/master/10.9-libcxx/stable/main/finkinfo/net/nut.info[Fink recipe] and link:http://pdb.finkproject.org/pdb/package.php/nut[Fink package overview] * link:http://trac.macports.org/browser/trunk/dports/sysutils/nut/Portfile[MacPorts recipe] - illumos/Solaris: * link:https://github.com/OpenIndiana/oi-userland/tree/oi/hipster/components/sysutils/nut[OpenIndiana oi-userland recipe] and link:https://pkg.openindiana.org/hipster/en/search.shtml?token=nut&action=Search[OpenIndiana latest rolling builds] - Windows (complete port, Beta): * Current regular CI builds are available as tarballs with binaries from link:https://ci.appveyor.com/project/nut-travis/nut/build/artifacts[Appveyor CI] -- but it may be difficult to locate specifically the master-branch builds. See link:https://github.com/networkupstools/nut/wiki/NUT-for-Windows[NUT for Windows wiki article] for these details, and more. * link:https://www.networkupstools.org/package/windows/NUT-Installer-2.6.5-6.msi[(OBSOLETE) Windows MSI installer 2.6.5-6] Java packages ------------- - The jNut package has been split into its own link:https://github.com/networkupstools/jNut[GitHub repository]. - NUT Java support (client side, Beta) link:https://www.networkupstools.org/package/java/jNut-0.2-SNAPSHOT.tar.gz[jNUT 0.2-SNAPSHOT] - NUT Java Web support (client side using REST, Beta) link:https://www.networkupstools.org/package/java/jNutWebAPI-0.2-SNAPSHOT-src.tar.gz[jNutWebAPI 0.2-SNAPSHOT (sources)] Virtualization packages ----------------------- VMware ~~~~~~ - NUT client for VMware ESXi (several versions of both; offsite, by René Garcia). Since the hypervisor manager environment lacks access to hardware ports, this package only includes the `upsmon` client integration, and a NUT server must run in a VM with passed-through ports. + See link:https://github.com/networkupstools/nut/wiki/NUT-and-VMware-(ESXi)[NUT and VMware (ESXi) page on NUT Wiki] for more community-contributed details. + Note that the VIB package versioning is independent of NUT or VMware versions, they are however mentioned in downloadable file names. As of this writing, there are builds spanning VMware ESXi 5.0-8.0 and NUT 2.7.4-2.8.0. + WARNING: This module is provided "as is" and is not approved by VMware, you may lose VMware support if you install it. Use it at your own risks. * link:https://github.com/rgc2000/NutClient-ESXi[GitHub repository with build recipes], including link:https://github.com/rgc2000/NutClient-ESXi/releases[binary releases] * link:https://rene.margar.fr/2012/05/client-nut-pour-esxi-5-0/[Original blog entry (French)] * link:https://rene.margar.fr/2012/05/client-nut-pour-esxi-5-0/comment-page-22/#comment-13325[Historic details of the recipe evolution] * link:https://rene.margar.fr/downloads/NutClient-ESXi500-1.4.0.tar.gz[VIB package (in fact automatically redirects to latest build)] nut-2.8.3/docs/new-clients.txt0000644000200500020050000001532514777767434013220 00000000000000Creating new client =================== NUT provides bindings for several common languages that are presented below. All these are released under the same license as NUT (the GNU General Public License). If none of these suits you for technical or legal reasons, you can implement one easily using the <>. The latter approach has been used to create the Python 'PyNUTClient' module, the Nagios 'check_ups' plugin (and probably others), which can serve as a reference. C / C++ ------- Client access library ~~~~~~~~~~~~~~~~~~~~~ `libupsclient` and `libnutclient` libraries can be linked into other programs to give access to upsd and UPS status information. Both static and shared versions are provided. These library files and associated header files are not installed by default. You must `./configure --with-dev` to enable building and installing these files. The libraries can then be built and installed with `make` and `make install` as usual. This must be done before building other (non-NUT) programs which depend on them. Low-level library: libupsclient ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `libupsclient` provides a low-level interface to directly dialog with upsd. It is a wrapper around the NUT network protocol. For more information, refer to the linkman:upsclient[3], manual page and the various link:../man/index.html#devclient[upscli_*(3)] functions documentation referenced in the same file. Clients like upsc are provided as examples of how to retrieve data using the upsclient functions. link:https://www.networkupstools.org/projects.html[Other programs] not included in this package may also use this library, such as wmnut. High level library: libnutclient ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `libnutclient` provides a high-level interface representing devices, variables and commands with an object-oriented API in C++ and C. For more information, refer to the linkman:libnutclient[3] manual page. ------ #include #include #include #include using namespace nut; using namespace std; /* argv[1] is the mandatory NUT device name (@localhost), * used to list variables from * argv[2] is an optional command. When provided, it will be * executed and possibly with status tracking enabled */ int main(int argc, char **argv) { Client *client; try { // Connection client = new TcpClient("localhost", 3493); if (argc >= 2) { // Reading data from device Device mydev = client->getDevice(argv[1]); cout << "Description: " << mydev.getDescription() << endl; Variable var = mydev.getVariable("device.model"); cout << "Model: " << var.getValue()[0] << endl; if (argc >= 3) { // Authenticate to NUT server const char *user = getenv("NUT_USER"); const char *password = getenv("NUT_PASSWD"); client->authenticate(user ? user : "", password ? password : ""); // Enable command tracking, if available if (client->hasFeature(Client::TRACKING)) { cout << "Server can do command tracking" << std::endl; client->setFeature(Client::TRACKING, true); } else { std::cout << "Server can't do command tracking" << std::endl; } // Perform an asynchronous command TrackingID id = mydev.executeCommand(argv[2]); TrackingResult result; do { sleep(1); result = client->getTrackingResult(id); } while (result == PENDING); // Display result of command const char *output = ""; switch (result) { case SUCCESS: output = "SUCCESS"; break; case FAILURE: output = "FAILURE"; break; case UNKNOWN: output = "UNKNOWN"; break; } cout << "Command sent, result=" << output << endl; } } } catch (NutException &ex) { cerr << "Unexpected problem : " << ex.str() << endl; } delete client; return 0; } ------ Configuration helpers ~~~~~~~~~~~~~~~~~~~~~ NUT provides helper scripts to ease the configuration step of your program, by detecting the right compilation and link flags. For more information, refer to a <>. Python ------ The PyNUT module, contributed by David Goncalves, can be used for connecting a Python script to `upsd`. Note that this code (and the accompanying NUT-Monitor application, later separated into NUT-Monitor-py2gtk2 and NUT-Monitor-py3qt5, suitable for two generations of Python ecosystem) is licensed under the GPL v3. The `PyNUTClient` class abstracts the connection to the server. In order to list the status variables for `ups1` on the local `upsd`, the following commands could be used: $ cd scripts/python/module $ python ... >>> import PyNUT >>> from pprint import pprint >>> client = PyNUT.PyNUTClient() >>> vars = client.GetUPSVars('ups1') >>> pprint(vars) {'battery.charge': '90', 'battery.charge.low': '30', 'battery.runtime': '3690', 'battery.voltage': '230.0', ... Further examples are given in the `test_nutclient.py` file. To see the entire API, you can run `pydoc` from the `module` directory. If you wish to make the module available to everyone on the system, you will probably want to install it in the `site-packages` directory for your Python interpreter. (This is usually one of the last items in `sys.path`.) Perl ---- The old Perl bindings from CPAN have recently been updated and merged into the NUT source code. These operate in a similar fashion to the Python bindings, with the addition of access to single variables, and additional interpretation of the results. The Perl class instance encapsulates a single UPS, where the Python class instance represents a connection to the server (which may service multiple UPS units). ------ use UPS::Nut; $ups = new UPS::Nut( NAME => "myups", HOST => "somemachine.somewhere.com", PORT => "3493", USERNAME => "upsuser", PASSWORD => "upspasswd", TIMEOUT => 30, DEBUG => 1, DEBUGOUT => "/some/file/somewhere", ); if ($ups->Status() =~ /OB/) { print "Oh, no! Power failure!\n"; } tie %other_ups, 'UPS::Nut', NAME => "myups", HOST => "somemachine.somewhere.com", ... # same options as new(); ; print $other_ups{MFR}, " ", $other_ups{MODEL}, "\n"; ------ Java ---- The NUT Java support has been externalized. It is available at https://github.com/networkupstools/jnut nut-2.8.3/docs/chunked.xsl0000644000200500020050000000161314777534445012365 00000000000000 images/icons/ images/icons/ nut-2.8.3/docs/developers.txt0000644000200500020050000016774214777767434013153 00000000000000Information for developers ========================== This document is intended to explain some of the more useful things within the tree, and provide a standard for working on the code. General stuff -- common subdirectory ------------------------------------ String handling ~~~~~~~~~~~~~~~ Use `snprintf()`. It's even provided with a compatibility module if the target system doesn't have it natively. If you use `snprintf()` to load some value into a buffer, make sure you provide the format string. Don't use user-provided format strings without delicate verification, since that's an easy way to open yourself up to an exploit. Don't use `strcat()`. We have a neat wrapper for `snprintf()` called `snprintfcat()` that allows you to append to `char *` with a format string and all the usual string length checking of `snprintf()` routine. Error reporting ~~~~~~~~~~~~~~~ Don't call `syslog()` directly. Use `upslog_with_errno()` and `upslogx()`. They may also write to the `syslog`, `stderr`, or both as appropriate. This means you don't have to worry about whether you're running in the background or not. The `upslog_with_errno()` routine prints your message plus the string expansion of current `errno` value. The `upslogx()` just prints the message. `fatal_with_errno()` and `fatalx()` work the same way, but they also `exit(arg)` afterwards, where `arg` is the first argument of the `fatal*()` method -- typically `EXIT_FAILURE` or `EXIT_SUCCESS`. In most cases, you should not call `exit()` directly. Debugging information ~~~~~~~~~~~~~~~~~~~~~ The `upsdebug_with_errno()`, `upsdebugx()`, `upsdebug_hex()` and `upsdebug_ascii()` routines use the global `nut_debug_level`, so you don't have to mess around with `printf()`'s and `if`'s yourself. Use them. Memory allocation ~~~~~~~~~~~~~~~~~ `xmalloc()`, `xcalloc()`, `xrealloc()` and `xstrdup()` all check the results of the base calls before continuing, so you don't have to. Don't use the raw calls directly. Config file parsing ~~~~~~~~~~~~~~~~~~~ The configuration parser, called `parseconf`, is now up to its fourth major version. It has multiple entry points, and can handle many different jobs. It's usually used for parsing files, but it can also take input a line at a time or even a character at a time. You must initialize a context buffer with `pconf_init()` before using any other `parseconf` function. `pconf_encode()` is the only exception, since it operates on a buffer you supply and is an auxiliary function. Escaping special characters and quoting multiple-word elements is all handled by the state machine. Using the same code for all config files avoids code duplication. NOTE: this does not apply to drivers. Driver authors should use the `upsdrv_makevartable()` scheme to pick up values from 'ups.conf' file. Drivers should not have their own config files. Drivers may have their own data files, such as lists of hardware, mapping tables, or similar. The difference between a data file and a config file is that users should never be expected to edit a data file under normal circumstances. This technique might be used to add more hardware support to a driver without recompiling. vs. ~~~~~~~~~~~~~~~~~~~~~~~~~ This is already handled by autoconf, so just `#include "timehead.h"` and you will get the right headers on every system. Device drivers -- main.c ------------------------ The device drivers use `main.c` as their core. To write a new driver, you create a file with a series of support functions that will be called by main. These all have names that start with `upsdrv_`, and they will be called at different times by main depending on what needs to happen. See the <> for information on writing drivers, and also refer to the skeletal driver in `skel.c`. Portability ----------- Avoid things that will break on other systems. All the world is not an x86 Linux box. C comments ~~~~~~~~~~ There are still older systems out there that don't do C++ style comments. -------------------------------------- /* Comments look like this. */ // Not like this. -------------------------------------- Variable declarations go on top ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Newer versions of gcc allow you to declare a variable inside a function after code, somewhat like the way C++ operates, like this: ------------------------------------------------------------------------------- function do_stuff(void) { check_something(); int a; a = do_something_else(); } ------------------------------------------------------------------------------- While this will compile and run on these newer versions, it will fail miserably for anyone on an older system. That means you must not use it. Note that `gcc` only warns about this with `-pedantic` flag, and `clang` with a `-Weverything` (possibly `-Wextra`) flag, which can be enabled by developers with `configure --enable-warnings=...` option values (and made fatal with `configure --enable-Werror`), to ensure non-regression of code quality. It was reported that `clang-16` with such options does complain about non-portability to older C language revisions even if explicitly building for a newer revision. Please note that for the purposes of legacy-compatible variable declarations (on top of their scopes), a `NUT_UNUSED_VARIABLE(varname)` counts as code and should be used just below the declarations. Initial assignments to variables (also as return values of methods) may generally happen as part of their declarations. You can use scoping (e.g. `do { ... } while (0);`) where it makes sense to constrain visibility of temporary variables, such as in `switch/case` blocks. Variable declaration in loop block syntax ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Another feature that does not work on some compilers (e.g. conforming to "ANSI C"/C89/C90 standard) is initial variable declaration inside a 'for loop' block, like this: -------------------------------------------------------------------------------- function do_stuff(void) { /* This should declare "int i;" first, then use it in "for" loop: */ for (int i = 0; i < INT_MAX; ++i) { ... } /* Additional loops cause also an error about re-declaring a variable: */ for (int i = 10; i < 15; ++i) { ... } } -------------------------------------------------------------------------------- Other hints ~~~~~~~~~~~ TIP: At this point NUT is expected to work correctly when built with a "strict" C99 (or rather GNU99 on many systems) or newer standard. The NUT codebase may build in a mode without warnings made fatal on C89 (GNU89), but the emitted warnings indicate that those binaries may crash. By the end of 2021, NUT codebase has been revised to pass GNU and strict-C mode builds with C89 standard with the GCC toolkit (and on systems that do have the newer features in libraries, just hide them in standard headers); however CLANG toolkit is more restrictive about the C99+ syntax used. That said, some systems refuse to expose methods or types available in their system headers and binary libraries if strict-C mode is used alone, without extra system-specific defines to enable more than the baseline. It was also seen that cross-builds (e.g. NUT for Windows using mingw on Linux) may be unable to define `WIN32` and/or find symbols for linking when using a strict-C language standard. /////////// EDITOR NOTE: plus-plus sequences are seen by asciidoc as opening/closing tags of "literal" markup, so have to be escaped. But only pairs (the last standalone copy in a paragraph should NOT be escaped!) /////////// The C\++ support expects C\++11 or newer (not really configured or tested for older C\++98 or C\++03), modulo features that were deprecated in later language revisions (C++14 onwards) as highlighted by warnings from newer compilers. Note also that the NUT codebase currently relies on certain features, such as the printf format modifiers for `(s)size_t`, use of `long long`, some nuances about structure/array initializers, variadic macros for debugging, etc. that a pedantic C90 mode compilation warns is not part of the standard but a GNU extension (and part of C99 and newer standard revisions). Many of the "offences" against the older standard actually come from system and third-party header files. That said, the NUT CI farm does run non-regression builds with GNU C89 and "strict" C89 standard revisions and minimal passing warnings level, to ensure that codebase is and remains at least basically compliant. We try to cover a few distributions from early 2000's for this, either in regular CI builds or one-off local builds for community members with a zoo of old systems. If somebody in the community actually requires to build and run NUT on systems that old, where newer compilers are not available, pull requests to fix the offending coding issues in some way that does not break other use-cases are welcome. Continuous Integration and Automated Builds ------------------------------------------- To ease and automate the build scenarios which were deemed important for quality assurance and non-regression checks of NUT, several solutions were introduced over time. For more information, and perhaps inspiration for building a similar solution, please see the *NUT Quality Assurance and Build Automation Guide*, and specifically its chapters on linkdoc:qa-guide[Static analysis by compilers,CI_compiler_warnings], linkdoc:qa-guide[ci_build.sh script,CI_BUILD_SH,ci_build.adoc], linkdoc:qa-guide[Continuous Integration (NUT CI farm) technologies,NUTCI_farm_technologies] and linkdoc:qa-guide[Continuous Integration (NUT CI farm) build agent preparation,NUTCI_farm_agents]. Integrated Development Environments (IDEs) and debugging NUT ------------------------------------------------------------ Much of NUT has been coded using classic editors of developers' preference, like `vi`, `nano`, Midnight Commander `mcedit`, `gedit`/`pluma`, NotePad++ and tools like `meld` or WinMerge for file comparison and merge. Modern IDEs however do offer benefits, specifically for live debugging sessions in a more convenient fashion than with command-line `gdb` directly. They also simplify writing AsciiDoc files with real-time rendering support. NOTE: Due to use of `libtool` wrappers in "autotools" driven projects, it may be tricky to attach the debugger (mixing the correct `LD_LIBRARY_PATH` or equivalent with a binary under a `.libs` subdirectory; on some platforms you may be better off copying shared objects to the directory with the binary being tested). IDEs that were tested to work with NUT development and real-time debugger tracing include: * Sun NetBeans 8.2 on Solaris, Linux (including local and remote build and debug ability); * Apache NetBeans 17 on Windows with MSYS2 support (as MinGW toolkit); * Visual Studio Code (VSCode) on Windows with MSYS2 support. Some supporting maintenance and development is doable with IntelliJ IDEA, making some things easier to do than with a simple Notepad, but it does not handle C/C++ development as such. Take note that some IDEs can store their project data in the source root directory of a project (such as NUT codebase). While `.gitignore` rules can take care of not adding your local configuration into the SCM, these locations can be wiped by a careless `git clean -fdX`. You are advised to explore configuring your IDE to store project configurations outside the source codebase location, or to track such subdirectories as `nbproject` or `nb-cache` or `.idea` as a separate Git repository (not necessarily a submodule of NUT nor really diligently tracked) to avoid such surprises. IDE notes on Windows ~~~~~~~~~~~~~~~~~~~~ General settings for builds on Windows ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When working in a native Windows environment with link:https://www.msys2.org/[MSYS2] (providing MinGW x64 among other things), you may need to ensure certain environment variables are set before you start the IDE (shortcuts and wrappers that start your console apply them via shell). WARNING: If you set such environment variables system-wide for your user profile (or wrap the IDE start-up by a script to set them), it may compromise your ability to use *other* MSYS2 profiles and/or other builds of these toolkits (packaged by e.g. Git for Windows or PERL for Windows projects) generally, or in the same IDE session, respectively. You may want to do this in a dedicated user account! Examples below assume you installed MSYS2 into `C:\msys64` (by default) and are using the "MinGW X64" profile for GCC builds (nuances may differ for 32-bit, CLANG, UCRT and other profile variants). Also keep in mind that not all dependencies and tools involved in a fully-fledged NUT build are easily available or usable on Windows (e.g. the spell checker). See linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] for better detailed package lists for different operating systems including Windows, and feel welcome to post pull requests with suggestions about new tool-chains that might fare better than those already tried and documented. * Make sure its tools are in the `PATH`: + Control Panel => "Edit the system environment variables" => "Environment variables..." (button) => "Edit..." or create "New..." `Path` setting ("User variable" level suffices) => ** Make sure `C:\msys64\mingw64\bin` and `C:\msys64\usr\bin` are both there. ** Depending on further installed toolkits, you may want to add `C:\Program Files\Git\cmd` or `C:\Program Files\Microsoft VS Code\bin` (preferably use deployment-dependent spellings without white-space like `Progra~1` to err on the safe side of variable expansions later). * Make sure that MSYS2 (and tools which integrate with it) know its home: + Open Environment variables window as above, and "Edit..." or create "New..." `MSYS_HOME` setting => Set to `C:\msys64\mingw64\bin` * Restart the IDE (if already running) for it to acknowledge the system configuration change. Otherwise, NetBeans for example claims there is no shell for it to run `make` or open Terminal pane windows, and fails to start the built programs due to lack of DLL files they were linked against (such as `libssl` usually needed for any networked part of the codebase). You might still have to fiddle with DLL files built in other directories of the NUT project, when preparing to debug certain programs, e.g. for `dummy-ups` testing you may need to: ------ :; cp ./clients/.libs/libupsclient-6.dll ./drivers/.libs/ ------ To ensure builds with debug symbols, you may add `CFLAGS` and `CXXFLAGS` set to `-g3 -gdwarf-2` or similar to `configure` options, or if that confuses the cross-build (it tends to assume those values are part of GCC path), you may have to hack them into your local copy of `configure.ac`, after the `AM_INIT_AUTOMAKE([subdir-objects])` line: ------ CFLAGS="$CFLAGS -g3 -gdwarf-2" CXXFLAGS="$CXXFLAGS -g3 -gdwarf-2" ------ ...and re-run the `./autogen.sh` script. GDB on Windows ^^^^^^^^^^^^^^ Examples below assume that whichever IDE you are using, the primary goal is to debug some issues with NUT on that platform. This may require you to craft a configuration file for the GNU Debugger, e.g. `C:\Users\abuild\.gdbinit` for the examples below. One is not required however, and may be missing. Another thing to keep in mind is that with `libtool` involved, the actual binary for testing would be in a `.libs` subdirectory and you may have some fun with ensuring that DLLs are found to start them -- see the notes above. NetBeans on Windows ^^^^^^^^^^^^^^^^^^^ When you install newer link:https://netbeans.apache.org/[Apache NetBeans] releases (14, 17 as of this writing), you may need to enable the use of "NetBeans 8.2 Plugin Portal" (check under Tools/Plugins/Settings) and install the "C/C++" plugin only available there at the moment. In turn, that older build of a plugin package may require that your system provides the `unpack200(.exe)` tool which was shipped with JDK11 or older (you may have to install that just to get the tool, or copy its binary from another system). Under Tools/Options menu open the C/C++ tab and further its Build Tools sub-tab. NOTE: NetBeans allows you to easily define different Tool Collections, including those associated with a different build host (accessible over SSH and source/build paths optionally shared over NFS or similar technology, or copied over). This allows you to run the IDE on your desktop while debugging a build running on a server or embedded system. Make sure you have a MinGW Tool Collection for the "localhost" build host with such settings as: |=== | Option name | Sample value | Family | GNU MinGW | Encoding | UTF-8 | Base Directory | `C:\msys64\mingw64\bin` | C Compiler | `C:\msys64\mingw64\bin\gcc.exe` | C++ Compiler | `C:\msys64\mingw64\bin\g++.exe` | Assembler | `C:\msys64\mingw64\bin\as.exe` | Make Command | `C:\msys64\usr\bin\make.exe` | Debugger Command | `C:\msys64\mingw64\bin\gdb.exe` |=== In the Code Assistance sub-tab check that there are toolkit-specific and general include paths, e.g. both C and C++ Compiler settings might involve: |=== | `C:\msys64\mingw64\lib\gcc\x86_64-w64-mingw32\12.2.0\include` | `C:\msys64\mingw64\include` | `C:\msys64\mingw64\lib\gcc\x86_64-w64-mingw32\12.2.0\include-fixed` | `C:\msys64\mingw64\x86_64-w64-mingw32\include` |=== On top of that, C++ Compiler settings may include: |=== | `C:\msys64\mingw64\include\12.2.0` | `C:\msys64\mingw64\include\12.2.0\x86_64-w64-mingw32` | `C:\msys64\mingw64\include\12.2.0\backward` |=== In the "Other" sub-tab, set default standards to C99 and C++11 to match common NUT codebase expectations. Finally, open/create a "nut" project pointing to your git checkout workspace. Next part of configuration regards build/debug configurations, which you can find on the toolbar or as File / Project Properties. The main configuration for debugging a particular binary (and NUT has tons of those, good luck in case you want to debug several simultaneously) is in the *Run* and *Debug* categories. You may want to define different Configuration profiles to track the individual Run/Debug settings for different tested binaries, while the Build/Make settings would remain the same. Alternatively, you may set the *Make* category's "Build Result" as the path to the binary you would test, and use `${OUTPUT_PATH}` variable as its name in the "Run Command" (still likely need custom arguments) and "Symbol File" below. When you investigate interactions of two or more programs, but only want to debug (step through) just one of them, you are advised to run each of the others from a dedicated terminal session, and just bump their debug verbosity. * In the *Build* category, set the Build Host (localhost) and Tool Collection (MinGW). In expert part of the settings, un-check "platform-independent" and revise that the `TOOLS_PATH=C:\msys64\mingw64\bin` while the `UTILITIES_PATH=C:\msys64\usr\bin`. * In the *Pre-Build* category likely keep the Working Directory as `.` and the `Pre-Build First` generally unchecked (so only enable it to reconfigure the project, which takes time and is not needed for every rebuild iteration), but you may still pre-set the Command line to something like the following (on one line): + ------ bash -c "rm -f configure Makefile; ./autogen.sh && ./configure CC='${IDE_CC}' CXX='${IDE_CXX}' --with-all=auto --with-docs=skip" ------ + In some cases, NOT specifying the `CC`, `CXX` and the flags actually succeeds while passing their options fails the configuration ("Compiler can not create executables" etc.) probably due to path resolution issues between the native and MinGW environments. + NOTE: In practice, you may have an easier time using NUT `./ci_build.sh` helper or running a more specific `./autogen.sh && ./configure ...` spell similar to the above example or customized otherwise, in the MinGW x64 console window to actually configure a NUT source code setup, than to maintain one via the IDE. Running (re-)builds with the IDE (as you just edit non-recipe sources and iterate with a debugger) using externally configured Makefiles works fine. * In the *Make* category you may want to customize for parallelized builds on multi-CPU systems with something like: ** Build Command: `${MAKE} -j 6 -f Makefile` ** Clean Command: `${MAKE} -f Makefile clean` * In the *Run* category you should set the "Run Command" to point to your binary (note the `.libs` sub-directory, and see comments above regarding possibly needed copies of shared objects) and its arguments (all on one line), e.g.: + ------ C:\Users\abuild\Desktop\nut\drivers\.libs\usbhid-ups.exe -s ups -x port=auto -d1 -DDDDDD ------ + Other useful settings may be to keep "Build First" checked, and if the "Internal Terminal" does not work for you as the debugged program's console -- set the "Console Type" to "External Terminal" of type "Command Window". Unfortunately, NetBeans on Windows may have issues running terminal tabs unless CygWin is installed. * In the *Debug* category you should set the "Symbol File" to point to your tested binary (e.g. `C:\Users\abuild\Desktop\nut\drivers\.libs\usbhid-ups.exe` to match the "Run Command" example above) and specify "Follow Fork Mode" as "child" and "Detach On Fork" as "off". "Reverse Debugging" may be useful too in some situations. Finally, select your "Gdb Init File" if you have one, e.g. `C:\Users\abuild\.gdbinit`. Microsoft VS Code ^^^^^^^^^^^^^^^^^ With this IDE you can benefit from numerous Extensions from its Marketplace, the ones found useful for NUT development and debugging include: * AsciiDoc (by asciidoctor) * EditorConfig for VS Code (by EditorConfig) * C/C++ (by Microsoft) * C/C++ Extension pack (by Microsoft) * Makefile tool (by Microsoft) * MSYS2/Cygwin/MinGW/Clang support (by okhlybov) * Native Debug (GDB, LLDB ... Debugger support; by WebFreak) Configurations are tracked locally in JSON files where you would need to add some entries. Examples below highlight the needed keys and values; your files may have others: * `.vscode/launch.json` (can create one via Run/Add Configuration... menu defines ways to launch the debug session for a program: + ------ { "configurations": [ { "name": "CPPDBG GDB usbhid-ups", "type": "cppdbg", "request": "launch", "program": "C:\\Users\\abuild\\Desktop\\nut\\drivers\\.libs\\usbhid-ups.exe", "additionalSOLibSearchPath": "C:\\Users\\abuild\\Desktop\\nut\\.inst\\mingw64\\bin", "stopAtConnect": true, "args": ["-s", "ups", "-DDDDDD", "-d1", "-x", "port=auto"], "stopAtEntry": false, "cwd": "C:\\Users\\abuild\\Desktop\\nut", "environment": [], "externalConsole": false, "MIMode": "gdb", "miDebuggerPath": "C:\\msys64\\mingw64\\bin\\gdb.exe", "targetArchitecture": "x64", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true }, { "description": "Set Disassembly Flavor to Intel", "text": "-gdb-set disassembly-flavor intel", "ignoreFailures": true } ], "preLaunchTask": "make usbhid-ups" }, { // Alternately with LLDB (clang), the rest looks like above: "name": "CPPDBG LLDB usbhid-ups", "MIMode": "lldb", "miDebuggerPath": "C:\\msys64\\usr\\bin\\lldb.exe", }, ... ] } ------ * `.vscode/tasks.json` defines other tasks, such as the `preLaunchTask` mentioned above (assuming you have configured the build externally in the MinGW x64 terminal session): + ------ { "tasks": [ { "type": "shell", "label": "make usbhid-ups", "command": "C:\\msys64\\usr\\bin\\make usbhid-ups", "options": { "cwd": "${workspaceFolder}/drivers" }, "problemMatcher": [ "$gcc" ], "group": { "kind": "build", "isDefault": true } }, ... ] } ------ * `.vscode/c_cpp_properties.json` defines general compiler settings, e.g.: + ------ { "configurations": [ { "name": "Win32", "includePath": [ "${workspaceFolder}/**", "C:\\msys64\\mingw64\\include\\libusb-1.0", "C:\\msys64\\mingw64\\include", "C:\\msys64\\usr\\include" ], "defines": [ "_DEBUG", "UNICODE", "_UNICODE" ], "compilerPath": "C:\\msys64\\mingw64\\bin\\gcc.exe", "cStandard": "c99", "cppStandard": "c++11", "intelliSenseMode": "windows-gcc-x64", "configurationProvider": "ms-vscode.makefile-tools" } ], "version": 4 } ------ IntelliJ IDEA ^^^^^^^^^^^^^ It is worth mentioning IntelliJ IDEA as another free (as of Community Edition) and popular IDE, however it is of limited use for NUT development. Its ecosystem does feature a good AsciiDoc plugin, Python and of course the Java/Groovy support, so IDEA is helpful for maintenance of NUT documentation, helper scripts and CI recipes. It lacks however C/C++ language support (allegedly a different product in the IntelliJ portfolio is dedicated to that), so for the core NUT project sources it is just a fancy text editor (with `.editorconfig` support) without syntax highlighting or codebase cross-reference aids, build/run/debug support, etc. Still, it is possible to run builds and tests in embedded or external terminal session -- so it is not worse than editing with legacy tools, and navigation or code-base-wide search is arguably easier. //////// TODO: Make note of settings (and Run as Administrator) to use symlinks in MinGW x64. Check if required for sane (iterative re-)builds? ;) //////// Coding style ------------ This is how we do things: ------------------------------------------------------------------------------- int open_subspace(char *ship, int privacy) { if (!privacy) return insecure_channel(ship); if (!init_privacy(ship)) fatal_with_errno("Can't open secure channel"); return secure_channel(ship); } ------------------------------------------------------------------------------- The basic idea is that we try to group things into functions, and then find ways to drop out of them when we can't go any further. There's another way to program this involving a big else chunk and a bunch of braces, and it can be hard to follow. You can read this from top to bottom and have a pretty good idea of what's going on without having to track too much `{ }` nesting and indenting. We don't really care for `pretentiousVariableNamingSchemes`, but you can probably get away with it in your own driver that we will never have to touch. If your function or variable names start pushing important code off the right margin of the screen, expect them to meet the byte chainsaw sooner or later. All types defined with `typedef` should end in `_t`, because this is easier to read, and it enables tools (such as `indent` and `emacs`) to display the source code correctly. Indenting with tabs vs. spaces ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Another thing to notice is that the indenting happens with tabs instead of spaces. This lets everyone have their personal tab-width setting without inflicting much pain on other developers. If you use a space, then you've fixed the spacing in stone and have really annoyed half of the people out there. Note that tabs apply only to *indenting*. Alignment of text after any non-tab character has appeared on the line must be done by spaces in order for it to remain at the same alignment when someone views tabs at a different widths. One common example for this is multi-line if condition: -------------------------------------------------------------------------------- if (something && something_else) { -------------------------------------------------------------------------------- which may be written without mixing tabs and spaces to indent, as: -------------------------------------------------------------------------------- if (something && something_else ) { -------------------------------------------------------------------------------- Another example is tables of definitions that are better aligned with (non-leading) spaces at least between names and values not too many characters wide; it still helps to align the columns with spaces at offsets divisible by 4 or 8 (consistently for the whole table): -------------------------------------------------------------------------------- #define SHORT_MACRO 1 /* flag comment */ #define SOMETHING_WITH_A_VERY_LONG_NAME 255 /* flag comment */ -------------------------------------------------------------------------------- While at it, we encourage indentation of nested preprocessor macros and pragmas, by adding a single space character for each inner level, as well as commenting the `#else` and `#endif` parts (especially if they are far away from their opening `#if`/`#ifdef`/`#ifndef` statement) to help visual navigation in the source code base. Please take care to keep the hash `#` character of the preprocessor lines in the left-most column, since some implementations of `cpp` parser used for analysis default to "traditional" (pre-C89) syntax shared with other languages, and then ignore lines which do not start with the hash character (or worse, ignore only some of them but not others). -------------------------------------------------------------------------------- #ifdef WITH_SSL # ifdef WITH_NSS /* some code for NSS */ # endif /* WITH_NSS */ # ifdef WITH_OPENSSL # ifndef WIN32 /* some code for OpenSSL on POSIX systems */ # else /* not WIN32 */ /* some code for OpenSSL on Windows */ # endif /* not WIN32 */ # endif /* WITH_OPENSSL */ #else /* not WITH_SSL */ /* report that crypto support is not built */ #endif /* WITH_SSL */ -------------------------------------------------------------------------------- If you write something that uses leading spaces, you may get away with it in a driver that's relatively secluded. However, if we have to work on that code, expect it to get reformatted according to the above. Patches to existing code that don't conform to the coding style being used in that file will probably be dropped. If it's something we really need, it will be grudgingly reformatted before being included. When in doubt, have a look at Linus's take on this topic in the Linux kernel -- link:https://github.com/torvalds/linux/blob/master/Documentation/process/coding-style.rst[Documentation/CodingStyle]. He's done a far better job of explaining this. Line breaks ~~~~~~~~~~~ It is better to have lines that are longer than 80 characters than to wrap lines in random places. This makes it easier to work with tools such as `grep`, and it also lets each developer choose their own window size and tab setting without being stuck to one particular choice. Of course, this does not mean that lines should be made unnecessarily long when there is a better alternative (see the note on `pretentiousVariableNamingSchemes` above). Certainly there should not be more than one statement per line. Please do not use ------------------------------------------------------------------------------- if (condition) break; ------------------------------------------------------------------------------- but use the following: ------------------------------------------------------------------------------- if (condition) { break; } ------------------------------------------------------------------------------- NOTE: Earlier revisions of coding style might suggest avoiding braces if just one line is added as condition/loop/etc. handling code. Current approach is to welcome them even for single lines: on one hand, this confirms the intention that only this line is the conditional code; on another, this minimizes the context differences for later code comparisons, relocation, refactoring, etc. Un-used variables and function arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Whenever a function needs to satisfy a particular API, it can end up taking arguments that are not used in practice (think a too-trivial signal handler). While some compilers offer the facility of decorations like `__attribute__(unused)`, this proved not to be a portable solution. Also the abilities of newer C/C++ standard revisions are of no help to the vast range of existing systems that run NUT today and expect to be able to do so tomorrow (hence the required C99+ support noted above). In NUT codebase we prefer to mark un-used variables explicitly in the body of the function (or an `#ifdef` branch of its code) using the `NUT_UNUSED_VARIABLE(varname)` as a routine call inside a function body, referring to the macro defined in `common.h`. Please note that for the purposes of legacy-compatible variable declarations (on top of their scopes), `NUT_UNUSED_VARIABLE(varname)` counts as code and should happen below the declarations. To display in a rough example: ------------------------------------------------------------------------------- static void signal_X_handler(int signal_X) { NUT_UNUSED_VARIABLE(signal_X); /* We have explicitly got nothing to do if we catch signal X */ return; } ------------------------------------------------------------------------------- All this having been said, we do detect and use the support for pragmas to quiesce the complaints about such situations, but limit their use to processing of certain third-party header files. Miscellaneous coding style tools -------------------------------- NUT codebase includes an `.editorconfig` file which should be supported by most of the IDEs and text editors nowadays. Many support this format specification (at least partially) out of the box, possibly with some configuration toggle in the GUI. Others may need a plugin, see more at https://editorconfig.org/#pre-installed page. There are also command-line tools to verify and/or enforce compliance of source files to configuration. NOTE: A long-standing plan is to define a `clang-format` specification for all the different nuances like where we do and don't want spaces around parentheses, how to align multi-line conditional expressions, etc. in a way that most of the current NUT code base would already conform. Taking the first step is the hardest part, so PRs are welcome :) You can go a long way towards converting your source code to the NUT coding style by piping it through the following command: :; indent -kr -i8 -T FILE -l1000 -nhnl This next command does a reasonable job of converting most C++ style comments (but not URLs and DOCTYPE strings): :; sed 's#\(^\|[ \t]\)//[ \t]*\(.*\)[ \t]*#/* \2 */#' Emacs users can adjust how tabs are displayed. For example, it is possible to set a tab stop to be 3 spaces, rather than the usual 8. (Note that in the saved file, one indentation level will still correspond to one tab stop; the difference is only how the file is rendered on screen). It is even possible to set this on a per-directory basis, by putting something like this into your `.emacs` file: ------------------------------------------------------------------------------- ;; NUT style (defun nut-c-mode () "C mode with adjusted defaults for use with the NUT sources." (interactive) (c-mode) (c-set-style "K&R") (setq c-basic-offset 3) ;; 3 spaces C-indentation (setq tab-width 3)) ;; 3 spaces per tab ;; apply NUT style to all C source files in all subdirectories of nut/ (setq auto-mode-alist (cons '(".*/nut/.*\\.[ch]$". nut-c-mode) auto-mode-alist)) ------------------------------------------------------------------------------- Finishing touches ~~~~~~~~~~~~~~~~~ We like code that uses `const` and `static` liberally. If you don't need to expose a function or global variable to the outside world, `static` is your friend. If nobody should edit the contents of some buffer that's behind a pointer, `const` keeps them honest. We always compile with `-Wall`, so things like `const` and `static` help you find implementation flaws. Functions that attempt to modify a constant or access something outside their scope will throw a warning or even fail to compile in some cases. This is what we want. Switch case vs. default vs. enum ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NUT codebase often uses the `switch/case/case.../default` construct to handle conditional situations expressed by discrete numeric values (the `case value:` labels). Different compilers and their different warning settings require different rules to be satisfied, and those are sometimes at odds: * a `switch` should definitively handle all cases, so must have a `default` label -- this works well for general numeric variables; * an `enum`'s valid values are known at compile time, and each must be handled explicitly (even if implemented as many `case value:` labels preceding the same code block), so... * ...a `default` label is redundant (should never be reachable) in a `switch` that handles all `enum` values -- but this notion is a head-on crash vs. the first rule above. Ultimately, some cases require the wall of `pragma` directives below against warnings at this spot, and we use the `default` label handling to be sure, as the least-worst solution (ultra-long lines wrapped for readability in this document): ---- #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) \ && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) \ || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT # pragma GCC diagnostic ignored "-Wcovered-switch-default" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE # pragma GCC diagnostic ignored "-Wunreachable-code" #endif /* Older CLANG (e.g. clang-3.4) seems to not support the GCC pragmas above */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunreachable-code" # pragma clang diagnostic ignored "-Wcovered-switch-default" #endif /* All enum cases defined as of the time of coding * have been covered above. Handle later definitions, * memory corruptions and buggy inputs below... */ default: fatalx(EXIT_FAILURE, "no suitable definition found!"); #ifdef __clang__ # pragma clang diagnostic pop #endif #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) \ && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_COVERED_SWITCH_DEFAULT) \ || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE) ) # pragma GCC diagnostic pop #endif ---- Switch case fall-through ~~~~~~~~~~~~~~~~~~~~~~~~ While C standards allow to write `switch` statements to "fall through" from handling one case into another, modern compilers frown upon that practice and spew warnings which complicate detecting real bugs in the code (and also looking back at some of the cases written decades ago, it is not trivial to state whether the fall-through was intentional or really is a bug). Compilers which detect such problem usually offer ways to decorate the code with comments or attributes to keep it quiet it in cases where the jump is intentional; also C++17 introduces special keywords for that in the standard. NUT aiming to be portable and independent of compilers as much as possible, prefers the arguably clearer and standards-based way of using `goto` into the next intended operation, even though it is a couple of lines away, e.g.: int uppercase = 0; switch (char_opt) { case 'U': uppercase = 1; goto fallthrough_case_u_option; case 'u': fallthrough_case_u_option: process_u_option(uppercase); break; } In trivial cases, like falling through to `default` which just returns, it may be clearer and more maintainable (adding other option cases in the future) to just `return same_result` in the code block that would fall through otherwise and avoid `goto` statements altogether. Spaghetti ~~~~~~~~~ If you use a `goto` that jumps over long distances (see "Switch case fall-through" section above), expect us to drop it when our head stops spinning. It gives us flashbacks to the very old code we wrote. We've tried to clean up our act, and you should make the effort as well. We're not making a blanket statement about gotos, since everything probably has at least one good use. There are a few cases where a goto is more efficient than any other approach, but you probably won't encounter them very often in this software. Legacy code ~~~~~~~~~~~ There are parts of the source tree that do not yet conform to these specs. Part of this is due to the fact that the coding style has been evolving slightly over the course of the project. Some of the code you see in these directories is 5 years old, and things have gotten cleaner since then. Don't worry -- it'll get cleaned up the next time something in the vicinity gets a visit. Memory leak checking ~~~~~~~~~~~~~~~~~~~~ We can't say enough good things about valgrind. If you do anything with dynamic memory in your code, you need to use this. Just compile with `gcc -g` and start the program inside `valgrind`. Run it through the suspected area and then exit cleanly. Then valgrind will tell you if you've done anything dodgy like freeing regions twice, leaving files open, reading uninitialized memory, or if you've leaked memory anywhere. For NUT, there are prepared integrations like `configure --with-valgrind`. See also `scripts/valgrind` in NUT sources for a helper tool and resource files to suppress common third-party problems. For more information, refer to the link:http://valgrind.kde.org[Valgrind] project. Conclusion ~~~~~~~~~~ The summary: please be kind to our eyes. There's a lot of stuff in here, and many people have put a lot of time and energy to improve it. Submitting patches ------------------ Current preference for suggesting changes is to open a pull request on GitHub for the https://github.com/networkupstools/nut/ project. For some cases, small patches that arrive by mailing list in unified format (`diff -Naur`) as plain text attachments with no HTML and a brief summary at the top are easy to handle, but sadly also easy to overlook. If a patch is sent to the nut-upsdev mailing list, it stands a better chance of being seen immediately. However, it is likely to be dropped if any issues cannot be resolved quickly. If your code might not work for others, or if it is a large change, your best bet is to submit a pull request or create an link:https://github.com/networkupstools/nut/issues[issue on GitHub]. The issue tracker allows us to track the patches, and related discussion for clarifications or a review process, over a longer period of time, and it is less likely that a patch will fall through the cracks. Posting a reminder to the developers (via the nut-upsdev list) about a patch on GitHub is fair game, if the maintainers do not react in a few days. Patch cohesion -------------- Patches should have some kind of unifying element. One patch set is one message, and it should all touch similar things. If you have to edit 6 files to add support for neutrino detection in UPS hardware, that's fine. However, sending one huge patch that does massive separate changes all over the tree is not recommended. That kind of patch has to be split up and evaluated separately, assuming the core developers care enough to do that instead of just dropping it. If you have to make big changes in lots of places, send multiple patches -- one per item. The finishing touches: manual pages and device entry in HCL ----------------------------------------------------------- If you change something that involves an argument to a program or configuration file parsing, the man page is probably now out of date. If you don't update it, we have to, and we have enough to do as it is. If you write a new driver, send in the man page when you send us the source code for your driver. Otherwise, we will be forced to write a skeletal man page that will probably miss many of the finer points of the driver and hardware. The same remark goes for device entries: if you add support for new models, please remember to also complete the hardware compatibility list, present in link:data/driver.list.in[]. This will be used to generate both textual, static HTML and dynamic searchable HTML for the website. Finally, don't forget about fame and glory: if you added or substantially updated a driver, your copyright belongs in the heading comment (along with existing ones). For vendor backed (or sponsored) contributions we welcome an entry in the link:docs/acknowledgements.txt[] file as well, to track and know the industry players who help make NUT better and more useful. It is nice to update the link:NEWS.adoc[] file for significant development to be seen as part of next release, as well as to update the link:UPGRADING.adoc[] file for potentially breaking changes and similar heads-up notes for third-party teams (distribution packagers, clients and bindings, etc.) Source code management ---------------------- We currently use a Git repository hosted at GitHub to track changes to the NUT source code. This allows you to "fork" the repository (in GitHub parlance), "clone" it to your workstation(s), make a new "branch" with your changes, and post them back online for peer review prior to integration. To obtain permission to commit directly to the common upstream NUT repository, you must be prepared to spend a fair amount of time contributing to the NUT codebase. Most developers will be well served by committing to their own forked Git repository (preferably in a uniquely named branch for each new contribution), and having the NUT team merge their changes using pull requests. Git offers a little more flexibility than the +svn update+ command. You may fetch other developers' changes into your repository, but hold off on actually combining them with your branch until you have compared the two branches (for instance, with `gitk --all`). Git also allows you to accumulate more than one commit worth of changes before pushing to another repository. This allows development to continue without a constant network connection. For a quick change to a file in the Git working copy, you can use `git diff` to generate a patch to send to the nut-upsdev mailing list. If you have more extensive changes, you can use `git format-patch` on a complete commit or branch, and send the resulting series of patches to the list. If you use GitHub's web-based editor to make changes, it tends to create lots of small commits, one per change per file. Unless there is reason to keep the intermediate history, we will probably collapse (or "squash" in Git parlance) the entire branch into one commit with a `git rebase -i` before merging. The link:https://git.wiki.kernel.org/index.php/GitSvnCrashCourse[GitSvnCrashCourse] wiki page has some useful information for long-time users of Subversion. Git access ~~~~~~~~~~ Anonymous Git checkouts are possible: :; git clone git://github.com/networkupstools/nut.git or :; git clone https://github.com/networkupstools/nut.git if it is necessary to get around a pesky firewall that blocks the native Git protocol. For a quicker checkout (when you don't need the entire repository history), you can limit the depth of the clone: :; git clone --depth 1 git://github.com/networkupstools/nut.git OPTIONALLY you can then fetch known git tags, so semantic versions look better (based off a recent release, see linkdoc:developer-guide[NUT Versioning,versioning,docs/nut-versioning.adoc] for more details): :; cd nut :; git fetch --tags --all Mercurial (hg) access ~~~~~~~~~~~~~~~~~~~~~ There are those who prefer the simplicity and self-consistency of the Mercurial SCM client over the hodgepodge of unique commands which make up Git. Rather than debate the merits of each system, we will gently guide you towards the link:http://hg-git.github.com/[hg-git project] which would theoretically be a transparent bridge between the central Git repository, and your local Mercurial working copy. Other tools for hg/git interoperability are sure to exist. We would welcome any feedback about this process on the nut-upsdev mailing list. Subversion (SVN) access ~~~~~~~~~~~~~~~~~~~~~~~ If you prefer to check out the NUT source code using an SVN client, GitHub has a link:https://github.com/blog/966-improved-subversion-client-support[SVN interface to Git repositories] hosted on their servers. You can fork a copy of the NUT repository and commit to your fork with SVN. Be aware that the examples in the GitHub blog post might result in a checkout that includes all of the current branches, as well as the trunk. You are most likely interested in a command line similar to the following: :; svn co https://github.com/networkupstools/nut/trunk nut-trunk-svn Ignoring generated files ------------------------ The NUT repository generally only holds files which are not generated from other files. This prevents spurious differences from being recorded in the repository history. If you add a driver, it is recommended that you add the driver executable name to the `.gitignore` file in that directory. Similarly, files generated from `*.in` and `*.am` source templates should be ignored as well. We try to include a number of generated files in the tarball releases with `make dist` hooks in order to minimize the number of dependencies for end users, but the assumption is that a developer can install the packages needed to regenerate those files. Commit message formatting ------------------------- From the `git commit` man page: [quote] Though not required, it's a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description. The text up to the first blank line in a commit message is treated as the commit title, and that title is used throughout git. If your commit is just a change to one component, such as the HCL, upsd or a specific driver, prefix your commit message in a way that matches similar commits (typically with the file name(s), check `git log` for inspiration). This helps when searching the repository or tracking down a regression. Referring to previous commits can be tricky. If you are referring to the immediate parent of a given commit, it suffices to say "the previous commit". (Are you correcting a typo in the previous commit? If you haven't pushed yet, consider using the `git commit --amend` command instead of creating a new commit.) For other commits, even though tools like gitk and GitHub's repository viewers recognize Git hashes and create links automatically, it is best to add some context such as the commit title or a date. You may notice that some older commits have `[[SVN:####]]` tags and Fossil-ID footers. These were lifted from the old SVN commit messages using reposurgeon, and should *not* be used as a guide for future commits. Commit sign-off --------------- Please also note that since 2023 we explicitly ask for contributions to be "Signed Off" according to "Developer Certificate of Origin" as represented in the `LICENSE-DCO` file in the root of NUT source tree (verbatim copy of Version 1.1 of DCO published at https://developercertificate.org/ web site). This is exactly the same one created and used by the Linux kernel developers. This is a developer's certification that he or she has the right to submit the patch for inclusion into the project. Simply submitting a contribution implies this agreement, however, please include a "Signed-off-by" tag in every patch (this tag is a conventional way to confirm that you agree to the DCO). In other words, this tag certifies that committer has the rights to submit this work under the same license as the project and agrees to the terms of a Developer Certificate of Origin. Note that while git commit hook tricks are available to automatically sign off all commits, these signatures are intended to be a conscious (legally meaningful) act -- hence they are not automated in git core with an easy configuration option. For more details see: * https://github.com/networkupstools/nut/issues/1994 * https://github.com/networkupstools/nut/wiki/Code-contributions,-PRs,-PGP-and-DCO * https://stackoverflow.com/questions/1962094/what-is-the-sign-off-feature-in-git-for * https://stackoverflow.com/questions/15015894/git-add-signed-off-by-line-using-format-signoff-not-working You are also encouraged to set up a PGP key, make its public part known, and use it to sign your git commits (in addition to the `Signed-Off-By` tag) by also passing a `-S` option or calling `git config commit.gpgsign true` once. Numerous public articles can walk you through this ordeal, including: * https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits * https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key * https://www.kernel.org/doc/html/v4.19/process/maintainer-pgp-guide.html Repository etiquette and quality assurance ------------------------------------------ For developers who have commit access to the common upstream NUT repository: Please keep the Git "master" branch in working condition at all times. The "master" branch may be used to generate daily tarballs, it provides the baseline for new contributions, and occasionally is tagged for a new release. It should not contain broken code. If you need to commit incremental changes that leave the system in a broken state, please do so in a separate branch and merge the changes back into "master" once they are complete. To help keep the codebase ever-green, we run a number of CI tests and builds in various conditions, including older compilers, different C/C++ standard revisions, and an assortment of operating systems; a section below elaborates on this in more detail. You are encouraged to use `git rebase -i` on your private Git branches to separate your changes into <<_patch_cohesion,logical changes>>. From there, you can generate patches for the issue tracker, or the nut-upsdev mailing list. Note that once you rebase a branch, anyone else who has a copy of this branch will need to rebase on top of your rebased branch. Obviously, this hinders collaboration. In this case, we recommend that you rebase only in your private repository, and push when things are ready for discussion. Merging instead of rebasing will help with collaboration, but please do not turn the repository history into a pile of spaghetti by merging unnecessarily. (Test merges can be done on integration branches, which can be discarded if the merge is trivial.) Be sure that your commit messages are descriptive when merging. If you haven't created a commit out of your local changes yet, and you want to fetch the latest code, you can also use +git stash+ before pulling, then +git stash pop+ to apply your saved changes. Here is an example workflow (using a slightly older `git` command-line syntax, so it works verbatim on more platforms): ------------------------------------------------------------------------------ :; git clone -o central git://github.com/networkupstools/nut.git :; cd nut :; git remote add -f USERNAME git://github.com/USERNAME/nut.git ### OPTIONALLY you can then fetch known git tags, so semantic ### versions look better (based off a recent release): :; git fetch --tags --all :; git checkout master :; git branch my-new-feature :; git checkout my-new-feature # Hack away :; git add changed-file.c :; git commit -s # Fix a typo in a file or commit message: :; git commit -s -a --amend # Someone committed something to the central repository. Fetch it. :; git fetch central :; git rebase central/master # Publish your branch to your GitHub repository: :; git push USERNAME my-new-feature ------------------------------------------------------------------------------ If you are new to Git, but are familiar with SVN, some of the following links may be of use: * link:https://web.archive.org/web/20191224210950/https://git-scm.com/course/svn.html[Git - SVN Crash Course (archived)] * link:https://git-scm.com/book/en/v2/Git-and-Other-Systems-Migrating-to-Git[Git and Other Systems - Migrating to Git] * link:https://www.git-tower.com/learn/git/ebook/en/command-line/appendix/from-subversion-to-git[Switching from Subversion to Git] * link:https://www.atlassian.com/git/tutorials/migrating-overview[Migrate from SVN to Git] [[building]] Building the Code ----------------- For a developer, the NUT build process starts with `./autogen.sh`. This script generates the `./configure` script that end users typically invoke to build NUT. If you are making a number of changes to the NUT source tree, configuring with the `--enable-maintainer-mode` flag will ensure that after you change a `Makefile.am`, nearby `Makefile.in` and `Makefile` get regenerated. At a minimum, you will need at least: * autoconf * automake * libtool * Python * Perl [NOTE] ====== See linkdoc:qa-guide[Prerequisites for building NUT on different OSes,NUT_Config_Prereqs,docs/config-prereqs.txt] for better detailed package lists for different operating systems. See `ci_build.sh` for automating many practical scenarios, for easier iterations. It is optional, but highly recommended, to have Python 2.x or 3.x, and Perl, to generate some files included into the `configure` script whose presence is checked by autotools when it is generated. Neutered files can be just "touched" to pass the `autogen.sh` if these interpreters are not available, and effectively skip those parts of the build later on -- `autogen.sh` will then advise which special environment variables to `export` in your situation and re-run it. ====== Even if you do not use your distribution's packages of NUT, installing the distribution's list of build dependencies for NUT can reduce the amount of trial-and-error when installing dependencies. For instance, in Debian, you can run `apt-get build-dep nut` to install all of the auto* tools as well as any development libraries and headers -- as known for the version of NUT packaged with the OS distribution release you are using. After running `./autogen.sh`, you can pass your local configuration options to `./configure` and run `make` from the top-level directory. To avoid the need for root privileges when testing new NUT code, you may wish to use `--prefix=$HOME/local/nut --with-statepath=/tmp`. You can also keep compilation times down by only building the driver which you are currently working on: `--with-drivers=driver1,dummy-ups`. Before pushing your commits upstream, please run `make distcheck-light`. This checks that the Makefiles are not broken, that all the relevant files are distributed, and that there are no compilation or installation errors. Note that unless you specifically pass `--with-doc=skip` to `configure`, this requires all of the dependencies necessary to build the documentation to be locally installed on your system, including `asciidoc`, `a2x`, `xsltproc`, `dblatex` and any additional XSL stylesheets. Running `make distcheck-light` is especially important if you have added or removed files, or updated `configure.ac` or some `Makefile.am` file. Remember: simply adding a file to Git does not mean it will be distributed. To distribute a file, you must update the corresponding `Makefile.am` with `EXTRA_DIST` entry and possibly other recipe handling. There is also `make distcheck`, which runs an even stricter set of tests than `make distcheck-light`, but will not work unless you have all of the optional third-party libraries and features installed. Finally note, that since 2017 the GitHub upstream project was monitored by Travis CI (in addition to earlier multi-platform buildbots which occasionally did not work), replaced since 2021 by a dedicated NUT CI farm and a number of free cloud CI resources to test some 200-300 scenarios with different combinations of build environments and tooling implementations. This means that if your posted improvements are based on current NUT "master" branch, the resulting pull request should get tested for a number of scenarios automatically. If your code adds a substantial feature, consider extending the `Jenkinsfile-dynamatrix` and/or `ci_build.sh` scripts in the workspace root to add another `BUILD_TYPE` to the matrix of tests run in parallel. nut-2.8.3/docs/history.txt0000644000200500020050000005543514777534445012471 00000000000000ifdef::website[] Project history =============== endif::website[] This page is an attempt to document how everything came together. The Network UPS Tools team would like to warmly thank Russell Kroll. Russell initially started this project, maintaining and improving it for over 8 years (1996 -- mid 2005). Prototypes and experiments -------------------------- May 1996: early status hacks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ APC's Powerchute was running on kadets.d20.co.edu (a BSD/OS box) with SCO binary emulation. Early test versions ran in cron, pulled status from the log files and wrote them to a .plan file. You could see the results by fingering `pwrchute@kadets.d20.co.edu` while it lasted: ------------------------------------------------------------------------ Last login Sat May 11 21:33 (MDT) on ttyp0 from intrepid.rmi.net Plan: Welcome to the UPS monitor service at kadets.d20.co.edu. The Smart-UPS attached to kadets generated a report at 14:24:01 on 05/17/96. During the measured period, the following data points were taken: Voltage ranged from 115.0 VAC to 116.3 VAC. The UPS generated 116.3 VAC at 60.00 Hz. The battery level was at 27.60 volts. The load placed on the UPS was 024.9 percent. UPS temperature was measured at 045.0 degrees Celsius. Measurements are taken every 10 minutes by the upsd daemon. This report is generated by a script written by Russell Kroll. Modified for compatibility with the BSD/OS cron daemon by Neil Schroeder ------------------------------------------------------------------------ This same status data could also be seen with a web browser, since we had rigged up a CGI wrapper script which called finger. January 1997: initial protocol tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Initial tests with a freestanding non-daemon program provided a few basic status registers from the UPS. The 940-0024C cable was not yet understood, so this happened over the [attachment:apcevilhack.jpg evil two-wire serial hack]. ------------------------------------------------------------------------ Communicating with SMART-UPS 700 S/N WS9643050926 [10/17/96] Input voltage range: 117.6 VAC - 118.9 VAC Load is 010.9% of capacity, battery is charged to 100.0% of capacity ------------------------------------------------------------------------ Note that today's apcsmart driver still displays the serial number when it starts, since it is derived from this original code. September 1997: first client/server code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The first split daemon/client code was written. upsd spoke directly to the UPS (APC Smart models only) and communicated with upsc by sending binary structures in UDP datagrams. The first CGI interface existed, but it was all implemented with shell scripts. The main script would call upsc to retrieve status values. Then it would cat a template file through sed to plug them into the page. image::images/old-cgi.png[Old CGI screenshot] upsstats actually has since returned to using templates, despite having a period in the middle when it used hardcoded HTML. The images were also created with shell scripts. Each script would call upsc to get the right value (utility, upsload, battcap). It then took the value, plugged it into a command file with sed, and passed that into 'fly', a program which used an interpreted language to create images. fly actually uses gd, just like upsimage does today. This code later evolved into Smart UPS Tools 0.10. Smart UPS Tools --------------- March 1998: first public release ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Version 0.10 was released on March 10, 1998. It used the same design as the pre-release prototype. This made expansion difficult as the binary structure used for network communications would break any time a new variable was added. Due to byte-ordering and struct alignment issues, the code usually couldn't talk over the network to a system with a different architecture. It was also hopelessly bound to one type of UPS hardware. Five more releases followed with this design followed. The last was 0.34, released October 27, 1998. June 1999: Redesigned, rewritten ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Following a long period of inactivity and two months of prerelease testing versions, 0.40.0 was released on June 5, 1999. It featured a complete redesign and rewrite of all of the code. The layering was now in three pieces, with the single driver (smartups) separate from the server (upsd). Clients remained separate as before and still used UDP to talk to the server, but they now used a text-based protocol instead of the brittle binary structs. A typical request like "REQ UTILITY" would be answered with "ANS UTILITY 120.0". The ups-trust425-625 driver appeared shortly after the release of 0.40.0, marking the first expansion beyond APC hardware. Over the months that followed, the backupspro driver would be forked from the smartups driver to handle the APC Back-UPS Pro line. Then the backups driver was written to handle the APC Back-UPS contact-closure models. These drivers would later be renamed and recombined, with smartups and backupspro becoming apcsmart, and backups became genericups. The drivers stored status data in an array. At first, they passed this data to upsd by saving it to a file. upsd would reread this file every few seconds to keep a copy for itself. This was later expanded to allow shared memory mode, where only a stub would remain on the disk. The drivers and server then passed data through the shared memory space. upsd picked up the ability to monitor multiple drivers on the system, and the "upsname@hostname" scheme was born. Access controls were added, and then the network code was expanded to allow TCP communications, which at this point were on port 3305. Network UPS Tools ----------------- September 1999: new name, new URL ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Several visitors to the web page and subscribers to the mailing lists provided suggestions to rename the project. The old name no longer accurately described it, and it was perilously close to APC's "Smart-UPS" trademark. Rather than risk problems in the future, the name was changed. Kern Sibbald provided the winner: Network UPS Tools, which captures the essence of the project and makes for great short tarball filenames: nut-x.y.z.tar.gz. The new name was first applied to 0.42.0, released October 31, 1999. This is also when the web pages moved from the old `http://www.exploits.org/~rkroll/smartupstools/` URL to the replacement at `http://www.exploits.org/nut/` to coincide with the name change. More drivers were written and the hardware support continued to grow. upsmon picked up the concepts of what is now known as "primary" and "secondary", and could now handle environments where multiple systems get power from a single UPS. Manager mode was added to allow changing the value of read/write variables in certain UPS models. June 2001: common driver core ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Up to this point, all of the drivers compiled into freestanding programs, each providing their own implementation of main(). This meant they all had to check the incoming arguments and act uniformly. Unfortunately, not all of the programs behaved the same way, and it was hard to document and use consistently. It also meant that startup scripts had to be edited depending on what kind of hardware was attached. Starting in 0.45.0, released June 11, 2001, there was a new common core for all drivers called `main.c`. It provided the main function and called back to the `upsdrv_*` functions provided by the hardware-specific part of the drivers. This allowed driver authors to focus on the UPS hardware without worrying about the housekeeping stuff that needs to happen. This new design provided an obvious way to configure drivers from one file, and so `ups.conf` was born. This eventually spawned upsdrvctl, and now all drivers based on this common core could be started or stopped with one command. Startup scripts now could contain "upsdrvctl start", and it didn't matter what kind of hardware or how many UPSes you had on one system. Interestingly, at the end of this month, Arnaud Quette entered the UPS world, as a subcontractor of the now defunct MGE UPS SYSTEMS. This marked the start of a future successful collaboration. May 2002: casting off old drivers, IANA port, towards 1.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ During the 0.45.x series, both the old standalone drivers and the ones which had been converted to the common core were released together. Before the release of 0.50.0 on May 24, 2002, all of the old drivers were removed. While this shrank the list of supported hardware, it set the precedent for removing code which isn't receiving regular maintenance. The assumption is that the code will be brought back up to date by someone if they actually need it. Otherwise, it's just dead weight in the tree. This change meant that all remaining drivers could be controlled with the `upsdrvctl` and `ups.conf`, allowing the documentation to be greatly simplified. There was no longer any reason to say "do this, unless you have this driver, then do this". IANA granted an official port number to the project, and the network code switched to port 3493. It had previously been on 3305 which is assigned to `odette-ftp`. 3305 was probably picked in 1997 because it was the fifth project to spawn from some common UDP server code. After 0.50.1, the 0.99 tree was created to provide a tree which would receive nothing but bug fixes in preparation for the release of 1.0. As it turned out, very few things required fixing, and there were only three releases in this tree. Leaving 0.x territory --------------------- August 2002: first stable tree: NUT 1.0.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After nearly 5 years of having a 0.x version number, 1.0.0 was released on August 19, 2002. This milestone meant that all of the base features that you would expect to find were intact: good hardware support, a network server with security controls, and system shutdowns that worked. The design was showing signs of wear from the rapid expansion, but this was intentionally ignored for the moment. The focus was on getting a good version out that would provide a reasonable base while the design issues could be addressed in the future, and I'm confident that we succeeded. November 2002: second stable tree: NUT 1.2.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ One day after the release of 1.0.0, 1.1.0 started the new development tree. During that development cycle, the CGI programs were rewritten to use template files instead of hard-coded HTML, thus bringing back the flexibility of the original unreleased prototype from 5 years before. The `multimon` was removed from the tree, as the new `upsstats` could do both jobs by loading different templates. A new client library called upsclient was created, and it replaced upsfetch. This new library only supported TCP connections, and used an opaque context struct to keep state for each connection. As a result, client programs could now do things that used multiple connections without any conflicts. This was done primarily to allow OpenSSL support, but there were other benefits from the redesign. upsd and the clients could now use OpenSSL for basic authentication and encryption, but this was not included by default. This was provided as a bonus feature for those users who cared to read about it and enable the option, as the initial setup was complex. After the 1.1 tree was frozen and deemed complete, it became the second stable tree with the release of 1.2.0 on November 5, 2002. April 2003: new naming scheme, better driver glue, and an overhauled protocol ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Following an extended period with no development tree, 1.3.0 got things moving again on April 13, 2003. The focus of this tree was to rewrite the driver-server communication layer and replace the static naming scheme for variables and commands. Up to this point, all variables had names like STATUS, UTILITY, and OUTVOLT. They had been created as drivers were added to the tree, and there was little consistency. For example, it probably should have been INVOLT and OUTVOLT, but there was no OUTVOLT originally, so UTILITY was all we had. This same pattern repeated with ACFREQ -- is it incoming or outgoing? -- and many more. To solve this problem, all variables and commands were renamed to a hierarchical scheme that had obvious grouping. STATUS became ups.status. UTILITY turned into input.voltage, and OUTVOLT is output.voltage. ACFREQ is input.frequency, and the new output.frequency is also now supported. Every other variable or command was renamed in this fashion. These variables had been shared between the drivers and upsd as values. That is, for each name like STATUS, there was a #define somewhere in the tree with an INFO_ prefix that gave it a number. INFO_STATUS was 0x0006, INFO_UTILITY was 0x0004, and so on, with each name having a matching number. This number was stored in an int within a structure which was part of the array that was either written to disk or shared memory. That structure had several restrictions on expansion and was dropped as the data sharing method between the drivers and the server. It was replaced by a new system of text-based messages over Unix domain sockets. Drivers now accepted a short list of commands from upsd, and would push out updates asynchronously. upsd no longer had to poll the state files or shared memory. It could just select all of the driver and client fds and act on events. At the same time, the network protocol on port 3493 was overhauled to take advantage of the new naming scheme. The existing "REQ STATUS@su700", "ANS STATUS@su700 OL" scheme was showing signs of age, and it really only supported the UPS name (@su700) as an afterthought. The new protocol would now use commands like GET and LIST, leading to exchanges like "GET VAR su700 ups.status" and "VAR su700 ups.status OL". These responses contain enough data to stand alone, so clients can now handle them asynchronously. July 2003: third stable tree: NUT 1.4.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ On July 25, 2003, 1.4.0 was released. It contained support for both the old "REQ" style protocol (with names like STATUS), and the new "GET" style protocol (with names like ups.status). This tree is provided to bridge the gap between all of the old releases and the upcoming 2.0. 2.0 will be released without support for the old REQ/STATUS protocol. The hope is that client authors and those who have implemented their own monitoring software will use the 1.4 cycle to change to the new protocol. The 1.4 releases contain a lot of compatibility code to make sure both work at the same time. July 2003: pushing towards 2.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.5.0 forked from 1.4.0 and was released on July 29, 2003. The first changes were to throw out anything which was providing compatibility with the older versions of the software. This means that 1.5 and the eventual 2.0 will not talk to anything older than 1.4. This tree continues to evolve with new serial routines for the drivers which are intended to replace the aging upscommon code which dates back to the early 0.x releases. The original routines would call alarm and read in a tight loop while fetching characters. The new functions are much cleaner, and wait for data with select. This makes for much cleaner code and easier strace/ktrace logs, since the number of syscalls has been greatly reduced. There has also been a push to make sure the data from the UPS is well-formed and is actually usable before sending updates out to upsd. This started during 1.3 as drivers were adapted to use the dstate functions and the new variable/command names. Some drivers which were not converted to the new naming scheme or didn't do sanity checks on the incoming UPS data from the serial port were dropped from the tree. This tree was released as 2.0.0. Backwards and Forwards Compatibility (NUT v1.x vs. v2.x) -------------------------------------------------------- The old network code spans a range from about 0.41.1 when TCP support was introduced up to the recent 1.4 series. It used variable names like STATUS, UTILITY, and LOADPCT. Many of these names go back to the earliest prototypes of this software from 1997. At that point there was no way to know that so many drivers would come along and introduce so many new variables and commands. The resulting mess grew out of control over the years. During the 1.3 development cycle, all variables and instant commands were renamed to fit into a tree-like structure. There are major groups, like input, output and battery. Members of those groups have been arranged to make sense - input.voltage and output.voltage compliment each other. The old names were UTILITY and OUTVOLT. The benefits in this change are obvious. The 1.4 clients can talk to either type of server, and can handle either naming scheme. 1.4 servers have a compatibility mode where they can answer queries for both names, even though the drivers are internally using the new format. When 1.4 clients talk to 1.4 or 2.0 (or more recent) servers, they will use the new names. Here's a table to make it easier to visualize: [options="header"] |============================================= | 4+| Server version | *Client version* | 1.0 | 1.2 | 1.4 | 2.0+ | 1.0 | yes | yes | yes | no | 1.2 | yes | yes | yes | no | 1.4 | yes | yes | yes | yes | 2.0+ | no | no | yes | yes |============================================= Version 2.0, and more recent, do not contain backwards compatibility for the old protocol and variable/command names. As a result, 2.0 clients can't talk to anything older than a 1.4 server. If you ask a 2.0 client to fetch "STATUS", it will fail. You'll have to ask for "ups.status" instead. Authors of separate monitoring programs should have used the 1.4 series to write support for the new variables and command names. Client software can easily support both versions as long as they like. If upsd returns 'ERR UNKNOWN-COMMAND' to a GET request, you need to use REQ. networkupstools.org ------------------- November 2003: a new URL ~~~~~~~~~~~~~~~~~~~~~~~~ The bandwidth demands of a project like this have slowly been forcing me to offload certain parts to other servers. The download links have pointed offsite for many months, and other large things like certain UPS protocols have followed. As the traffic grows, it's clear that having the project attached to exploits.org is not going to work. The solution was to register a new domain and set up mirrors. There are two initial web servers, with more on the way. The main project URL has changed from `http://www.exploits.org/nut/` to https://www.networkupstools.org. The actual content is hosted on various mirrors which are updated regularly with rsync, so the days of dribbling bits through my DSL should be over. This is also when all of the web pages were redesigned to have a simpler look with fewer links on the left side. The old web pages used to have 30 or more links on the top page, and most of them vanished when you dropped down one level. The links are now constant on the entire site, and the old links now live in their own groups in separate directories. Second major version -------------------- March 2004: NUT 2.0.0 ~~~~~~~~~~~~~~~~~~~~~ NUT 2.0.0 arrived on March 23, 2004. The jump to version 2 shows the difference in the protocols and naming that happened during the 1.3 and 1.5 development series. 2.0 no longer ships with backwards compatibility code, so it's smaller and cleaner than 1.4. The change of leadership ------------------------ February 2005: NUT 2.0.1 ~~~~~~~~~~~~~~~~~~~~~~~~ The year 2004 was marked by a release slowdown, since Russell was busy with personal subjects. But the patches queue was still growing quickly. At that time, the development process was still centralized. There was no revision control system (like the current Subversion repository), nor trackers to interact with NUT development. Russell was receiving all the patches and requests, and doing all the work on his own, including releases. Russell was more and more thinking about giving the project leadership to Arnaud Quette, which finally happened with the 2.0.1 release in February 2005. This marked a new era for NUT... First, Arnaud aimed at opening up the development by creating a project on the http://www.debian.org/[Debian] http://alioth.debian.org/projects/nut/[Alioth Forge]. This allowed to build the team of hackers that Russell dreamed about. It also allows to ensure NUT's continuation, whatever happens to the leader. And that would most of all boost the projects contributions. //////////////////////////////////////////////////////////////////////// *sandbox* TO BE COMPLETED + ADD A LINK TO IDEA / FUTURE link on the team + history mention: - MGE supporting officially, - USB / SNMP / XML drivers (first non serial drivers), - Power Management (HAL) bridging, - PDU support, - perl / python support... - client history and evolution (wmnut: 01/01/2002) release history
  • July 7, 2008: Client activity: new client NUT-Monitor
  • June 27, 2008: Client activity: new Python class PyNUT
  • June 19, 2008: Client activity: KNutClient 0.9.4
  • May 7, 2008: 2.2.2 released
  • December 21, 2007: 2.2.1 released
  • August 31, 2007: Client activity: UPS Monitor link update
  • August 31, 2007: Client activity: Windows NUT client 1.5.0
  • July 5, 2007: 2.2.0 released
  • June 5, 2007: Client activity: collectd NUT plugin
  • April 10, 2007: Client activity: KNutClient 0.9.3
  • January 15, 2007: 2.0.5 released
  • January 8, 2007: Client activity: Windows NUT client fall back on old LISTRW technique */ if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) { fatalx(EXIT_FAILURE, "Error: upsd is too old to support this query"); } fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); } ret = upscli_list_next(ups, numq, query, &numa, &answer); while (ret == 1) { /* RW */ if (numa < 4) { fatalx(EXIT_FAILURE, "Error: insufficient data (got %" PRIuSIZE " args, need at least 4)", numa); } /* sock this entry away for later */ ltmp = xmalloc(sizeof(struct list_t)); ltmp->name = xstrdup(answer[2]); ltmp->next = NULL; if (llast) { llast->next = ltmp; } else { lhead = ltmp; } llast = ltmp; ret = upscli_list_next(ups, numq, query, &numa, &answer); } /* use the list to get descriptions and types */ ltmp = lhead; while (ltmp) { lnext = ltmp->next; print_rw(ltmp->name); free(ltmp->name); free(ltmp); ltmp = lnext; } } int main(int argc, char **argv) { int i; uint16_t port; const char *prog = xbasename(argv[0]); const char *net_connect_timeout = NULL; char *password = NULL, *username = NULL, *setvar = NULL, *s = NULL; /* NOTE: Caller must `export NUT_DEBUG_LEVEL` to see debugs for upsc * and NUT methods called from it. This line aims to just initialize * the subsystem, and set initial timestamp. Debugging the client is * primarily of use to developers, so is not exposed via `-D` args. */ s = getenv("NUT_DEBUG_LEVEL"); if (s && str_to_int(s, &i, 10) && i > 0) { nut_debug_level = i; } upsdebugx(1, "Starting NUT client: %s", prog); while ((i = getopt(argc, argv, "+hls:p:t:u:wVW:")) != -1) { switch (i) { case 's': setvar = optarg; break; case 'l': if (setvar) { upslogx(LOG_WARNING, "Listing mode requested, overriding setvar specified earlier!"); setvar = NULL; } break; case 'p': password = optarg; break; case 't': if (!str_to_uint(optarg, &timeout, 10)) fatal_with_errno(EXIT_FAILURE, "Could not convert the provided value for timeout ('-t' option) to unsigned int"); break; case 'u': username = optarg; break; case 'w': tracking_enabled = 1; break; case 'V': /* just show the version and optional * CONFIG_FLAGS banner if available */ print_banner_once(prog, 1); nut_report_config_flags(); exit(EXIT_SUCCESS); case 'W': net_connect_timeout = optarg; break; case 'h': default: usage(prog); exit(EXIT_SUCCESS); } } if (upscli_init_default_connect_timeout(net_connect_timeout, NULL, UPSCLI_DEFAULT_CONNECT_TIMEOUT) < 0) { fatalx(EXIT_FAILURE, "Error: invalid network timeout: %s", net_connect_timeout); } argc -= optind; argv += optind; if (argc < 1) { usage(prog); exit(EXIT_SUCCESS); } /* be a good little client that cleans up after itself */ atexit(clean_exit); if (upscli_splitname(argv[0], &upsname, &hostname, &port) != 0) { fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]"); } ups = xcalloc(1, sizeof(*ups)); if (upscli_connect(ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); } if (setvar) { /* setting a variable */ do_setvar(setvar, username, password); } else { /* if not, get the list of supported read/write variables */ print_rwlist(); } exit(EXIT_SUCCESS); } /* Formal do_upsconf_args implementation to satisfy linker on AIX */ #if (defined NUT_PLATFORM_AIX) void do_upsconf_args(char *upsname, char *var, char *val) { fatalx(EXIT_FAILURE, "INTERNAL ERROR: formal do_upsconf_args called"); } #endif /* end of #if (defined NUT_PLATFORM_AIX) */ nut-2.8.3/clients/Makefile.in0000644000200500020050000016054715001555010012752 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Network UPS Tools: clients VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @WITH_SSL_TRUE@am__append_1 = $(LIBSSL_LIBS) $(LIBSSL_LDFLAGS_RPATH) @WITH_SSL_TRUE@am__append_2 = $(LIBSSL_LIBS) $(LIBSSL_LDFLAGS_RPATH) @WITH_SSL_TRUE@am__append_3 = $(LIBSSL_CFLAGS) @WITH_CGI_TRUE@am__append_4 = $(LIBGD_CFLAGS) bin_PROGRAMS = upsc$(EXEEXT) upslog$(EXEEXT) upsrw$(EXEEXT) \ upscmd$(EXEEXT) sbin_PROGRAMS = upsmon$(EXEEXT) upssched$(EXEEXT) $(am__EXEEXT_1) @HAVE_WINDOWS_SOCKETS_TRUE@am__append_5 = message @HAVE_CXX11_TRUE@am__append_6 = libnutclient.la libnutclientstub.la @HAVE_CXX11_TRUE@@WITH_DEV_TRUE@am__append_7 = nutclient.h nutclientmem.h @HAVE_CXX11_FALSE@@WITH_DEV_TRUE@am__append_8 = nutclient.h nutclientmem.h @WITH_CGI_TRUE@cgiexec_PROGRAMS = upsstats.cgi$(EXEEXT) \ @WITH_CGI_TRUE@ upsimage.cgi$(EXEEXT) upsset.cgi$(EXEEXT) @HAVE_WINDOWS_SOCKETS_TRUE@am__append_9 = -lws2_32 @WITH_SSL_TRUE@am__append_10 = $(LIBSSL_LDFLAGS_RPATH) $(LIBSSL_LIBS) @HAVE_WINDOWS_TRUE@am__append_11 = -no-undefined @HAVE_CXX11_TRUE@@HAVE_WINDOWS_TRUE@am__append_12 = -no-undefined @HAVE_CXX11_FALSE@am__append_13 = nutclient.h nutclient.cpp \ @HAVE_CXX11_FALSE@ nutclientmem.h nutclientmem.cpp @HAVE_CXX11_TRUE@@HAVE_WINDOWS_TRUE@am__append_14 = -no-undefined subdir = clients ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___attribute__.m4 \ $(top_srcdir)/m4/ax_c_pragmas.m4 \ $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/ax_compare_version.m4 \ $(top_srcdir)/m4/ax_realpath.m4 \ $(top_srcdir)/m4/ax_realpath_lib.m4 \ $(top_srcdir)/m4/ax_run_or_link_ifelse.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/nut_arg_with.m4 \ $(top_srcdir)/m4/nut_check_asciidoc.m4 \ $(top_srcdir)/m4/nut_check_aspell.m4 \ $(top_srcdir)/m4/nut_check_bool.m4 \ $(top_srcdir)/m4/nut_check_cppcheck.m4 \ $(top_srcdir)/m4/nut_check_headers_windows.m4 \ $(top_srcdir)/m4/nut_check_libavahi.m4 \ $(top_srcdir)/m4/nut_check_libfreeipmi.m4 \ $(top_srcdir)/m4/nut_check_libgd.m4 \ $(top_srcdir)/m4/nut_check_libgpiod.m4 \ $(top_srcdir)/m4/nut_check_libltdl.m4 \ $(top_srcdir)/m4/nut_check_libmodbus.m4 \ $(top_srcdir)/m4/nut_check_libneon.m4 \ $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ $(top_srcdir)/m4/nut_check_libnss.m4 \ $(top_srcdir)/m4/nut_check_libopenssl.m4 \ $(top_srcdir)/m4/nut_check_libpowerman.m4 \ $(top_srcdir)/m4/nut_check_libregex.m4 \ $(top_srcdir)/m4/nut_check_libsystemd.m4 \ $(top_srcdir)/m4/nut_check_libusb.m4 \ $(top_srcdir)/m4/nut_check_libwrap.m4 \ $(top_srcdir)/m4/nut_check_os.m4 \ $(top_srcdir)/m4/nut_check_pkgconfig.m4 \ $(top_srcdir)/m4/nut_check_python.m4 \ $(top_srcdir)/m4/nut_check_socketlib.m4 \ $(top_srcdir)/m4/nut_compiler_family.m4 \ $(top_srcdir)/m4/nut_func_getnameinfo_argtypes.m4 \ $(top_srcdir)/m4/nut_report_feature.m4 \ $(top_srcdir)/m4/nut_stash_warnings.m4 \ $(top_srcdir)/m4/nut_type_socklen_t.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(dist_bin_SCRIPTS) \ $(am__include_HEADERS_DIST) $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cgiexecdir)" \ "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(libdir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)" @HAVE_WINDOWS_SOCKETS_TRUE@am__EXEEXT_1 = message$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(cgiexec_PROGRAMS) $(sbin_PROGRAMS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } LTLIBRARIES = $(lib_LTLIBRARIES) @HAVE_CXX11_TRUE@libnutclient_la_DEPENDENCIES = \ @HAVE_CXX11_TRUE@ $(top_builddir)/common/libcommonclient.la am__libnutclient_la_SOURCES_DIST = nutclient.h nutclient.cpp @HAVE_CXX11_TRUE@am_libnutclient_la_OBJECTS = nutclient.lo libnutclient_la_OBJECTS = $(am_libnutclient_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libnutclient_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libnutclient_la_LDFLAGS) \ $(LDFLAGS) -o $@ @HAVE_CXX11_TRUE@am_libnutclient_la_rpath = -rpath $(libdir) @HAVE_CXX11_TRUE@libnutclientstub_la_DEPENDENCIES = libnutclient.la am__libnutclientstub_la_SOURCES_DIST = nutclientmem.h nutclientmem.cpp @HAVE_CXX11_TRUE@am_libnutclientstub_la_OBJECTS = nutclientmem.lo libnutclientstub_la_OBJECTS = $(am_libnutclientstub_la_OBJECTS) libnutclientstub_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(libnutclientstub_la_LDFLAGS) \ $(LDFLAGS) -o $@ @HAVE_CXX11_TRUE@am_libnutclientstub_la_rpath = -rpath $(libdir) am__DEPENDENCIES_1 = @WITH_SSL_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ @WITH_SSL_TRUE@ $(am__DEPENDENCIES_1) libupsclient_la_DEPENDENCIES = \ $(top_builddir)/common/libcommonclient.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am_libupsclient_la_OBJECTS = upsclient.lo libupsclient_la_OBJECTS = $(am_libupsclient_la_OBJECTS) libupsclient_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libupsclient_la_LDFLAGS) $(LDFLAGS) \ -o $@ am__message_SOURCES_DIST = message.c @HAVE_WINDOWS_SOCKETS_TRUE@am_message_OBJECTS = message.$(OBJEXT) message_OBJECTS = $(am_message_OBJECTS) message_LDADD = $(LDADD) am__DEPENDENCIES_3 = $(top_builddir)/common/libcommonclient.la \ libupsclient.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) message_DEPENDENCIES = $(am__DEPENDENCIES_3) am_upsc_OBJECTS = upsc.$(OBJEXT) upsc_OBJECTS = $(am_upsc_OBJECTS) upsc_LDADD = $(LDADD) upsc_DEPENDENCIES = $(am__DEPENDENCIES_3) am_upscmd_OBJECTS = upscmd.$(OBJEXT) upscmd_OBJECTS = $(am_upscmd_OBJECTS) upscmd_LDADD = $(LDADD) upscmd_DEPENDENCIES = $(am__DEPENDENCIES_3) am_upsimage_cgi_OBJECTS = upsimage.$(OBJEXT) cgilib.$(OBJEXT) upsimage_cgi_OBJECTS = $(am_upsimage_cgi_OBJECTS) am__DEPENDENCIES_4 = $(am__DEPENDENCIES_3) upsimage_cgi_DEPENDENCIES = $(am__DEPENDENCIES_4) \ $(am__DEPENDENCIES_1) am_upslog_OBJECTS = upslog.$(OBJEXT) upslog_OBJECTS = $(am_upslog_OBJECTS) am__DEPENDENCIES_5 = $(top_builddir)/common/libcommon.la \ libupsclient.la $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) upslog_DEPENDENCIES = $(am__DEPENDENCIES_5) am_upsmon_OBJECTS = upsmon.$(OBJEXT) upsmon_OBJECTS = $(am_upsmon_OBJECTS) upsmon_DEPENDENCIES = $(am__DEPENDENCIES_5) am_upsrw_OBJECTS = upsrw.$(OBJEXT) upsrw_OBJECTS = $(am_upsrw_OBJECTS) upsrw_LDADD = $(LDADD) upsrw_DEPENDENCIES = $(am__DEPENDENCIES_3) am_upssched_OBJECTS = upssched.$(OBJEXT) upssched_OBJECTS = $(am_upssched_OBJECTS) upssched_DEPENDENCIES = $(top_builddir)/common/libcommonclient.la \ $(top_builddir)/common/libparseconf.la $(am__DEPENDENCIES_1) am_upsset_cgi_OBJECTS = upsset.$(OBJEXT) cgilib.$(OBJEXT) upsset_cgi_OBJECTS = $(am_upsset_cgi_OBJECTS) upsset_cgi_LDADD = $(LDADD) upsset_cgi_DEPENDENCIES = $(am__DEPENDENCIES_3) am_upsstats_cgi_OBJECTS = upsstats.$(OBJEXT) cgilib.$(OBJEXT) upsstats_cgi_OBJECTS = $(am_upsstats_cgi_OBJECTS) upsstats_cgi_LDADD = $(LDADD) upsstats_cgi_DEPENDENCIES = $(am__DEPENDENCIES_3) SCRIPTS = $(dist_bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/cgilib.Po ./$(DEPDIR)/message.Po \ ./$(DEPDIR)/nutclient.Plo ./$(DEPDIR)/nutclientmem.Plo \ ./$(DEPDIR)/upsc.Po ./$(DEPDIR)/upsclient.Plo \ ./$(DEPDIR)/upscmd.Po ./$(DEPDIR)/upsimage.Po \ ./$(DEPDIR)/upslog.Po ./$(DEPDIR)/upsmon.Po \ ./$(DEPDIR)/upsrw.Po ./$(DEPDIR)/upssched.Po \ ./$(DEPDIR)/upsset.Po ./$(DEPDIR)/upsstats.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(libnutclient_la_SOURCES) $(libnutclientstub_la_SOURCES) \ $(libupsclient_la_SOURCES) $(message_SOURCES) $(upsc_SOURCES) \ $(upscmd_SOURCES) $(upsimage_cgi_SOURCES) $(upslog_SOURCES) \ $(upsmon_SOURCES) $(upsrw_SOURCES) $(upssched_SOURCES) \ $(upsset_cgi_SOURCES) $(upsstats_cgi_SOURCES) DIST_SOURCES = $(am__libnutclient_la_SOURCES_DIST) \ $(am__libnutclientstub_la_SOURCES_DIST) \ $(libupsclient_la_SOURCES) $(am__message_SOURCES_DIST) \ $(upsc_SOURCES) $(upscmd_SOURCES) $(upsimage_cgi_SOURCES) \ $(upslog_SOURCES) $(upsmon_SOURCES) $(upsrw_SOURCES) \ $(upssched_SOURCES) $(upsset_cgi_SOURCES) \ $(upsstats_cgi_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__include_HEADERS_DIST = upsclient.h nutclient.h nutclientmem.h HEADERS = $(include_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) A2X = @A2X@ ACLOCAL = @ACLOCAL@ ALTPIDPATH = @ALTPIDPATH@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ ASCIIDOC = @ASCIIDOC@ ASPELL = @ASPELL@ ASPELL_FILTER_LIB_PATH = @ASPELL_FILTER_LIB_PATH@ ASPELL_FILTER_SHARE_PATH = @ASPELL_FILTER_SHARE_PATH@ ASPELL_FILTER_TEX_PATH = @ASPELL_FILTER_TEX_PATH@ AUGPARSE = @AUGPARSE@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ BSDKVMPROCLIBS = @BSDKVMPROCLIBS@ CC = @CC@ CCACHE_BASEDIR = @CCACHE_BASEDIR@ CCACHE_DIR = @CCACHE_DIR@ CCACHE_NAMESPACE = @CCACHE_NAMESPACE@ CCACHE_PATH = @CCACHE_PATH@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFIG_CFLAGS = @CONFIG_CFLAGS@ CONFIG_CPPFLAGS = @CONFIG_CPPFLAGS@ CONFIG_CXXFLAGS = @CONFIG_CXXFLAGS@ CONFIG_FLAGS = @CONFIG_FLAGS@ CONFIG_LDFLAGS = @CONFIG_LDFLAGS@ CONFPATH = @CONFPATH@ CPP = @CPP@ CPPCHECK = @CPPCHECK@ CPPFLAGS = @CPPFLAGS@ CPPUNIT_CFLAGS = @CPPUNIT_CFLAGS@ CPPUNIT_LIBS = @CPPUNIT_LIBS@ CPPUNIT_NUT_CXXFLAGS = @CPPUNIT_NUT_CXXFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH = @CYGPATH@ CYGPATH_W = @CYGPATH_W@ DBLATEX = @DBLATEX@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DEPLOYED_DUMMYUPS = @DEPLOYED_DUMMYUPS@ DEPLOYED_UPSC = @DEPLOYED_UPSC@ DEPLOYED_UPSD = @DEPLOYED_UPSD@ DEPLOYED_UPSIMAGE = @DEPLOYED_UPSIMAGE@ DLLTOOL = @DLLTOOL@ DOC_BUILD_LIST = @DOC_BUILD_LIST@ DOC_CHECK_LIST = @DOC_CHECK_LIST@ DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ DRIVER_MAN_LIST_PAGES = @DRIVER_MAN_LIST_PAGES@ DRVPATH = @DRVPATH@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FORCE_NUT_VERSION = @FORCE_NUT_VERSION@ GDLIB_CONFIG = @GDLIB_CONFIG@ GETENT = @GETENT@ GREP = @GREP@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ ID = @ID@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDD = @LDD@ LDFLAGS = @LDFLAGS@ LDFLAGS_NUT_RPATH = @LDFLAGS_NUT_RPATH@ LDFLAGS_NUT_RPATH_CXX = @LDFLAGS_NUT_RPATH_CXX@ LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@ LIBAVAHI_LIBS = @LIBAVAHI_LIBS@ LIBDIR = @LIBDIR@ LIBGD_CFLAGS = @LIBGD_CFLAGS@ LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ LIBGPIO_CFLAGS = @LIBGPIO_CFLAGS@ LIBGPIO_LIBS = @LIBGPIO_LIBS@ LIBI2C_LIBS = @LIBI2C_LIBS@ LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@ LIBIPMI_LIBS = @LIBIPMI_LIBS@ LIBLTDL_CFLAGS = @LIBLTDL_CFLAGS@ LIBLTDL_LIBS = @LIBLTDL_LIBS@ LIBMODBUS_CFLAGS = @LIBMODBUS_CFLAGS@ LIBMODBUS_LIBS = @LIBMODBUS_LIBS@ LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ LIBNEON_LIBS = @LIBNEON_LIBS@ LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ LIBNETSNMP_LIBS = @LIBNETSNMP_LIBS@ LIBOBJS = @LIBOBJS@ LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ LIBPOWERMAN_LIBS = @LIBPOWERMAN_LIBS@ LIBREGEX_LIBS = @LIBREGEX_LIBS@ LIBS = @LIBS@ LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ LIBSSL_LDFLAGS_RPATH = @LIBSSL_LDFLAGS_RPATH@ LIBSSL_LIBS = @LIBSSL_LIBS@ LIBSSL_REQUIRES = @LIBSSL_REQUIRES@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ LIBUSB_CONFIG = @LIBUSB_CONFIG@ LIBUSB_LIBS = @LIBUSB_LIBS@ LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ LIBWRAP_LIBS = @LIBWRAP_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LN_S_R = @LN_S_R@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MAN_SECTION_API = @MAN_SECTION_API@ MAN_SECTION_API_BASE = @MAN_SECTION_API_BASE@ MAN_SECTION_CFG = @MAN_SECTION_CFG@ MAN_SECTION_CFG_BASE = @MAN_SECTION_CFG_BASE@ MAN_SECTION_CMD_SYS = @MAN_SECTION_CMD_SYS@ MAN_SECTION_CMD_SYS_BASE = @MAN_SECTION_CMD_SYS_BASE@ MAN_SECTION_CMD_USR = @MAN_SECTION_CMD_USR@ MAN_SECTION_CMD_USR_BASE = @MAN_SECTION_CMD_USR_BASE@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ NETLIBS = @NETLIBS@ NETLIBS_GETADDRS = @NETLIBS_GETADDRS@ NET_SNMP_CONFIG = @NET_SNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ NUT_AM_EXPORT_CCACHE_BASEDIR = @NUT_AM_EXPORT_CCACHE_BASEDIR@ NUT_AM_EXPORT_CCACHE_DIR = @NUT_AM_EXPORT_CCACHE_DIR@ NUT_AM_EXPORT_CCACHE_NAMESPACE = @NUT_AM_EXPORT_CCACHE_NAMESPACE@ NUT_AM_EXPORT_CCACHE_PATH = @NUT_AM_EXPORT_CCACHE_PATH@ NUT_AM_MAKE_CAN_EXPORT = @NUT_AM_MAKE_CAN_EXPORT@ NUT_CONFIG_CFLAGS = @NUT_CONFIG_CFLAGS@ NUT_CONFIG_CPPFLAGS = @NUT_CONFIG_CPPFLAGS@ NUT_CONFIG_CXXFLAGS = @NUT_CONFIG_CXXFLAGS@ NUT_CONFIG_LDFLAGS = @NUT_CONFIG_LDFLAGS@ NUT_DATADIR = @NUT_DATADIR@ NUT_LIBEXECDIR = @NUT_LIBEXECDIR@ NUT_MANDIR = @NUT_MANDIR@ NUT_NETVERSION = @NUT_NETVERSION@ NUT_SOURCE_GITREV = @NUT_SOURCE_GITREV@ NUT_SOURCE_GITREV_IS_PRERELEASE = @NUT_SOURCE_GITREV_IS_PRERELEASE@ NUT_SOURCE_GITREV_IS_RELEASE = @NUT_SOURCE_GITREV_IS_RELEASE@ NUT_SOURCE_GITREV_NUMERIC = @NUT_SOURCE_GITREV_NUMERIC@ NUT_SOURCE_GITREV_SEMVER = @NUT_SOURCE_GITREV_SEMVER@ NUT_WEBSITE_BASE = @NUT_WEBSITE_BASE@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OS_NAME = @OS_NAME@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_DURING_CONFIGURE = @PATH_DURING_CONFIGURE@ PATH_SEPARATOR = @PATH_SEPARATOR@ PIDPATH = @PIDPATH@ PKGCONFIGDIR = @PKGCONFIGDIR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PORT = @PORT@ POWERDOWNFLAG = @POWERDOWNFLAG@ PREFIX = @PREFIX@ PWDTOOL = @PWDTOOL@ PYTHON = @PYTHON@ PYTHON2 = @PYTHON2@ PYTHON2_SITE_PACKAGES = @PYTHON2_SITE_PACKAGES@ PYTHON3 = @PYTHON3@ PYTHON3_SITE_PACKAGES = @PYTHON3_SITE_PACKAGES@ PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@ RANLIB = @RANLIB@ REALPATH = @REALPATH@ RUN_AS_GROUP = @RUN_AS_GROUP@ RUN_AS_USER = @RUN_AS_USER@ SBINDIR = @SBINDIR@ SED = @SED@ SEMLIBS = @SEMLIBS@ SERLIBS = @SERLIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOURCE_HIGHLIGHT = @SOURCE_HIGHLIGHT@ STATEPATH = @STATEPATH@ STRIP = @STRIP@ SUN_LIBUSB = @SUN_LIBUSB@ SYSTEMCTL = @SYSTEMCTL@ SYSTEMD_ANALYZE_PROGRAM = @SYSTEMD_ANALYZE_PROGRAM@ SYSTEMD_DAEMON_ARGS_DRIVER = @SYSTEMD_DAEMON_ARGS_DRIVER@ SYSTEMD_DAEMON_ARGS_UPSD = @SYSTEMD_DAEMON_ARGS_UPSD@ SYSTEMD_DAEMON_ARGS_UPSLOG = @SYSTEMD_DAEMON_ARGS_UPSLOG@ SYSTEMD_DAEMON_ARGS_UPSMON = @SYSTEMD_DAEMON_ARGS_UPSMON@ SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER = @SYSTEMD_DAEMON_NOTIFYACCESS_DRIVER@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSD = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSD@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSLOG@ SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON = @SYSTEMD_DAEMON_NOTIFYACCESS_UPSMON@ SYSTEMD_DAEMON_TYPE_DRIVER = @SYSTEMD_DAEMON_TYPE_DRIVER@ SYSTEMD_DAEMON_TYPE_UPSD = @SYSTEMD_DAEMON_TYPE_UPSD@ SYSTEMD_DAEMON_TYPE_UPSLOG = @SYSTEMD_DAEMON_TYPE_UPSLOG@ SYSTEMD_DAEMON_TYPE_UPSMON = @SYSTEMD_DAEMON_TYPE_UPSMON@ SYSTEMD_DAEMON_WATCHDOG_DRIVER = @SYSTEMD_DAEMON_WATCHDOG_DRIVER@ SYSTEMD_DAEMON_WATCHDOG_UPSD = @SYSTEMD_DAEMON_WATCHDOG_UPSD@ SYSTEMD_DAEMON_WATCHDOG_UPSLOG = @SYSTEMD_DAEMON_WATCHDOG_UPSLOG@ SYSTEMD_DAEMON_WATCHDOG_UPSMON = @SYSTEMD_DAEMON_WATCHDOG_UPSMON@ SYSTEMD_SYSTEMCTL_PROGRAM = @SYSTEMD_SYSTEMCTL_PROGRAM@ SYSTEMD_TMPFILES_PROGRAM = @SYSTEMD_TMPFILES_PROGRAM@ TREE_VERSION = @TREE_VERSION@ VALGRIND = @VALGRIND@ VERSION = @VERSION@ WINDMC = @WINDMC@ WINDRES = @WINDRES@ WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ XMLLINT = @XMLLINT@ XSLTPROC = @XSLTPROC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DLLTOOL = @ac_ct_DLLTOOL@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_LD = @ac_ct_LD@ ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ auglensdir = @auglensdir@ auglenstestsdir = @auglenstestsdir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ cgiexecdir = @cgiexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ devddir = @devddir@ docdir = @docdir@ driverexecdir = @driverexecdir@ dummy_PKG_CONFIG = @dummy_PKG_CONFIG@ dummy_PKG_CONFIG_CFLAGS = @dummy_PKG_CONFIG_CFLAGS@ dummy_PKG_CONFIG_LIBS = @dummy_PKG_CONFIG_LIBS@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ freebsdquirksdir = @freebsdquirksdir@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ hotplugdir = @hotplugdir@ htmldir = @htmldir@ htmldocdir = @htmldocdir@ htmlmandir = @htmlmandir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ now = @now@ nut_with_nut_monitor = @nut_with_nut_monitor@ nut_with_nut_monitor_desktop = @nut_with_nut_monitor_desktop@ nut_with_nut_monitor_dir = @nut_with_nut_monitor_dir@ nut_with_nut_monitor_py2gtk2 = @nut_with_nut_monitor_py2gtk2@ nut_with_nut_monitor_py3qt5 = @nut_with_nut_monitor_py3qt5@ nut_with_pynut = @nut_with_pynut@ nut_with_pynut_py = @nut_with_pynut_py@ nut_with_pynut_py2 = @nut_with_pynut_py2@ nut_with_pynut_py3 = @nut_with_pynut_py3@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgconfigdir = @pkgconfigdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ systemdshutdowndir = @systemdshutdowndir@ systemdsystempresetdir = @systemdsystempresetdir@ systemdsystemunitdir = @systemdsystemunitdir@ systemdtmpfilesdir = @systemdtmpfilesdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ udevdir = @udevdir@ EXTRA_DIST = $(am__append_8) $(am__append_13) # ./clients/libupsclient.la samples (partial!) on... # Linux: # # The name that we can dlopen(3). # dlname='libupsclient.so.6' # # Names of this library. # library_names='libupsclient.so.6.0.1 libupsclient.so.6 libupsclient.so' # # Directory that this library needs to be installed in: # libdir='/usr/local/ups/lib' # WIN32: # dlname='libupsclient-6.dll' # library_names='libupsclient.dll.a' # libdir='//lib' CLEANFILES = libupsclient-version.h libupsclient-version.h.tmp* # nutclient.cpp for some legacy reason (maybe initial detached development?) # optionally includes "common.h" with the NUT build setup - and this option # was never triggered in fact, not until pushed through command line like this: AM_CXXFLAGS = -DHAVE_NUTCOMMON=1 -I$(top_srcdir)/include LDADD_FULL = $(top_builddir)/common/libcommon.la libupsclient.la \ $(NETLIBS) $(am__append_1) LDADD_CLIENT = $(top_builddir)/common/libcommonclient.la \ libupsclient.la $(NETLIBS) $(am__append_2) # by default, link programs in this directory with # the more compact libcommonclient.a bundle LDADD = $(LDADD_CLIENT) # Avoid per-target CFLAGS, because this will prevent re-use of object # files. In any case, CFLAGS are only -I options, so there is no harm, # but only add them if we really use the target. AM_CFLAGS = -I$(top_srcdir)/include $(am__append_3) $(am__append_4) dist_bin_SCRIPTS = upssched-cmd lib_LTLIBRARIES = libupsclient.la $(am__append_6) # Optionally deliverable as part of NUT public API: @WITH_DEV_TRUE@include_HEADERS = upsclient.h $(am__append_7) upsc_SOURCES = upsc.c upsclient.h upscmd_SOURCES = upscmd.c upsclient.h upsrw_SOURCES = upsrw.c upsclient.h upslog_SOURCES = upslog.c upsclient.h upslog.h upslog_LDADD = $(LDADD_FULL) upsmon_SOURCES = upsmon.c upsmon.h upsclient.h upsmon_LDADD = $(LDADD_FULL) @HAVE_WINDOWS_SOCKETS_TRUE@message_SOURCES = message.c upssched_SOURCES = upssched.c upssched.h upssched_LDADD = $(top_builddir)/common/libcommonclient.la $(top_builddir)/common/libparseconf.la $(NETLIBS) upsimage_cgi_SOURCES = upsimage.c upsclient.h upsimagearg.h cgilib.c cgilib.h upsimage_cgi_LDADD = $(LDADD) $(LIBGD_LDFLAGS) upsset_cgi_SOURCES = upsset.c upsclient.h cgilib.c cgilib.h upsstats_cgi_SOURCES = upsstats.c upsclient.h status.h upsstats.h \ upsimagearg.h cgilib.c cgilib.h # not LDADD... why? libupsclient_la_SOURCES = upsclient.c upsclient.h libupsclient_la_LIBADD = $(top_builddir)/common/libcommonclient.la \ $(am__append_9) $(am__append_10) # Below we set API versions of public libraries # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # Note that changes here may have to be reflected in packaging (the shared # object .so names would differ) # libupsclient version information libupsclient_la_LDFLAGS = -version-info 7:0:0 -export-symbols-regex \ '^(upscli_|nut_debug_level)' $(am__append_11) # libnutclient version information and build @HAVE_CXX11_TRUE@libnutclient_la_SOURCES = nutclient.h nutclient.cpp @HAVE_CXX11_TRUE@libnutclient_la_LDFLAGS = -version-info 2:2:0 \ @HAVE_CXX11_TRUE@ $(am__append_12) # Needed in not-standalone builds with -DHAVE_NUTCOMMON=1 # which is defined for in-tree CXX builds above: @HAVE_CXX11_TRUE@libnutclient_la_LIBADD = $(top_builddir)/common/libcommonclient.la # libnutclientstub version information and build @HAVE_CXX11_TRUE@libnutclientstub_la_SOURCES = nutclientmem.h nutclientmem.cpp @HAVE_CXX11_TRUE@libnutclientstub_la_LDFLAGS = -version-info 1:1:0 \ @HAVE_CXX11_TRUE@ $(am__append_14) @HAVE_CXX11_TRUE@libnutclientstub_la_LIBADD = libnutclient.la MAINTAINERCLEANFILES = Makefile.in .dirstamp all: all-am .SUFFIXES: .SUFFIXES: .c .cpp .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu clients/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu clients/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-cgiexecPROGRAMS: $(cgiexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(cgiexec_PROGRAMS)'; test -n "$(cgiexecdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(cgiexecdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(cgiexecdir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(cgiexecdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(cgiexecdir)$$dir" || exit $$?; \ } \ ; done uninstall-cgiexecPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(cgiexec_PROGRAMS)'; test -n "$(cgiexecdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(cgiexecdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(cgiexecdir)" && rm -f $$files clean-cgiexecPROGRAMS: @list='$(cgiexec_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libnutclient.la: $(libnutclient_la_OBJECTS) $(libnutclient_la_DEPENDENCIES) $(EXTRA_libnutclient_la_DEPENDENCIES) $(AM_V_CXXLD)$(libnutclient_la_LINK) $(am_libnutclient_la_rpath) $(libnutclient_la_OBJECTS) $(libnutclient_la_LIBADD) $(LIBS) libnutclientstub.la: $(libnutclientstub_la_OBJECTS) $(libnutclientstub_la_DEPENDENCIES) $(EXTRA_libnutclientstub_la_DEPENDENCIES) $(AM_V_CXXLD)$(libnutclientstub_la_LINK) $(am_libnutclientstub_la_rpath) $(libnutclientstub_la_OBJECTS) $(libnutclientstub_la_LIBADD) $(LIBS) libupsclient.la: $(libupsclient_la_OBJECTS) $(libupsclient_la_DEPENDENCIES) $(EXTRA_libupsclient_la_DEPENDENCIES) $(AM_V_CCLD)$(libupsclient_la_LINK) -rpath $(libdir) $(libupsclient_la_OBJECTS) $(libupsclient_la_LIBADD) $(LIBS) message$(EXEEXT): $(message_OBJECTS) $(message_DEPENDENCIES) $(EXTRA_message_DEPENDENCIES) @rm -f message$(EXEEXT) $(AM_V_CCLD)$(LINK) $(message_OBJECTS) $(message_LDADD) $(LIBS) upsc$(EXEEXT): $(upsc_OBJECTS) $(upsc_DEPENDENCIES) $(EXTRA_upsc_DEPENDENCIES) @rm -f upsc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upsc_OBJECTS) $(upsc_LDADD) $(LIBS) upscmd$(EXEEXT): $(upscmd_OBJECTS) $(upscmd_DEPENDENCIES) $(EXTRA_upscmd_DEPENDENCIES) @rm -f upscmd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upscmd_OBJECTS) $(upscmd_LDADD) $(LIBS) upsimage.cgi$(EXEEXT): $(upsimage_cgi_OBJECTS) $(upsimage_cgi_DEPENDENCIES) $(EXTRA_upsimage_cgi_DEPENDENCIES) @rm -f upsimage.cgi$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upsimage_cgi_OBJECTS) $(upsimage_cgi_LDADD) $(LIBS) upslog$(EXEEXT): $(upslog_OBJECTS) $(upslog_DEPENDENCIES) $(EXTRA_upslog_DEPENDENCIES) @rm -f upslog$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upslog_OBJECTS) $(upslog_LDADD) $(LIBS) upsmon$(EXEEXT): $(upsmon_OBJECTS) $(upsmon_DEPENDENCIES) $(EXTRA_upsmon_DEPENDENCIES) @rm -f upsmon$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upsmon_OBJECTS) $(upsmon_LDADD) $(LIBS) upsrw$(EXEEXT): $(upsrw_OBJECTS) $(upsrw_DEPENDENCIES) $(EXTRA_upsrw_DEPENDENCIES) @rm -f upsrw$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upsrw_OBJECTS) $(upsrw_LDADD) $(LIBS) upssched$(EXEEXT): $(upssched_OBJECTS) $(upssched_DEPENDENCIES) $(EXTRA_upssched_DEPENDENCIES) @rm -f upssched$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upssched_OBJECTS) $(upssched_LDADD) $(LIBS) upsset.cgi$(EXEEXT): $(upsset_cgi_OBJECTS) $(upsset_cgi_DEPENDENCIES) $(EXTRA_upsset_cgi_DEPENDENCIES) @rm -f upsset.cgi$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upsset_cgi_OBJECTS) $(upsset_cgi_LDADD) $(LIBS) upsstats.cgi$(EXEEXT): $(upsstats_cgi_OBJECTS) $(upsstats_cgi_DEPENDENCIES) $(EXTRA_upsstats_cgi_DEPENDENCIES) @rm -f upsstats.cgi$(EXEEXT) $(AM_V_CCLD)$(LINK) $(upsstats_cgi_OBJECTS) $(upsstats_cgi_LDADD) $(LIBS) install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgilib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutclient.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nutclientmem.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsclient.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upscmd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsimage.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upslog.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsmon.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsrw.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upssched.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsstats.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cpp.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(SCRIPTS) $(HEADERS) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cgiexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-binPROGRAMS clean-cgiexecPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/cgilib.Po -rm -f ./$(DEPDIR)/message.Po -rm -f ./$(DEPDIR)/nutclient.Plo -rm -f ./$(DEPDIR)/nutclientmem.Plo -rm -f ./$(DEPDIR)/upsc.Po -rm -f ./$(DEPDIR)/upsclient.Plo -rm -f ./$(DEPDIR)/upscmd.Po -rm -f ./$(DEPDIR)/upsimage.Po -rm -f ./$(DEPDIR)/upslog.Po -rm -f ./$(DEPDIR)/upsmon.Po -rm -f ./$(DEPDIR)/upsrw.Po -rm -f ./$(DEPDIR)/upssched.Po -rm -f ./$(DEPDIR)/upsset.Po -rm -f ./$(DEPDIR)/upsstats.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-includeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-cgiexecPROGRAMS \ install-dist_binSCRIPTS install-libLTLIBRARIES \ install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/cgilib.Po -rm -f ./$(DEPDIR)/message.Po -rm -f ./$(DEPDIR)/nutclient.Plo -rm -f ./$(DEPDIR)/nutclientmem.Plo -rm -f ./$(DEPDIR)/upsc.Po -rm -f ./$(DEPDIR)/upsclient.Plo -rm -f ./$(DEPDIR)/upscmd.Po -rm -f ./$(DEPDIR)/upsimage.Po -rm -f ./$(DEPDIR)/upslog.Po -rm -f ./$(DEPDIR)/upsmon.Po -rm -f ./$(DEPDIR)/upsrw.Po -rm -f ./$(DEPDIR)/upssched.Po -rm -f ./$(DEPDIR)/upsset.Po -rm -f ./$(DEPDIR)/upsstats.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-cgiexecPROGRAMS \ uninstall-dist_binSCRIPTS uninstall-includeHEADERS \ uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-cgiexecPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-cgiexecPROGRAMS install-data \ install-data-am install-dist_binSCRIPTS install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-includeHEADERS install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-cgiexecPROGRAMS \ uninstall-dist_binSCRIPTS uninstall-includeHEADERS \ uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libcommonclient.la \ $(top_builddir)/common/libparseconf.la: dummy +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) #|s_upsdebug|fatalx|fatal_with_errno|xcalloc|xbasename|print_banner_once)' @HAVE_WINDOWS_TRUE@ # Many versions of MingW seem to fail to build non-static DLL without this libupsclient-version.h: libupsclient.la @echo " GENERATE-HEADER $@" ; \ RES=0; \ dlname_filter() { sed -e 's/^[^=]*=//' -e 's/^"\(.*\)"$$/\1/' -e 's/^'"'"'\(.*\)'"'"'$$/\1/' ; }; \ SOFILE_LIBUPSCLIENT="`grep -E '^dlname' '$?' | dlname_filter`" \ || SOFILE_LIBUPSCLIENT="" ; \ if [ x"$${SOFILE_LIBUPSCLIENT-}" = x ] ; then \ printf "#ifdef SOFILE_LIBUPSCLIENT\n# undef SOFILE_LIBUPSCLIENT\n#endif\n\n" ; \ printf "#ifdef SOPATH_LIBUPSCLIENT\n# undef SOPATH_LIBUPSCLIENT\n#endif\n\n" ; \ else \ printf "#ifndef SOFILE_LIBUPSCLIENT\n# define SOFILE_LIBUPSCLIENT \"%s\"\n#endif\n\n" "$${SOFILE_LIBUPSCLIENT}" ; \ printf "#ifndef SOPATH_LIBUPSCLIENT\n# define SOPATH_LIBUPSCLIENT \"%s/%s\"\n#endif\n\n" "@LIBDIR@" "$${SOFILE_LIBUPSCLIENT}" ; \ fi > "$@".tmp.$$$$ && \ if test -f "$@" && test -s "$@" ; then \ if cmp -s "$@.tmp.$$$$" "$@" ; then \ echo " GENERATE-HEADER $@ did not change" ; \ else \ echo " GENERATE-HEADER $@ got changed" ; \ cp "$@.tmp.$$$$" "$@" ; \ fi ; \ else \ echo " GENERATE-HEADER $@ was absent"; \ cp "$@.tmp.$$$$" "$@" ; \ fi \ || RES=$$?; \ rm -f "$@.tmp.$$$$" ; \ exit $$RES @HAVE_CXX11_TRUE@@HAVE_WINDOWS_TRUE@ # Many versions of MingW seem to fail to build non-static DLL without this @HAVE_CXX11_TRUE@@HAVE_WINDOWS_TRUE@ # Many versions of MingW seem to fail to build non-static DLL without this dummy: # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! #clean-local: # $(AM_V_at)rm -rf $(builddir)/.deps # Helper for only the enabled libs to get built: all-libs-local: $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \ libupsclient-version.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nut-2.8.3/clients/upsimage.c0000644000200500020050000005617614777767434012727 00000000000000/* upsimage - cgi program to create graphical ups information reports Status: 20020814 - Simon Rozman - redesigned the meters 20020823 - Simon Rozman - added support for width, height and scale_height parameters - added support for outvolt - noimage now writes out a clue, why upsimage failed 20020902 - Simon Rozman - background now transparent by default - added support for colorization parameters - removed linear antialiasing of the scale, until I come up with a better algorithm 20020913 - Simon Rozman - added width, height and scale_height to imgarg table 20020928 - Simon Rozman - added imgvar table to hold description, how to draw each UPS variable supported - added support for ACFREQ, OUT_FREQ and UPSTEMP Copyrights: (C) 1998 Russell Kroll (C) 2002 Simon Rozman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "nut_stdint.h" #include "upsclient.h" #include "cgilib.h" #include #include #include #include "upsimagearg.h" #define MAX_CGI_STRLEN 64 /* network timeout for initial connection, in seconds */ #define UPSCLI_DEFAULT_CONNECT_TIMEOUT "10" static char *monhost = NULL, *cmd = NULL; static uint16_t port; static char *upsname, *hostname; static UPSCONN_t ups; #define RED(x) ((x >> 16) & 0xff) #define GREEN(x) ((x >> 8) & 0xff) #define BLUE(x) (x & 0xff) void parsearg(char *var, char *value) { long long i, v; /* Be big enough to fit all expected inputs; truncate later */ /* avoid bogus junk from evil people */ if ((strlen(var) > MAX_CGI_STRLEN) || (strlen(value) > MAX_CGI_STRLEN)) return; if (!strcmp(var, "host")) { free(monhost); monhost = xstrdup(value); return; } if (!strcmp(var, "display")) { free(cmd); cmd = xstrdup(value); return; } /* see if this is one of the shared (upsimagearg.h) variables */ for (i = 0; imgarg[i].name != NULL; i++) { if (!strcmp(imgarg[i].name, var)) { if (!strncmp(value, "0x", 2)) v = (long long)strtoul(value + 2, (char **)NULL, 16); else v = (long long)atoi(value); /* avoid false numbers from bad people */ if (v < imgarg[i].min) imgarg[i].val = imgarg[i].min; else if (v > imgarg[i].max) imgarg[i].val = imgarg[i].max; else { assert (v < INT_MAX); assert (v > INT_MIN); imgarg[i].val = (int)v; } return; } } } /* return the value from the URL or the default if it wasn't set */ static int get_imgarg(const char *name) { int i; for (i = 0; imgarg[i].name != NULL; i++) if (!strcmp(imgarg[i].name, name)) return imgarg[i].val; return -1; } /* write the HTML header then have gd dump the image */ static void drawimage(gdImagePtr im) __attribute__((noreturn)); static void drawimage(gdImagePtr im) { printf("Pragma: no-cache\n"); printf("Content-type: image/png\n\n"); gdImagePng(im, stdout); gdImageDestroy(im); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } /* helper function to allocate color in the image */ static int color_alloc(gdImagePtr im, int rgb) { return gdImageColorAllocate(im, RED(rgb), GREEN(rgb), BLUE(rgb)); } /* draws the scale behind the bar indicator */ static void drawscale( gdImagePtr im, /* image where we would like to draw scale */ int lvllo, int lvlhi, /* min and max numbers on the scale */ int step, int step5, int step10, /* steps for minor, submajor and major dashes */ int redlo1, int redhi1, /* first red zone start and end */ int redlo2, int redhi2, /* second red zone start and end */ int grnlo, int grnhi) /* green zone start and end */ { int col1, col2, back_color, scale_num_color, ok_zone_maj_color, ok_zone_min_color, neutral_zone_maj_color, neutral_zone_min_color, warn_zone_maj_color, warn_zone_min_color; char lbltxt[SMALLBUF]; int y, level, range; int width, height, scale_height; back_color = color_alloc(im, get_imgarg("back_col")); scale_num_color = color_alloc(im, get_imgarg("scale_num_col")); ok_zone_maj_color = color_alloc(im, get_imgarg("ok_zone_maj_col")); ok_zone_min_color = color_alloc(im, get_imgarg("ok_zone_min_col")); neutral_zone_maj_color = color_alloc(im, get_imgarg("neutral_zone_maj_col")); neutral_zone_min_color = color_alloc(im, get_imgarg("neutral_zone_min_col")); warn_zone_maj_color = color_alloc(im, get_imgarg("warn_zone_maj_col")); warn_zone_min_color = color_alloc(im, get_imgarg("warn_zone_min_col")); width = get_imgarg("width"); height = get_imgarg("height"); scale_height = get_imgarg("scale_height"); /* start out with a background color and make it transparent */ gdImageFilledRectangle(im, 0, 0, width, height, back_color); gdImageColorTransparent(im, back_color); range = lvlhi - lvllo; /* draw scale to correspond with the values */ for (level = lvlhi; level >= lvllo; level -= step) { /* select dash RGB color according to the level */ if (((redlo1 <= level) && (level <=redhi1)) || ((redlo2 <= level) && (level <=redhi2))) { col1 = warn_zone_maj_color; col2 = warn_zone_min_color; } else if ((grnlo <= level) && (level <= grnhi)) { col1 = ok_zone_maj_color; col2 = ok_zone_min_color; } else { col1 = neutral_zone_maj_color; col2 = neutral_zone_min_color; } /* calculate integer value for y */ y = scale_height * (lvlhi - level) / range; /* draw major, semimajor or minor dash accordingly */ if (level % step10 == 0) { gdImageLine(im, 0, y, width, y, col1); } else { if (level % step5 == 0) gdImageLine(im, 5, y, width - 5, y, col2); else gdImageLine(im, 10, y, width - 10, y, col2); } } /* put the values on the scale */ for (level = lvlhi; level >= lvllo; level -= step) { if (level % step10 == 0) { y = scale_height * (lvlhi - level) / range; snprintf(lbltxt, sizeof(lbltxt), "%d", level); gdImageString(im, gdFontMediumBold, width - (int)(strlen(lbltxt)) * gdFontMediumBold->w, y, (unsigned char *) lbltxt, scale_num_color); } } } /* draws the bar style indicator */ static void drawbar( int lvllo, int lvlhi, /* min and max numbers on the scale */ int step, int step5, int step10, /* steps for minor, submajor and major dashes */ int redlo1, int redhi1, /* first red zone start and end */ int redlo2, int redhi2, /* second red zone start and end */ int grnlo, int grnhi, /* green zone start and end */ double value, /* UPS variable value to draw */ const char *format /* printf style format to be used when rendering summary text */ ) __attribute__((noreturn)); static void drawbar( int lvllo, int lvlhi, /* min and max numbers on the scale */ int step, int step5, int step10, /* steps for minor, submajor and major dashes */ int redlo1, int redhi1, /* first red zone start and end */ int redlo2, int redhi2, /* second red zone start and end */ int grnlo, int grnhi, /* green zone start and end */ double value, /* UPS variable value to draw */ const char *format /* printf style format to be used when rendering summary text */ ) { gdImagePtr im; int bar_color, summary_color; char text[SMALLBUF]; int bar_y; int width, height, scale_height; /* get the dimension parameters */ width = get_imgarg("width"); height = get_imgarg("height"); scale_height = get_imgarg("scale_height"); /* create the image */ im = gdImageCreate(width, height); /* draw the scale */ drawscale(im, lvllo, lvlhi, step, step5, step10, redlo1, redhi1, redlo2, redhi2, grnlo, grnhi); /* allocate colors for the bar and summary text */ bar_color = color_alloc(im, get_imgarg("bar_col")); summary_color = color_alloc(im, get_imgarg("summary_col")); /* rescale UPS value to fit in the scale */ bar_y = (int)((1.0 - (value - lvllo) / (lvlhi - lvllo)) * scale_height); /* sanity checks: */ /* 1: if value is above maximum, then bar_y goes negative */ if (bar_y < 0) bar_y = 0; /* 2: if value is below minimum, bar_y goes off the scale */ if (bar_y > scale_height) bar_y = scale_height; /* draw it */ gdImageFilledRectangle(im, 25, bar_y, width - 25, scale_height, bar_color); /* stick the text version of the value at the bottom center */ #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(text, sizeof(text), format, value); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif gdImageString(im, gdFontMediumBold, (width - (int)(strlen(text))*gdFontMediumBold->w)/2, height - gdFontMediumBold->h, (unsigned char *) text, summary_color); drawimage(im); /* NOTREACHED */ } /* draws the error image */ static void noimage(const char *fmt, ...) __attribute__((noreturn)); static void noimage(const char *fmt, ...) { gdImagePtr im; int back_color, summary_color; int width, height; char msg[SMALLBUF]; va_list ap; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vsnprintf(msg, sizeof(msg), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); width = get_imgarg("width"); height = get_imgarg("height"); im = gdImageCreate(width, height); back_color = color_alloc(im, get_imgarg("back_col")); summary_color = color_alloc(im, get_imgarg("summary_col")); gdImageFilledRectangle(im, 0, 0, width, height, back_color); gdImageColorTransparent(im, back_color); if (width > height) gdImageString(im, gdFontMediumBold, (width - (int)(strlen(msg))*gdFontMediumBold->w)/2, (height - gdFontMediumBold->h)/2, (unsigned char *) msg, summary_color); else gdImageStringUp(im, gdFontMediumBold, (width - gdFontMediumBold->h)/2, (height + (int)(strlen(msg))*gdFontMediumBold->w)/2, (unsigned char *) msg, summary_color); drawimage(im); /* NOTE: Earlier code called noimage() and then exit(EXIT_FAILURE); * to signal an error via process exit code. Now that drawimage() * always ends with exit(EXIT_SUCCESS) - which might make webserver * feel good - the command-line use if any suffers no error returns. */ /* NOTREACHED */ } /* draws bar indicator when minimum, nominal or maximum values for the given UPS variable can be determined. deviation < 0 means that values below nom should be grey instead of green */ static void drawgeneralbar(double var, int min, int nom, int max, int deviation, const char *format) __attribute__((noreturn)); static void drawgeneralbar(double var, int min, int nom, int max, int deviation, const char *format) { int hi, lo, step1, step5, step10, graybelownom=0; if(deviation < 0) { deviation=-deviation; graybelownom=1; } if ((nom == -1) && ((min == -1) || (max == -1))) noimage("Can't determine range"); /* if min, max and nom are mixed up, arrange them appropriately */ if (nom != -1) { if (min == -1) min = nom - 3*deviation; if (max == -1) max = nom + 3*deviation; } else { /* if nominal value isn't available, assume, it's the average between min and max */ nom = (min + max) / 2; } /* draw scale in the background */ if ((max - min) <= 50) { /* the scale is sparse enough to draw finer scale */ step1 = 1; step5 = 5; step10 = 10; } else if((max - min) <= 100) { step1 = 2; step5 = 10; step10 = 20; } else { step1 = 5; step5 = 20; step10 = 40; } /* round min and max points to get high and low numbers for graph */ lo = ((min - deviation) / step10) * step10; hi = ((max + deviation + step10/2) / step10) * step10; if(!graybelownom) { drawbar(lo, hi, step1, step5, step10, max, hi, lo, min, nom - deviation, nom + deviation, var, format); } else { drawbar(lo, hi, step1, step5, step10, 0, min, max, hi, nom, max, var, format); } /* NOTREACHED */ } /* draws input and output voltage bar style indicators */ static void draw_utility(double var, int min, int nom, int max, int deviation, const char *format) __attribute__((noreturn)); static void draw_utility(double var, int min, int nom, int max, int deviation, const char *format) { /* hack: deal with hardware that doesn't have known transfer points */ if (min == -1) { if(var < 200) { min = 90; } else if(var < 300) { min = 200; } else { min = 340; } } /* somewhere between 220 and 230 V, to keep everybody satisfied */ if (nom == -1) { if(var < 200) { nom = 110; } else if(var < 300) { nom = 225; } else { nom = 400; } } /* symmetrical around nom */ if (max == -1) max = nom+(nom-min); /* Acceptable range of voltage is 85%-110% of nominal voltage * in EU at least. Be conservative and say +-10% */ deviation = (int)(nom * 0.1); drawgeneralbar(var, min, nom, max, deviation, format); /* NOTREACHED */ } /* draws battery.percent bar style indicator */ static void draw_battpct(double var, int min, int nom, int max, int deviation, const char *format) __attribute__((noreturn)); static void draw_battpct(double var, int min, int nom, int max, int deviation, const char *format) { NUT_UNUSED_VARIABLE(nom); NUT_UNUSED_VARIABLE(max); NUT_UNUSED_VARIABLE(deviation); if (min < 0) { min = 50; } drawbar(0, 100, 2, 10, 20, 0, min, -1, -1, 80, 100, var, format); } /* draws battery.voltage bar style indicator */ static void draw_battvolt(double var, int min, int nom, int max, int deviation, const char *format) __attribute__((noreturn)); static void draw_battvolt(double var, int min, int nom, int max, int deviation, const char *format) { if(nom == -1) { /* Use a fixed set of reasonable nominal voltages, seems to * be the only way to get reasonable behaviour during * discharge */ if(var < 9) nom = 6; else if(var < 18) nom = 12; else if(var < 30) nom = 24; else if(var < 60) nom = 48; else if(var < 120) nom = 96; else if(var < 230) nom = 192; else nom = 384; } if(min == -1) { min = (int)(nom/2*1.6+1); /* Assume a 2V cell is dead at 1.6V */ } if(max == -1) { max = (int)(nom/2*2.3+1); /* Assume 2.3V float charge voltage */ } if (nom < min || nom > max) nom = -1; deviation = (int)(-nom*0.05); /* 5% deviation from nominal voltage */ if(deviation==0) { deviation = -1; } drawgeneralbar(var, min, nom, max, deviation, format); } /* draws ups.load bar style indicator */ static void draw_upsload(double var, int min, int nom, int max, int deviation, const char *format) __attribute__((noreturn)); static void draw_upsload(double var, int min, int nom, int max, int deviation, const char *format) { NUT_UNUSED_VARIABLE(min); NUT_UNUSED_VARIABLE(nom); NUT_UNUSED_VARIABLE(max); NUT_UNUSED_VARIABLE(deviation); drawbar(0, 125, 5, 5, 25, 100, 125, -1, -1, 0, 50, var, format); } /* draws temperature bar style indicator */ static void draw_temperature(double var, int min, int nom, int max, int deviation, const char *format) __attribute__((noreturn)); static void draw_temperature(double var, int min, int nom, int max, int deviation, const char *format) { int hi = get_imgarg("tempmax"); int lo = get_imgarg("tempmin"); NUT_UNUSED_VARIABLE(nom); NUT_UNUSED_VARIABLE(deviation); drawbar(lo, hi, 1, 5, 10, lo, min, max, hi, -1, -1, var, format); } /* draws humidity bar style indicator */ static void draw_humidity(double var, int min, int nom, int max, int deviation, const char *format) __attribute__((noreturn)); static void draw_humidity(double var, int min, int nom, int max, int deviation, const char *format) { NUT_UNUSED_VARIABLE(nom); NUT_UNUSED_VARIABLE(deviation); drawbar(0, 100, 2, 10, 20, 0, min, max, 100, -1, -1, var, format); } static int get_var(const char *var, char *buf, size_t buflen) { int ret; size_t numq, numa; const char *query[4]; char **answer; query[0] = "VAR"; query[1] = upsname; query[2] = var; numq = 3; ret = upscli_get(&ups, numq, query, &numa, &answer); if (ret < 0) return 0; if (numa < numq) return 0; snprintf(buf, buflen, "%s", answer[3]); return 1; } int main(int argc, char **argv) { char str[SMALLBUF]; int i, min, nom, max; double var = 0; NUT_UNUSED_VARIABLE(argc); NUT_UNUSED_VARIABLE(argv); extractcgiargs(); upscli_init_default_connect_timeout(NULL, NULL, UPSCLI_DEFAULT_CONNECT_TIMEOUT); /* no 'host=' or 'display=' given */ if ((!monhost) || (!cmd)) noimage("No host or display"); if (!checkhost(monhost, NULL)) noimage("Access denied"); upsname = hostname = NULL; if (upscli_splitname(monhost, &upsname, &hostname, &port) != 0) { noimage("Invalid UPS definition (upsname[@hostname[:port]])\n"); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ #endif } if (upscli_connect(&ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { noimage("Can't connect to server:\n%s\n", upscli_strerror(&ups)); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ #endif } for (i = 0; imgvar[i].name; i++) if (!strcmp(cmd, imgvar[i].name)) { /* sanity check whether we have draw function registered with this variable */ if (!imgvar[i].drawfunc) { noimage("Draw function N/A"); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ #endif } /* get the variable value */ if (get_var(imgvar[i].name, str, sizeof(str)) == 1) { var = strtod(str, NULL); } else { /* no value, no fun */ snprintf(str, sizeof(str), "%s N/A", imgvar[i].name); noimage(str); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); /* Should not get here in practice, but compiler is afraid we can fall through */ #endif } /* when getting minimum, nominal and maximum values, we first look if the marginal value is supported by the UPS driver, if not, we look it up in the imgarg table under the SAME name */ /* get the minimum value */ if (imgvar[i].minimum) { if (get_var(imgvar[i].minimum, str, sizeof(str)) == 1) { min = atoi(str); } else { min = get_imgarg(imgvar[i].minimum); } } else { min = -1; } /* get the nominal value */ if (imgvar[i].nominal) { if (get_var(imgvar[i].nominal, str, sizeof(str)) == 1) { nom = atoi(str); } else { nom = get_imgarg(imgvar[i].nominal); } } else { nom = -1; } /* get the maximum value */ if (imgvar[i].maximum) { if (get_var(imgvar[i].maximum, str, sizeof(str)) == 1) { max = atoi(str); } else { max = get_imgarg(imgvar[i].maximum); } } else { max = -1; } imgvar[i].drawfunc(var, min, nom, max, imgvar[i].deviation, imgvar[i].format); exit(EXIT_SUCCESS); } noimage("Unknown display"); #ifndef HAVE___ATTRIBUTE__NORETURN exit(EXIT_FAILURE); #endif } imgvar_t imgvar[] = { { "input.voltage", "input.transfer.low", "input.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "input.L1-N.voltage", "input.transfer.low", "input.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "input.L2-N.voltage", "input.transfer.low", "input.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "input.L3-N.voltage", "input.transfer.low", "input.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "input.L1-L2.voltage", "input.transfer.low", "input.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "input.L2-L3.voltage", "input.transfer.low", "input.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "input.L3-L1.voltage", "input.transfer.low", "input.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "battery.charge", "battery.charge.low", NULL, NULL, 0, "%.1f %%", draw_battpct }, { "battery.voltage", "battery.voltage.low", "battery.voltage.nominal", "battery.voltage.high", 0, "%.1f VDC", draw_battvolt }, /* We use 'high' ASCII for the degrees symbol, since the gdImageString() * function doesn't understand UTF-8 or HTML escape sequences. :-( */ { "ups.temperature", "ups.temperature.low", NULL, "ups.temperature.high", 0, "%.1f \260C", draw_temperature }, /* Same here. */ { "ambient.temperature", "ambient.temperature.low", NULL, "ambient.temperature.high", 0, "%.1f \260C", draw_temperature }, { "ambient.humidity", "ambient.humidity.low", NULL, "ambient.humidity.high", 0, "%.1f %%", draw_humidity }, { "input.frequency", NULL, "input.frequency.nominal", NULL, 2, "%.1f Hz", drawgeneralbar }, { "ups.load", NULL, NULL, NULL, 0, "%.1f %%", draw_upsload }, { "output.L1.power.percent", NULL, NULL, NULL, 0, "%.1f %%", draw_upsload }, { "output.L2.power.percent", NULL, NULL, NULL, 0, "%.1f %%", draw_upsload }, { "output.L3.power.percent", NULL, NULL, NULL, 0, "%.1f %%", draw_upsload }, { "output.L1.realpower.percent", NULL, NULL, NULL, 0, "%.1f %%", draw_upsload }, { "output.L2.realpower.percent", NULL, NULL, NULL, 0, "%.1f %%", draw_upsload }, { "output.L3.realpower.percent", NULL, NULL, NULL, 0, "%.1f %%", draw_upsload }, { "output.voltage", "input.transfer.low", "output.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "output.L1-N.voltage", "input.transfer.low", "output.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "output.L2-N.voltage", "input.transfer.low", "output.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "output.L3-N.voltage", "input.transfer.low", "output.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "output.L1-L2.voltage", "input.transfer.low", "output.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "output.L2-L3.voltage", "input.transfer.low", "output.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "output.L3-L1.voltage", "input.transfer.low", "output.voltage.nominal", "input.transfer.high", 0, "%.1f VAC", draw_utility }, { "output.frequency", NULL, "output.frequency.nominal", NULL, 2, "%.1f Hz", drawgeneralbar }, { NULL, NULL, NULL, NULL, 0, NULL, NULL } }; nut-2.8.3/clients/upsclient.c0000644000200500020050000014764314777767434013123 00000000000000/* upsclient - network communications functions for UPS clients Copyright (C) 2002 Russell Kroll 2008 Arjen de Korte 2020 - 2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" /* safe because it doesn't contain prototypes */ #include "nut_platform.h" #ifndef WIN32 # ifdef HAVE_PTHREAD /* this include is needed on AIX to have errno stored in thread local storage */ # include # endif #endif /* !WIN32 */ #include #include #include #include #include #ifndef WIN32 # include # include # include # include # include # define SOCK_OPT_CAST #else /* => WIN32 */ # define SOCK_OPT_CAST (char *) /* Those 2 files for support of getaddrinfo, getnameinfo and freeaddrinfo on Windows 2000 and older versions */ # include # include /* This override network system calls to adapt to Windows specificity */ # define W32_NETWORK_CALL_OVERRIDE # include "wincompat.h" # undef W32_NETWORK_CALL_OVERRIDE #endif /* WIN32 */ #include "common.h" #include "nut_stdint.h" #include "nut_float.h" #include "timehead.h" #include "upsclient.h" /* WA for Solaris/i386 bug: non-blocking connect sets errno to ENOENT */ #if (defined NUT_PLATFORM_SOLARIS) # define SOLARIS_i386_NBCONNECT_ENOENT(status) ( (!strcmp("i386", CPU_TYPE)) ? (ENOENT == (status)) : 0 ) #else # define SOLARIS_i386_NBCONNECT_ENOENT(status) (0) #endif /* end of Solaris/i386 WA for non-blocking connect */ /* WA for AIX bug: non-blocking connect sets errno to 0 */ #if (defined NUT_PLATFORM_AIX) # define AIX_NBCONNECT_0(status) (0 == (status)) #else # define AIX_NBCONNECT_0(status) (0) #endif /* end of AIX WA for non-blocking connect */ #ifdef WITH_NSS # include # include # include # include # include # include #endif /* WITH_NSS */ #define UPSCLIENT_MAGIC 0x19980308 #define SMALLBUF 512 #ifdef SHUT_RDWR #define shutdown_how SHUT_RDWR #else #define shutdown_how 2 #endif static struct { int flags; const char *str; } upscli_errlist[] = { { 0, "Unknown error" }, /* 0: UPSCLI_ERR_UNKNOWN */ { 0, "Variable not supported by UPS" }, /* 1: UPSCLI_ERR_VARNOTSUPP */ { 0, "No such host" }, /* 2: UPSCLI_ERR_NOSUCHHOST */ { 0, "Invalid response from server" }, /* 3: UPSCLI_ERR_INVRESP */ { 0, "Unknown UPS" }, /* 4: UPSCLI_ERR_UNKNOWNUPS */ { 0, "Invalid list type" }, /* 5: UPSCLI_ERR_INVLISTTYPE */ { 0, "Access denied" }, /* 6: UPSCLI_ERR_ACCESSDENIED */ { 0, "Password required" }, /* 7: UPSCLI_ERR_PWDREQUIRED */ { 0, "Password incorrect" }, /* 8: UPSCLI_ERR_PWDINCORRECT */ { 0, "Missing argument" }, /* 9: UPSCLI_ERR_MISSINGARG */ { 0, "Data stale" }, /* 10: UPSCLI_ERR_DATASTALE */ { 0, "Variable unknown" }, /* 11: UPSCLI_ERR_VARUNKNOWN */ { 0, "Already logged in" }, /* 12: UPSCLI_ERR_LOGINTWICE */ { 0, "Already set password" }, /* 13: UPSCLI_ERR_PWDSETTWICE */ { 0, "Unknown variable type" }, /* 14: UPSCLI_ERR_UNKNOWNTYPE */ { 0, "Unknown variable" }, /* 15: UPSCLI_ERR_UNKNOWNVAR */ { 0, "Read-only variable" }, /* 16: UPSCLI_ERR_VARREADONLY */ { 0, "New value is too long" }, /* 17: UPSCLI_ERR_TOOLONG */ { 0, "Invalid value for variable" }, /* 18: UPSCLI_ERR_INVALIDVALUE */ { 0, "Set command failed" }, /* 19: UPSCLI_ERR_SETFAILED */ { 0, "Unknown instant command" }, /* 20: UPSCLI_ERR_UNKINSTCMD */ { 0, "Instant command failed" }, /* 21: UPSCLI_ERR_CMDFAILED */ { 0, "Instant command not supported" }, /* 22: UPSCLI_ERR_CMDNOTSUPP */ { 0, "Invalid username" }, /* 23: UPSCLI_ERR_INVUSERNAME */ { 0, "Already set username" }, /* 24: UPSCLI_ERR_USERSETTWICE */ { 0, "Unknown command" }, /* 25: UPSCLI_ERR_UNKCOMMAND */ { 0, "Invalid argument" }, /* 26: UPSCLI_ERR_INVALIDARG */ { 1, "Send failure: %s" }, /* 27: UPSCLI_ERR_SENDFAILURE */ { 1, "Receive failure: %s" }, /* 28: UPSCLI_ERR_RECVFAILURE */ { 1, "socket failure: %s" }, /* 29: UPSCLI_ERR_SOCKFAILURE */ { 1, "bind failure: %s" }, /* 30: UPSCLI_ERR_BINDFAILURE */ { 1, "Connection failure: %s" }, /* 31: UPSCLI_ERR_CONNFAILURE */ { 1, "Write error: %s" }, /* 32: UPSCLI_ERR_WRITE */ { 1, "Read error: %s" }, /* 33: UPSCLI_ERR_READ */ { 0, "Invalid password" }, /* 34: UPSCLI_ERR_INVPASSWORD */ { 0, "Username required" }, /* 35: UPSCLI_ERR_USERREQUIRED */ { 0, "SSL is not available", }, /* 36: UPSCLI_ERR_SSLFAIL */ { 2, "SSL error: %s", }, /* 37: UPSCLI_ERR_SSLERR */ { 0, "Server disconnected", }, /* 38: UPSCLI_ERR_SRVDISC */ { 0, "Driver not connected", }, /* 39: UPSCLI_ERR_DRVNOTCONN */ { 0, "Memory allocation failure", }, /* 40: UPSCLI_ERR_NOMEM */ { 3, "Parse error: %s", }, /* 41: UPSCLI_ERR_PARSE */ { 0, "Protocol error", }, /* 42: UPSCLI_ERR_PROTOCOL */ }; typedef struct HOST_CERT_s { const char *host; const char *certname; int certverify; int forcessl; struct HOST_CERT_s *next; } HOST_CERT_t; static HOST_CERT_t* upscli_find_host_cert(const char* hostname); /* Flag for SSL init */ static int upscli_initialized = 0; /* 0 means no timeout in upscli_connect() */ static struct timeval upscli_default_connect_timeout = {0, 0}; static int upscli_default_connect_timeout_initialized = 0; #ifdef WITH_OPENSSL static SSL_CTX *ssl_ctx; #elif defined(WITH_NSS) /* WITH_OPENSLL */ static int verify_certificate = 1; static HOST_CERT_t *first_host_cert = NULL; static char* nsscertname = NULL; static char* nsscertpasswd = NULL; #endif /* WITH_OPENSSL | WITH_NSS */ #ifdef WITH_OPENSSL static void ssl_debug(void) { unsigned long e; char errmsg[SMALLBUF]; while ((e = ERR_get_error()) != 0) { ERR_error_string_n(e, errmsg, sizeof(errmsg)); upsdebugx(2, "ssl_debug: %s", errmsg); } } static int ssl_error(SSL *ssl, ssize_t ret) { int e; if (ret >= INT_MAX) { upslogx(LOG_ERR, "ssl_error() ret=%" PRIiSIZE " would not fit in an int", ret); return -1; } e = SSL_get_error(ssl, (int)ret); switch (e) { case SSL_ERROR_WANT_READ: upslogx(LOG_ERR, "ssl_error() ret=%" PRIiSIZE " SSL_ERROR_WANT_READ", ret); break; case SSL_ERROR_WANT_WRITE: upslogx(LOG_ERR, "ssl_error() ret=%" PRIiSIZE " SSL_ERROR_WANT_WRITE", ret); break; case SSL_ERROR_SYSCALL: if (ret == 0 && ERR_peek_error() == 0) { upslogx(LOG_ERR, "ssl_error() EOF from client"); } else { upslogx(LOG_ERR, "ssl_error() ret=%" PRIiSIZE " SSL_ERROR_SYSCALL", ret); } break; default: upslogx(LOG_ERR, "ssl_error() ret=%" PRIiSIZE " SSL_ERROR %d", ret, e); ssl_debug(); } return -1; } #elif defined(WITH_NSS) /* WITH_OPENSSL */ static char *nss_password_callback(PK11SlotInfo *slot, PRBool retry, void *arg) { NUT_UNUSED_VARIABLE(retry); NUT_UNUSED_VARIABLE(arg); upslogx(LOG_INFO, "Intend to retrieve password for %s / %s: password %sconfigured", PK11_GetSlotName(slot), PK11_GetTokenName(slot), nsscertpasswd?"":"not "); return nsscertpasswd ? PL_strdup(nsscertpasswd) : NULL; } static void nss_error(const char* funcname) { char buffer[SMALLBUF]; PRInt32 length = PR_GetErrorText(buffer); if (length > 0 && length < SMALLBUF) { upsdebugx(1, "nss_error %ld in %s : %s", (long)PR_GetError(), funcname, buffer); }else{ upsdebugx(1, "nss_error %ld in %s", (long)PR_GetError(), funcname); } } static SECStatus AuthCertificate(CERTCertDBHandle *arg, PRFileDesc *fd, PRBool checksig, PRBool isServer) { UPSCONN_t *ups = (UPSCONN_t *)SSL_RevealPinArg(fd); SECStatus status = SSL_AuthCertificate(arg, fd, checksig, isServer); upslogx(LOG_INFO, "Intend to authenticate server %s : %s", ups?ups->host:"", status==SECSuccess?"SUCCESS":"FAILED"); if (status != SECSuccess) { nss_error("SSL_AuthCertificate"); } return status; } static SECStatus AuthCertificateDontVerify(CERTCertDBHandle *arg, PRFileDesc *fd, PRBool checksig, PRBool isServer) { UPSCONN_t *ups = (UPSCONN_t *)SSL_RevealPinArg(fd); NUT_UNUSED_VARIABLE(arg); NUT_UNUSED_VARIABLE(checksig); NUT_UNUSED_VARIABLE(isServer); upslogx(LOG_INFO, "Do not intend to authenticate server %s", ups?ups->host:""); return SECSuccess; } static SECStatus BadCertHandler(UPSCONN_t *arg, PRFileDesc *fd) { HOST_CERT_t* cert; NUT_UNUSED_VARIABLE(fd); upslogx(LOG_WARNING, "Certificate validation failed for %s", (arg&&arg->host)?arg->host:""); /* BadCertHandler is called when the NSS certificate validation is failed. * If the certificate verification (user conf) is mandatory, reject authentication * else accept it. */ cert = upscli_find_host_cert(arg->host); if (cert != NULL) { return cert->certverify==0 ? SECSuccess : SECFailure; } else { return verify_certificate==0 ? SECSuccess : SECFailure; } } static SECStatus GetClientAuthData(UPSCONN_t *arg, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey) { CERTCertificate *cert; SECKEYPrivateKey *privKey; SECStatus status = NSS_GetClientAuthData(arg, fd, caNames, pRetCert, pRetKey); if (status == SECFailure) { if (nsscertname != NULL) { cert = PK11_FindCertFromNickname(nsscertname, NULL); if(cert==NULL) { upslogx(LOG_ERR, "Can not find self-certificate"); nss_error("GetClientAuthData / PK11_FindCertFromNickname"); }else{ privKey = PK11_FindKeyByAnyCert(cert, NULL); if(privKey==NULL){ upslogx(LOG_ERR, "Can not find private key related to self-certificate"); nss_error("GetClientAuthData / PK11_FindKeyByAnyCert"); }else{ *pRetCert = cert; *pRetKey = privKey; status = SECSuccess; } } } else { upslogx(LOG_ERR, "Self-certificate name not configured"); } } return status; } static void HandshakeCallback(PRFileDesc *fd, UPSCONN_t *client_data) { NUT_UNUSED_VARIABLE(fd); upslogx(LOG_INFO, "SSL handshake done successfully with server %s", client_data->host); } #endif /* WITH_OPENSSL | WITH_NSS */ int upscli_init(int certverify, const char *certpath, const char *certname, const char *certpasswd) { const char *quiet_init_ssl; #ifdef WITH_OPENSSL long ret; int ssl_mode = SSL_VERIFY_NONE; NUT_UNUSED_VARIABLE(certname); NUT_UNUSED_VARIABLE(certpasswd); #elif defined(WITH_NSS) /* WITH_OPENSSL */ SECStatus status; #else NUT_UNUSED_VARIABLE(certverify); NUT_UNUSED_VARIABLE(certpath); NUT_UNUSED_VARIABLE(certname); NUT_UNUSED_VARIABLE(certpasswd); #endif /* WITH_OPENSSL | WITH_NSS */ if (upscli_initialized == 1) { upslogx(LOG_WARNING, "upscli already initialized"); return -1; } if (upscli_default_connect_timeout_initialized == 0) { /* There may be an envvar waiting to be parsed */ upsdebugx(1, "%s: upscli_default_connect_timeout was not initialized, checking now", __func__); upscli_init_default_connect_timeout(NULL, NULL, NULL); } quiet_init_ssl = getenv("NUT_QUIET_INIT_SSL"); if (quiet_init_ssl != NULL) { if (*quiet_init_ssl == '\0' || (strncmp(quiet_init_ssl, "true", 4) && strncmp(quiet_init_ssl, "TRUE", 4) && strncmp(quiet_init_ssl, "1", 1) ) ) { upsdebugx(1, "NUT_QUIET_INIT_SSL='%s' value was not recognized, ignored", quiet_init_ssl); quiet_init_ssl = NULL; } } #ifdef WITH_OPENSSL #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_load_error_strings(); SSL_library_init(); ssl_ctx = SSL_CTX_new(SSLv23_client_method()); #else ssl_ctx = SSL_CTX_new(TLS_client_method()); #endif if (!ssl_ctx) { upslogx(LOG_ERR, "Can not initialize SSL context"); return -1; } #if OPENSSL_VERSION_NUMBER < 0x10100000L /* set minimum protocol TLSv1 */ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #else ret = SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION); if (ret != 1) { upslogx(LOG_ERR, "Can not set minimum protocol to TLSv1"); return -1; } #endif if (!certpath) { if (certverify == 1) { upslogx(LOG_ERR, "Can not verify certificate if any is specified"); return -1; /* Failed : cert is mandatory but no certfile */ } } else { switch(certverify) { case 0: ssl_mode = SSL_VERIFY_NONE; break; default: ssl_mode = SSL_VERIFY_PEER; break; } ret = SSL_CTX_load_verify_locations(ssl_ctx, NULL, certpath); if (ret != 1) { upslogx(LOG_ERR, "Failed to load certificate from pemfile %s", certpath); return -1; } SSL_CTX_set_verify(ssl_ctx, ssl_mode, NULL); } #elif defined(WITH_NSS) /* WITH_OPENSSL */ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); PK11_SetPasswordFunc(nss_password_callback); if (certpath) { if (quiet_init_ssl != NULL) { upsdebugx(1, "Init SSL with certificate database located at %s", certpath); } else { upslogx(LOG_INFO, "Init SSL with certificate database located at %s", certpath); } status = NSS_Init(certpath); } else { if (quiet_init_ssl != NULL) { upsdebugx(1, "Init SSL without certificate database"); } else { upslogx(LOG_NOTICE, "Init SSL without certificate database"); } status = NSS_NoDB_Init(NULL); } if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL context"); nss_error("upscli_init / NSS_[NoDB]_Init"); return -1; } status = NSS_SetDomesticPolicy(); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not initialize SSL policy"); nss_error("upscli_init / NSS_SetDomesticPolicy"); return -1; } SSL_ClearSessionCache(); status = SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not enable SSLv3"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_SSL3)"); return -1; } status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not enable TLSv1"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_ENABLE_TLS)"); return -1; } status = SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE); if (status != SECSuccess) { upslogx(LOG_ERR, "Can not disable SSLv2 hello compatibility"); nss_error("upscli_init / SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO)"); return -1; } if (certname) { nsscertname = xstrdup(certname); } if (certpasswd) { nsscertpasswd = xstrdup(certpasswd); } verify_certificate = certverify; #else /* Note: historically we do not return with error here, * just fall through to below and treat as initialized. */ upslogx(LOG_ERR, "upscli_init called but SSL wasn't compiled in"); #endif /* WITH_OPENSSL | WITH_NSS */ upscli_initialized = 1; return 1; } void upscli_add_host_cert(const char* hostname, const char* certname, int certverify, int forcessl) { #ifdef WITH_NSS HOST_CERT_t* cert = xmalloc(sizeof(HOST_CERT_t)); cert->next = first_host_cert; cert->host = xstrdup(hostname); cert->certname = xstrdup(certname); cert->certverify = certverify; cert->forcessl = forcessl; first_host_cert = cert; #else NUT_UNUSED_VARIABLE(hostname); NUT_UNUSED_VARIABLE(certname); NUT_UNUSED_VARIABLE(certverify); NUT_UNUSED_VARIABLE(forcessl); #endif /* WITH_NSS */ } static HOST_CERT_t* upscli_find_host_cert(const char* hostname) { #ifdef WITH_NSS HOST_CERT_t* cert = first_host_cert; if (hostname != NULL) { while (cert != NULL) { if (cert->host != NULL && strcmp(cert->host, hostname)==0 ) { return cert; } cert = cert->next; } } #else NUT_UNUSED_VARIABLE(hostname); #endif /* WITH_NSS */ return NULL; } int upscli_cleanup(void) { #ifdef WITH_OPENSSL if (ssl_ctx) { SSL_CTX_free(ssl_ctx); ssl_ctx = NULL; } #endif /* WITH_OPENSSL */ #ifdef WITH_NSS /* Called to force cache clearing to prevent NSS shutdown failures. * http://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslfnc.html#1138601 */ SSL_ClearSessionCache(); NSS_Shutdown(); PR_Cleanup(); /* Called to release memory arena used by NSS/NSPR. * Prevent to show all PL_ArenaAllocate mem alloc as leaks. * https://developer.mozilla.org/en/NSS_Memory_allocation */ PL_ArenaFinish(); #endif /* WITH_NSS */ upscli_initialized = 0; return 1; } const char *upscli_strerror(UPSCONN_t *ups) { #ifdef WITH_OPENSSL unsigned long err; char sslbuf[UPSCLI_ERRBUF_LEN]; #endif #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif if (!ups) { return upscli_errlist[UPSCLI_ERR_INVALIDARG].str; } if (ups->upsclient_magic != UPSCLIENT_MAGIC) { return upscli_errlist[UPSCLI_ERR_INVALIDARG].str; } if (ups->upserror > UPSCLI_ERR_MAX) { return "Invalid error number"; } switch (upscli_errlist[ups->upserror].flags) { case 0: /* simple error */ return upscli_errlist[ups->upserror].str; case 1: /* add message from system's strerror */ snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, upscli_errlist[ups->upserror].str, strerror(ups->syserrno)); return ups->errbuf; case 2: /* SSL error */ #ifdef WITH_OPENSSL err = ERR_get_error(); if (err) { ERR_error_string(err, sslbuf); snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, upscli_errlist[ups->upserror].str, sslbuf); } else { snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, upscli_errlist[ups->upserror].str, "peer disconnected"); } #elif defined(WITH_NSS) /* WITH_OPENSSL */ if (PR_GetErrorTextLength() < UPSCLI_ERRBUF_LEN) { PR_GetErrorText(ups->errbuf); } else { snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, "SSL error #%ld, message too long to be displayed", (long)PR_GetError()); } #else snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, "SSL error, but SSL wasn't enabled at compile-time"); #endif /* WITH_OPENSSL | WITH_NSS */ return ups->errbuf; case 3: /* parsing (parseconf) error */ snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, upscli_errlist[ups->upserror].str, ups->pc_ctx.errmsg); return ups->errbuf; default: break; } #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif /* fallthrough */ snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, "Unknown error flag %d", upscli_errlist[ups->upserror].flags); return ups->errbuf; } /* Read up to buflen bytes from fd and return the number of bytes read. If no data is available within d_sec + d_usec, return 0. On error, a value < 0 is returned (errno indicates error). */ static ssize_t upscli_select_read(const int fd, void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec) { ssize_t ret; fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = d_sec; tv.tv_usec = d_usec; ret = select(fd + 1, &fds, NULL, NULL, &tv); if (ret < 1) { return ret; } return read(fd, buf, buflen); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* internal: abstract the SSL calls for the other functions */ static ssize_t net_read(UPSCONN_t *ups, char *buf, size_t buflen, const time_t timeout) { ssize_t ret = -1; #ifdef WITH_SSL if (ups->ssl) { #ifdef WITH_OPENSSL /* SSL_* routines deal with int type for return and buflen * We might need to window our I/O if we exceed 2GB (in * 32-bit builds)... Not likely to exceed in 64-bit builds, * but smaller systems with 16-bits might be endangered :) */ int iret; assert(buflen <= INT_MAX); iret = SSL_read(ups->ssl, buf, (int)buflen); assert(iret <= SSIZE_MAX); ret = (ssize_t)iret; #elif defined(WITH_NSS) /* WITH_OPENSSL */ /* PR_* routines deal in PRInt32 type * We might need to window our I/O if we exceed 2GB :) */ assert(buflen <= PR_INT32_MAX); ret = PR_Read(ups->ssl, buf, (PRInt32)buflen); #endif /* WITH_OPENSSL | WITH_NSS*/ if (ret < 1) { ups->upserror = UPSCLI_ERR_SSLERR; } return ret; } #endif ret = upscli_select_read(ups->fd, buf, buflen, timeout, 0); /* error reading data, server disconnected? */ if (ret < 0) { ups->upserror = UPSCLI_ERR_READ; ups->syserrno = errno; } /* no data available, server disconnected? */ if (ret == 0) { ups->upserror = UPSCLI_ERR_SRVDISC; } return ret; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif /* Write up to buflen bytes to fd and return the number of bytes written. If no data is available within d_sec + d_usec, return 0. On error, a value < 0 is returned (errno indicates error). */ static ssize_t upscli_select_write(const int fd, const void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec) { ssize_t ret; fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = d_sec; tv.tv_usec = d_usec; ret = select(fd + 1, NULL, &fds, NULL, &tv); if (ret < 1) { return ret; } return write(fd, buf, buflen); } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC # pragma GCC diagnostic ignored "-Wtype-limits" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC # pragma GCC diagnostic ignored "-Wtautological-constant-out-of-range-compare" #endif /* internal: abstract the SSL calls for the other functions */ static ssize_t net_write(UPSCONN_t *ups, const char *buf, size_t buflen, const time_t timeout) { ssize_t ret = -1; #ifdef WITH_SSL if (ups->ssl) { #ifdef WITH_OPENSSL /* SSL_* routines deal with int type for return and buflen * We might need to window our I/O if we exceed 2GB (in * 32-bit builds)... Not likely to exceed in 64-bit builds, * but smaller systems with 16-bits might be endangered :) */ int iret; assert(buflen <= INT_MAX); iret = SSL_write(ups->ssl, buf, (int)buflen); assert(iret <= SSIZE_MAX); ret = (ssize_t)iret; #elif defined(WITH_NSS) /* WITH_OPENSSL */ /* PR_* routines deal in PRInt32 type * We might need to window our I/O if we exceed 2GB :) */ assert(buflen <= PR_INT32_MAX); ret = PR_Write(ups->ssl, buf, (PRInt32)buflen); #endif /* WITH_OPENSSL | WITH_NSS */ if (ret < 1) { ups->upserror = UPSCLI_ERR_SSLERR; } return ret; } #endif ret = upscli_select_write(ups->fd, buf, buflen, timeout, 0); /* error writing data, server disconnected? */ if (ret < 0) { ups->upserror = UPSCLI_ERR_WRITE; ups->syserrno = errno; } /* not ready for writing, server disconnected? */ if (ret == 0) { ups->upserror = UPSCLI_ERR_SRVDISC; } return ret; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP_BESIDEFUNC) && ( (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TYPE_LIMITS_BESIDEFUNC) || (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_TAUTOLOGICAL_CONSTANT_OUT_OF_RANGE_COMPARE_BESIDEFUNC) ) # pragma GCC diagnostic pop #endif #ifdef WITH_SSL /* * 1 : OK * -1 : ERROR * 0 : SSL NOT SUPPORTED */ static int upscli_sslinit(UPSCONN_t *ups, int verifycert) { #ifdef WITH_OPENSSL int res; #elif defined(WITH_NSS) /* WITH_OPENSSL */ SECStatus status; PRFileDesc *socket; HOST_CERT_t *cert; #endif /* WITH_OPENSSL | WITH_NSS */ char buf[UPSCLI_NETBUF_LEN]; /* Intend to initialize upscli with no ssl db if not already done. * Compatibility stuff for old clients which do not initialize them. */ if (upscli_initialized==0) { upsdebugx(3, "upscli not initialized, " "force initialisation without SSL configuration"); upscli_init(0, NULL, NULL, NULL); } /* see if upsd even talks SSL/TLS */ snprintf(buf, sizeof(buf), "STARTTLS\n"); if (upscli_sendline(ups, buf, strlen(buf)) != 0) { return -1; } if (upscli_readline(ups, buf, sizeof(buf)) != 0) { return -1; } if (strncmp(buf, "OK STARTTLS", 11) != 0) { return 0; /* not supported */ } /* upsd is happy, so let's crank up the client */ #ifdef WITH_OPENSSL if (!ssl_ctx) { upsdebugx(3, "SSL context is not available"); return 0; } ups->ssl = SSL_new(ssl_ctx); if (!ups->ssl) { upsdebugx(3, "Can not create SSL socket"); return 0; } if (SSL_set_fd(ups->ssl, ups->fd) != 1) { upsdebugx(3, "Can not bind file descriptor to SSL socket"); return -1; } if (verifycert != 0) { SSL_set_verify(ups->ssl, SSL_VERIFY_PEER, NULL); } else { SSL_set_verify(ups->ssl, SSL_VERIFY_NONE, NULL); } res = SSL_connect(ups->ssl); switch(res) { case 1: upsdebugx(3, "SSL connected (%s)", SSL_get_version(ups->ssl)); break; case 0: upslog_with_errno(1, "SSL_connect do not accept handshake."); ssl_error(ups->ssl, res); return -1; default: upslog_with_errno(1, "Unknown return value from SSL_connect %d", res); ssl_error(ups->ssl, res); return -1; } return 1; #elif defined(WITH_NSS) /* WITH_OPENSSL */ socket = PR_ImportTCPSocket(ups->fd); if (socket == NULL){ nss_error("upscli_sslinit / PR_ImportTCPSocket"); return -1; } ups->ssl = SSL_ImportFD(NULL, socket); if (ups->ssl == NULL){ nss_error("upscli_sslinit / SSL_ImportFD"); return -1; } if (SSL_SetPKCS11PinArg(ups->ssl, ups) == -1){ nss_error("upscli_sslinit / SSL_SetPKCS11PinArg"); return -1; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type-strict" #endif if (verifycert) { status = SSL_AuthCertificateHook(ups->ssl, (SSLAuthCertificate)AuthCertificate, CERT_GetDefaultCertDB()); } else { status = SSL_AuthCertificateHook(ups->ssl, (SSLAuthCertificate)AuthCertificateDontVerify, CERT_GetDefaultCertDB()); } if (status != SECSuccess) { nss_error("upscli_sslinit / SSL_AuthCertificateHook"); return -1; } status = SSL_BadCertHook(ups->ssl, (SSLBadCertHandler)BadCertHandler, ups); if (status != SECSuccess) { nss_error("upscli_sslinit / SSL_BadCertHook"); return -1; } status = SSL_GetClientAuthDataHook(ups->ssl, (SSLGetClientAuthData)GetClientAuthData, ups); if (status != SECSuccess) { nss_error("upscli_sslinit / SSL_GetClientAuthDataHook"); return -1; } status = SSL_HandshakeCallback(ups->ssl, (SSLHandshakeCallback)HandshakeCallback, ups); if (status != SECSuccess) { nss_error("upscli_sslinit / SSL_HandshakeCallback"); return -1; } #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CAST_FUNCTION_TYPE_STRICT) #pragma GCC diagnostic pop #endif cert = upscli_find_host_cert(ups->host); if (cert != NULL && cert->certname != NULL) { upslogx(LOG_INFO, "Connecting in SSL to '%s' and look at certificate called '%s'", ups->host, cert->certname); status = SSL_SetURL(ups->ssl, cert->certname); } else { upslogx(LOG_NOTICE, "Connecting in SSL to '%s' (no certificate name specified)", ups->host); status = SSL_SetURL(ups->ssl, ups->host); } if (status != SECSuccess) { nss_error("upscli_sslinit / SSL_SetURL"); return -1; } status = SSL_ResetHandshake(ups->ssl, PR_FALSE); if (status != SECSuccess) { nss_error("upscli_sslinit / SSL_ResetHandshake"); ups->ssl = NULL; /* EKI wtf unimport or free the socket ? */ return -1; } status = SSL_ForceHandshake(ups->ssl); if (status != SECSuccess) { nss_error("upscli_sslinit / SSL_ForceHandshake"); ups->ssl = NULL; /* EKI wtf unimport or free the socket ? */ /* TODO : Close the connection. */ return -1; } return 1; #endif /* WITH_OPENSSL | WITH_NSS */ } #else /* WITH_SSL */ static int upscli_sslinit(UPSCONN_t *ups, int verifycert) { NUT_UNUSED_VARIABLE(ups); NUT_UNUSED_VARIABLE(verifycert); return 0; /* not supported */ } #endif /* WITH_SSL */ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags, struct timeval * timeout) { int sock_fd; struct addrinfo hints, *res, *ai; char sport[NI_MAXSERV]; int v, certverify, tryssl, forcessl, ret; HOST_CERT_t* hostcert; fd_set wfds; int error; socklen_t error_size; #ifndef WIN32 long fd_flags; #else /* WIN32 */ HANDLE event = NULL; unsigned long argp; WSADATA WSAdata; WSAStartup(2,&WSAdata); #endif /* WIN32 */ if (!ups) { return -1; } /* clear out any lingering junk */ memset(ups, 0, sizeof(*ups)); ups->upsclient_magic = UPSCLIENT_MAGIC; ups->fd = -1; if (!host) { upslogx(LOG_WARNING, "%s: Host not specified", __func__); ups->upserror = UPSCLI_ERR_NOSUCHHOST; return -1; } snprintf(sport, sizeof(sport), "%" PRIuMAX, (uintmax_t)port); memset(&hints, 0, sizeof(hints)); if (flags & UPSCLI_CONN_INET6) { hints.ai_family = AF_INET6; } else if (flags & UPSCLI_CONN_INET) { hints.ai_family = AF_INET; } else { hints.ai_family = AF_UNSPEC; } hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; while ((v = getaddrinfo(host, sport, &hints, &res)) != 0) { switch (v) { case EAI_AGAIN: continue; case EAI_NONAME: upslogx(LOG_WARNING, "%s: Host not found: '%s'", __func__, NUT_STRARG(host)); ups->upserror = UPSCLI_ERR_NOSUCHHOST; return -1; case EAI_MEMORY: upslogx(LOG_WARNING, "%s: Insufficient memory", __func__); ups->upserror = UPSCLI_ERR_NOMEM; return -1; case EAI_SYSTEM: ups->syserrno = errno; break; default: break; } upslog_with_errno(LOG_WARNING, "%s: Unknown error happened during getaddrinfo()", __func__); ups->upserror = UPSCLI_ERR_UNKNOWN; return -1; } for (ai = res; ai != NULL; ai = ai->ai_next) { sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock_fd < 0) { switch (errno) { case EAFNOSUPPORT: case EINVAL: break; default: ups->upserror = UPSCLI_ERR_SOCKFAILURE; ups->syserrno = errno; } continue; } /* non blocking connect */ if(timeout != NULL) { #ifndef WIN32 fd_flags = fcntl(sock_fd, F_GETFL); fd_flags |= O_NONBLOCK; fcntl(sock_fd, F_SETFL, fd_flags); #else /* WIN32 */ event = CreateEvent(NULL, /* Security */ FALSE, /* auto-reset */ FALSE, /* initial state */ NULL); /* no name */ /* Associate socket event to the socket via its Event object */ WSAEventSelect( sock_fd, event, FD_CONNECT ); CloseHandle(event); #endif /* WIN32 */ } while ((v = connect(sock_fd, ai->ai_addr, ai->ai_addrlen)) < 0) { #ifndef WIN32 if(errno == EINPROGRESS || SOLARIS_i386_NBCONNECT_ENOENT(errno) || AIX_NBCONNECT_0(errno)) { #else /* WIN32 */ if(errno == WSAEWOULDBLOCK) { #endif /* WIN32 */ FD_ZERO(&wfds); FD_SET(sock_fd, &wfds); select(sock_fd+1,NULL,&wfds,NULL, timeout); if (FD_ISSET(sock_fd, &wfds)) { error_size = sizeof(error); getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, SOCK_OPT_CAST &error, &error_size); if( error == 0) { /* connect successful */ v = 0; break; } errno = error; } else { /* Timeout */ v = -1; ups->upserror = UPSCLI_ERR_CONNFAILURE; ups->syserrno = ETIMEDOUT; break; } } switch (errno) { case EAFNOSUPPORT: break; case EINTR: case EAGAIN: continue; default: ups->upserror = UPSCLI_ERR_CONNFAILURE; ups->syserrno = errno; } break; } if (v < 0) { close(sock_fd); /* if timeout, break out so client can continue */ /* match Linux behavior that updates timeout struct */ if (timeout != NULL && ups->upserror == UPSCLI_ERR_CONNFAILURE && ups->syserrno == ETIMEDOUT ) { /* https://stackoverflow.com/a/29147085/4715872 * obviously INET6_ADDRSTRLEN is expected to be larger * than INET_ADDRSTRLEN, but this may be required in case * if for some unexpected reason IPv6 is not supported, and * INET6_ADDRSTRLEN is defined as 0 * but this is not very likely and I am aware of no cases of * this in practice (editor) */ char addrstr[(INET6_ADDRSTRLEN > INET_ADDRSTRLEN ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN) + 1]; addrstr[0] = '\0'; switch (ai->ai_family) { case AF_INET: { struct sockaddr_in addr_in; memcpy(&addr_in, ai->ai_addr, sizeof(addr_in)); inet_ntop(AF_INET, &(addr_in.sin_addr), addrstr, INET_ADDRSTRLEN); break; } case AF_INET6: { struct sockaddr_in6 addr_in6; memcpy(&addr_in6, ai->ai_addr, sizeof(addr_in6)); inet_ntop(AF_INET6, &(addr_in6.sin6_addr), addrstr, INET6_ADDRSTRLEN); break; } default: break; } upslogx(LOG_WARNING, "%s: Connection to host timed out: '%s'", __func__, *addrstr ? addrstr : NUT_STRARG(host)); break; } continue; } /* switch back to blocking operation */ if (timeout != NULL) { #ifndef WIN32 fd_flags = fcntl(sock_fd, F_GETFL); fd_flags &= ~O_NONBLOCK; fcntl(sock_fd, F_SETFL, fd_flags); #else /* WIN32 */ argp = 0; ioctlsocket(sock_fd, FIONBIO, &argp); #endif /* WIN32 */ } ups->fd = sock_fd; ups->upserror = 0; ups->syserrno = 0; break; } freeaddrinfo(res); if (ups->fd < 0) { return -1; } pconf_init(&ups->pc_ctx, NULL); ups->host = xstrdup(host); if (!ups->host) { ups->upserror = UPSCLI_ERR_NOMEM; upscli_disconnect(ups); return -1; } ups->port = port; hostcert = upscli_find_host_cert(host); if (hostcert != NULL) { /* An host security rule is specified. */ certverify = hostcert->certverify; forcessl = hostcert->forcessl; } else { certverify = (flags & UPSCLI_CONN_CERTVERIF) != 0 ? 1 : 0; forcessl = (flags & UPSCLI_CONN_REQSSL) != 0 ? 1 : 0; } tryssl = (flags & UPSCLI_CONN_TRYSSL) != 0 ? 1 : 0; if (tryssl || forcessl) { ret = upscli_sslinit(ups, certverify); if (forcessl && ret != 1) { upslogx(LOG_ERR, "Can not connect to NUT server %s in SSL, disconnect", host); ups->upserror = UPSCLI_ERR_SSLFAIL; upscli_disconnect(ups); return -1; } else if (tryssl && ret == -1) { upslogx(LOG_NOTICE, "Error while connecting to NUT server %s, disconnect", host); upscli_disconnect(ups); return -1; } else if (tryssl && ret == 0) { if (certverify != 0) { upslogx(LOG_NOTICE, "Can not connect to NUT server %s in SSL and " "certificate is needed, disconnect", host); upscli_disconnect(ups); return -1; } upsdebugx(3, "Can not connect to NUT server %s in SSL, continue unencrypted", host); } else { upslogx(LOG_INFO, "Connected to NUT server %s in SSL", host); if (certverify == 0) { /* you REALLY should set CERTVERIFY to 1 if using SSL... */ upslogx(LOG_WARNING, "Certificate verification is disabled"); } } } return 0; } int upscli_connect(UPSCONN_t *ups, const char *host, uint16_t port, int flags) { struct timeval tv = {0, 0}, *ptv = NULL; if (upscli_default_connect_timeout_initialized == 0) { /* There may be an envvar waiting to be parsed */ upscli_init_default_connect_timeout(NULL, NULL, NULL); /* Failed or not (bad envvar), avoid looping messages * about bad value parsing for every upscli_connect() */ upscli_default_connect_timeout_initialized = 1; } tv = upscli_default_connect_timeout; if (tv.tv_sec != 0 || tv.tv_usec != 0) { /* By default, ptv==NULL for a blocking upscli_tryconnect() */ ptv = &tv; } return upscli_tryconnect(ups, host, port, flags, ptv); } /* map upsd error strings back to upsclient internal numbers */ static struct { int errnum; const char *text; } upsd_errlist[] = { { UPSCLI_ERR_VARNOTSUPP, "VAR-NOT-SUPPORTED" }, { UPSCLI_ERR_UNKNOWNUPS, "UNKNOWN-UPS" }, { UPSCLI_ERR_ACCESSDENIED, "ACCESS-DENIED" }, { UPSCLI_ERR_PWDREQUIRED, "PASSWORD-REQUIRED" }, { UPSCLI_ERR_PWDINCORRECT, "PASSWORD-INCORRECT" }, { UPSCLI_ERR_MISSINGARG, "MISSING-ARGUMENT" }, { UPSCLI_ERR_DATASTALE, "DATA-STALE" }, { UPSCLI_ERR_VARUNKNOWN, "VAR-UNKNOWN" }, { UPSCLI_ERR_LOGINTWICE, "ALREADY-LOGGED-IN" }, { UPSCLI_ERR_PWDSETTWICE, "ALREADY-SET-PASSWORD" }, { UPSCLI_ERR_UNKNOWNTYPE, "UNKNOWN-TYPE" }, { UPSCLI_ERR_UNKNOWNVAR, "UNKNOWN-VAR" }, { UPSCLI_ERR_VARREADONLY, "READONLY" }, { UPSCLI_ERR_TOOLONG, "TOO-LONG" }, { UPSCLI_ERR_INVALIDVALUE, "INVALID-VALUE" }, { UPSCLI_ERR_SETFAILED, "SET-FAILED" }, { UPSCLI_ERR_UNKINSTCMD, "UNKNOWN-INSTCMD" }, { UPSCLI_ERR_CMDFAILED, "INSTCMD-FAILED" }, { UPSCLI_ERR_CMDNOTSUPP, "CMD-NOT-SUPPORTED" }, { UPSCLI_ERR_INVUSERNAME, "INVALID-USERNAME" }, { UPSCLI_ERR_USERSETTWICE, "ALREADY-SET-USERNAME" }, { UPSCLI_ERR_UNKCOMMAND, "UNKNOWN-COMMAND" }, { UPSCLI_ERR_INVPASSWORD, "INVALID-PASSWORD" }, { UPSCLI_ERR_USERREQUIRED, "USERNAME-REQUIRED" }, { UPSCLI_ERR_DRVNOTCONN, "DRIVER-NOT-CONNECTED" }, { 0, NULL, } }; static int upscli_errcheck(UPSCONN_t *ups, char *buf) { int i; if (!ups) { return -1; } if (!buf) { ups->upserror = UPSCLI_ERR_INVALIDARG; return -1; } /* see if it's even an error now */ if (strncmp(buf, "ERR", 3) != 0) { return 0; } /* look it up in the table */ for (i = 0; upsd_errlist[i].text != NULL; i++) { if (!strncmp(&buf[4], upsd_errlist[i].text, strlen(upsd_errlist[i].text))) { ups->upserror = upsd_errlist[i].errnum; return -1; } } /* hmm - don't know what upsd is telling us */ ups->upserror = UPSCLI_ERR_UNKNOWN; return -1; } static void build_cmd(char *buf, size_t bufsize, const char *cmdname, size_t numarg, const char **arg) { size_t i; size_t len; char enc[UPSCLI_NETBUF_LEN]; const char *format; memset(buf, '\0', bufsize); snprintf(buf, bufsize, "%s", cmdname); /* encode all arguments so they arrive intact */ for (i = 0; i < numarg; i++) { if (strchr(arg[i], ' ')) { format = " \"%s\""; /* wrap in "" */ } else { format = " %s"; } /* snprintfcat would tie us to common */ len = strlen(buf); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif snprintf(buf + len, bufsize - len, format, pconf_encode(arg[i], enc, sizeof(enc))); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif } len = strlen(buf); snprintf(buf + len, bufsize - len, "\n"); } /* make sure upsd is giving us what we asked for */ static int verify_resp(size_t num, const char **q, char **a) { size_t i; for (i = 0; i < num; i++) { if (strcasecmp(q[i], a[i]) != 0) { /* FUTURE: handle -/+ options here */ return 0; /* mismatch */ } } return 1; /* OK */ } int upscli_get(UPSCONN_t *ups, size_t numq, const char **query, size_t *numa, char ***answer) { char cmd[UPSCLI_NETBUF_LEN], tmp[UPSCLI_NETBUF_LEN]; if (!ups) { return -1; } if (numq < 1) { ups->upserror = UPSCLI_ERR_INVALIDARG; return -1; } /* create the string to send to upsd */ build_cmd(cmd, sizeof(cmd), "GET", numq, query); if (upscli_sendline(ups, cmd, strlen(cmd)) != 0) { return -1; } if (upscli_readline(ups, tmp, sizeof(tmp)) != 0) { return -1; } if (upscli_errcheck(ups, tmp) != 0) { return -1; } if (!pconf_line(&ups->pc_ctx, tmp)) { ups->upserror = UPSCLI_ERR_PARSE; return -1; } /* q: [GET] VAR * * a: VAR */ if (ups->pc_ctx.numargs < numq) { ups->upserror = UPSCLI_ERR_PROTOCOL; return -1; } if (!verify_resp(numq, query, ups->pc_ctx.arglist)) { ups->upserror = UPSCLI_ERR_PROTOCOL; return -1; } *numa = ups->pc_ctx.numargs; *answer = ups->pc_ctx.arglist; return 0; } int upscli_list_start(UPSCONN_t *ups, size_t numq, const char **query) { char cmd[UPSCLI_NETBUF_LEN], tmp[UPSCLI_NETBUF_LEN]; if (!ups) { return -1; } if (numq < 1) { ups->upserror = UPSCLI_ERR_INVALIDARG; return -1; } /* create the string to send to upsd */ build_cmd(cmd, sizeof(cmd), "LIST", numq, query); if (upscli_sendline(ups, cmd, strlen(cmd)) != 0) { return -1; } if (upscli_readline(ups, tmp, sizeof(tmp)) != 0) { return -1; } if (upscli_errcheck(ups, tmp) != 0) { return -1; } if (!pconf_line(&ups->pc_ctx, tmp)) { ups->upserror = UPSCLI_ERR_PARSE; return -1; } if (ups->pc_ctx.numargs < 2) { ups->upserror = UPSCLI_ERR_PROTOCOL; return -1; } /* the response must start with BEGIN LIST */ if ((strcasecmp(ups->pc_ctx.arglist[0], "BEGIN") != 0) || (strcasecmp(ups->pc_ctx.arglist[1], "LIST") != 0)) { ups->upserror = UPSCLI_ERR_PROTOCOL; return -1; } /* q: [LIST] VAR * * a: [BEGIN LIST] VAR */ /* compare q[0]... to a[2]... */ if (!verify_resp(numq, query, &ups->pc_ctx.arglist[2])) { ups->upserror = UPSCLI_ERR_PROTOCOL; return -1; } return 0; } int upscli_list_next(UPSCONN_t *ups, size_t numq, const char **query, size_t *numa, char ***answer) { char tmp[UPSCLI_NETBUF_LEN]; if (!ups) { return -1; } if (upscli_readline(ups, tmp, sizeof(tmp)) != 0) { return -1; } if (upscli_errcheck(ups, tmp) != 0) { return -1; } if (!pconf_line(&ups->pc_ctx, tmp)) { ups->upserror = UPSCLI_ERR_PARSE; return -1; } if (ups->pc_ctx.numargs < 1) { ups->upserror = UPSCLI_ERR_PROTOCOL; return -1; } *numa = ups->pc_ctx.numargs; *answer = ups->pc_ctx.arglist; /* see if this is the end */ if (ups->pc_ctx.numargs >= 2) { if ((!strcmp(ups->pc_ctx.arglist[0], "END")) && (!strcmp(ups->pc_ctx.arglist[1], "LIST"))) return 0; } /* q: VAR */ /* a: VAR */ if (!verify_resp(numq, query, ups->pc_ctx.arglist)) { ups->upserror = UPSCLI_ERR_PROTOCOL; return -1; } /* just another part of the list */ return 1; } ssize_t upscli_sendline_timeout(UPSCONN_t *ups, const char *buf, size_t buflen, const time_t timeout) { ssize_t ret; if (!ups) { return -1; } if (ups->fd < 0) { ups->upserror = UPSCLI_ERR_DRVNOTCONN; return -1; } if ((!buf) || (buflen < 1)) { ups->upserror = UPSCLI_ERR_INVALIDARG; return -1; } if (ups->upsclient_magic != UPSCLIENT_MAGIC) { ups->upserror = UPSCLI_ERR_INVALIDARG; return -1; } ret = net_write(ups, buf, buflen, timeout); if (ret < 1) { upscli_disconnect(ups); return -1; } return 0; } ssize_t upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen) { return upscli_sendline_timeout(ups, buf, buflen, 0); } ssize_t upscli_readline_timeout(UPSCONN_t *ups, char *buf, size_t buflen, const time_t timeout) { ssize_t ret; size_t recv; if (!ups) { return -1; } if (ups->fd < 0) { ups->upserror = UPSCLI_ERR_DRVNOTCONN; return -1; } if ((!buf) || (buflen < 1)) { ups->upserror = UPSCLI_ERR_INVALIDARG; return -1; } if (ups->upsclient_magic != UPSCLIENT_MAGIC) { ups->upserror = UPSCLI_ERR_INVALIDARG; return -1; } for (recv = 0; recv < (buflen-1); recv++) { if (ups->readidx == ups->readlen) { ret = net_read(ups, ups->readbuf, sizeof(ups->readbuf), timeout); if (ret < 1) { upscli_disconnect(ups); return -1; } /* Here ret is safe to cast since it is >=1 and certainly * fits under SIZE_MAX being it signed sibling */ ups->readlen = (size_t)ret; ups->readidx = 0; } buf[recv] = ups->readbuf[ups->readidx++]; if (buf[recv] == '\n') { break; } } buf[recv] = '\0'; return 0; } ssize_t upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen) { return upscli_readline_timeout(ups, buf, buflen, DEFAULT_NETWORK_TIMEOUT); } /* split upsname[@hostname[:port]] into separate components */ int upscli_splitname(const char *buf, char **upsname, char **hostname, uint16_t *port) { char *sat, *ssc, tmp[SMALLBUF], *last = NULL; /* paranoia */ if ((!buf) || (!upsname) || (!hostname) || (!port)) { return -1; } if (snprintf(tmp, sizeof(tmp), "%s", buf) < 1) { fprintf(stderr, "upscli_splitname: can't parse empty string\n"); return -1; } sat = strchr(tmp, '@'); ssc = strchr(tmp, ':'); /* someone passed a "@hostname" string? */ if (sat == tmp) { fprintf(stderr, "upscli_splitname: got empty upsname string\n"); return -1; } if ((*upsname = xstrdup(strtok_r(tmp, "@", &last))) == NULL) { fprintf(stderr, "upscli_splitname: xstrdup failed\n"); return -1; } /* someone passed a "@hostname" string (take two)? */ if (!**upsname) { fprintf(stderr, "upscli_splitname: got empty upsname string\n"); return -1; } /* fprintf(stderr, "upscli_splitname3: got buf='%s', tmp='%s', upsname='%s', possible hostname:port='%s'\n", NUT_STRARG(buf), NUT_STRARG(tmp), NUT_STRARG(*upsname), NUT_STRARG((sat ? sat+1 : sat))); */ /* only a upsname is specified, fill in defaults */ if (sat == NULL) { if (ssc) { /* TOTHINK: Consult isdigit(ssc+1) to shortcut * `upsname:port` into `upsname@localhost:port`? */ fprintf(stderr, "upscli_splitname: port specified, but not a hostname\n"); return -1; } if ((*hostname = xstrdup("localhost")) == NULL) { fprintf(stderr, "upscli_splitname: xstrdup failed\n"); return -1; } *port = PORT; return 0; } /* someone passed a "upsname@" string? */ if (!(*(sat+1))) { fprintf(stderr, "upscli_splitname: got the @ separator and then an empty hostname[:port] string\n"); return -1; } return upscli_splitaddr(sat+1, hostname, port); } /* split hostname[:port] into separate components */ int upscli_splitaddr(const char *buf, char **hostname, uint16_t *port) { char *s, tmp[SMALLBUF], *last = NULL; long l; /* paranoia */ if ((!buf) || (!hostname) || (!port)) { return -1; } if (snprintf(tmp, sizeof(tmp), "%s", buf) < 1) { fprintf(stderr, "upscli_splitaddr: can't parse empty string\n"); return -1; } s = strchr(tmp, '@'); /* someone passed a "@hostname" string? */ if (s) { fprintf(stderr, "upscli_splitaddr: wrong call? " "Got upsname@hostname[:port] string where " "only hostname[:port] was expected: %s\n", buf); /* let it pass, but probably fail later */ } if (*tmp == '[') { /* NOTE: Brackets are required for colon-separated IPv6 * addresses, to differentiate from a port number. For * example, `[1234:5678]:3493` would seem right. */ if (strchr(tmp, ']') == NULL) { fprintf(stderr, "upscli_splitaddr: missing closing bracket in [domain literal]\n"); return -1; } if ((*hostname = xstrdup(strtok_r(tmp+1, "]", &last))) == NULL) { fprintf(stderr, "upscli_splitaddr: xstrdup failed\n"); return -1; } /* no port specified, use default */ if (((s = strtok_r(NULL, "\0", &last)) == NULL) || (*s != ':')) { *port = PORT; return 0; } } else { s = strchr(tmp, ':'); if ((*hostname = xstrdup(strtok_r(tmp, ":", &last))) == NULL) { fprintf(stderr, "upscli_splitaddr: xstrdup failed\n"); return -1; } /* no port specified, use default */ if (s == NULL) { *port = PORT; return 0; } } /* Check that "long" port fits in an "uint16_t" so is in IP range * (under 65536) */ if ((*(++s) == '\0') || ((l = strtol(s, NULL, 10)) < 1 ) || (l > 65535)) { fprintf(stderr, "upscli_splitaddr: no port specified after ':' separator\n"); return -1; } *port = (uint16_t)l; return 0; } int upscli_disconnect(UPSCONN_t *ups) { if (!ups) { return -1; } if (ups->upsclient_magic != UPSCLIENT_MAGIC) { return -1; } pconf_finish(&ups->pc_ctx); free(ups->host); ups->host = NULL; if (ups->fd < 0) { return 0; } net_write(ups, "LOGOUT\n", 7, 0); #ifdef WITH_OPENSSL if (ups->ssl) { SSL_shutdown(ups->ssl); SSL_free(ups->ssl); ups->ssl = NULL; } #elif defined(WITH_NSS) /* WITH_OPENSSL */ if (ups->ssl) { PR_Shutdown(ups->ssl, PR_SHUTDOWN_BOTH); PR_Close(ups->ssl); ups->ssl = NULL; } #endif /* WITH_OPENSSL | WITH_NSS */ shutdown(ups->fd, shutdown_how); close(ups->fd); ups->fd = -1; return 0; } int upscli_fd(UPSCONN_t *ups) { if (!ups) { return -1; } if (ups->upsclient_magic != UPSCLIENT_MAGIC) { return -1; } return ups->fd; } int upscli_upserror(UPSCONN_t *ups) { if (!ups) { return -1; } if (ups->upsclient_magic != UPSCLIENT_MAGIC) { return -1; } return ups->upserror; } int upscli_ssl(UPSCONN_t *ups) { if (!ups) { return -1; } if (ups->upsclient_magic != UPSCLIENT_MAGIC) { return -1; } #ifdef WITH_SSL if (ups->ssl) { return 1; } #endif /* WITH_SSL */ return 0; } int upscli_set_default_connect_timeout(const char *secs) { double fsecs; if (secs) { if (str_to_double(secs, &fsecs, 10) < 1) { return -1; } if (d_equal(fsecs, 0.0)) { upscli_default_connect_timeout.tv_sec = 0; upscli_default_connect_timeout.tv_usec = 0; return 0; } if (fsecs < 0.0) { return -1; } upscli_default_connect_timeout.tv_sec = (time_t)fsecs; fsecs *= 1000000; upscli_default_connect_timeout.tv_usec = (suseconds_t)((int)fsecs % 1000000); } else { upscli_default_connect_timeout.tv_sec = 0; upscli_default_connect_timeout.tv_usec = 0; } return 0; } void upscli_get_default_connect_timeout(struct timeval *ptv) { if (ptv) { *ptv = upscli_default_connect_timeout; } } int upscli_init_default_connect_timeout(const char *cli_secs, const char *config_secs, const char *default_secs) { const char *envvar_secs, *cause = "built-in"; int failed = 0, applied = 0; /* First the very default: blocking connections as we always had */ upscli_default_connect_timeout.tv_sec = 0; upscli_default_connect_timeout.tv_usec = 0; /* Then try a program's built-in default, if any */ if (default_secs) { if (upscli_set_default_connect_timeout(default_secs) < 0) { upslogx(LOG_WARNING, "%s: default_secs='%s' value was not recognized, ignored", __func__, default_secs); failed++; } else { cause = "default_secs"; applied++; } } /* Then override with envvar setting, if any (and if its value is valid) */ envvar_secs = getenv("NUT_DEFAULT_CONNECT_TIMEOUT"); if (envvar_secs) { if (upscli_set_default_connect_timeout(envvar_secs) < 0) { upslogx(LOG_WARNING, "%s: NUT_DEFAULT_CONNECT_TIMEOUT='%s' value was not recognized, ignored", __func__, envvar_secs); failed++; } else { cause = "envvar_secs"; applied++; } } /* Then override with config-file setting, if any (and if its value is valid) */ if (config_secs) { if (upscli_set_default_connect_timeout(config_secs) < 0) { upslogx(LOG_WARNING, "%s: config_secs='%s' value was not recognized, ignored", __func__, config_secs); failed++; } else { cause = "config_secs"; applied++; } } /* Then override with command-line setting, if any (and if its value is valid) */ if (cli_secs) { if (upscli_set_default_connect_timeout(cli_secs) < 0) { upslogx(LOG_WARNING, "%s: cli_secs='%s' value was not recognized, ignored", __func__, cli_secs); failed++; } else { cause = "cli_secs"; applied++; } } upsdebugx(1, "%s: upscli_default_connect_timeout=%" PRIiMAX ".%06" PRIiMAX " sec assigned from: %s", __func__, (intmax_t)upscli_default_connect_timeout.tv_sec, (intmax_t)upscli_default_connect_timeout.tv_usec, cause); /* Some non-built-in value was OK */ if (applied) { upscli_default_connect_timeout_initialized++; return 0; } /* None of provided non-built-in values was OK */ if (failed) return -1; /* At least we have the built-in default and nothing failed */ upscli_default_connect_timeout_initialized++; return 0; } /* Pick up the methods below from libcommon and expose in the NUT client API */ int upscli_str_contains_token(const char *string, const char *token) { return str_contains_token(string, token); } int upscli_str_add_unique_token(char *tgt, size_t tgtsize, const char *token, int (*callback_always)(char *, size_t, const char *), int (*callback_unique)(char *, size_t, const char *) ) { return str_add_unique_token(tgt, tgtsize, token, callback_always, callback_unique); } nut-2.8.3/clients/upssched.h0000644000200500020050000000113014777767434012714 00000000000000/* upssched.h - supporting structures */ #ifndef NUT_UPSSCHED_H_SEEN #define NUT_UPSSCHED_H_SEEN 1 #include #include "common.h" #define SERIALIZE_INIT 1 #define SERIALIZE_SET 2 #define SERIALIZE_WAIT 3 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* track client connections */ typedef struct conn_s { TYPE_FD fd; #ifdef WIN32 char buf[LARGEBUF]; OVERLAPPED read_overlapped; #endif /* WIN32 */ PCONF_CTX_t ctx; struct conn_s *next; } conn_t; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_UPSSCHED_H_SEEN */ nut-2.8.3/clients/upslog.h0000644000200500020050000000354214777767434012420 00000000000000/* upslog.h - table of functions for handling various logging functions */ #ifndef NUT_UPSLOG_H_SEEN #define NUT_UPSLOG_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* log targets, defined independently of monitored "systems" below, because * several devices can get logged into the same target (stdout or filename) */ struct logtarget_t { char *logfn; FILE *logfile; struct logtarget_t *next; }; /* monitored "systems" */ struct monhost_ups_t { char *monhost; char *upsname; char *hostname; uint16_t port; UPSCONN_t *ups; struct logtarget_t *logtarget; struct monhost_ups_t *next; }; /* function list */ typedef struct flist_s { void (*fptr)(const char *arg, const struct monhost_ups_t *monhost_ups_print); const char *arg; struct flist_s *next; } flist_t; static void do_host(const char *arg, const struct monhost_ups_t *monhost_ups_print); static void do_upshost(const char *arg, const struct monhost_ups_t *monhost_ups_print); static void do_pid(const char *arg, const struct monhost_ups_t *monhost_ups_print); static void do_time(const char *arg, const struct monhost_ups_t *monhost_ups_print); static void do_var(const char *arg, const struct monhost_ups_t *monhost_ups_print); static void do_etime(const char *arg, const struct monhost_ups_t *monhost_ups_print); /* This is only used in upslog.c, but refers to routines declared here... * To move or not to move?.. */ static struct { const char *name; void (*func)(const char *arg, const struct monhost_ups_t *monhost_ups_print); } logcmds[] = { { "HOST", do_host }, { "UPSHOST", do_upshost }, { "PID", do_pid }, { "TIME", do_time }, { "VAR", do_var }, { "ETIME", do_etime }, { NULL, (void(*)(const char*, const struct monhost_ups_t *))(NULL) } }; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_UPSLOG_H_SEEN */ nut-2.8.3/clients/message.c0000644000200500020050000000035014777767434012520 00000000000000#ifdef WIN32 #include int main(int argc, char ** argv) { if (argc < 2) return 1; MessageBox(NULL, argv[1], "Network UPS Tools", MB_OK|MB_ICONEXCLAMATION|MB_SERVICE_NOTIFICATION); return 0; } #endif /* WIN32 */ nut-2.8.3/clients/upsset.c0000644000200500020050000006127514777767434012434 00000000000000/* upsset - CGI program to manage read/write variables Copyright (C) 1999 Russell Kroll This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #ifndef WIN32 #include #include #include #include #else /* WIN32 */ #include "wincompat.h" #endif /* WIN32 */ #include "nut_stdint.h" #include "upsclient.h" #include "cgilib.h" #include "parseconf.h" struct list_t { char *name; struct list_t *next; }; /* see the stock upsset.conf for the whole rant on what this is */ #define MAGIC_ENABLE_STRING "I_HAVE_SECURED_MY_CGI_DIRECTORY" #define HARD_UPSVAR_LIMIT_NUM 64 #define HARD_UPSVAR_LIMIT_LEN 256 /* network timeout for initial connection, in seconds */ #define UPSCLI_DEFAULT_CONNECT_TIMEOUT "10" static char *monups, *username, *password, *function, *upscommand; /* set once the MAGIC_ENABLE_STRING is found in the upsset.conf */ static int magic_string_set = 0; static uint16_t port; static char *upsname, *hostname; static UPSCONN_t ups; typedef struct { char *var; char *value; void *next; } uvtype_t; static uvtype_t *firstuv = NULL; void parsearg(char *var, char *value) { char *ptr; uvtype_t *last, *tmp = NULL; static int upsvc = 0; /* store variables from a SET command for the later commit */ if (!strncmp(var, "UPSVAR_", 7)) { /* if someone bombs us with variables, stop at some point */ if (upsvc > HARD_UPSVAR_LIMIT_NUM) return; /* same idea: throw out anything that's much too long */ if (strlen(value) > HARD_UPSVAR_LIMIT_LEN) return; ptr = strchr(var, '_'); if (!ptr) /* sanity check */ return; ptr++; tmp = last = firstuv; while (tmp) { last = tmp; tmp = tmp->next; } tmp = xmalloc(sizeof(uvtype_t)); tmp->var = xstrdup(ptr); tmp->value = xstrdup(value); tmp->next = NULL; if (last) last->next = tmp; else firstuv = tmp; upsvc++; return; } if (!strcmp(var, "username")) { free(username); username = xstrdup(value); } if (!strcmp(var, "password")) { free(password); password = xstrdup(value); } if (!strcmp(var, "function")) { free(function); function = xstrdup(value); } if (!strcmp(var, "monups")) { free(monups); monups = xstrdup(value); } if (!strcmp(var, "upscommand")) { free(upscommand); upscommand = xstrdup(value); } } static void do_header(const char *title) { printf("\n"); printf("\n"); printf("upsset: %s\n", title); printf("\n"); printf("\n"); printf("
    \n"); } static void start_table(void) { printf("\n"); printf("\n"); } /* propagate login details across pages - no cookies here! */ static void do_hidden(const char *next) { printf("\n", username); printf("\n", password); if (next) printf("\n", next); } /* generate SELECT chooser from hosts.conf entries */ static void upslist_arg(size_t numargs, char **arg) { if (numargs < 3) return; /* MONITOR */ if (!strcmp(arg[0], "MONITOR")) { printf("\n", arg[2]); } } /* called for fatal errors in parseconf like malloc failures */ static void upsset_hosts_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf(hosts.conf): %s", errmsg); } /* this defaults to wherever we are now, ups and function-wise */ static void do_pickups(const char *currfunc) { char hostfn[NUT_PATH_MAX + 1]; PCONF_CTX_t ctx; snprintf(hostfn, sizeof(hostfn), "%s/hosts.conf", confpath()); printf("
    \n"); printf("Select UPS and function:\n
    \n"); pconf_init(&ctx, upsset_hosts_err); if (!pconf_file_begin(&ctx, hostfn)) { pconf_finish(&ctx); printf("Error: hosts.conf unavailable\n"); printf("\n"); /* stderr is for the admin - should wind up in error.log */ fprintf(stderr, "upsset: %s\n", ctx.errmsg); return; } printf("\n"); printf("\n"); do_hidden(NULL); printf("\n"); printf("\n"); } static void error_page(const char *next, const char *title, const char *fmt, ...) __attribute__((noreturn)); static void error_page(const char *next, const char *title, const char *fmt, ...) { char msg[SMALLBUF]; va_list ap; va_start(ap, fmt); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic push #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY #pragma GCC diagnostic ignored "-Wformat-security" #endif vsnprintf(msg, sizeof(msg), fmt, ap); #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL #pragma GCC diagnostic pop #endif va_end(ap); do_header(title); start_table(); printf("
    \n"); printf("\n"); printf("
    \n"); printf("Network UPS Tools upsset %s\n", UPS_VERSION); printf("
    \n"); printf("Error: %s\n", msg); printf("
    \n"); do_pickups(next); printf("
    \n"); printf("
    \n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } static void loginscreen(void) __attribute__((noreturn)); static void loginscreen(void) { do_header("Login"); printf("
    \n"); start_table(); printf("\n"); printf("Username\n"); printf("\n"); printf("\n"); printf("\n"); printf("Password\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("
    \n"); printf("\n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } /* try to connect to upsd - generate an error page if it fails */ static void upsd_connect(void) { if (upscli_splitname(monups, &upsname, &hostname, &port) != 0) { error_page("showsettings", "UPS name is unusable", "Unable to split UPS name [%s]", monups); /* NOTREACHED */ } if (upscli_connect(&ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { error_page("showsettings", "Connect failure", "Unable to connect to %s: %s", monups, upscli_strerror(&ups)); /* NOTREACHED */ } } static void print_cmd(const char *cmd) { int ret; size_t numq, numa; char **answer; const char *query[4]; query[0] = "CMDDESC"; query[1] = upsname; query[2] = cmd; numq = 3; ret = upscli_get(&ups, numq, query, &numa, &answer); if ((ret < 0) || (numa < numq)) return; /* CMDDESC */ printf("\n", cmd, answer[3]); } /* generate a list of instant commands */ static void showcmds(void) { int ret; size_t numq, numa; const char *query[2]; char **answer; struct list_t *lhead, *llast, *ltmp, *lnext; char *desc; if (!checkhost(monups, &desc)) error_page("showsettings", "Access denied", "Access to that host is not authorized"); upsd_connect(); llast = lhead = NULL; query[0] = "CMD"; query[1] = upsname; numq = 2; ret = upscli_list_start(&ups, numq, query); if (ret < 0) { fprintf(stderr, "LIST CMD %s failed: %s\n", upsname, upscli_strerror(&ups)); error_page("showcmds", "Server protocol error", "LIST CMD command failed"); /* NOTREACHED */ } ret = upscli_list_next(&ups, numq, query, &numa, &answer); while (ret == 1) { /* CMD upsname cmdname */ if (numa < 3) { fprintf(stderr, "Error: insufficient data " "(got %" PRIuSIZE " args, need at least 3)\n", numa); return; } ltmp = xmalloc(sizeof(struct list_t)); ltmp->name = xstrdup(answer[2]); ltmp->next = NULL; if (llast) llast->next = ltmp; else lhead = ltmp; llast = ltmp; ret = upscli_list_next(&ups, numq, query, &numa, &answer); } if (!lhead) error_page("showcmds", "No instant commands supported", "This UPS doesn't support any instant commands."); do_header("Instant commands"); printf("
    \n"); start_table(); /* include the description from checkhost() if present */ if (desc) printf("%s\n", desc); printf("\n"); printf("Instant commands\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); do_hidden("docmd"); printf("\n", monups); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("
    \n"); printf("\n"); do_pickups("showcmds"); printf("\n"); printf("\n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } /* handle setting authentication data in the server */ static void send_auth(const char *next) { char buf[SMALLBUF]; snprintf(buf, sizeof(buf), "USERNAME %s\n", username); if (upscli_sendline(&ups, buf, strlen(buf)) < 0) { fprintf(stderr, "Can't set username: %s\n", upscli_strerror(&ups)); error_page(next, "Can't set username", "Set username failed: %s", upscli_strerror(&ups)); } if (upscli_readline(&ups, buf, sizeof(buf)) < 0) { /* test for old upsd that doesn't do USERNAME */ if (upscli_upserror(&ups) == UPSCLI_ERR_UNKCOMMAND) { error_page(next, "Protocol mismatch", "upsd version too old - USERNAME not supported"); } error_page(next, "Can't set user name", "Set user name failed: %s", upscli_strerror(&ups)); } snprintf(buf, sizeof(buf), "PASSWORD %s\n", password); if (upscli_sendline(&ups, buf, strlen(buf)) < 0) error_page(next, "Can't set password", "Password set failed: %s", upscli_strerror(&ups)); if (upscli_readline(&ups, buf, sizeof(buf)) < 0) error_page(next, "Can't set password", "Password set failed: %s", upscli_strerror(&ups)); } static void docmd(void) __attribute__((noreturn)); static void docmd(void) { char buf[SMALLBUF], *desc; if (!checkhost(monups, &desc)) error_page("showsettings", "Access denied", "Access to that host is not authorized"); /* the user is messing with us */ if (!upscommand) error_page("showcmds", "Form error", "No instant command selected"); /* (l)user took the default blank option */ if (strlen(upscommand) == 0) error_page("showcmds", "Form error", "No instant command selected"); upsd_connect(); send_auth("showcmds"); snprintf(buf, sizeof(buf), "INSTCMD %s %s\n", upsname, upscommand); if (upscli_sendline(&ups, buf, strlen(buf)) < 0) { do_header("Error while issuing command"); start_table(); printf("Error sending command: %s\n", upscli_strerror(&ups)); printf("\n"); do_pickups("showcmds"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } if (upscli_readline(&ups, buf, sizeof(buf)) < 0) { do_header("Error while reading command response"); start_table(); printf("Error reading command response: %s\n", upscli_strerror(&ups)); printf("\n"); do_pickups("showcmds"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } do_header("Issuing command"); start_table(); printf("
    \n");
    	printf("Sending command: %s\n", upscommand);
    	printf("Response: %s\n", buf);
    	printf("
    \n"); printf("\n"); do_pickups("showcmds"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } static const char *get_data(const char *type, const char *varname) { int ret; size_t numq, numa; char **answer; const char *query[4]; query[0] = type; query[1] = upsname; query[2] = varname; numq = 3; ret = upscli_get(&ups, numq, query, &numa, &answer); if ((ret < 0) || (numa < numq)) return NULL; /* */ return answer[3]; } static void do_string(const char *varname, int maxlen) { const char *val; val = get_data("VAR", varname); if (!val) { printf("Unavailable\n"); fprintf(stderr, "do_string: can't get current value of %s\n", varname); return; } printf("\n", varname, val, maxlen); } static void do_enum(const char *varname) { int ret; size_t numq, numa; char **answer, *val; const char *query[4], *tmp; /* get current value */ tmp = get_data("VAR", varname); if (!tmp) { printf("Unavailable\n"); fprintf(stderr, "do_enum: can't get current value of %s\n", varname); return; } /* tmp is a pointer into answer - have to save it somewhere else */ val = xstrdup(tmp); query[0] = "ENUM"; query[1] = upsname; query[2] = varname; numq = 3; ret = upscli_list_start(&ups, numq, query); if (ret < 0) { printf("Unavailable\n"); fprintf(stderr, "Error doing ENUM %s %s: %s\n", upsname, varname, upscli_strerror(&ups)); free(val); return; } ret = upscli_list_next(&ups, numq, query, &numa, &answer); printf("\n"); } static void do_type(const char *varname) { int ret; size_t i, numq, numa; char **answer; const char *query[4]; query[0] = "TYPE"; query[1] = upsname; query[2] = varname; numq = 3; ret = upscli_get(&ups, numq, query, &numa, &answer); if ((ret < 0) || (numa < numq)) { printf("Unknown type\n"); return; } /* TYPE ... */ for (i = 3; i < numa; i++) { if (!strcasecmp(answer[i], "ENUM")) { do_enum(varname); return; } if (!strncasecmp(answer[i], "STRING:", 7)) { char *ptr, len; long l; /* split out the : data */ ptr = strchr(answer[i], ':'); *ptr++ = '\0'; l = strtol(ptr, (char **) NULL, 10); assert(l <= 127); /* FIXME: Loophole about longer numbers? Why are we limited to char at all here? */ len = (char)l; do_string(varname, len); return; } /* ignore this one */ if (!strcasecmp(answer[i], "RW")) continue; printf("Unrecognized\n"); } } static void print_rw(const char *arg_upsname, const char *varname) { const char *tmp; printf("\n", arg_upsname); printf("\n"); printf(""); tmp = get_data("DESC", varname); if ((tmp) && (strcmp(tmp, "Unavailable") != 0)) printf("%s", tmp); else printf("%s", varname); printf("\n"); printf("\n"); do_type(varname); printf("\n"); printf("\n"); } static void showsettings(void) __attribute__((noreturn)); static void showsettings(void) { int ret; size_t numq, numa; const char *query[2]; char **answer, *desc = NULL; struct list_t *lhead, *llast, *ltmp, *lnext; if (!checkhost(monups, &desc)) error_page("showsettings", "Access denied", "Access to that host is not authorized"); upsd_connect(); query[0] = "RW"; query[1] = upsname; numq = 2; ret = upscli_list_start(&ups, numq, query); if (ret < 0) { fprintf(stderr, "LIST RW %s failed: %s\n", upsname, upscli_strerror(&ups)); error_page("showsettings", "Server protocol error", "LIST RW command failed"); /* NOTREACHED */ } llast = lhead = NULL; ret = upscli_list_next(&ups, numq, query, &numa, &answer); while (ret == 1) { /* sock this entry away for later */ ltmp = xmalloc(sizeof(struct list_t)); ltmp->name = xstrdup(answer[2]); ltmp->next = NULL; if (llast) llast->next = ltmp; else lhead = ltmp; llast = ltmp; ret = upscli_list_next(&ups, numq, query, &numa, &answer); } do_header("Current settings"); printf("
    \n"); start_table(); /* include the description from checkhost() if present */ if (desc) printf("%s\n", desc); printf("\n"); printf("Setting\n"); printf("Value\n"); /* use the list to get descriptions and types */ ltmp = lhead; while (ltmp) { lnext = ltmp->next; print_rw(upsname, ltmp->name); free(ltmp->name); free(ltmp); ltmp = lnext; } printf("\n"); printf("\n"); do_hidden("savesettings"); printf("\n", monups); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf("
    \n"); printf("\n"); do_pickups("showsettings"); printf("\n"); printf("\n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } static int setvar(const char *var, const char *val) { char buf[SMALLBUF], enc[SMALLBUF]; const char *tmp; /* get old value */ tmp = get_data("VAR", var); if (!tmp) { printf("Can't get old value for %s, aborting SET\n", var); return 0; } /* don't send a SET if it hasn't chnaged */ if (!strcmp(tmp, val)) return 0; printf("set %s to %s (was %s)\n", var, val, tmp); snprintf(buf, sizeof(buf), "SET VAR %s %s \"%s\"\n", upsname, var, pconf_encode(val, enc, sizeof(enc))); if (upscli_sendline(&ups, buf, strlen(buf)) < 0) { printf("Error: SET failed: %s\n", upscli_strerror(&ups)); return 0; } if (upscli_readline(&ups, buf, sizeof(buf)) < 0) { printf("Error: SET failed: %s\n", upscli_strerror(&ups)); return 0; } if (strncmp(buf, "OK", 2) != 0) { printf("Unexpected response: %s\n", buf); return 0; } printf("OK\n"); return 1; } /* turn a form submission of settings into SET commands for upsd */ static void savesettings(void) __attribute__((noreturn)); static void savesettings(void) { int changed = 0; char *desc; uvtype_t *upsvar; if (!checkhost(monups, &desc)) error_page("showsettings", "Access denied", "Access to that host is not authorized"); upsd_connect(); upsvar = firstuv; send_auth("showsettings"); do_header("Saving settings"); start_table(); printf("
    \n");
    
    	while (upsvar) {
    		changed += setvar(upsvar->var, upsvar->value);
    		upsvar = upsvar->next;
    	}
    
    	if (changed == 0)
    		printf("No settings changed.\n");
    	else
    		printf("Updated %d setting%s.\n",
    			changed, changed == 1 ? "" : "s");
    
    	printf("
    \n"); printf("\n"); do_pickups("showsettings"); printf("\n"); printf("\n"); printf("\n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } static void initial_pickups(void) __attribute__((noreturn)); static void initial_pickups(void) { do_header("Select a UPS"); start_table(); printf("\n"); do_pickups(""); printf("\n"); printf("\n"); printf("\n"); printf("\n"); upscli_disconnect(&ups); exit(EXIT_SUCCESS); } static void upsset_conf_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf(upsset.conf): %s", errmsg); } /* see if the user has confirmed their cgi directory's secure state */ static void check_conf(void) { char fn[NUT_PATH_MAX + 1]; PCONF_CTX_t ctx; snprintf(fn, sizeof(fn), "%s/upsset.conf", confpath()); pconf_init(&ctx, upsset_conf_err); if (!pconf_file_begin(&ctx, fn)) { pconf_finish(&ctx); printf("
    \n");
    		printf("Error: Can't open upsset.conf to verify security settings.\n");
    		printf("Refusing to start until this is fixed.\n");
    		printf("
    \n"); /* leave something in the httpd log for the admin */ fprintf(stderr, "upsset.conf does not exist to permit execution\n"); exit(EXIT_FAILURE); } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } if (ctx.numargs < 1) continue; if (!strcmp(ctx.arglist[0], MAGIC_ENABLE_STRING)) magic_string_set = 1; } pconf_finish(&ctx); /* if we've been enabled, jump out of here and go to work */ if (magic_string_set == 1) return; printf("
    \n");
    	printf("Error: Secure mode has not been enabled in upsset.conf.\n");
    	printf("Refusing to start until this is fixed.\n");
    	printf("
    \n"); /* leave something in the httpd log for the admin */ fprintf(stderr, "upsset.conf does not permit execution\n"); exit(EXIT_FAILURE); } int main(int argc, char **argv) { NUT_UNUSED_VARIABLE(argc); NUT_UNUSED_VARIABLE(argv); username = password = function = monups = NULL; printf("Content-type: text/html\n\n"); /* see if the magic string is present in the config file */ check_conf(); upscli_init_default_connect_timeout(NULL, NULL, UPSCLI_DEFAULT_CONNECT_TIMEOUT); /* see if there's anything waiting .. the server my not close STDIN properly */ if (1) { fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); tv.tv_sec = 0; tv.tv_usec = 250000; /* wait for up to 250ms for a POST response */ if ((select(STDIN_FILENO+1, &fds, 0, 0, &tv)) > 0) extractpostargs(); } if ((!username) || (!password) || (!function)) loginscreen(); if ((!strcmp(function, "pickups")) || (!monups)) initial_pickups(); if (!strcmp(function, "showsettings")) showsettings(); if (!strcmp(function, "savesettings")) savesettings(); #if 0 /* FUTURE */ if (!strcmp(function, "showstatus")) showstatus(); #endif if (!strcmp(function, "showcmds")) showcmds(); if (!strcmp(function, "docmd")) docmd(); printf("Error: Unhandled function name [%s]\n", function); return 0; } nut-2.8.3/clients/upsmon.h0000644000200500020050000002732115001552635012401 00000000000000/* upsmon.h - headers and other useful things for upsmon.h Copyright (C) 2000 Russell Kroll 2012 Arnaud Quette 2017 Eaton (author: Arnaud Quette ) 2020-2025 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_UPSMON_H_SEEN #define NUT_UPSMON_H_SEEN 1 #include "state.h" /* flags for ups->status */ #define ST_ONLINE (1 << 0) /* UPS is on line (OL) */ #define ST_ONBATT (1 << 1) /* UPS is on battery (OB) */ #define ST_LOWBATT (1 << 2) /* UPS has a low battery (LB) */ #define ST_FSD (1 << 3) /* primary has set forced shutdown flag */ #define ST_PRIMARY (1 << 4) /* we are the primary (manager) of this UPS */ #define ST_MASTER ST_PRIMARY /* legacy alias */ #define ST_LOGIN (1 << 5) /* we are logged into this UPS */ #define ST_CLICONNECTED (1 << 6) /* upscli_connect returned OK */ #define ST_CAL (1 << 7) /* UPS calibration in progress (CAL) */ #define ST_OFF (1 << 8) /* UPS is administratively off or asleep (OFF) */ #define ST_BYPASS (1 << 9) /* UPS is on bypass so not protecting */ #define ST_ECO (1 << 10) /* UPS is in ECO (High Efficiency) mode or similar tweak, e.g. Energy Saver System mode */ #define ST_ALARM (1 << 11) /* UPS has at least one active alarm */ #define ST_OTHER (1 << 12) /* UPS has at least one unclassified status token */ #define ST_OVER (1 << 13) /* UPS is overloaded */ #define ST_TRIM (1 << 14) /* UPS is trimming incoming voltage */ #define ST_BOOST (1 << 15) /* UPS is boosting incoming voltage */ /* required contents of flag file */ #define SDMAGIC "upsmon-shutdown-file" #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* UPS tracking structure */ typedef struct { UPSCONN_t conn; /* upsclient state descriptor */ char *sys; /* raw system name from .conf */ char *upsname; /* just upsname */ char *hostname; /* just hostname */ uint16_t port; /* just the port */ unsigned int pv; /* power value from conf */ char *un; /* username (optional for now) */ char *pw; /* password from conf */ int status; /* status (see flags above) */ st_tree_t *status_tokens; /* parsed ups.status, mapping each token to whatever value if it is currently set (evicted when not) */ int retain; /* tracks deletions at reload */ /* handle suppression of COMMOK and ONLINE at startup */ int commstate; /* these start at -1, and only */ int linestate; /* fire on a 0->1 transition */ int offstate; /* fire on a 0->1 transition, may */ /* be delayed vs. seeing OFF state */ int bypassstate; /* fire on a 0->1 transition; */ /* delays not implemented now */ int ecostate; /* fire on a 0->1 transition; */ /* delays not implemented now */ int alarmstate; /* fire on a 0->1 transition; */ /* delays not implemented now */ int overstate; /* fire on a 0->1 transition; */ /* see detailed comment for pollfail_log_throttle_max in upsmon.c * about handling of poll failure log throttling (syslog storage I/O) */ int pollfail_log_throttle_state; /* Last (error) state which we throttle */ int pollfail_log_throttle_count; /* How many pollfreq loops this UPS was in this state since last logged report? */ time_t lastpoll; /* time of last successful poll */ time_t lastnoncrit; /* time of last non-crit poll */ time_t lastrbwarn; /* time of last REPLBATT warning*/ time_t lastncwarn; /* time of last NOCOMM warning */ time_t offsince; /* time of recent entry into OFF state */ time_t oblbsince; /* time of recent entry into OB LB state (normally this causes immediate shutdown alert, unless we are configured to delay it) */ time_t oversince; /* time of recent entry into OVER state */ void *next; } utype_t; /* notify identifiers */ #define NOTIFY_ONLINE 0 /* UPS went on-line */ #define NOTIFY_ONBATT 1 /* UPS went on battery */ #define NOTIFY_LOWBATT 2 /* UPS went to low battery */ #define NOTIFY_FSD 3 /* Primary upsmon set FSD flag */ #define NOTIFY_COMMOK 4 /* Communication established */ #define NOTIFY_COMMBAD 5 /* Communication lost */ #define NOTIFY_SHUTDOWN 6 /* System shutdown in progress */ #define NOTIFY_REPLBATT 7 /* UPS battery needs to be replaced */ #define NOTIFY_NOCOMM 8 /* UPS hasn't been contacted in a while */ #define NOTIFY_NOPARENT 9 /* privileged parent process died */ #define NOTIFY_CAL 10 /* UPS is performing calibration */ #define NOTIFY_NOTCAL 11 /* UPS is not anymore performing calibration */ #define NOTIFY_OFF 12 /* UPS is administratively OFF or asleep*/ #define NOTIFY_NOTOFF 13 /* UPS is not anymore administratively OFF or asleep*/ #define NOTIFY_BYPASS 14 /* UPS is administratively on bypass */ #define NOTIFY_NOTBYPASS 15 /* UPS is not anymore administratively on bypass */ #define NOTIFY_ECO 16 /* UPS is in ECO mode or similar */ #define NOTIFY_NOTECO 17 /* UPS is not anymore in ECO mode or similar */ #define NOTIFY_ALARM 18 /* UPS has at least one active alarm */ #define NOTIFY_NOTALARM 19 /* UPS has no active alarms */ #define NOTIFY_OVER 20 /* UPS is overloaded */ #define NOTIFY_NOTOVER 21 /* UPS is not anymore overloaded */ #define NOTIFY_TRIM 22 /* UPS is trimming incoming voltage (called "buck" in some hardware) */ #define NOTIFY_NOTTRIM 23 /* UPS is not anymore trimming incoming voltage */ #define NOTIFY_BOOST 24 /* UPS is boosting incoming voltage */ #define NOTIFY_NOTBOOST 25 /* UPS is not anymore boosting incoming voltage */ /* Special handling below */ #define NOTIFY_OTHER 28 /* UPS has at least one unclassified status token */ #define NOTIFY_NOTOTHER 29 /* UPS has no unclassified status tokens anymore */ #define NOTIFY_SUSPEND_STARTING 30 /* OS is entering sleep/suspend/hibernate slumber mode, and we know it */ #define NOTIFY_SUSPEND_FINISHED 31 /* OS just finished sleep/suspend/hibernate slumber mode, and we know it */ /* notify flag values */ #define NOTIFY_IGNORE (1 << 0) /* don't do anything */ #define NOTIFY_SYSLOG (1 << 1) /* send the msg to the syslog */ #define NOTIFY_WALL (1 << 2) /* send the msg to all users */ #define NOTIFY_EXEC (1 << 3) /* send the msg to NOTIFYCMD script */ /* flags are set to NOTIFY_SYSLOG | NOTIFY_WALL at program init */ /* except under Windows where they are set to NOTIFY_SYSLOG only */ /* the user can override with NOTIFYFLAGS in the upsmon.conf */ #ifdef WIN32 #define NOTIFY_DEFAULT NOTIFY_SYSLOG #else /* !WIN32 */ #define NOTIFY_DEFAULT (NOTIFY_SYSLOG | NOTIFY_WALL) #endif /* !WIN32 */ /* This is only used in upsmon.c, but might it also have external consumers?.. * To move or not to move?.. */ static struct { unsigned int type; const char *name; char *msg; /* NULL until overridden */ const char *stockmsg; int flags; } notifylist[] = { { NOTIFY_ONLINE, "ONLINE", NULL, "UPS %s on line power", NOTIFY_DEFAULT }, { NOTIFY_ONBATT, "ONBATT", NULL, "UPS %s on battery", NOTIFY_DEFAULT }, { NOTIFY_LOWBATT, "LOWBATT", NULL, "UPS %s battery is low", NOTIFY_DEFAULT }, { NOTIFY_FSD, "FSD", NULL, "UPS %s: forced shutdown in progress", NOTIFY_DEFAULT }, { NOTIFY_COMMOK, "COMMOK", NULL, "Communications with UPS %s established", NOTIFY_DEFAULT }, { NOTIFY_COMMBAD, "COMMBAD", NULL, "Communications with UPS %s lost", NOTIFY_DEFAULT }, { NOTIFY_SHUTDOWN, "SHUTDOWN", NULL, "Auto logout and shutdown proceeding", NOTIFY_DEFAULT }, { NOTIFY_REPLBATT, "REPLBATT", NULL, "UPS %s battery needs to be replaced", NOTIFY_DEFAULT }, { NOTIFY_NOCOMM, "NOCOMM", NULL, "UPS %s is unavailable", NOTIFY_DEFAULT }, { NOTIFY_NOPARENT, "NOPARENT", NULL, "upsmon parent process died - shutdown impossible", NOTIFY_DEFAULT }, { NOTIFY_CAL, "CAL", NULL, "UPS %s: calibration in progress", NOTIFY_DEFAULT }, { NOTIFY_NOTCAL, "NOTCAL", NULL, "UPS %s: calibration finished", NOTIFY_DEFAULT }, { NOTIFY_OFF, "OFF", NULL, "UPS %s: administratively OFF or asleep", NOTIFY_DEFAULT }, { NOTIFY_NOTOFF, "NOTOFF", NULL, "UPS %s: no longer administratively OFF or asleep", NOTIFY_DEFAULT }, { NOTIFY_BYPASS, "BYPASS", NULL, "UPS %s: on bypass (powered, not protecting)", NOTIFY_DEFAULT }, { NOTIFY_NOTBYPASS,"NOTBYPASS",NULL, "UPS %s: no longer on bypass", NOTIFY_DEFAULT }, { NOTIFY_ECO, "ECO", NULL, "UPS %s: in ECO mode (as defined by vendor)", NOTIFY_DEFAULT }, { NOTIFY_NOTECO, "NOTECO", NULL, "UPS %s: no longer in ECO mode", NOTIFY_DEFAULT }, /* NOTE: We remember the ups.alarm value and report it here, * maybe optionally - e.g. check if the "ALARM" formatting * string has actually one or two "%s" placeholders inside. * Do issue a new notification if ups.alarm value changes. */ { NOTIFY_ALARM, "ALARM", NULL, "UPS %s: one or more active alarms: [%s]", NOTIFY_DEFAULT }, { NOTIFY_NOTALARM, "NOTALARM", NULL, "UPS %s is no longer in an alarm state (no active alarms)", NOTIFY_DEFAULT }, { NOTIFY_OVER, "OVER", NULL, "UPS %s: overloaded", NOTIFY_DEFAULT }, { NOTIFY_NOTOVER, "NOTOVER", NULL, "UPS %s: no longer overloaded", NOTIFY_DEFAULT }, { NOTIFY_TRIM, "TRIM", NULL, "UPS %s: trimming incoming voltage", NOTIFY_DEFAULT }, { NOTIFY_NOTTRIM, "NOTTRIM", NULL, "UPS %s: no longer trimming incoming voltage", NOTIFY_DEFAULT }, { NOTIFY_BOOST, "BOOST", NULL, "UPS %s: boosting incoming voltage", NOTIFY_DEFAULT }, { NOTIFY_NOTBOOST, "NOTBOOST", NULL, "UPS %s: no longer boosting incoming voltage", NOTIFY_DEFAULT }, /* Special handling, two string placeholders! * Reported when status_tokens tree changes (and is not empty in the end) */ { NOTIFY_OTHER, "OTHER", NULL, "UPS %s: has at least one unclassified status token: [%s]", NOTIFY_DEFAULT }, /* Reported when status_tokens tree becomes empty */ { NOTIFY_NOTOTHER, "NOTOTHER", NULL, "UPS %s has no unclassified status tokens anymore", NOTIFY_DEFAULT }, { NOTIFY_SUSPEND_STARTING, "SUSPEND_STARTING", NULL, "OS is entering sleep/suspend/hibernate mode", NOTIFY_DEFAULT }, { NOTIFY_SUSPEND_FINISHED, "SUSPEND_FINISHED", NULL, "OS just finished sleep/suspend/hibernate mode, de-activating obsolete UPS readings to avoid an unfortunate shutdown", NOTIFY_DEFAULT }, { 0, NULL, NULL, NULL, 0 } }; /* values for signals passed between processes */ #ifndef WIN32 #define SIGCMD_FSD SIGUSR1 #define SIGCMD_STOP SIGTERM #define SIGCMD_RELOAD SIGHUP #else /* WIN32 */ #define SIGCMD_FSD COMMAND_FSD #define SIGCMD_STOP COMMAND_STOP #define SIGCMD_RELOAD COMMAND_RELOAD #endif /* WIN32 */ /* various constants */ /* network timeout for initial connection, in seconds */ #define UPSCLI_DEFAULT_CONNECT_TIMEOUT "10" #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_UPSMON_H_SEEN */ nut-2.8.3/clients/nutclientmem.h0000644000200500020050000001051614777767434013612 00000000000000/* nutclientmem.h - definitions for nutclientmem C/C++ library Copyright (C) 2021 Eric Clappier This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUTCLIENTMEM_HPP_SEEN #define NUTCLIENTMEM_HPP_SEEN 1 /* Begin of C++ nutclient library declaration */ #ifdef __cplusplus #include "nutclient.h" namespace nut { typedef std::vector ListValue; typedef std::map ListObject; typedef std::map ListDevice; /** * Memory client stub. * Class to stub TCPClient for test (data store in local memory). */ class MemClientStub : public Client { public: /** * Construct a nut MemClientStub object. */ MemClientStub() {} ~MemClientStub() override {} virtual void authenticate(const std::string& user, const std::string& passwd) override { NUT_UNUSED_VARIABLE(user); NUT_UNUSED_VARIABLE(passwd); } virtual void logout() override {} virtual Device getDevice(const std::string& name) override; virtual std::set getDeviceNames() override; virtual std::string getDeviceDescription(const std::string& name) override; virtual std::set getDeviceVariableNames(const std::string& dev) override; virtual std::set getDeviceRWVariableNames(const std::string& dev) override; virtual std::string getDeviceVariableDescription(const std::string& dev, const std::string& name) override; virtual ListValue getDeviceVariableValue(const std::string& dev, const std::string& name) override; virtual ListObject getDeviceVariableValues(const std::string& dev) override; virtual ListDevice getDevicesVariableValues(const std::set& devs) override; virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::string& value) override; virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const ListValue& values) override; virtual std::set getDeviceCommandNames(const std::string& dev) override; virtual std::string getDeviceCommandDescription(const std::string& dev, const std::string& name) override; virtual TrackingID executeDeviceCommand(const std::string& dev, const std::string& name, const std::string& param="") override; virtual void deviceLogin(const std::string& dev) override; /* Note: "master" is deprecated, but supported * for mixing old/new client/server combos: */ virtual void deviceMaster(const std::string& dev) override; virtual void devicePrimary(const std::string& dev) override; virtual void deviceForcedShutdown(const std::string& dev) override; virtual int deviceGetNumLogins(const std::string& dev) override; virtual std::set deviceGetClients(const std::string& dev) override; virtual std::map> listDeviceClients(void) override; virtual TrackingResult getTrackingResult(const TrackingID& id) override; virtual bool isFeatureEnabled(const Feature& feature) override; virtual void setFeature(const Feature& feature, bool status) override; private: ListDevice _values; }; } /* namespace nut */ #endif /* __cplusplus */ /* End of C++ nutclient library declaration */ /* Begin of C nutclient library declaration */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * Nut MEM client dedicated types and functions */ /** * Hidden structure representing a MEM connection. * NUTCLIENT_MEM_t is back compatible to NUTCLIENT_t. */ typedef NUTCLIENT_t NUTCLIENT_MEM_t; /** * Create a client to NUTD using memory. * \return New client or nullptr if failed. */ NUTCLIENT_MEM_t nutclient_mem_create_client(); #ifdef __cplusplus } #endif /* __cplusplus */ /* End of C nutclient library declaration */ #endif /* NUTCLIENTMEM_HPP_SEEN */ nut-2.8.3/clients/Makefile.am0000644000200500020050000001647014777767434012776 00000000000000# Network UPS Tools: clients # Export certain values for ccache which NUT ci_build.sh can customize, # to facilitate developer iteration re-runs of "make" later. # At least GNU and BSD make implementations are okay with this syntax. @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_NAMESPACE@export CCACHE_NAMESPACE=@CCACHE_NAMESPACE@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_BASEDIR@export CCACHE_BASEDIR=@CCACHE_BASEDIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_DIR@export CCACHE_DIR=@CCACHE_DIR@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export CCACHE_PATH=@CCACHE_PATH@ @NUT_AM_MAKE_CAN_EXPORT@@NUT_AM_EXPORT_CCACHE_PATH@export PATH=@PATH_DURING_CONFIGURE@ EXTRA_DIST = CLEANFILES = # nutclient.cpp for some legacy reason (maybe initial detached development?) # optionally includes "common.h" with the NUT build setup - and this option # was never triggered in fact, not until pushed through command line like this: AM_CXXFLAGS = -DHAVE_NUTCOMMON=1 -I$(top_srcdir)/include # Make sure out-of-dir dependencies exist (especially when dev-building parts): $(top_builddir)/common/libcommon.la \ $(top_builddir)/common/libcommonclient.la \ $(top_builddir)/common/libparseconf.la: dummy +@cd $(@D) && $(MAKE) $(AM_MAKEFLAGS) $(@F) LDADD_FULL = $(top_builddir)/common/libcommon.la libupsclient.la $(NETLIBS) if WITH_SSL LDADD_FULL += $(LIBSSL_LIBS) $(LIBSSL_LDFLAGS_RPATH) endif WITH_SSL LDADD_CLIENT = $(top_builddir)/common/libcommonclient.la libupsclient.la $(NETLIBS) if WITH_SSL LDADD_CLIENT += $(LIBSSL_LIBS) $(LIBSSL_LDFLAGS_RPATH) endif WITH_SSL # by default, link programs in this directory with # the more compact libcommonclient.a bundle LDADD = $(LDADD_CLIENT) # Avoid per-target CFLAGS, because this will prevent re-use of object # files. In any case, CFLAGS are only -I options, so there is no harm, # but only add them if we really use the target. AM_CFLAGS = -I$(top_srcdir)/include if WITH_SSL AM_CFLAGS += $(LIBSSL_CFLAGS) endif WITH_SSL if WITH_CGI AM_CFLAGS += $(LIBGD_CFLAGS) endif WITH_CGI bin_PROGRAMS = upsc upslog upsrw upscmd dist_bin_SCRIPTS = upssched-cmd sbin_PROGRAMS = upsmon upssched if HAVE_WINDOWS_SOCKETS sbin_PROGRAMS += message endif HAVE_WINDOWS_SOCKETS lib_LTLIBRARIES = libupsclient.la if HAVE_CXX11 lib_LTLIBRARIES += libnutclient.la lib_LTLIBRARIES += libnutclientstub.la endif HAVE_CXX11 # Optionally deliverable as part of NUT public API: if WITH_DEV include_HEADERS = upsclient.h if HAVE_CXX11 include_HEADERS += nutclient.h nutclientmem.h else !HAVE_CXX11 EXTRA_DIST += nutclient.h nutclientmem.h endif !HAVE_CXX11 endif WITH_DEV if WITH_CGI cgiexec_PROGRAMS = upsstats.cgi upsimage.cgi upsset.cgi endif WITH_CGI upsc_SOURCES = upsc.c upsclient.h upscmd_SOURCES = upscmd.c upsclient.h upsrw_SOURCES = upsrw.c upsclient.h upslog_SOURCES = upslog.c upsclient.h upslog.h upslog_LDADD = $(LDADD_FULL) upsmon_SOURCES = upsmon.c upsmon.h upsclient.h upsmon_LDADD = $(LDADD_FULL) if HAVE_WINDOWS_SOCKETS message_SOURCES = message.c endif HAVE_WINDOWS_SOCKETS upssched_SOURCES = upssched.c upssched.h upssched_LDADD = $(top_builddir)/common/libcommonclient.la $(top_builddir)/common/libparseconf.la $(NETLIBS) upsimage_cgi_SOURCES = upsimage.c upsclient.h upsimagearg.h cgilib.c cgilib.h upsimage_cgi_LDADD = $(LDADD) $(LIBGD_LDFLAGS) upsset_cgi_SOURCES = upsset.c upsclient.h cgilib.c cgilib.h upsstats_cgi_SOURCES = upsstats.c upsclient.h status.h upsstats.h \ upsimagearg.h cgilib.c cgilib.h # not LDADD... why? libupsclient_la_SOURCES = upsclient.c upsclient.h libupsclient_la_LIBADD = $(top_builddir)/common/libcommonclient.la if HAVE_WINDOWS_SOCKETS libupsclient_la_LIBADD += -lws2_32 endif HAVE_WINDOWS_SOCKETS if WITH_SSL libupsclient_la_LIBADD += $(LIBSSL_LDFLAGS_RPATH) $(LIBSSL_LIBS) endif WITH_SSL # Below we set API versions of public libraries # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # Note that changes here may have to be reflected in packaging (the shared # object .so names would differ) # libupsclient version information libupsclient_la_LDFLAGS = -version-info 7:0:0 libupsclient_la_LDFLAGS += -export-symbols-regex '^(upscli_|nut_debug_level)' #|s_upsdebug|fatalx|fatal_with_errno|xcalloc|xbasename|print_banner_once)' if HAVE_WINDOWS # Many versions of MingW seem to fail to build non-static DLL without this libupsclient_la_LDFLAGS += -no-undefined endif HAVE_WINDOWS # ./clients/libupsclient.la samples (partial!) on... # Linux: # # The name that we can dlopen(3). # dlname='libupsclient.so.6' # # Names of this library. # library_names='libupsclient.so.6.0.1 libupsclient.so.6 libupsclient.so' # # Directory that this library needs to be installed in: # libdir='/usr/local/ups/lib' # WIN32: # dlname='libupsclient-6.dll' # library_names='libupsclient.dll.a' # libdir='//lib' CLEANFILES += libupsclient-version.h libupsclient-version.h.tmp* libupsclient-version.h: libupsclient.la @echo " GENERATE-HEADER $@" ; \ RES=0; \ dlname_filter() { sed -e 's/^[^=]*=//' -e 's/^"\(.*\)"$$/\1/' -e 's/^'"'"'\(.*\)'"'"'$$/\1/' ; }; \ SOFILE_LIBUPSCLIENT="`grep -E '^dlname' '$?' | dlname_filter`" \ || SOFILE_LIBUPSCLIENT="" ; \ if [ x"$${SOFILE_LIBUPSCLIENT-}" = x ] ; then \ printf "#ifdef SOFILE_LIBUPSCLIENT\n# undef SOFILE_LIBUPSCLIENT\n#endif\n\n" ; \ printf "#ifdef SOPATH_LIBUPSCLIENT\n# undef SOPATH_LIBUPSCLIENT\n#endif\n\n" ; \ else \ printf "#ifndef SOFILE_LIBUPSCLIENT\n# define SOFILE_LIBUPSCLIENT \"%s\"\n#endif\n\n" "$${SOFILE_LIBUPSCLIENT}" ; \ printf "#ifndef SOPATH_LIBUPSCLIENT\n# define SOPATH_LIBUPSCLIENT \"%s/%s\"\n#endif\n\n" "@LIBDIR@" "$${SOFILE_LIBUPSCLIENT}" ; \ fi > "$@".tmp.$$$$ && \ if test -f "$@" && test -s "$@" ; then \ if cmp -s "$@.tmp.$$$$" "$@" ; then \ echo " GENERATE-HEADER $@ did not change" ; \ else \ echo " GENERATE-HEADER $@ got changed" ; \ cp "$@.tmp.$$$$" "$@" ; \ fi ; \ else \ echo " GENERATE-HEADER $@ was absent"; \ cp "$@.tmp.$$$$" "$@" ; \ fi \ || RES=$$?; \ rm -f "$@.tmp.$$$$" ; \ exit $$RES if HAVE_CXX11 # libnutclient version information and build libnutclient_la_SOURCES = nutclient.h nutclient.cpp libnutclient_la_LDFLAGS = -version-info 2:2:0 # Needed in not-standalone builds with -DHAVE_NUTCOMMON=1 # which is defined for in-tree CXX builds above: libnutclient_la_LIBADD = $(top_builddir)/common/libcommonclient.la if HAVE_WINDOWS # Many versions of MingW seem to fail to build non-static DLL without this libnutclient_la_LDFLAGS += -no-undefined endif HAVE_WINDOWS else !HAVE_CXX11 EXTRA_DIST += nutclient.h nutclient.cpp endif !HAVE_CXX11 if HAVE_CXX11 # libnutclientstub version information and build libnutclientstub_la_SOURCES = nutclientmem.h nutclientmem.cpp libnutclientstub_la_LDFLAGS = -version-info 1:1:0 libnutclientstub_la_LIBADD = libnutclient.la if HAVE_WINDOWS # Many versions of MingW seem to fail to build non-static DLL without this libnutclientstub_la_LDFLAGS += -no-undefined endif HAVE_WINDOWS else !HAVE_CXX11 EXTRA_DIST += nutclientmem.h nutclientmem.cpp endif !HAVE_CXX11 dummy: MAINTAINERCLEANFILES = Makefile.in .dirstamp # NOTE: Do not clean ".deps" in SUBDIRS of the main project, # the root Makefile.am takes care of that! #clean-local: # $(AM_V_at)rm -rf $(builddir)/.deps # Helper for only the enabled libs to get built: all-libs-local: $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \ libupsclient-version.h nut-2.8.3/clients/upsstats.c0000644000200500020050000005151714777767434012775 00000000000000/* upsstats - cgi program to generate the main ups info page Copyright (C) 1998 Russell Kroll Copyright (C) 2005 Arnaud Quette This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "nut_stdint.h" #include "timehead.h" #include "upsclient.h" #include "status.h" #include "cgilib.h" #include "parseconf.h" #include "upsstats.h" #include "upsimagearg.h" #define MAX_CGI_STRLEN 128 #define MAX_PARSE_ARGS 16 /* network timeout for initial connection, in seconds */ #define UPSCLI_DEFAULT_CONNECT_TIMEOUT "10" static char *monhost = NULL; static int use_celsius = 1, refreshdelay = -1, treemode = 0; /* from cgilib's checkhost() */ static char *monhostdesc = NULL; static uint16_t port; static char *upsname, *hostname; static char *upsimgpath="upsimage.cgi", *upsstatpath="upsstats.cgi"; static UPSCONN_t ups; static FILE *tf; static long forofs = 0; static ulist_t *ulhead = NULL, *currups = NULL; static int skip_clause = 0, skip_block = 0; void parsearg(char *var, char *value) { /* avoid bogus junk from evil people */ if ((strlen(var) > MAX_CGI_STRLEN) || (strlen(value) > MAX_CGI_STRLEN)) return; if (!strcmp(var, "host")) { free(monhost); monhost = xstrdup(value); return; } if (!strcmp(var, "refresh")) refreshdelay = (int) strtol(value, (char **) NULL, 10); if (!strcmp(var, "treemode")) { /* FIXME: Validate that treemode is allowed */ treemode = 1; } } static void report_error(void) { if (upscli_upserror(&ups) == UPSCLI_ERR_VARNOTSUPP) printf("Not supported\n"); else printf("[error: %s]\n", upscli_strerror(&ups)); } /* make sure we're actually connected to upsd */ static int check_ups_fd(int do_report) { if (upscli_fd(&ups) == -1) { if (do_report) report_error(); return 0; } /* also check for insanity in currups */ if (!currups) { if (do_report) printf("No UPS specified for monitoring\n"); return 0; } /* must be OK */ return 1; } static int get_var(const char *var, char *buf, size_t buflen, int verbose) { int ret; size_t numq, numa; const char *query[4]; char **answer; if (!check_ups_fd(1)) return 0; if (!upsname) { if (verbose) printf("[No UPS name specified]\n"); return 0; } query[0] = "VAR"; query[1] = upsname; query[2] = var; numq = 3; ret = upscli_get(&ups, numq, query, &numa, &answer); if (ret < 0) { if (verbose) report_error(); return 0; } if (numa < numq) { if (verbose) printf("[Invalid response]\n"); return 0; } snprintf(buf, buflen, "%s", answer[3]); return 1; } static void parse_var(const char *var) { char answer[SMALLBUF]; if (!get_var(var, answer, sizeof(answer), 1)) return; printf("%s", answer); } static void do_status(void) { int i; char status[SMALLBUF], *ptr, *last = NULL; if (!get_var("ups.status", status, sizeof(status), 1)) { return; } for (ptr = strtok_r(status, " \n", &last); ptr != NULL; ptr = strtok_r(NULL, " \n", &last)) { /* expand from table in status.h */ for (i = 0; stattab[i].name != NULL; i++) { if (!strcasecmp(ptr, stattab[i].name)) { printf("%s
    ", stattab[i].desc); } } } } static void do_runtime(void) { int total, hours, minutes, seconds; char runtime[SMALLBUF]; if (!get_var("battery.runtime", runtime, sizeof(runtime), 1)) return; total = (int) strtol(runtime, (char **) NULL, 10); hours = total / 3600; minutes = (total - (hours * 3600)) / 60; seconds = total % 60; printf("%02d:%02d:%02d", hours, minutes, seconds); } static int do_date(const char *buf) { char datebuf[SMALLBUF]; time_t tod; struct tm tmbuf; time(&tod); if (strftime(datebuf, sizeof(datebuf), buf, localtime_r(&tod, &tmbuf))) { printf("%s", datebuf); return 1; } return 0; } static int get_img_val(const char *var, const char *desc, const char *imgargs) { char answer[SMALLBUF]; if (!get_var(var, answer, sizeof(answer), 1)) return 1; printf("sys, var); if ((imgargs) && (strlen(imgargs) > 0)) printf("&%s", imgargs); printf("\" ALT=\"%s: %s\">", desc, answer); return 1; } /* see if is valid - table from upsimagearg.h */ static void check_imgarg(char *arg, char *out, size_t outlen) { int i; char *ep; ep = strchr(arg, '='); if (!ep) return; *ep++= '\0'; /* if it's allowed, append it so it can become part of the URL */ for (i = 0; imgarg[i].name != NULL; i++) { if (!strcmp(imgarg[i].name, arg)) { if (strlen(out) == 0) snprintf(out, outlen, "%s=%s", arg, ep); else snprintfcat(out, outlen, "&%s=%s", arg, ep); return; } } } /* split out the var=val commands from the IMG line */ static void split_imgarg(char *in, char *out, size_t outlen) { char *ptr, *sp; if (strlen(in) < 3) return; ptr = in; sp = strchr(ptr, ' '); /* split by spaces, then check each one (can't use parseconf...) */ while (sp) { *sp++ = '\0'; check_imgarg(ptr, out, outlen); ptr = sp; sp = strchr(ptr, ' '); } check_imgarg(ptr, out, outlen); } /* IMG [==] ... */ static int do_img(char *buf) { char *type, *ptr, imgargs[SMALLBUF]; memset(imgargs, '\0', sizeof(imgargs)); type = buf; ptr = strchr(buf, ' '); if (ptr) { *ptr++ = '\0'; split_imgarg(ptr, imgargs, sizeof(imgargs)); } /* only allow known types through */ if (!strcmp(type, "input.voltage") || !strcmp(type, "input.L1-N.voltage") || !strcmp(type, "input.L2-N.voltage") || !strcmp(type, "input.L3-N.voltage") || !strcmp(type, "input.L1-L2.voltage") || !strcmp(type, "input.L2-L3.voltage") || !strcmp(type, "input.L3-L1.voltage")) { return get_img_val(type, "Input voltage", imgargs); } if (!strcmp(type, "battery.voltage")) return get_img_val(type, "Battery voltage", imgargs); if (!strcmp(type, "battery.charge")) return get_img_val(type, "Battery charge", imgargs); if (!strcmp(type, "output.voltage") || !strcmp(type, "output.L1-N.voltage") || !strcmp(type, "output.L2-N.voltage") || !strcmp(type, "output.L3-N.voltage") || !strcmp(type, "output.L1-L2.voltage") || !strcmp(type, "output.L2-L3.voltage") || !strcmp(type, "output.L3-L1.voltage")) { return get_img_val(type, "Output voltage", imgargs); } if (!strcmp(type, "ups.load") || !strcmp(type, "output.L1.power.percent") || !strcmp(type, "output.L2.power.percent") || !strcmp(type, "output.L3.power.percent") || !strcmp(type, "output.L1.realpower.percent") || !strcmp(type, "output.L2.realpower.percent") || !strcmp(type, "output.L3.realpower.percent")) { return get_img_val(type, "UPS load", imgargs); } if (!strcmp(type, "input.frequency")) return get_img_val(type, "Input frequency", imgargs); if (!strcmp(type, "output.frequency")) return get_img_val(type, "Output frequency", imgargs); if (!strcmp(type, "ups.temperature")) return get_img_val(type, "UPS temperature", imgargs); if (!strcmp(type, "ambient.temperature")) return get_img_val(type, "Ambient temperature", imgargs); if (!strcmp(type, "ambient.humidity")) return get_img_val(type, "Ambient humidity", imgargs); return 0; } static void ups_connect(void) { static ulist_t *lastups = NULL; char *newups, *newhost; uint16_t newport; /* try to minimize reconnects */ if (lastups) { /* don't reconnect if these are both the same UPS */ if (!strcmp(lastups->sys, currups->sys)) { lastups = currups; return; } /* see if it's just on the same host */ newups = newhost = NULL; if (upscli_splitname(currups->sys, &newups, &newhost, &newport) != 0) { printf("Unusable UPS definition [%s]\n", currups->sys); fprintf(stderr, "Unusable UPS definition [%s]\n", currups->sys); exit(EXIT_FAILURE); } if ((!strcmp(newhost, hostname)) && (port == newport)) { free(upsname); upsname = newups; free(newhost); lastups = currups; return; } /* not the same upsd, so disconnect */ free(newups); free(newhost); } upscli_disconnect(&ups); free(upsname); free(hostname); if (upscli_splitname(currups->sys, &upsname, &hostname, &port) != 0) { printf("Unusable UPS definition [%s]\n", currups->sys); fprintf(stderr, "Unusable UPS definition [%s]\n", currups->sys); exit(EXIT_FAILURE); } if (upscli_connect(&ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) fprintf(stderr, "UPS [%s]: can't connect to server: %s\n", currups->sys, upscli_strerror(&ups)); lastups = currups; } static void do_hostlink(void) { if (!currups) { return; } printf("sys); if (refreshdelay > 0) { printf("&refresh=%d", refreshdelay); } printf("\">%s", currups->desc); } static void do_treelink(void) { if (!currups) { return; } printf("All data", upsstatpath, currups->sys); } /* see if the UPS supports this variable - skip to the next ENDIF if not */ /* if val is not null, value returned by var must be equal to val to match */ static void do_ifsupp(const char *var, const char *val) { char dummy[SMALLBUF]; /* if not connected, act like it's not supported and skip the rest */ if (!check_ups_fd(0)) { skip_clause = 1; return; } if (!get_var(var, dummy, sizeof(dummy), 0)) { skip_clause = 1; return; } if(!val) { return; } if(strcmp(dummy, val)) { skip_clause = 1; return; } } static int breakargs(char *s, char **aargs) { char *p; int i=0; aargs[i]=NULL; for(p=s; *p && i<(MAX_PARSE_ARGS-1); p++) { if(aargs[i] == NULL) { aargs[i] = p; aargs[i+1] = NULL; } if(*p==' ') { *p='\0'; i++; } } /* Check how many valid args we got */ for(i=0; aargs[i]; i++); return i; } static void do_ifeq(const char *s) { char var[SMALLBUF]; char *aa[MAX_PARSE_ARGS]; int nargs; strcpy(var, s); nargs = breakargs(var, aa); if(nargs != 2) { printf("upsstats: IFEQ: Argument error!\n"); return; } do_ifsupp(aa[0], aa[1]); } /* IFBETWEEN var1 var2 var3. Skip if var3 not between var1 * and var2 */ static void do_ifbetween(const char *s) { char var[SMALLBUF]; char *aa[MAX_PARSE_ARGS]; char tmp[SMALLBUF]; int nargs; long v1, v2, v3; char *isvalid=NULL; strcpy(var, s); nargs = breakargs(var, aa); if(nargs != 3) { printf("upsstats: IFBETWEEN: Argument error!\n"); return; } if (!check_ups_fd(0)) { return; } if (!get_var(aa[0], tmp, sizeof(tmp), 0)) { return; } v1 = strtol(tmp, &isvalid, 10); if(tmp == isvalid) { return; } if (!get_var(aa[1], tmp, sizeof(tmp), 0)) { return; } v2 = strtol(tmp, &isvalid, 10); if(tmp == isvalid) { return; } if (!get_var(aa[2], tmp, sizeof(tmp), 0)) { return; } v3 = strtol(tmp, &isvalid, 10); if(tmp == isvalid) { return; } if(v1 > v3 || v2 < v3) { skip_clause = 1; return; } } static void do_upsstatpath(const char *s) { if(strlen(s)) { upsstatpath = strdup(s); } } static void do_upsimgpath(const char *s) { if(strlen(s)) { upsimgpath = strdup(s); } } static void do_temp(const char *var) { char tempc[SMALLBUF]; double tempf; if (!get_var(var, tempc, sizeof(tempc), 1)) return; if (use_celsius) { printf("%s", tempc); return; } tempf = (strtod(tempc, (char **) NULL) * 1.8) + 32; printf("%.1f", tempf); } static void do_degrees(void) { printf("°"); if (use_celsius) printf("C"); else printf("F"); } /* plug in the right color string (like #FF0000) for the UPS status */ static void do_statuscolor(void) { int severity, i; char stat[SMALLBUF], *sp, *ptr; if (!check_ups_fd(0)) { /* can't print the warning here - give a red error condition */ printf("#FF0000"); return; } if (!get_var("ups.status", stat, sizeof(stat), 0)) { /* status not available - give yellow as a warning */ printf("#FFFF00"); return; } severity = 0; sp = stat; while (sp) { ptr = strchr(sp, ' '); if (ptr) *ptr++ = '\0'; /* expand from table in status.h */ for (i = 0; stattab[i].name != NULL; i++) if (!strcmp(stattab[i].name, sp)) if (stattab[i].severity > severity) severity = stattab[i].severity; sp = ptr; } switch(severity) { case 0: printf("#00FF00"); break; /* green : OK */ case 1: printf("#FFFF00"); break; /* yellow : warning */ default: printf("#FF0000"); break; /* red : error */ } } static int do_command(char *cmd) { /* ending an if block? */ if (!strcmp(cmd, "ENDIF")) { skip_clause = 0; skip_block = 0; return 1; } /* Skipping a block means skip until ENDIF, so... */ if (skip_block) { return 1; } /* Toggle state when we run across ELSE */ if (!strcmp(cmd, "ELSE")) { if (skip_clause) { skip_clause = 0; } else { skip_block = 1; } return 1; } /* don't do any commands if skipping a section */ if (skip_clause == 1) { return 1; } if (!strncmp(cmd, "VAR ", 4)) { parse_var(&cmd[4]); return 1; } if (!strcmp(cmd, "HOST")) { printf("%s", currups->sys); return 1; } if (!strcmp(cmd, "HOSTDESC")) { printf("%s", currups->desc); return 1; } if (!strcmp(cmd, "RUNTIME")) { do_runtime(); return 1; } if (!strcmp(cmd, "STATUS")) { do_status(); return 1; } if (!strcmp(cmd, "STATUSCOLOR")) { do_statuscolor(); return 1; } if (!strcmp(cmd, "TEMPF")) { use_celsius = 0; return 1; } if (!strcmp(cmd, "TEMPC")) { use_celsius = 1; return 1; } if (!strncmp(cmd, "DATE ", 5)) { return do_date(&cmd[5]); } if (!strncmp(cmd, "IMG ", 4)) { return do_img(&cmd[4]); } if (!strcmp(cmd, "VERSION")) { printf("%s", UPS_VERSION); return 1; } if (!strcmp(cmd, "REFRESH")) { if (refreshdelay > 0) { printf("", refreshdelay); } return 1; } if (!strcmp(cmd, "FOREACHUPS")) { forofs = ftell(tf); currups = ulhead; ups_connect(); return 1; } if (!strcmp(cmd, "ENDFOR")) { /* if not in a for, ignore this */ if (forofs == 0) { return 1; } currups = currups->next; if (currups) { fseek(tf, forofs, SEEK_SET); ups_connect(); } return 1; } if (!strcmp(cmd, "HOSTLINK")) { do_hostlink(); return 1; } if (!strcmp(cmd, "TREELINK")) { do_treelink(); return 1; } if (!strncmp(cmd, "IFSUPP ", 7)) { do_ifsupp(&cmd[7], NULL); return 1; } if (!strcmp(cmd, "UPSTEMP")) { do_temp("ups.temperature"); return 1; } if (!strcmp(cmd, "BATTTEMP")) { do_temp("battery.temperature"); return 1; } if (!strcmp(cmd, "AMBTEMP")) { do_temp("ambient.temperature"); return 1; } if (!strcmp(cmd, "DEGREES")) { do_degrees(); return 1; } if (!strncmp(cmd, "IFEQ ", 5)) { do_ifeq(&cmd[5]); return 1; } if (!strncmp(cmd, "IFBETWEEN ", 10)) { do_ifbetween(&cmd[10]); return 1; } if (!strncmp(cmd, "UPSSTATSPATH ", 13)) { do_upsstatpath(&cmd[13]); return 1; } if (!strncmp(cmd, "UPSIMAGEPATH ", 13)) { do_upsimgpath(&cmd[13]); return 1; } return 0; } static void parse_line(const char *buf) { char cmd[SMALLBUF]; size_t i, len; char do_cmd = 0; for (i = 0; buf[i]; i += len) { len = strcspn(&buf[i], "@"); if (len == 0) { if (do_cmd) { do_command(cmd); do_cmd = 0; } else { cmd[0] = '\0'; do_cmd = 1; } i++; /* skip over the '@' character */ continue; } assert (len < INT_MAX); if (do_cmd) { snprintf(cmd, sizeof(cmd), "%.*s", (int)len, &buf[i]); continue; } if (skip_clause || skip_block) { /* ignore this */ continue; } /* pass it trough */ printf("%.*s", (int)len, &buf[i]); } } static void display_template(const char *tfn) { char fn[NUT_PATH_MAX + 1], buf[LARGEBUF]; snprintf(fn, sizeof(fn), "%s/%s", confpath(), tfn); tf = fopen(fn, "r"); if (!tf) { fprintf(stderr, "upsstats: Can't open %s: %s\n", fn, strerror(errno)); printf("Error: can't open template file (%s)\n", tfn); exit(EXIT_FAILURE); } while (fgets(buf, sizeof(buf), tf)) { parse_line(buf); } fclose(tf); } static void display_tree(int verbose) { size_t numq, numa; const char *query[4]; char **answer; if (!upsname) { if (verbose) printf("[No UPS name specified]\n"); return; } query[0] = "VAR"; query[1] = upsname; numq = 2; if (upscli_list_start(&ups, numq, query) < 0) { if (verbose) report_error(); return; } printf("\n"); printf("\n"); printf("upsstat: data tree of %s\n", currups->desc); printf("\n"); printf("\n"); printf("
    \n"); printf("\n"); /* include the description from checkhost() if present */ printf("\n"); printf("\n"); while (upscli_list_next(&ups, numq, query, &numa, &answer) == 1) { /* VAR */ if (numa < 4) { if (verbose) printf("[Invalid response]\n"); return; } printf("\n"); printf("\n", answer[2]); printf("\n"); printf("\n", answer[3]); printf("\n"); } printf("
    \n"); printf("%s\n", currups->desc); printf("
    %s:%s
    \n"); printf("
    \n"); /* FIXME (AQ): add a save button (?), and a checkbt for showing var.desc */ printf("\n"); } static void add_ups(char *sys, char *desc) { ulist_t *tmp, *last; tmp = last = ulhead; while (tmp) { last = tmp; tmp = tmp->next; } tmp = xmalloc(sizeof(ulist_t)); tmp->sys = xstrdup(sys); tmp->desc = xstrdup(desc); tmp->next = NULL; if (last) last->next = tmp; else ulhead = tmp; } /* called for fatal errors in parseconf like malloc failures */ static void upsstats_hosts_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf(hosts.conf): %s", errmsg); } static void load_hosts_conf(void) { char fn[NUT_PATH_MAX + 1]; PCONF_CTX_t ctx; snprintf(fn, sizeof(fn), "%s/hosts.conf", CONFPATH); pconf_init(&ctx, upsstats_hosts_err); if (!pconf_file_begin(&ctx, fn)) { pconf_finish(&ctx); printf("\n"); printf("\n"); printf("Error: can't open hosts.conf\n"); printf("\n"); printf("Error: can't open hosts.conf\n"); printf("\n"); /* leave something for the admin */ fprintf(stderr, "upsstats: %s\n", ctx.errmsg); exit(EXIT_FAILURE); } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { upslogx(LOG_ERR, "Parse error: %s:%d: %s", fn, ctx.linenum, ctx.errmsg); continue; } if (ctx.numargs < 3) continue; /* MONITOR */ if (!strcmp(ctx.arglist[0], "MONITOR")) add_ups(ctx.arglist[1], ctx.arglist[2]); } pconf_finish(&ctx); if (!ulhead) { printf("\n"); printf("\n"); printf("Error: no hosts to monitor\n"); printf("\n"); printf("Error: no hosts to monitor (check hosts.conf)\n"); printf("\n"); /* leave something for the admin */ fprintf(stderr, "upsstats: no hosts to monitor\n"); exit(EXIT_FAILURE); } } static void display_single(void) { if (!checkhost(monhost, &monhostdesc)) { printf("Access to that host [%s] is not authorized.\n", monhost); exit(EXIT_FAILURE); } add_ups(monhost, monhostdesc); currups = ulhead; ups_connect(); /* switch between data tree view and standard single view */ if (treemode) display_tree(1); else display_template("upsstats-single.html"); upscli_disconnect(&ups); } int main(int argc, char **argv) { NUT_UNUSED_VARIABLE(argc); NUT_UNUSED_VARIABLE(argv); extractcgiargs(); upscli_init_default_connect_timeout(NULL, NULL, UPSCLI_DEFAULT_CONNECT_TIMEOUT); printf("Content-type: text/html\n"); printf("Pragma: no-cache\n"); printf("\n"); /* if a host is specified, use upsstats-single.html instead */ if (monhost) { display_single(); exit(EXIT_SUCCESS); } /* default: multimon replacement mode */ load_hosts_conf(); currups = ulhead; display_template("upsstats.html"); upscli_disconnect(&ups); return 0; } nut-2.8.3/clients/upssched-cmd0000755000200500020050000000314014777767434013235 00000000000000#! /bin/sh # # This script should be called by upssched via the CMDSCRIPT directive. # # Here is a quick example to show how to handle a bunch of possible # timer names with the help of the case structure. # # This script may be replaced with another program without harm # (just be sure to avoid clashes with package-delivered files # which might overwrite your custom changes). # # The first argument passed to your CMDSCRIPT is the name of the timer # from your AT lines in upssched.conf. # Feel free to remove or comment away these lines when you actually # customize the script for your deployment: echo "`date -u`: $0: THIS IS A SAMPLE SCRIPT, PLEASE TAILOR IT FOR YOUR DEPLOYMENT OF NUT!" >&2 logger -t upssched-cmd "THIS IS A SAMPLE SCRIPT, PLEASE TAILOR IT FOR YOUR DEPLOYMENT OF NUT!" printf "`date -u`: UPSNAME='%s'\tNOTIFYTYPE='%s'\targs=%s\n" "$UPSNAME" "$NOTIFYTYPE" "$@" >&2 printf "UPSNAME='%s' NOTIFYTYPE='%s' args=%s\n" "$UPSNAME" "$NOTIFYTYPE" "$@" | logger -t upssched-cmd-received-NOTIFYTYPE #set # Handle received timer names, as defined in your upssched.conf (example): case "$1" in onbattwarn) # Send a notification mail echo "The UPS has been on battery for awhile" \ | mail -s"UPS monitor" bofh@pager.example.com # Create a flag-file on the filesystem, for your own processing /usr/bin/touch /some/path/ups-on-battery ;; ups-back-on-power) # Delete the flag-file on the filesystem /bin/rm -f /some/path/ups-on-battery ;; upsgone) logger -t upssched-cmd "The communication with UPS has been gone for awhile" ;; *) logger -t upssched-cmd "Unrecognized command: $1" ;; esac nut-2.8.3/clients/nutclient.h0000644000200500020050000007544714777767434013131 00000000000000/* nutclient.h - definitions for nutclient C/C++ library Copyright (C) 2012 Emilien Kia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUTCLIENT_HPP_SEEN #define NUTCLIENT_HPP_SEEN 1 /* Begin of C++ nutclient library declaration */ #ifdef __cplusplus #include #include #include #include #include #include #include /* See include/common.h for details behind this */ #ifndef NUT_UNUSED_VARIABLE #define NUT_UNUSED_VARIABLE(x) (void)(x) #endif namespace nut { namespace internal { class Socket; } /* namespace internal */ class Client; class TcpClient; class Device; class Variable; class Command; /** * Basic nut exception. */ class NutException : public std::exception { public: NutException(const std::string& msg):_msg(msg){} NutException(const NutException&) = default; NutException& operator=(NutException& rhs) = default; virtual ~NutException() noexcept override; virtual const char * what() const noexcept override {return this->_msg.c_str();} virtual std::string str() const noexcept {return this->_msg;} private: std::string _msg; }; /** * System error. */ class SystemException : public NutException { public: SystemException(); SystemException(const SystemException&) = default; SystemException& operator=(SystemException& rhs) = default; virtual ~SystemException() noexcept override; private: static std::string err(); }; /** * IO oriented nut exception. */ class IOException : public NutException { public: IOException(const std::string& msg):NutException(msg){} IOException(const IOException&) = default; IOException& operator=(IOException& rhs) = default; virtual ~IOException() noexcept override; }; /** * IO oriented nut exception specialized for unknown host */ class UnknownHostException : public IOException { public: UnknownHostException():IOException("Unknown host"){} UnknownHostException(const UnknownHostException&) = default; UnknownHostException& operator=(UnknownHostException& rhs) = default; virtual ~UnknownHostException() noexcept override; }; /** * IO oriented nut exception when client is not connected */ class NotConnectedException : public IOException { public: NotConnectedException():IOException("Not connected"){} NotConnectedException(const NotConnectedException&) = default; NotConnectedException& operator=(NotConnectedException& rhs) = default; virtual ~NotConnectedException() noexcept override; }; /** * IO oriented nut exception when there is no response. */ class TimeoutException : public IOException { public: TimeoutException():IOException("Timeout"){} TimeoutException(const TimeoutException&) = default; TimeoutException& operator=(TimeoutException& rhs) = default; virtual ~TimeoutException() noexcept override; }; /** * Cookie given when performing async action, used to redeem result at a later date. */ typedef std::string TrackingID; /** * Result of an async action. */ typedef enum { UNKNOWN, PENDING, SUCCESS, INVALID_ARGUMENT, FAILURE, } TrackingResult; typedef std::string Feature; /** * A nut client is the starting point to dialog to NUTD. * It can connect to an NUTD then retrieve its device list. * Use a specific client class to connect to a NUTD. */ class Client { friend class Device; friend class Variable; friend class Command; public: virtual ~Client(); /** * Intend to authenticate to a NUTD server. * Set the username and password associated to the connection. * \param user User name. * \param passwd Password. * \todo Is his method is global to all connection protocol or is it specific to TCP ? * \note Actually, authentication fails only if already set, not if bad values are sent. */ virtual void authenticate(const std::string& user, const std::string& passwd) = 0; /** * Disconnect from the NUTD server. * \todo Is his method is global to all connection protocol or is it specific to TCP ? */ virtual void logout() = 0; /** * Device manipulations. * \see nut::Device * \{ */ /** * Retrieve a device from its name. * If the device does not exist, a bad (not ok) device is returned. * \param name Name of the device. * \return The device. */ virtual Device getDevice(const std::string& name); /** * Retrieve the list of all devices supported by UPSD server. * \return The set of supported devices. */ virtual std::set getDevices(); /** * Test if a device is supported by the NUTD server. * \param dev Device name. * \return true if supported, false otherwise. */ virtual bool hasDevice(const std::string& dev); /** * Retrieve names of devices supported by NUTD server. * \return The set of names of supported devices. */ virtual std::set getDeviceNames() = 0; /** * Retrieve the description of a device. * \param name Device name. * \return Device description. */ virtual std::string getDeviceDescription(const std::string& name) = 0; /** \} */ /** * Variable manipulations. * \see nut::Variable * \{ */ /** * Retrieve names of all variables supported by a device. * \param dev Device name * \return Variable names */ virtual std::set getDeviceVariableNames(const std::string& dev) = 0; /** * Retrieve names of read/write variables supported by a device. * \param dev Device name * \return RW variable names */ virtual std::set getDeviceRWVariableNames(const std::string& dev) = 0; /** * Test if a variable is supported by a device. * \param dev Device name * \param name Variable name * \return true if the variable is supported. */ virtual bool hasDeviceVariable(const std::string& dev, const std::string& name); /** * Retrieve the description of a variable. * \param dev Device name * \param name Variable name * \return Variable description if provided. */ virtual std::string getDeviceVariableDescription(const std::string& dev, const std::string& name) = 0; /** * Retrieve values of a variable. * \param dev Device name * \param name Variable name * \return Variable values (usually one) if available. */ virtual std::vector getDeviceVariableValue(const std::string& dev, const std::string& name) = 0; /** * Retrieve values of all variables of a device. * \param dev Device name * \return Variable values indexed by variable names. */ virtual std::map > getDeviceVariableValues(const std::string& dev); /** * Retrieve values of all variables of a set of devices. * \param devs Device names * \return Variable values indexed by variable names, indexed by device names. */ virtual std::map > > getDevicesVariableValues(const std::set& devs); /** * Intend to set the value of a variable. * \param dev Device name * \param name Variable name * \param value Variable value */ virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::string& value) = 0; /** * Intend to set the value of a variable. * \param dev Device name * \param name Variable name * \param values Vector of variable values */ virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::vector& values) = 0; /** \} */ /** * Instant command manipulations. * \see nut::Command * \{ */ /** * Retrieve names of all commands supported by a device. * \param dev Device name * \return Command names */ virtual std::set getDeviceCommandNames(const std::string& dev) = 0; /** * Test if a command is supported by a device. * \param dev Device name * \param name Command name * \return true if the command is supported. */ virtual bool hasDeviceCommand(const std::string& dev, const std::string& name); /** * Retrieve the description of a command. * \param dev Device name * \param name Command name * \return Command description if provided. */ virtual std::string getDeviceCommandDescription(const std::string& dev, const std::string& name) = 0; /** * Intend to execute a command. * \param dev Device name * \param name Command name * \param param Additional command parameter */ virtual TrackingID executeDeviceCommand(const std::string& dev, const std::string& name, const std::string& param="") = 0; /** \} */ /** * Device specific commands. * \{ */ /** * Log the current user (if authenticated) for a device. * \param dev Device name. */ virtual void deviceLogin(const std::string& dev) = 0; /** * Retrieve the number of user logged-in for the specified device. * \param dev Device name. * \return Number of logged-in users. */ virtual int deviceGetNumLogins(const std::string& dev) = 0; /** * Who did a deviceLogin() to this dev? * \param dev Device name. * \return List of clients e.g. {'127.0.0.1', 'admin-workstation.local.domain'} */ virtual std::set deviceGetClients(const std::string& dev) = 0; /* NOTE: "master" is deprecated since NUT v2.8.0 in favor of "primary". * For the sake of old/new server/client interoperability, * practical implementations should try to use one and fall * back to the other, and only fail if both return "ERR". */ virtual void deviceMaster(const std::string& dev) = 0; virtual void devicePrimary(const std::string& dev) = 0; virtual void deviceForcedShutdown(const std::string& dev) = 0; /** * Lists all clients of all devices (which have at least one client) * \return Map with device names vs. list of their connected clients */ virtual std::map> listDeviceClients(void) = 0; /** * Retrieve the result of a tracking ID. * \param id Tracking ID. */ virtual TrackingResult getTrackingResult(const TrackingID& id) = 0; virtual bool hasFeature(const Feature& feature); virtual bool isFeatureEnabled(const Feature& feature) = 0; virtual void setFeature(const Feature& feature, bool status) = 0; static const Feature TRACKING; protected: Client(); }; /** * TCP NUTD client. * It connect to NUTD with a TCP socket. */ class TcpClient : public Client { /* We have a number of direct-call methods we do not expose * generally, but still want covered with integration tests */ friend class NutActiveClientTest; public: /** * Construct a nut TcpClient object. * You must call one of TcpClient::connect() after. */ TcpClient(); /** * Construct a nut TcpClient object then connect it to the specified server. * \param host Server host name. * \param port Server port. */ TcpClient(const std::string& host, uint16_t port = 3493); ~TcpClient() override; /** * Connect it to the specified server. * \param host Server host name. * \param port Server port. */ void connect(const std::string& host, uint16_t port = 3493); /** * Connect to the server. * Host name and ports must have already set (useful for reconnection). */ void connect(); /** * Enable or disable std::cerr tracing of internal Socket operations * during connect() processing. Primarily for developer troubleshooting. */ void setDebugConnect(bool d); /** * Test if the connection is active. * \return tru if the connection is active. */ bool isConnected()const; /** * Force the deconnection. */ void disconnect(); /** * Set the timeout in seconds. * \param timeout Timeout n seconds, negative to block operations. */ void setTimeout(time_t timeout); /** * Retrieve the timeout. * \returns Current timeout in seconds. */ time_t getTimeout()const; /** * Retriueve the host name of the server the client is connected to. * \return Server host name */ std::string getHost()const; /** * Retriueve the port of host of the server the client is connected to. * \return Server port */ uint16_t getPort()const; virtual void authenticate(const std::string& user, const std::string& passwd) override; virtual void logout() override; virtual Device getDevice(const std::string& name) override; virtual std::set getDeviceNames() override; virtual std::string getDeviceDescription(const std::string& name) override; virtual std::set getDeviceVariableNames(const std::string& dev) override; virtual std::set getDeviceRWVariableNames(const std::string& dev) override; virtual std::string getDeviceVariableDescription(const std::string& dev, const std::string& name) override; virtual std::vector getDeviceVariableValue(const std::string& dev, const std::string& name) override; virtual std::map > getDeviceVariableValues(const std::string& dev) override; virtual std::map > > getDevicesVariableValues(const std::set& devs) override; virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::string& value) override; virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::vector& values) override; virtual std::set getDeviceCommandNames(const std::string& dev) override; virtual std::string getDeviceCommandDescription(const std::string& dev, const std::string& name) override; virtual TrackingID executeDeviceCommand(const std::string& dev, const std::string& name, const std::string& param="") override; virtual void deviceLogin(const std::string& dev) override; /* FIXME: Protocol update needed to handle master/primary alias * and probably an API bump also, to rename/alias the routine. */ virtual void deviceMaster(const std::string& dev) override; virtual void devicePrimary(const std::string& dev) override; virtual void deviceForcedShutdown(const std::string& dev) override; virtual int deviceGetNumLogins(const std::string& dev) override; virtual std::set deviceGetClients(const std::string& dev) override; virtual std::map> listDeviceClients(void) override; virtual TrackingResult getTrackingResult(const TrackingID& id) override; virtual bool isFeatureEnabled(const Feature& feature) override; virtual void setFeature(const Feature& feature, bool status) override; protected: std::string sendQuery(const std::string& req); void sendAsyncQueries(const std::vector& req); static void detectError(const std::string& req); TrackingID sendTrackingQuery(const std::string& req); std::vector get(const std::string& subcmd, const std::string& params = ""); std::vector > list(const std::string& subcmd, const std::string& params = ""); std::vector > parseList(const std::string& req); static std::vector explode(const std::string& str, size_t begin=0); static std::string escape(const std::string& str); private: std::string _host; uint16_t _port; time_t _timeout; internal::Socket* _socket; }; /** * Device attached to a client. * Device is a lightweight class which can be copied easily. */ class Device { friend class Client; friend class TcpClient; friend class TcpClientMock; #ifdef _NUTCLIENTTEST_BUILD friend class NutClientTest; #endif public: ~Device(); Device(const Device& dev); Device& operator=(const Device& dev); /** * Retrieve the name of the device. * The name is the unique id under which NUTD known the device. */ std::string getName()const; /** * Retrieve the client to which the device is attached. */ const Client* getClient()const; /** * Retrieve the client to which the device is attached. */ Client* getClient(); /** * Test if the device is valid (has a name and is attached to a client). */ bool isOk()const; /** * Test if the device is valid (has a name and is attached to a client). * @see Device::isOk() */ operator bool()const; /** * Test if the device is not valid (has no name or is not attached to any client). * @see Device::isOk() */ bool operator!()const; /** * Test if the two devices are sames (same name ad same client attached to). */ bool operator==(const Device& dev)const; /** * Comparison operator. */ bool operator<(const Device& dev)const; /** * Retrieve the description of the devce if specified. */ std::string getDescription(); /** * Intend to retrieve the value of a variable of the device. * \param name Name of the variable to get. * \return Value of the variable, if available. */ std::vector getVariableValue(const std::string& name); /** * Intend to retrieve values of all variables of the devices. * \return Map of all variables values indexed by their names. */ std::map > getVariableValues(); /** * Retrieve all variables names supported by the device. * \return Set of available variable names. */ std::set getVariableNames(); /** * Retrieve all Read/Write variables names supported by the device. * \return Set of available Read/Write variable names. */ std::set getRWVariableNames(); /** * Intend to set the value of a variable of the device. * \param name Variable name. * \param value New variable value. */ void setVariable(const std::string& name, const std::string& value); /** * Intend to set values of a variable of the device. * \param name Variable name. * \param values Vector of new variable values. */ void setVariable(const std::string& name, const std::vector& values); /** * Retrieve a Variable object representing the specified variable. * \param name Variable name. * \return Variable object. */ Variable getVariable(const std::string& name); /** * Retrieve Variable objects representing all variables available for the device. * \return Set of Variable objects. */ std::set getVariables(); /** * Retrieve Variable objects representing all Read/Write variables available for the device. * \return Set of Variable objects. */ std::set getRWVariables(); /** * Retrieve names of all commands supported by the device. * \return Set of available command names. */ std::set getCommandNames(); /** * Retrieve objects for all commands supported by the device. * \return Set of available Command objects. */ std::set getCommands(); /** * Retrieve an object representing a command of the device. * \param name Command name. * \return Command object. */ Command getCommand(const std::string& name); /** * Intend to execute a command on the device. * \param name Command name. * \param param Additional command parameter */ TrackingID executeCommand(const std::string& name, const std::string& param=""); /** * Login current client's user for the device. */ void login(); /** * Who did a login() to this dev? */ std::set getClients(); /* FIXME: Protocol update needed to handle master/primary alias * and probably an API bump also, to rename/alias the routine. */ void master(); void primary(); void forcedShutdown(); /** * Retrieve the number of logged user for the device. * \return Number of users. */ int getNumLogins(); protected: Device(Client* client, const std::string& name); private: Client* _client; std::string _name; }; /** * Variable attached to a device. * Variable is a lightweight class which can be copied easily. */ class Variable { friend class Device; friend class TcpClient; friend class TcpClientMock; #ifdef _NUTCLIENTTEST_BUILD friend class NutClientTest; #endif public: ~Variable(); Variable(const Variable& var); Variable& operator=(const Variable& var); /** * Retrieve variable name. */ std::string getName()const; /** * Retrieve the device to which the variable is attached to. */ const Device* getDevice()const; /** * Retrieve the device to which the variable is attached to. */ Device* getDevice(); /** * Test if the variable is valid (has a name and is attached to a device). */ bool isOk()const; /** * Test if the variable is valid (has a name and is attached to a device). * @see Variable::isOk() */ operator bool()const; /** * Test if the variable is not valid (has no name or is not attached to any device). * @see Variable::isOk() */ bool operator!()const; /** * Test if the two variables are sames (same name ad same device attached to). */ bool operator==(const Variable& var)const; /** * Less-than operator (based on variable name) to allow variable sorting. */ bool operator<(const Variable& var)const; /** * Intend to retrieve variable value. * \return Value of the variable. */ std::vector getValue(); /** * Intend to retireve variable description. * \return Variable description if provided. */ std::string getDescription(); /** * Intend to set a value to the variable. * \param value New variable value. */ void setValue(const std::string& value); /** * Intend to set (multiple) values to the variable. * \param values Vector of new variable values. */ void setValues(const std::vector& values); protected: Variable(Device* dev, const std::string& name); private: Device* _device; std::string _name; }; /** * Command attached to a device. * Command is a lightweight class which can be copied easily. */ class Command { friend class Device; friend class TcpClient; friend class TcpClientMock; #ifdef _NUTCLIENTTEST_BUILD friend class NutClientTest; #endif public: ~Command(); Command(const Command& cmd); Command& operator=(const Command& cmd); /** * Retrieve command name. */ std::string getName()const; /** * Retrieve the device to which the command is attached to. */ const Device* getDevice()const; /** * Retrieve the device to which the command is attached to. */ Device* getDevice(); /** * Test if the command is valid (has a name and is attached to a device). */ bool isOk()const; /** * Test if the command is valid (has a name and is attached to a device). * @see Command::isOk() */ operator bool()const; /** * Test if the command is not valid (has no name or is not attached to any device). * @see Command::isOk() */ bool operator!()const; /** * Test if the two commands are sames (same name ad same device attached to). */ bool operator==(const Command& var)const; /** * Less-than operator (based on command name) to allow comand sorting. */ bool operator<(const Command& var)const; /** * Intend to retireve command description. * \return Command description if provided. */ std::string getDescription(); /** * Intend to execute the instant command on device. * \param param Optional additional command parameter */ void execute(const std::string& param=""); protected: Command(Device* dev, const std::string& name); private: Device* _device; std::string _name; }; } /* namespace nut */ #endif /* __cplusplus */ /* End of C++ nutclient library declaration */ /* Begin of C nutclient library declaration */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * Array of string manipulation functions. * \{ */ /** Array of string.*/ typedef char** strarr; /** * Alloc an array of string. */ strarr strarr_alloc(size_t count); /** * Free an array of string. */ void strarr_free(strarr arr); /** * Convert C++ types into an array of string. */ strarr stringvector_to_strarr(const std::vector& strset); strarr stringset_to_strarr(const std::set& strset); /** * Nut general client types and functions. * \{ */ /** Hidden structure representing a connection to NUTD. */ typedef void* NUTCLIENT_t; /** * Destroy a client. * \param client Nut client handle. */ void nutclient_destroy(NUTCLIENT_t client); /** * Authenticate into the server. * \param client Nut client handle. * \param login User name. * \param passwd Password. */ void nutclient_authenticate(NUTCLIENT_t client, const char* login, const char* passwd); /** * Log out from server. * \param client Nut client handle. */ void nutclient_logout(NUTCLIENT_t client); /** * Register current user on the device. * \param client Nut client handle. * \param dev Device name to test. */ void nutclient_device_login(NUTCLIENT_t client, const char* dev); /** * Retrieve the number of users registered on a device. * \param client Nut client handle. * \param dev Device name to test. */ int nutclient_get_device_num_logins(NUTCLIENT_t client, const char* dev); /** * Set current user as master user of the device. * \param client Nut client handle. * \param dev Device name to test. */ /* FIXME: Protocol update needed to handle master/primary alias * and probably an API bump also, to rename/alias the routine. */ void nutclient_device_master(NUTCLIENT_t client, const char* dev); void nutclient_device_primary(NUTCLIENT_t client, const char* dev); /** * Set the FSD flag for the device. * \param client Nut client handle. * \param dev Device name to test. */ void nutclient_device_forced_shutdown(NUTCLIENT_t client, const char* dev); /** * Retrieve the list of devices of a client. * \param client Nut client handle. * \return Array of string containing device names. Must be freed with strarr_free(strarr). */ strarr nutclient_get_devices(NUTCLIENT_t client); /** * Test if a device is supported by the client. * \param client Nut client handle. * \param dev Device name to test. * \return 1 if supported, 0 otherwise. */ int nutclient_has_device(NUTCLIENT_t client, const char* dev); /** * Intend to retrieve device description. * \param client Nut client handle. * \param dev Device name to test. * \return Description of device. Must be freed after use. */ char* nutclient_get_device_description(NUTCLIENT_t client, const char* dev); /** * Intend to retrieve device variable names. * \param client Nut client handle. * \param dev Device name. * \return Array of string containing variable names. Must be freed with strarr_free(strarr). */ strarr nutclient_get_device_variables(NUTCLIENT_t client, const char* dev); /** * Intend to retrieve device read/write variable names. * \param client Nut client handle. * \param dev Device name. * \return Array of string containing read/write variable names. Must be freed with strarr_free(strarr). */ strarr nutclient_get_device_rw_variables(NUTCLIENT_t client, const char* dev); /** * Test if a variable is supported by the device and the client. * \param client Nut client handle. * \param dev Device name. * \param var Variable name. * \return 1 if supported, 0 otherwise. */ int nutclient_has_device_variable(NUTCLIENT_t client, const char* dev, const char* var); /** * Intend to retrieve device variable description. * \param client Nut client handle. * \param dev Device name. * \param var Variable name. * \return Description of device variable. Must be freed after use. */ char* nutclient_get_device_variable_description(NUTCLIENT_t client, const char* dev, const char* var); /** * Intend to retrieve device variable values. * \param client Nut client handle. * \param dev Device name. * \param var Variable name. * \return Array of string containing variable values. Must be freed with strarr_free(strarr). */ strarr nutclient_get_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var); /** * Intend to set device variable value. * \param client Nut client handle. * \param dev Device name. * \param var Variable name. * \param value Value to set. */ void nutclient_set_device_variable_value(NUTCLIENT_t client, const char* dev, const char* var, const char* value); /** * Intend to set device variable multiple values. * \param client Nut client handle. * \param dev Device name. * \param var Variable name. * \param values Values to set. The cller is responsible to free it after call. */ void nutclient_set_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var, const strarr values); /** * Intend to retrieve device command names. * \param client Nut client handle. * \param dev Device name. * \return Array of string containing command names. Must be freed with strarr_free(strarr). */ strarr nutclient_get_device_commands(NUTCLIENT_t client, const char* dev); /** * Test if a command is supported by the device and the client. * \param client Nut client handle. * \param dev Device name. * \param cmd Command name. * \return 1 if supported, 0 otherwise. */ int nutclient_has_device_command(NUTCLIENT_t client, const char* dev, const char* cmd); /** * Intend to retrieve device command description. * \param client Nut client handle. * \param dev Device name. * \param cmd Command name. * \return Description of device command. Must be freed after use. */ char* nutclient_get_device_command_description(NUTCLIENT_t client, const char* dev, const char* cmd); /** * Intend to execute device command. * \param client Nut client handle. * \param dev Device name. * \param cmd Command name. */ void nutclient_execute_device_command(NUTCLIENT_t client, const char* dev, const char* cmd, const char* param=""); /** \} */ /** * Nut TCP client dedicated types and functions * \{ */ /** * Hidden structure representing a TCP connection to NUTD. * NUTCLIENT_TCP_t is back compatible to NUTCLIENT_t. */ typedef NUTCLIENT_t NUTCLIENT_TCP_t; /** * Create a client to NUTD using a TCP connection. * \param host Host name to connect to. * \param port Host port. * \return New client or nullptr if failed. */ NUTCLIENT_TCP_t nutclient_tcp_create_client(const char* host, uint16_t port); /** * Test if a nut TCP client is connected. * \param client Nut TCP client handle. * \return 1 if connected, 0 otherwise. */ int nutclient_tcp_is_connected(NUTCLIENT_TCP_t client); /** * Disconnect a nut TCP client. * \param client Nut TCP client handle. */ void nutclient_tcp_disconnect(NUTCLIENT_TCP_t client); /** * Intend to reconnect a nut TCP client. * \param client Nut TCP client handle. * \return 0 if correctly connected. * \todo Implement different error codes. */ int nutclient_tcp_reconnect(NUTCLIENT_TCP_t client); /** * Set the timeout value for the TCP connection. * \param timeout Timeout in seconds, negative for blocking. */ void nutclient_tcp_set_timeout(NUTCLIENT_TCP_t client, time_t timeout); /** * Retrieve the timeout value for the TCP connection. * \return Timeout value in seconds. */ time_t nutclient_tcp_get_timeout(NUTCLIENT_TCP_t client); /** \} */ #ifdef __cplusplus } #endif /* __cplusplus */ /* End of C nutclient library declaration */ #endif /* NUTCLIENT_HPP_SEEN */ nut-2.8.3/clients/cgilib.c0000644000200500020050000001034414777767434012331 00000000000000/* cgilib - common routines for CGI programs Copyright (C) 1999 Russell Kroll This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include #include #include "cgilib.h" #include "parseconf.h" static char *unescape(char *buf) { size_t i, buflen; char ch, *newbuf, hex[8]; buflen = strlen(buf) + 2; newbuf = xmalloc(buflen); *newbuf = '\0'; fflush(stdout); for (i = 0; i < buflen - 1; i++) { ch = buf[i]; if (ch == '+') ch = ' '; if (ch == '%') { long l; if (i + 2 > buflen) fatalx(EXIT_FAILURE, "string too short for escaped char"); hex[0] = buf[++i]; hex[1] = buf[++i]; hex[2] = '\0'; if (!isxdigit((unsigned char) hex[0]) || !isxdigit((unsigned char) hex[1])) fatalx(EXIT_FAILURE, "bad escape char"); l = strtol(hex, NULL, 16); assert(l>=0); assert(l<=255); ch = (char)l; /* FIXME: Loophole about non-ASCII symbols in top 128 values, or negatives for signed char... */ if ((ch == 10) || (ch == 13)) ch = ' '; } snprintfcat(newbuf, buflen, "%c", ch); } return newbuf; } void extractcgiargs(void) { char *query, *ptr, *eq, *varname, *value, *amp; char *cleanval, *cleanvar; query = getenv("QUERY_STRING"); if (query == NULL) return; /* not run as a cgi script! */ if (strlen(query) == 0) return; /* no query string to parse! */ /* varname=value&varname=value&varname=value ... */ ptr = query; while (ptr) { varname = ptr; eq = strchr(varname, '='); if (!eq) { ptr = strchr(varname, '&'); if (ptr) *ptr++ = '\0'; cleanvar = unescape(varname); parsearg(cleanvar, ""); free(cleanvar); continue; } *eq = '\0'; value = eq + 1; amp = strchr(value, '&'); if (amp) { ptr = amp + 1; *amp = '\0'; } else ptr = NULL; cleanvar = unescape(varname); cleanval = unescape(value); parsearg(cleanvar, cleanval); free(cleanvar); free(cleanval); } } void extractpostargs(void) { char buf[SMALLBUF], *ptr, *cleanval; int ch; ch = fgetc(stdin); buf[0] = '\0'; while (ch != EOF) { if (ch == '&') { ptr = strchr(buf, '='); if (!ptr) parsearg(buf, ""); else { *ptr++ = '\0'; cleanval = unescape(ptr); parsearg(buf, cleanval); free(cleanval); } buf[0] = '\0'; } else snprintfcat(buf, sizeof(buf), "%c", ch); ch = fgetc(stdin); } if (strlen(buf) != 0) { ptr = strchr(buf, '='); if (!ptr) parsearg(buf, ""); else { *ptr++ = '\0'; cleanval = unescape(ptr); parsearg(buf, cleanval); free(cleanval); } } } /* called for fatal errors in parseconf like malloc failures */ static void cgilib_err(const char *errmsg) { upslogx(LOG_ERR, "Fatal error in parseconf(ups.conf): %s", errmsg); } int checkhost(const char *host, char **desc) { char fn[NUT_PATH_MAX + 1]; PCONF_CTX_t ctx; if (!host) return 0; /* deny null hostnames */ snprintf(fn, sizeof(fn), "%s/hosts.conf", confpath()); pconf_init(&ctx, cgilib_err); if (!pconf_file_begin(&ctx, fn)) { pconf_finish(&ctx); fprintf(stderr, "%s\n", ctx.errmsg); return 0; /* failed: deny access */ } while (pconf_file_next(&ctx)) { if (pconf_parse_error(&ctx)) { fprintf(stderr, "Error: %s:%d: %s\n", fn, ctx.linenum, ctx.errmsg); continue; } /* MONITOR */ if (ctx.numargs < 3) continue; if (strcmp(ctx.arglist[0], "MONITOR") != 0) continue; if (!strcmp(ctx.arglist[1], host)) { if (desc) *desc = xstrdup(ctx.arglist[2]); pconf_finish(&ctx); return 1; /* found: allow access */ } } pconf_finish(&ctx); return 0; /* not found: access denied */ } nut-2.8.3/clients/nutclientmem.cpp0000644000200500020050000001402514777534445014136 00000000000000/* nutclientmem.cpp - nutclientmem C++ library implementation Copyright (C) 2021 Eric Clappier This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "nutclientmem.h" namespace nut { /* * * Memory Client stub implementation * */ Device MemClientStub::getDevice(const std::string& name) { NUT_UNUSED_VARIABLE(name); throw NutException("Not implemented"); } std::set MemClientStub::getDeviceNames() { throw NutException("Not implemented"); } std::string MemClientStub::getDeviceDescription(const std::string& name) { NUT_UNUSED_VARIABLE(name); throw NutException("Not implemented"); } std::set MemClientStub::getDeviceVariableNames(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } std::set MemClientStub::getDeviceRWVariableNames(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } std::string MemClientStub::getDeviceVariableDescription(const std::string& dev, const std::string& name) { NUT_UNUSED_VARIABLE(dev); NUT_UNUSED_VARIABLE(name); throw NutException("Not implemented"); } ListValue MemClientStub::getDeviceVariableValue(const std::string& dev, const std::string& name) { ListValue res; auto it_dev = _values.find(dev); if (it_dev != _values.end()) { auto map = it_dev->second; auto it_map = map.find(name); if (it_map != map.end()) { res = it_map->second; } } return res; } ListObject MemClientStub::getDeviceVariableValues(const std::string& dev) { ListObject res; auto it_dev = _values.find(dev); if (it_dev != _values.end()) { res = it_dev->second; } return res; } ListDevice MemClientStub::getDevicesVariableValues(const std::set& devs) { ListDevice res; for (auto itr = devs.begin(); itr != devs.end(); itr++) { std::string dev = *itr; auto it_dev = _values.find(dev); if (it_dev != _values.end()) { res.insert(std::pair(dev, it_dev->second)); } } return res; } TrackingID MemClientStub::setDeviceVariable(const std::string& dev, const std::string& name, const std::string& value) { auto it_dev = _values.find(dev); if (it_dev == _values.end()) { ListObject list; _values.emplace(dev, list); it_dev = _values.find(dev); } if (it_dev != _values.end()) { auto map = &(it_dev->second); auto it_map = map->find(name); if (it_map != map->end()) { it_map->second[0] = value; } else { ListValue list_value; list_value.push_back(value); map->emplace(name, list_value); } } return ""; } TrackingID MemClientStub::setDeviceVariable(const std::string& dev, const std::string& name, const ListValue& values) { auto it_dev = _values.find(dev); if (it_dev != _values.end()) { auto map = &(it_dev->second); auto it_map = map->find(name); if (it_map != map->end()) { it_map->second = values; } else { map->emplace(name, values); } } return ""; } std::set MemClientStub::getDeviceCommandNames(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } std::string MemClientStub::getDeviceCommandDescription(const std::string& dev, const std::string& name) { NUT_UNUSED_VARIABLE(dev); NUT_UNUSED_VARIABLE(name); throw NutException("Not implemented"); } TrackingID MemClientStub::executeDeviceCommand(const std::string& dev, const std::string& name, const std::string& param) { NUT_UNUSED_VARIABLE(dev); NUT_UNUSED_VARIABLE(name); NUT_UNUSED_VARIABLE(param); throw NutException("Not implemented"); } std::map> MemClientStub::listDeviceClients(void) { throw NutException("Not implemented"); } std::set MemClientStub::deviceGetClients(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } void MemClientStub::deviceLogin(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } /* Note: "master" is deprecated, but supported * for mixing old/new client/server combos: */ void MemClientStub::deviceMaster(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } void MemClientStub::devicePrimary(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } void MemClientStub::deviceForcedShutdown(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } int MemClientStub::deviceGetNumLogins(const std::string& dev) { NUT_UNUSED_VARIABLE(dev); throw NutException("Not implemented"); } TrackingResult MemClientStub::getTrackingResult(const TrackingID& id) { NUT_UNUSED_VARIABLE(id); throw NutException("Not implemented"); //return TrackingResult::SUCCESS; } bool MemClientStub::isFeatureEnabled(const Feature& feature) { NUT_UNUSED_VARIABLE(feature); throw NutException("Not implemented"); } void MemClientStub::setFeature(const Feature& feature, bool status) { NUT_UNUSED_VARIABLE(feature); NUT_UNUSED_VARIABLE(status); throw NutException("Not implemented"); } } /* namespace nut */ /** * C nutclient API. */ extern "C" { NUTCLIENT_MEM_t nutclient_mem_create_client() { nut::MemClientStub* client = new nut::MemClientStub; try { return static_cast(client); } catch(nut::NutException& ex) { // TODO really catch it NUT_UNUSED_VARIABLE(ex); delete client; return nullptr; } } } /* extern "C" */ nut-2.8.3/clients/status.h0000644000200500020050000000330514777767434012427 00000000000000/* status.h - translation of status abbreviations to descriptions Copyright (C) 1999 Russell Kroll This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NUT_STATUS_H_SEEN #define NUT_STATUS_H_SEEN 1 #ifdef __cplusplus /* *INDENT-OFF* */ extern "C" { /* *INDENT-ON* */ #endif /* This is only used in upsstats.c, but might it also have external consumers?.. * To move or not to move?.. */ static struct { char *name; char *desc; int severity; } stattab[] = { { "OFF", "OFF", 1 }, { "OL", "ONLINE", 0 }, { "OB", "ON BATTERY", 2 }, { "LB", "LOW BATTERY", 2 }, { "RB", "REPLACE BATTERY", 2 }, { "OVER", "OVERLOAD", 2 }, { "TRIM", "VOLTAGE TRIM", 1 }, { "BOOST", "VOLTAGE BOOST", 1 }, { "CAL", "CALIBRATION", 1 }, { "BYPASS", "BYPASS", 2 }, /* NOTE: "ECO" should not be happening as a status * or alarm anymore... in NUT core code base */ { "ECO", "ECO", 1 }, { "ALARM", "ALARM", 2 }, { NULL, NULL, 0 } }; #ifdef __cplusplus /* *INDENT-OFF* */ } /* *INDENT-ON* */ #endif #endif /* NUT_STATUS_H_SEEN */ nut-2.8.3/clients/upssched.c0000644000200500020050000011247214777767434012723 00000000000000/* upssched.c - upsmon's scheduling helper for offset timers Copyright (C) 2000 Russell Kroll This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* design notes for the curious: * * 1. we get called with a upsname and notifytype from upsmon * 2. the config file is searched for an AT condition that matches * 3. the conditions on any matching lines are parsed * * starting a timer: the timer is added to the daemon's timer queue * cancelling a timer: the timer is removed from that queue * execute a command: the command is passed straight to the cmdscript * * if the daemon is not already running and is required (to start a timer) * it will be started automatically * * when the time arrives, the command associated with a timer will be * executed by the daemon (via the cmdscript) * * timers can be cancelled at any time before they trigger * * the daemon will shut down automatically when no more timers are active * */ #include "common.h" #include #ifndef WIN32 # include # include # include # include # include # include # include #else /* WIN32 */ # include "wincompat.h" # include # include #endif /* WIN32 */ #include "upssched.h" #include "timehead.h" #include "nut_stdint.h" typedef struct ttype_s { char *name; time_t etime; struct ttype_s *next; } ttype_t; static ttype_t *thead = NULL; static conn_t *connhead = NULL; static char *cmdscript = NULL, *pipefn = NULL, *lockfn = NULL; /* ups name and notify type (string) as received from upsmon */ static const char *upsname, *notify_type, *prog = NULL; #ifdef WIN32 static OVERLAPPED connect_overlapped; # define BUF_LEN 512 #endif /* WIN32 */ #define PARENT_STARTED -2 #define PARENT_UNNECESSARY -3 #define MAX_TRIES 30 #define EMPTY_WAIT 15 /* min passes with no timers to exit */ #define US_LISTEN_BACKLOG 16 #define US_SOCK_BUF_LEN 256 #define US_MAX_READ 128 /* --- server functions --- */ static void exec_cmd(const char *cmd) { int err; char buf[LARGEBUF]; snprintf(buf, sizeof(buf), "%s %s", cmdscript, cmd); err = system(buf); #ifndef WIN32 if (WIFEXITED(err)) { if (WEXITSTATUS(err)) { upslogx(LOG_INFO, "exec_cmd(%s) returned %d", buf, WEXITSTATUS(err)); } } else { if (WIFSIGNALED(err)) { upslogx(LOG_WARNING, "exec_cmd(%s) terminated with signal %d", buf, WTERMSIG(err)); } else { upslogx(LOG_ERR, "Execute command failure: %s", buf); } } #else /* WIN32 */ if(err != -1) { upslogx(LOG_INFO, "Execute command \"%s\" OK", buf); } else { upslogx(LOG_ERR, "Execute command failure : %s", buf); } #endif /* WIN32 */ return; } static void removetimer(ttype_t *tfind) { ttype_t *tmp, *last; last = NULL; tmp = thead; while (tmp) { if (tmp == tfind) { /* found it */ if (last == NULL) /* deleting first */ thead = tmp->next; else last->next = tmp->next; free(tmp->name); free(tmp); return; } last = tmp; tmp = tmp->next; } /* this one should never happen */ upslogx(LOG_ERR, "removetimer: failed to locate target at %p", (void *)tfind); } static void checktimers(void) { ttype_t *tmp, *tmpnext; time_t now; static int emptyctr = 0; /* if the queue is empty we might be ready to exit */ if (!thead) { emptyctr++; /* wait a little while in case someone wants us again */ if (emptyctr < EMPTY_WAIT) return; if (nut_debug_level) upslogx(LOG_INFO, "Timer queue empty, exiting"); #ifdef UPSSCHED_RACE_TEST upslogx(LOG_INFO, "triggering race: sleeping 15 sec before exit"); sleep(15); #endif upsdebugx(1, "Timer queue empty, closing pipe and exiting upssched daemon"); unlink(pipefn); exit(EXIT_SUCCESS); } emptyctr = 0; /* flip through LL, look for activity */ tmp = thead; time(&now); while (tmp) { tmpnext = tmp->next; if (now >= tmp->etime) { if (nut_debug_level) upslogx(LOG_INFO, "Event: %s ", tmp->name); exec_cmd(tmp->name); /* delete from queue */ removetimer(tmp); } tmp = tmpnext; } } static void start_timer(const char *name, const char *ofsstr) { time_t now; long ofs; ttype_t *tmp, *last; /* get the time */ time(&now); /* add an event for +